前言
FlashDB是一款超轻量级的嵌入式数据库,专注于提供嵌入式产品的数据存储方案。与传统的基于文件系统的数据库不同,FlashDB 结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命。
FlashDB 提供两种数据库模式:
键值数据库 :是一种非关系数据库,它将数据存储为键值(Key-Value)对集合,其中键作为唯一标识符。KVDB 操作简洁,可扩展性强。
时序数据库 :时间序列数据库 (Time Series Database , 简称 TSDB),它将数据按照 时间顺序存储 。TSDB 数据具有时间戳,数据存储量大,插入及查询性能高。
移植步骤
FlashDB 底层的 Flash 管理及操作依赖于 RT-Thread 的 FAL (Flash Abstraction Layer) Flash 抽象层开源软件包 ,所以只需要将所用到的 Flash 对接到 FAL ,即可完成整个移植工作。
FlashDB的移植关键在于FAL的移植,FAL的移植的关键在于在片外flash上搭建FAL,具体步骤如下:
模拟SPI读写功能的实现(板子画错了,因此使用模拟SPI);//后续有机会添加会根据spi-bit-ops来实现模拟spi
挂载片外Flash(GD25Q16);
搭建FAL抽象层;
对接FlashDB。
1.模拟SPI读写功能的实现
1.1 新建一个空白的项目(不具体描述了吧)
1.2 在/board/Kconfig内添加以下内容,不清楚的话,需要回去了解一下RTT的构建与配置系统
menuconfig BSP_USING_SOFT_SPI_FLASH
bool "Enable SOFT SPI Flash(SOFT SPI)"
default n
select RT_USING_SPI
# select RT_USING_SPI_BITOPS
# select RT_SPI_BITOPS_DEBUG
select RT_USING_SFUD
if BSP_USING_SOFT_SPI_FLASH
config SOFT_SPI_FLASH_NAME
string "soft spi flash device name"
default "GD25Q16"
config SOFT_SPI_FLASH_BUS_NAME
string "spi flash bus name"
default "soft_spi1"
config SOFT_SPI_FLASH_DEVICE_NAME
string "spi flash device name"
default "soft_spi10"
endif
RTT的构建与配置系统:
1.3 在SConscript内添加以下内容,不清楚的话,需要回去了解一下RTT的构建与配置系统
path += [cwd + '/on-chip_drivers']
···
if GetDepend('BSP_USING_SOFT_SPI_FLASH'):
src += ['on-chip_drivers/soft_spi_flash.c']
src += ['on-chip_drivers/drv_soft_spi.c']
1.4 在hal_drivers下添加文件夹/on-chip_drivers,在文件夹内添加drv_soft_spi.c/drv_soft_spi.h/soft_spi_flash.c文件
drv_soft_spi.c:
/*
- Change Logs:
- Date Author Notes
- 2020-05-20 Roy.yu first version
- 2022-08-14 MXH fit ch32v307
*/
#include "board.h"
#include "rtconfig.h"
#ifdef BSP_USING_SOFT_SPI_FLASH
#include "drv_soft_spi.h"
#include <string.h>
//#define DRV_DEBUG
#define LOG_TAG "drv.spisoft"
#include <drv_log.h>
//enum{
// SOFT_SPI1_INDEX,
//};
#define SOFT_SPI1_BUS_CONFIG { \
.mosi_pin.GPIOx = GPIOD, \
.mosi_pin.GPIO_Pin = GPIO_Pin_4, \
.miso_pin.GPIOx = GPIOB, \
.miso_pin.GPIO_Pin = GPIO_Pin_5, \
.sclk_pin.GPIOx = GPIOD, \
.sclk_pin.GPIO_Pin = GPIO_Pin_6, \
.bus_name = "soft_spi1", \
}
//#define SOFT_SPI1_BUS_CONFIG { \
// .mosi_pin.GPIOx = GPIOB, \
// .mosi_pin.GPIO_Pin = GPIO_Pin_5, \
// .miso_pin.GPIOx = GPIOB, \
// .miso_pin.GPIO_Pin = GPIO_Pin_4, \
// .sclk_pin.GPIOx = GPIOB, \
// .sclk_pin.GPIO_Pin = GPIO_Pin_3, \
// .bus_name = "soft_spi1", \
//}
static struct ch32_soft_spi_config soft_spi_config[] ={
SOFT_SPI1_BUS_CONFIG,
};
static struct ch32_soft_spi soft_spi_bus_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])] = {0};
static rt_err_t ch32_spi_init(struct ch32_soft_spi *spi_drv, struct rt_spi_configuration *cfg)
{
RT_ASSERT(spi_drv != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
if (cfg->mode & RT_SPI_SLAVE){
return RT_EIO;
}
else
spi_drv->mode = RT_SPI_MASTER;
if (cfg->mode & RT_SPI_3WIRE){
return RT_EIO;
}
if (cfg->data_width == 8 || cfg->data_width == 16)
spi_drv->data_width = cfg->data_width;
else{
return RT_EIO;
}
if (cfg->mode & RT_SPI_CPHA){
spi_drv->cpha = 1;
}
else{
spi_drv->cpha = 0;
}
if (cfg->mode & RT_SPI_CPOL){
spi_drv->cpol = 1;
}
else{
spi_drv->cpol = 0;
}
if (cfg->mode & RT_SPI_NO_CS){
}
else{
}
if (cfg->max_hz >= 1200000){
spi_drv->spi_delay = 0;
}else if (cfg->max_hz >= 1000000){
spi_drv->spi_delay = 8;
}else if (cfg->max_hz >= 830000){
spi_drv->spi_delay = 16;
}
LOG_D("SPI limiting freq: %d, BaudRatePrescaler: %d",
cfg->max_hz,
spi_drv->spi_delay);
if (cfg->mode & RT_SPI_MSB){
spi_drv->msb = 1;
}
else{
spi_drv->msb = 0;
}
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = spi_drv->config->mosi_pin.GPIO_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(spi_drv->config->mosi_pin.GPIOx, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = spi_drv->config->miso_pin.GPIO_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(spi_drv->config->miso_pin.GPIOx, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = spi_drv->config->sclk_pin.GPIO_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(spi_drv->config->sclk_pin.GPIOx, &GPIO_InitStruct);
// GPIO_Initure.Pin = spi_drv->config->mosi_pin.GPIO_Pin;
// GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_Initure.Pull = GPIO_PULLUP;
// GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// HAL_GPIO_Init(spi_drv->config->mosi_pin.GPIOx, &GPIO_Initure);
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx, spi_drv->config->mosi_pin.GPIO_Pin, GPIO_PIN_RESET);
// GPIO_Initure.Pin = spi_drv->config->miso_pin.GPIO_Pin;
// GPIO_Initure.Mode = GPIO_MODE_INPUT;
// GPIO_Initure.Pull = GPIO_NOPULL;
// GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// HAL_GPIO_Init(spi_drv->config->miso_pin.GPIOx, &GPIO_Initure);
// GPIO_Initure.Pin = spi_drv->config->sclk_pin.GPIO_Pin;
// GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_Initure.Pull = GPIO_PULLUP;
// GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// HAL_GPIO_Init(spi_drv->config->sclk_pin.GPIOx, &GPIO_Initure);
if(spi_drv->cpol)
// HAL_GPIO_WritePin(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin,GPIO_PIN_SET);
GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin, 1);
else
// HAL_GPIO_WritePin(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin,GPIO_PIN_RESET);
GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx,spi_drv->config->sclk_pin.GPIO_Pin, 0);
LOG_D("%s init done", spi_drv->config->bus_name);
return RT_EOK;
}
static inline void spi_delay(uint8_t time){
switch(time){
case 16:__NOP();
case 15:__NOP();
case 14:__NOP();
case 13:__NOP();
case 12:__NOP();
case 11:__NOP();
case 10:__NOP();
case 9:__NOP();
case 8:__NOP();
case 7:__NOP();
case 6:__NOP();
case 5:__NOP();
case 4:__NOP();
case 3:__NOP();
case 2:__NOP();
case 1:__NOP();
default:
break;
}
}
static rt_uint32_t soft_spi_read_write_bytes(struct ch32_soft_spi spi_drv, uint8_t send_buff, uint8_t* recv_buff, uint32_t len){
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha){ //CPHA=1
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
if(spi_drv->data_width == 16)
time = 1;
else
time = 0;
do{
for(uint8_t j = 0; j < 8; j++){
if ((send_buff[dataIndex] & 0x80) != 0){
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_SET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,1);
}else{
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_RESET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,0);
}
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
recv_buff[dataIndex] <<= 1;
// if (HAL_GPIO_ReadPin(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
if (GPIO_ReadInputDataBit(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff[dataIndex] |= 0x01;
spi_delay(spi_drv->spi_delay);
// if(time != 0 || j != 7){
if(time != 0 || j != 7 || spi_drv->cpha == 0){
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t soft_spi_read_bytes(struct ch32_soft_spi spi_drv, uint8_t recv_buff, uint32_t len){
uint8_t send_buff = spi_drv->dummy_data;
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha){ //CPHA=1
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
if(spi_drv->data_width == 16)
time = 1;
else
time = 0;
do{
for(uint8_t j = 0; j < 8; j++){
if ((send_buff & 0x80) != 0){
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_SET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,1);
}else{
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_RESET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,0);
}
send_buff <<= 1;
spi_delay(spi_drv->spi_delay);
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
recv_buff[dataIndex] <<= 1;
// if (HAL_GPIO_ReadPin(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
if (GPIO_ReadInputDataBit(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff[dataIndex] |= 0x01;
spi_delay(spi_drv->spi_delay);
// if(time != 0 || j != 7){
if(time != 0 || j != 7 || spi_drv->cpha == 0){
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t soft_spi_write_bytes(struct ch32_soft_spi spi_drv, uint8_t send_buff, uint32_t len){
uint8_t recv_buff = 0;
uint32_t dataIndex = 0;
uint8_t time = 0;
for(uint32_t i = 0; i<len; i++){
if(spi_drv->cpha){ //CPHA=1
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
if(spi_drv->data_width == 16)
time = 1;
else
time = 0;
do{
for(uint8_t j = 0; j < 8; j++){
if ((send_buff[dataIndex] & 0x80) != 0){
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_SET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,1);
}else{
// HAL_GPIO_WritePin(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,GPIO_PIN_RESET);
GPIO_WriteBit(spi_drv->config->mosi_pin.GPIOx,spi_drv->config->mosi_pin.GPIO_Pin,0);
}
send_buff[dataIndex] <<= 1;
spi_delay(spi_drv->spi_delay);
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
recv_buff <<= 1;
// if (HAL_GPIO_ReadPin(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
if (GPIO_ReadInputDataBit(spi_drv->config->miso_pin.GPIOx, spi_drv->config->miso_pin.GPIO_Pin))
recv_buff |= 0x01;
spi_delay(spi_drv->spi_delay);
// if(time != 0 || j != 7){
if(time != 0 || j != 7 || spi_drv->cpha == 0){
// HAL_GPIO_TogglePin(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin);
// GPIO_WriteBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin,
// (GPIO_ReadOutputDataBit(spi_drv->config->sclk_pin.GPIOx, spi_drv->config->sclk_pin.GPIO_Pin) ? 0 : 1));
spi_drv->config->sclk_pin.GPIOx->OUTDR ^= spi_drv->config->sclk_pin.GPIO_Pin;
}
}
dataIndex++;
}while(time--);
spi_delay(spi_drv->spi_delay);
}
return len;
}
static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message){
rt_uint32_t state;
rt_size_t message_length;
rt_uint8_t *recv_buf;
const rt_uint8_t *send_buf;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
RT_ASSERT(device->bus->parent.user_data != RT_NULL);
RT_ASSERT(message != RT_NULL);
struct ch32_soft_spi *spi_drv = rt_container_of(device->bus, struct ch32_soft_spi, spi_bus);
struct ch32_soft_spi_pin *cs = device->parent.user_data;
if (message->cs_take){
// HAL_GPIO_WritePin(cs->GPIOx, cs->GPIO_Pin, GPIO_PIN_RESET);
GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, 0);
}
LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
spi_drv->config->bus_name,
(uint32_t)message->send_buf,
(uint32_t)message->recv_buf, message->length);
message_length = message->length;
recv_buf = message->recv_buf;
send_buf = message->send_buf;
if(message_length){
if (message->send_buf && message->recv_buf){
state = soft_spi_read_write_bytes(spi_drv, (uint8_t *)send_buf, (uint8_t *)recv_buf, message_length);
}
else if (message->send_buf){
state = soft_spi_write_bytes(spi_drv, (uint8_t *)send_buf, message_length);
}
else{
memset((uint8_t *)recv_buf, 0xff, message_length);
state = soft_spi_read_bytes(spi_drv, (uint8_t *)recv_buf, message_length);
}
if (state != message_length){
LOG_I("spi transfer error : %d", state);
message->length = 0;
}
else{
LOG_D("%s transfer done", spi_drv->config->bus_name);
}
}
if (message->cs_release){
// HAL_GPIO_WritePin(cs->GPIOx, cs->GPIO_Pin, GPIO_PIN_SET);
GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, 1);
}
return message->length;
}
static rt_err_t spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *configuration){
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
struct ch32_soft_spi *spi_drv = rt_container_of(device->bus, struct ch32_soft_spi, spi_bus);
spi_drv->cfg = configuration;
return ch32_spi_init(spi_drv, configuration);
}
static const struct rt_spi_ops ch_spi_ops ={
.configure = spi_configure,
.xfer = spixfer,
};
static int rt_soft_spi_bus_init(void){
rt_err_t result
for (int i = 0
soft_spi_bus_obj[i].config = &soft_spi_config[i]
soft_spi_bus_obj[i].spi_bus.parent.user_data = &soft_spi_config[i]
result = rt_spi_bus_register(&soft_spi_bus_obj[i].spi_bus, soft_spi_config[i].bus_name, &ch_spi_ops)
RT_ASSERT(result == RT_EOK)
LOG_D("%s bus init done", soft_spi_config[i].bus_name)
}
return result
}
/**
- Attach the spi device to SPI bus, this function must be used after initialization.
*/
rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin){
RT_ASSERT(bus_name != RT_NULL);
RT_ASSERT(device_name != RT_NULL);
rt_err_t result;
struct rt_spi_device *spi_device;
struct ch32_soft_spi_pin *cs_pin;
GPIO_InitTypeDef GPIO_InitStruct;
// GPIO_Initure.Pin = cs_gpio_pin;
// GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_Initure.Pull = GPIO_PULLUP;
// GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
// HAL_GPIO_Init(cs_gpiox, &GPIO_Initure);
// HAL_GPIO_WritePin(cs_gpiox, cs_gpio_pin, GPIO_PIN_SET);
GPIO_InitStruct.GPIO_Pin = cs_gpio_pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(cs_gpiox, &GPIO_InitStruct);
spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
RT_ASSERT(spi_device != RT_NULL);
cs_pin = (struct ch32_soft_spi_pin *)rt_malloc(sizeof(struct ch32_soft_spi_pin));
RT_ASSERT(cs_pin != RT_NULL);
cs_pin->GPIOx = cs_gpiox;
cs_pin->GPIO_Pin = cs_gpio_pin;
result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
if (result != RT_EOK){
LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
}
RT_ASSERT(result == RT_EOK);
LOG_D("%s attach to %s done", device_name, bus_name);
return result;
}
int rt_soft_spi_init(void){
return rt_soft_spi_bus_init();
}
INIT_PREV_EXPORT(rt_soft_spi_init);
#endif /* RT_USING_SPI */
drv_soft_spi.h:
/*
- Change Logs:
- Date Author Notes
- 2020-05-20 Roy.yu first version
- 2022-08-14 MXH fit ch32v307
- Only for MSB
*/
#ifndef _DRV_SOFT_SPI_H
#define _DRV_SOFT_SPI_H
#include <rtthread.h>
#include "rtdevice.h"
#include <rthw.h>
#include "ch32v30x.h"
rt_err_t rt_soft_spi_device_attach(const char *bus_name, const char device_name, GPIO_TypeDef cs_gpiox, uint16_t cs_gpio_pin);
struct ch32_soft_spi_pin
{
GPIO_TypeDef* GPIOx;
uint16_t GPIO_Pin;
};
struct ch32_soft_spi_config
{
struct ch32_soft_spi_pin mosi_pin;
struct ch32_soft_spi_pin miso_pin;
struct ch32_soft_spi_pin sclk_pin;
char *bus_name;
};
struct ch32_soft_spi_device
{
rt_uint8_t cs_pin;
char *bus_name;
char *device_name;
};
/* stm32 soft spi dirver class */
struct ch32_soft_spi
{
uint8_t mode;
uint8_t cpha;
uint8_t cpol;
uint8_t data_width;
uint8_t msb;
uint16_t dummy_data;
uint32_t spi_delay;
struct ch32_soft_spi_config *config;
struct rt_spi_configuration *cfg;
struct rt_spi_bus spi_bus;
};
#endif /*_DRV_SOFT_SPI_H */
1.5 RT-Thread Settings配置
打开相应开关即可
1.6 效果(图片是最终效果,实际可以看到SPI BUS设备即可)
2.挂载片外Flash(GD25Q16)
2.1 soft_spi_flash.c添加以下代码:
/*
- Copyright (c) 2006-2022, RT-Thread Development Team
- SPDX-License-Identifier: Apache-2.0
- Change Logs:
- Date Author Notes
- 2022-08-14 MXH the first version
*/
#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_soft_spi.h"
#include "fal.h"
static int rt_sw_spi_flash_init(void)
{
rt_soft_spi_device_attach(SOFT_SPI_FLASH_BUS_NAME, SOFT_SPI_FLASH_DEVICE_NAME, GPIOB, GPIO_Pin_3);
// rt_soft_spi_device_attach(SOFT_SPI_FLASH_BUS_NAME, SOFT_SPI_FLASH_DEVICE_NAME, GPIOA, GPIO_Pin_15);
if (RT_NULL == rt_sfud_flash_probe(SOFT_SPI_FLASH_NAME, SOFT_SPI_FLASH_DEVICE_NAME))
{
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_sw_spi_flash_init);
2.2 效果(图片是最终效果,实际可以看到SPI Device、GD25Q16即可)
3.搭建FAL抽象层
3.1 开启FAL组件
3.2 打开fal组件的文件夹,可以看到/samples/porting中可以看到例程
将fal_cfg.h添加到/fal/inc文件夹下,并进行一定的修改,片内flash好像还有一定问题,暂时删去:
/*
- Copyright (c) 2006-2018, RT-Thread Development Team
- SPDX-License-Identifier: Apache-2.0
- Change Logs:
- Date Author Notes
- 2018-05-17 armink the first version
*/
#ifndef FAL_CFG_H
#define FAL_CFG_H
#include <rtconfig.h>
#include <board.h>
/* ===================== Flash device Configuration ========================= */
//extern const struct fal_flash_dev ch32_onchip_flash;
extern struct fal_flash_dev gd25q16_flash;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&gd25q16_flash, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "flashkv", SOFT_SPI_FLASH_NAME, 0, 8 * 1024, 0},\
{FAL_PART_MAGIC_WORD, "flashts", SOFT_SPI_FLASH_NAME, 8 * 1024, 2040 * 1024, 0},\
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* FAL_CFG_H */
3.3 soft_spi_flash.c修改为以下内容:
/*
- Copyright (c) 2006-2022, RT-Thread Development Team
- SPDX-License-Identifier: Apache-2.0
- Change Logs:
- Date Author Notes
- 2022-07-27 MXH the first version
*/
#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_soft_spi.h"
#include "fal.h"
#ifdef BSP_USING_SOFT_SPI_FLASH
static int rt_sw_spi_flash_init(void)
{
rt_soft_spi_device_attach(SOFT_SPI_FLASH_BUS_NAME, SOFT_SPI_FLASH_DEVICE_NAME, GPIOB, GPIO_Pin_3);
// rt_soft_spi_device_attach(SOFT_SPI_FLASH_BUS_NAME, SOFT_SPI_FLASH_DEVICE_NAME, GPIOA, GPIO_Pin_15);
if (RT_NULL == rt_sfud_flash_probe(SOFT_SPI_FLASH_NAME, SOFT_SPI_FLASH_DEVICE_NAME))
{
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_sw_spi_flash_init);
static int init(void);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
static int erase(long offset, size_t size);
static sfud_flash_t gd25q16_dev = NULL;
struct fal_flash_dev gd25q16_flash =
{
SOFT_SPI_FLASH_NAME,
0,
(2 * 1024 * 1024),
4096,
{
init,
read,
write,
erase
},
1
};
static int init(void)
{
#ifdef RT_USING_SFUD
gd25q16_dev = rt_sfud_flash_find_by_dev_name(SOFT_SPI_FLASH_NAME);
if(gd25q16_dev)
{
LOG_D("find flash dev %s.", gd25q16_dev->name);
}
else
{
LOG_E("don't find flash dev %s.", gd25q16_dev->name);
}
#else
extern sfud_flash sfud_norflash0;
gd25q16_dev = &sfud_norflash0;
#endif
if (NULL == gd25q16_dev)
{
return -RT_ERROR;
}
gd25q16_flash.blk_size = gd25q16_dev->chip.erase_gran;
gd25q16_flash.len = gd25q16_dev->chip.capacity;
return RT_EOK;
}
static int read(long offset, uint8_t *buf, size_t size)
{
assert(gd25q16_dev);
assert(gd25q16_dev->init_ok);
sfud_read(gd25q16_dev, gd25q16_flash.addr + offset, size, buf);
return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
assert(gd25q16_dev);
assert(gd25q16_dev->init_ok);
if (sfud_write(gd25q16_dev, gd25q16_flash.addr + offset, size, buf) != SFUD_SUCCESS)
{
return -RT_ERROR;
}
return size;
}
static int erase(long offset, size_t size)
{
assert(gd25q16_dev);
assert(gd25q16_dev->init_ok);
if (sfud_erase(gd25q16_dev, gd25q16_flash.addr + offset, size) != SFUD_SUCCESS)
{
return -RT_ERROR;
}
return size;
}
#endif/* end of BSP_USING_SOFT_SPI_FLASH */
3.4 在main.c中添加初始化代码
3.5 效果
4.对接FlashDB(这一步可以先把main函数里的初始化给删掉,不影响结果)
4.1 搜索并添加FlashDB软件包,默认配置如下
4.2 在/applications文件夹下添加database.c,代码内容如下
#include <stdio.h>
#include <board.h>
#include "rtthread.h"
#include <flashdb.h>
#include "drivers/rtc.h"
#include "time.h"
#define FDB_LOG_TAG "FLASHDB"
/* key */
#define KEY_BOOT_COUNT "boot_count"
#define KEY_DEVICE_ID "device_id"
/* value */
static uint32_t value_boot_count = 0;
static char value_device_id[] = "54549921";
/* kvdb & tsdb */
struct fdb_kvdb _global_kvdb = {0};
struct fdb_tsdb _global_tsdb = {0};
/* kvdb table */
static struct fdb_default_kv_node default_kv_table[] = {
{
KEY_BOOT_COUNT,
&value_boot_count,
sizeof(value_boot_count)
},
{
KEY_DEVICE_ID,
value_device_id,
sizeof(value_device_id)
}
}; /* int type KV */
static fdb_time_t get_time(void)
{
return (fdb_time_t)time(RT_NULL);
}
static int print_system_info(void)
{
struct fdb_blob blob;
{
fdb_kv_get_blob(&_global_kvdb, KEY_DEVICE_ID, fdb_blob_make(&blob, value_device_id, sizeof(value_device_id)));
if (blob.saved.len > 0) {
FDB_INFO("get the 'device_id' value is %s\n", value_device_id);
} else {
FDB_INFO("get the 'device_id' failed\n");
{
fdb_kv_set_blob(&_global_kvdb, KEY_DEVICE_ID, fdb_blob_make(&blob, value_device_id, sizeof(value_device_id)));
FDB_INFO("set the 'device_id' value to %s\n", value_device_id);
}
}
}
{
fdb_kv_get_blob(&_global_kvdb, KEY_BOOT_COUNT, fdb_blob_make(&blob, &value_boot_count, sizeof(value_boot_count)));
if (blob.saved.len > 0) {
FDB_INFO("get the 'boot_count' value is %d\n", value_boot_count);
} else {
FDB_INFO("get the 'boot_count' failed\n");
}
}
{
value_boot_count ++;
fdb_kv_set_blob(&_global_kvdb, KEY_BOOT_COUNT, fdb_blob_make(&blob, &value_boot_count, sizeof(value_boot_count)));
FDB_INFO("set the 'boot_count' value to %d\n", value_boot_count);
}
FDB_INFO("===========================================================\n");
}
static int datbase_init(void)
{
fdb_err_t result;
struct fdb_default_kv default_kv;
default_kv.kvs = default_kv_table;
default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);
result = fdb_kvdb_init(&_global_kvdb, "sys_info", "flashkv", &default_kv, NULL);
if (result != FDB_NO_ERR)
{
return -RT_ERROR;
}
else
{
print_system_info();
}
result = fdb_tsdb_init(&_global_tsdb, "storage_data", "flashts", get_time, 128, RT_NULL);
if (result != FDB_NO_ERR)
{
return -RT_ERROR;
}
else
{
extern void tsdb_sample(fdb_tsdb_t tsdb);
tsdb_sample(&_global_tsdb);
FDB_INFO("init tsdb success.\n");
}
return RT_EOK;
}
INIT_ENV_EXPORT(datbase_init);
4.3 效果
原作者:喵小黑