- /*
- * This file is part of the Serial Flash Universal Driver Library.
- *
- * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * 'Software'), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Function: Portable interface for each platform.
- * Created on: 2016-04-23
- */
- #include <sfud.h>
- #include <stdarg.h>
- #include "debug.h"
- typedef struct {
- SPI_TypeDef *spix;
- GPIO_TypeDef *cs_gpiox;
- uint16_t cs_gpio_pin;
- } spi_user_data, *spi_user_data_t;
- static char log_buf[32];
- void sfud_log_debug(const char *file, const long line, const char *format, ...);
- static void spi_lock(const sfud_spi *spi) {
- //__disable_irq();
- }
- static void spi_unlock(const sfud_spi *spi) {
- //__enable_irq();
- }
- /**
- * SPI write data then read data
- */
- static sfud_err spi_write_read(const sfud_spi *spi,const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
- size_t read_size) {
- sfud_err result = SFUD_SUCCESS;
- uint8_t send_data, read_data;
- spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;
- if (write_size) {
- SFUD_ASSERT(write_buf);
- }
- if (read_size) {
- SFUD_ASSERT(read_buf);
- }
- /**
- * add your spi write and read code
- */
- GPIO_WriteBit(spi_dev->cs_gpiox,spi_dev->cs_gpio_pin, Bit_RESET);//片选
- /* 开始读写数据 */
- for (size_t i = 0, retry_times; i < write_size + read_size; i++) {
- /* 先写缓冲区中的数据到 SPI 总线,数据写完后,再写 dummy(0xFF) 到 SPI 总线 */
- if (i < write_size) {
- send_data = *write_buf++;
- } else {
- send_data = SFUD_DUMMY_DATA;
- }
- /* 发送数据 */
- retry_times = 1000;
- while (SPI_I2S_GetFlagStatus(spi_dev->spix,SPI_I2S_FLAG_TXE) == RESET) {
- SFUD_RETRY_PROCESS(NULL, retry_times, result);
- }
- if (result != SFUD_SUCCESS) {
- goto exit;
- }
- SPI_I2S_SendData(spi_dev->spix,send_data);
- retry_times = 1000;
- while (SPI_I2S_GetFlagStatus(spi_dev->spix, SPI_I2S_FLAG_RXNE) == RESET) {
- SFUD_RETRY_PROCESS(NULL, retry_times, result);
- }
- if (result != SFUD_SUCCESS) {
- goto exit;
- }
- read_data = SPI_I2S_ReceiveData(spi_dev->spix);
- /* 写缓冲区中的数据发完后,再读取 SPI 总线中的数据到读缓冲区 */
- if (i >= write_size) {
- *read_buf++ = read_data;
- }
- }
- exit:
- GPIO_WriteBit(spi_dev->cs_gpiox,spi_dev->cs_gpio_pin, Bit_SET);//片选
- return result;
- }
- /* about 100 us delay */
- static void retry_delay_100us(void) {
- uint32_t delay = 100;
- while(delay--);
- }
- #ifdef SFUD_USING_QSPI
- /**
- * read flash data by QSPI
- */
- static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
- uint8_t *read_buf, size_t read_size) {
- sfud_err result = SFUD_SUCCESS;
- /**
- * add your qspi read flash data code
- */
- return result;
- }
- #endif /* SFUD_USING_QSPI */
- static spi_user_data spi1 = { .spix = FLASH_SPI, .cs_gpiox = FLASH_CS_GPIO_Port, .cs_gpio_pin = FLASH_CS_Pin };
- sfud_err sfud_spi_port_init(sfud_flash *flash) {
- sfud_err result = SFUD_SUCCESS;
- /**
- * add your port spi bus and device object initialize code like this:
- * 1. rcc initialize
- * 2. gpio initialize
- * 3. spi device initialize
- * 4. flash->spi and flash->retry item initialize
- * flash->spi.wr = spi_write_read; //Required
- * flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable
- * flash->spi.lock = spi_lock;
- * flash->spi.unlock = spi_unlock;
- * flash->spi.user_data = &spix;
- * flash->retry.delay = null;
- * flash->retry.times = 10000; //Required
- */
- flash->spi.wr = spi_write_read;
- flash->spi.lock = spi_lock;
- flash->spi.unlock = spi_unlock;
- flash->spi.user_data = &spi1;
- flash->retry.delay = retry_delay_100us;
- flash->retry.times = 60 * 10000;
- return result;
- }
- /**
- * This function is print debug info.
- *
- * @param file the file which has call this function
- * @param line the line number which has call this function
- * @param format output format
- * @param ... args
- */
- void sfud_log_debug(const char *file, const long line, const char *format, ...) {
- va_list args;
- /* args point to the first variable parameter */
- va_start(args, format);
- printf("[SFUD](%s:%ld) ", file, line);
- /* must use vprintf to print */
- vsnprintf(log_buf, sizeof(log_buf), format, args);
- printf("%s\n", log_buf);
- va_end(args);
- }
- /**
- * This function is print routine info.
- *
- * @param format output format
- * @param ... args
- */
- void sfud_log_info(const char *format, ...) {
- va_list args;
- /* args point to the first variable parameter */
- va_start(args, format);
- printf("[SFUD]");
- /* must use vprintf to print */
- vsnprintf(log_buf, sizeof(log_buf), format, args);
- printf("%s\n", log_buf);
- va_end(args);
- }
2)修改sfud_cfg.h,主要配置设备表
- /*
- * @Author: liuxingguo 1017041908@qq.com
- * @Date: 2024-05-16 17:33:32
- * @LastEditors: liuxingguo 1017041908@qq.com
- * @LastEditTime: 2024-06-11 17:24:01
- * @FilePath: \BG9801PG-02H-MCU-MB-AA1X0\User\SFUD\Inc\sfud_cfg.h
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
- /*
- * This file is part of the Serial Flash Universal Driver Library.
- *
- * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * 'Software'), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Function: It is the configure head file for this library.
- * Created on: 2016-04-23
- */
- #ifndef _SFUD_CFG_H_
- #define _SFUD_CFG_H_
- #include "debug.h"
- //#define SFUD_DEBUG_MODE
- //#define SFUD_INFO
- #define FLASH_SPI SPI3 //这里定义SPI
- //使能SFDP:JEDEC标准(JESD216)标准接口
- //注意:关闭后只会查询该库在 /sfud/inc/sfud_flash_def.h 中提供的Flash 信息表
- //这样虽然会降低软件的适配性,但减少代码量
- #define SFUD_USING_SFDP
- //#define SFUD_USING_FAST_READ 只有在QSPI下有用
- //是否使用该库自带的 Flash 参数信息表注意:关闭后该库只驱动支持 SFDP 规范的 Flash,也会适当的降低部分代码量。
- //另外 2.3.2 及 2.3.3 这两个宏定义至少定义一种,也可以两种方式都选择
- #define SFUD_USING_FLASH_INFO_TABLE
- enum {
- SFUD_W25Q_DEVICE_INDEX = 0,
- };
- //定义设备表
- #define SFUD_FLASH_DEVICE_TABLE \
- { \
- [SFUD_W25Q_DEVICE_INDEX] = {.name = "W25Q32JV", .spi.name = "SPI3"}, \
- }
- //#define SFUD_USING_QSPI
- #endif /* _SFUD_CFG_H_ */
3)修改fal_cfg.h
主要根据需要修改定义fal_flash_dev设备结构体
- /*
- * Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #ifndef _FAL_CFG_H_
- #define _FAL_CFG_H_
- #define FAL_DEBUG 1
- #define FAL_PART_HAS_TABLE_CFG
- #define FAL_USING_SFUD_PORT
- /* ===================== Flash device Configuration ========================= */
- extern struct fal_flash_dev nor_flash0;
- /* flash device table */
- #define FAL_FLASH_DEV_TABLE \
- { \
- &nor_flash0, \
- }
- /* ====================== Partition Configuration ========================== */
- #ifdef FAL_PART_HAS_TABLE_CFG
- /* partition table */
- #define FAL_PART_TABLE \
- { \
- {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "norflash0", 0, 1024*1024, 0}, \
- {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "norflash0", 1024*1024, 1024*1024, 0}, \
- }
- #endif /* FAL_PART_HAS_TABLE_CFG */
- #endif /* _FAL_CFG_H_ */
4)修改sfud.c中flash相关参数配置,如下
- sfud_flash sfud_norflash0 = {
- .name = "norflash0",
- .spi.name = "SPI3",
- .chip = { "W25Q32JV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 4L * 1024L * 1024L, SFUD_WM_PAGE_256B, 4096, 0x20 } };
同时封装一下初始化SFUD的函数
- int spi_sfud_init(void)
- {
- /* SFUD initialize */
- if (sfud_device_init(&sfud_norflash0) == SFUD_SUCCESS) {
- return 0;
- } else {
- return -1;
- }
- }
5)在fdb_cfg.h中定义FDB_WRITE_GRAN的写入粒度的值否则会报错
- define FDB_WRITE_GRAN 1 /* @NOTE you must define it for a value */
6、在主函数中添加初始化,代码如下
- /********************************** (C) COPYRIGHT *******************************
- * File Name : main.c
- * Author : WCH
- * Version : V1.0.0
- * Date : 2021/06/06
- * Description : Main program body.
- *********************************************************************************
- * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
- * Attention: This software (modified or not) and binary are used for
- * microcontroller manufactured by Nanjing Qinheng Microelectronics.
- *******************************************************************************/
- /*
- *@Note
- USART Print debugging routine:
- USART1_Tx(PA9).
- This example demonstrates using USART1(PA9) as a print debug port output.
- */
- #include "debug.h"
- #include <flashdb.h>
- #include <sfud.h>
- /* Global typedef */
- /* Global define */
- /* Global Variable */
- #define FDB_LOG_TAG "[main]"
- static uint32_t boot_count = 0;
- static time_t boot_time[10] = {0, 1, 2, 3};
- /* default KV nodes */
- static struct fdb_default_kv_node default_kv_table[] = {
- {"username", "armink", 0}, /* string KV */
- {"password", "123456", 0}, /* string KV */
- {"boot_count", &boot_count, sizeof(boot_count)}, /* int type KV */
- {"boot_time", &boot_time, sizeof(boot_time)}, /* int array type KV */
- };
- /* KVDB object */
- static struct fdb_kvdb kvdb = { 0 };
- /* TSDB object */
- struct fdb_tsdb tsdb = { 0 };
- /* counts for simulated timestamp */
- static int counts = 0;
- extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
- extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
- extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
- extern void tsdb_sample(fdb_tsdb_t tsdb);
- void SPI_Flash_Init(void);
- int8_t Flash_DbTest(void);
- static void lock(fdb_db_t db)
- {
- __disable_irq();
- }
- static void unlock(fdb_db_t db)
- {
- __enable_irq();
- }
- static fdb_time_t get_time(void)
- {
- /* Using the counts instead of timestamp.
- * Please change this function to return RTC time.
- */
- return ++counts;
- }
- /*********************************************************************
- * @fn main
- *
- * @brief Main program.
- *
- * @return none
- */
- int main(void)
- {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- SystemCoreClockUpdate();
- Delay_Init();
- USART_Printf_Init(115200);
- printf("SystemClk:%d\r\n",SystemCoreClock);
- printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
- printf("This is printf example\r\n");
- SPI_Flash_Init();//初始化SPI内部函数
- spi_sfud_init();//初始化SFUD 驱动
- Flash_DbTest();//运行测试例子
- while(1)
- {
- }
- }
- /*********************************************************************
- * @fn SPI_Flash_Init
- *
- * @brief Configuring the SPI for operation flash.
- *
- * @return none
- */
- void SPI_Flash_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- SPI_InitTypeDef SPI_InitStructure = {0};
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOE, ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOE, &GPIO_InitStructure);
- GPIO_SetBits(GPIOE, GPIO_Pin_6);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init(SPI3, &SPI_InitStructure);
- SPI_Cmd(SPI3, ENABLE);
- }
- int8_t Flash_DbTest(void) {
- fdb_err_t result;
- #ifdef FDB_USING_KVDB
- { /* KVDB Sample */
- struct fdb_default_kv default_kv;
- default_kv.kvs = default_kv_table;
- default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);
- /* set the lock and unlock function if you want */
- fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)lock);
- fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)unlock);
- /* Key-Value database initialization
- *
- * &kvdb: database object
- * "env": database name
- * "fdb_kvdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
- * Please change to YOUR partition name.
- * &default_kv: The default KV nodes. It will auto add to KVDB when first initialize successfully.
- * NULL: The user data if you need, now is empty.
- */
- result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, NULL);
- if (result != FDB_NO_ERR) {
- return -1;
- }
- /* run basic KV samples */
- kvdb_basic_sample(&kvdb);
- /* run string KV samples */
- kvdb_type_string_sample(&kvdb);
- /* run blob KV samples */
- kvdb_type_blob_sample(&kvdb);
- }
- #endif /* FDB_USING_KVDB */
- #ifdef FDB_USING_TSDB
- { /* TSDB Sample */
- /* set the lock and unlock function if you want */
- fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)lock);
- fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)unlock);
- /* Time series database initialization
- *
- * &tsdb: database object
- * "log": database name
- * "fdb_tsdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
- * Please change to YOUR partition name.
- * get_time: The get current timestamp function.
- * 128: maximum length of each log
- * NULL: The user data if you need, now is empty.
- */
- result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);
- /* read last saved time for simulated timestamp */
- fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);
- if (result != FDB_NO_ERR) {
- return -1;
- }
- /* run TSDB sample */
- tsdb_sample(&tsdb);
- }
- #endif
- }
7、编译下后运行成功,可以看到FlashDB初始化成功,并且可以看到重启次数、假设的温度值
综上,可以看到FlashDB可以设置相关参数、以及记录重启次数等功能,将FlashDB作为嵌入式数据库是非常方便地。
最后附上FlashDB的教程入门 - 快速开始 - 《FlashDB v2.1 使用教程》 - 书栈网 · BookStack