416|4

250

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

[兆易GD32H759I-EVAL]3.熟悉I2C、SPI操作EEPROM和SPI FLASH,移植FlashDB数据库 [复制链接]

 

1、I2C

    GD32H759系列MCU搭载了4个I2C通讯接口模块;支持主从机模式;支持7位地址、10位地址和广播地址;作为从机时,还支持多个7位从机地址的配置;通讯速率上支持100kHz的标速、400kHz的快速和1MHz的高速这3种通讯速率,同时还兼容SMBus3.0和PMBus1.3等功能。

 

2.原理图

    GD32H759I-EVAL板载了一颗I2C接口的EEPROM芯片,型号为AT24C02C-SSHM-T;与MCU的I2C1接口连接通讯,分配的引脚为PH4和PB11,如下所示:

 

3.EEPROM功能代码

  • #include "bsp_eeprom.h"
  • #include "platform.h"
  • void bsp_EepromInit(void)
  • {
  • rcu_periph_clock_enable(RCU_GPIOB);
  • rcu_periph_clock_enable(RCU_GPIOH);
  • rcu_periph_clock_enable(RCU_I2C1);
  • gpio_af_set(GPIOH, GPIO_AF_4, GPIO_PIN_4);
  • gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_11);
  • gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_4);
  • gpio_output_options_set(GPIOH, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, GPIO_PIN_4);
  • gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
  • gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
  • i2c_timing_config(I2C1, 0x01, 0x07, 0x00);
  • i2c_master_clock_config(I2C1, 0x2D, 0x87);
  • i2c_enable(I2C1);
  • }
  • void bsp_EepromI2cBusReset()
  • {
  • GPIO_BC(GPIOH) |= GPIO_PIN_4;
  • GPIO_BC(GPIOB) |= GPIO_PIN_11;
  • gpio_mode_set(GPIOH, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
  • gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_4);
  • gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
  • gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
  • __NOP();
  • __NOP();
  • __NOP();
  • __NOP();
  • __NOP();
  • GPIO_BOP(GPIOH) |= GPIO_PIN_4;
  • __NOP();
  • __NOP();
  • __NOP();
  • __NOP();
  • __NOP();
  • GPIO_BOP(GPIOB) |= GPIO_PIN_11;
  • gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_4);
  • gpio_output_options_set(GPIOH, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, GPIO_PIN_4);
  • gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
  • gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
  • }
  • void bsp_EepromWritePage(uint8_t *p_buffer, uint8_t write_address, uint8_t number_of_byte)
  • {
  • i2c_process_enum state = I2C_START;
  • uint16_t timeout = 0;
  • uint8_t end_flag = 0;
  • while (!end_flag)
  • {
  • switch (state)
  • {
  • case I2C_START:
  • i2c_master_addressing(I2C1, 0xA0, I2C_MASTER_TRANSMIT);
  • i2c_transfer_byte_number_config(I2C1, number_of_byte + 1);
  • I2C_STAT(I2C1) |= I2C_STAT_TBE;
  • i2c_automatic_end_enable(I2C1);
  • while (i2c_flag_get(I2C1, I2C_FLAG_I2CBSY) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_start_on_bus(I2C1);
  • timeout = 0;
  • state = I2C_SEND_ADDRESS;
  • }
  • else
  • {
  • bsp_EepromI2cBusReset();
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c bus is busy in page write!\n");
  • }
  • break;
  • case I2C_SEND_ADDRESS:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TBE)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_data_transmit(I2C1, write_address);
  • timeout = 0;
  • state = I2C_TRANSMIT_DATA;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends address timeout in page write!\n");
  • }
  • break;
  • case I2C_TRANSMIT_DATA:
  • while (number_of_byte--)
  • {
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TI)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_data_transmit(I2C1, *p_buffer);
  • p_buffer++;
  • timeout = 0;
  • state = I2C_STOP;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends data timeout in page write!\n");
  • return;
  • }
  • }
  • break;
  • case I2C_STOP:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_STPDET)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
  • timeout = 0;
  • state = I2C_END;
  • end_flag = 1;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends stop signal timeout in page write!\n");
  • }
  • break;
  • default:
  • state = I2C_START;
  • end_flag = 1;
  • timeout = 0;
  • printf("i2c master sends start signal in page write!\n");
  • break;
  • }
  • }
  • }
  • void bsp_EepromReadBuffer(uint8_t *p_buffer, uint8_t read_address, uint16_t number_of_byte)
  • {
  • uint32_t nbytes_reload = 0;
  • i2c_process_enum state = I2C_START;
  • uint32_t timeout = 0;
  • uint8_t end_flag = 0;
  • uint8_t restart_flag = 0;
  • uint8_t first_reload_flag = 1;
  • uint8_t last_reload_flag = 0;
  • while (!end_flag)
  • {
  • switch (state)
  • {
  • case I2C_START:
  • if (0 == restart_flag)
  • {
  • I2C_STAT(I2C1) |= I2C_STAT_TBE;
  • i2c_master_addressing(I2C1, 0xA0, I2C_MASTER_TRANSMIT);
  • i2c_transfer_byte_number_config(I2C1, 1);
  • i2c_automatic_end_disable(I2C1);
  • while (i2c_flag_get(I2C1, I2C_FLAG_I2CBSY) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_start_on_bus(I2C1);
  • timeout = 0;
  • state = I2C_SEND_ADDRESS;
  • }
  • else
  • {
  • bsp_EepromI2cBusReset();
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c bus is busy in read!\n");
  • }
  • }
  • else
  • {
  • i2c_start_on_bus(I2C1);
  • restart_flag = 0;
  • state = I2C_TRANSMIT_DATA;
  • }
  • break;
  • case I2C_SEND_ADDRESS:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TBE)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_data_transmit(I2C1, read_address);
  • timeout = 0;
  • state = I2C_RESTART;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends data timeout in read!\n");
  • }
  • break;
  • case I2C_RESTART:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TC)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_master_addressing(I2C1, 0xA0, I2C_MASTER_RECEIVE);
  • i2c_reload_enable(I2C1);
  • timeout = 0;
  • state = I2C_RELOAD;
  • restart_flag = 1;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends EEPROM's internal address timeout in read!\n");
  • }
  • break;
  • case I2C_RELOAD:
  • if (number_of_byte > 255)
  • {
  • number_of_byte = number_of_byte - 255;
  • nbytes_reload = 255;
  • }
  • else
  • {
  • nbytes_reload = number_of_byte;
  • last_reload_flag = 1;
  • }
  • if (1 == first_reload_flag)
  • {
  • i2c_transfer_byte_number_config(I2C1, nbytes_reload);
  • if (1 == last_reload_flag)
  • {
  • last_reload_flag = 0;
  • if (number_of_byte <= 255)
  • {
  • i2c_reload_disable(I2C1);
  • i2c_automatic_end_enable(I2C1);
  • }
  • }
  • first_reload_flag = 0;
  • state = I2C_START;
  • }
  • else
  • {
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TCR)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_transfer_byte_number_config(I2C1, nbytes_reload);
  • if (number_of_byte <= 255)
  • {
  • i2c_reload_disable(I2C1);
  • i2c_automatic_end_enable(I2C1);
  • }
  • timeout = 0;
  • state = I2C_TRANSMIT_DATA;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master reload data timeout in read!\n");
  • }
  • }
  • break;
  • case I2C_TRANSMIT_DATA:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_TBE)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • while (nbytes_reload)
  • {
  • if (i2c_flag_get(I2C1, I2C_FLAG_RBNE))
  • {
  • *p_buffer = i2c_data_receive(I2C1);
  • p_buffer++;
  • nbytes_reload--;
  • }
  • }
  • timeout = 0;
  • if (I2C_CTL1(I2C1) & I2C_CTL1_RELOAD)
  • {
  • timeout = 0;
  • state = I2C_RELOAD;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_STOP;
  • }
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master read data timeout in read!\n");
  • }
  • break;
  • case I2C_STOP:
  • while ((!i2c_flag_get(I2C1, I2C_FLAG_STPDET)) && (timeout < 20000))
  • {
  • timeout++;
  • }
  • if (timeout < 20000)
  • {
  • i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
  • timeout = 0;
  • state = I2C_END;
  • end_flag = 1;
  • }
  • else
  • {
  • timeout = 0;
  • state = I2C_START;
  • printf("i2c master sends stop signal timeout in read!\n");
  • }
  • break;
  • default:
  • state = I2C_START;
  • end_flag = 1;
  • timeout = 0;
  • printf("i2c master sends start signal in read!\n");
  • break;
  • }
  • }
  • }
  • void bsp_EepromWriteBuffer(uint8_t *p_buffer, uint8_t write_address, uint16_t number_of_byte)
  • {
  • uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;
  • address = write_address % 8;
  • count = 8 - address;
  • number_of_page = number_of_byte / 8;
  • number_of_single = number_of_byte % 8;
  • if (0 == address)
  • {
  • while (number_of_page--)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, 8);
  • PLATFORM_DelayMs(5);
  • write_address += 8;
  • p_buffer += 8;
  • }
  • if (0 != number_of_single)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, number_of_single);
  • PLATFORM_DelayMs(5);
  • }
  • }
  • else
  • {
  • if (number_of_byte < count)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, number_of_byte);
  • PLATFORM_DelayMs(5);
  • }
  • else
  • {
  • number_of_byte -= count;
  • number_of_page = number_of_byte / 8;
  • number_of_single = number_of_byte % 8;
  • if (0 != count)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, count);
  • PLATFORM_DelayMs(5);
  • write_address += count;
  • p_buffer += count;
  • }
  • while (number_of_page--)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, 8);
  • PLATFORM_DelayMs(5);
  • write_address += 8;
  • p_buffer += 8;
  • }
  • if (0 != number_of_single)
  • {
  • bsp_EepromWritePage(p_buffer, write_address, number_of_single);
  • PLATFORM_DelayMs(5);
  • }
  • }
  • }
  • }
  • void bsp_EepromTest(void)
  • {
  • uint8_t EepromWriteBuffer[256];
  • uint8_t EepromReadBuffer[256];
  • printf("\r\n");
  • printf("\r\nEEPROM Writing...");
  • for (uint16_t i = 0; i < 256; i++)
  • {
  • if ((i % 16) == 0)
  • {
  • printf("\r\n");
  • }
  • EepromWriteBuffer[i] = i;
  • printf("0x%02X ", EepromWriteBuffer[i]);
  • }
  • bsp_EepromWriteBuffer(EepromWriteBuffer, 0, 256);
  • printf("\r\n");
  • printf("\r\nEEPROM Reading...");
  • bsp_EepromReadBuffer(EepromReadBuffer, 0, 256);
  • for (uint16_t i = 0; i < 256; i++)
  • {
  • if ((i % 16) == 0)
  • {
  • printf("\r\n");
  • }
  • if (EepromReadBuffer[i] != EepromWriteBuffer[i])
  • {
  • printf("0x%02X ", EepromReadBuffer[i]);
  • printf("\r\nError : data read and write aren't matching!!!");
  • return;
  • }
  • printf("0x%02X ", EepromReadBuffer[i]);
  • }
  • printf("\r\n");
  • printf("\r\nEEPROM Test Pass!!!");
  • }

 

4.EEPROM运行结果

 

5.SPI

    GD32H759系列MCU搭载了最多6个SPI通讯接口模块和2个OSPI通讯接口模块;对于SPI接口,具有全双工、半双工、以及单工的主、从工作模式;支持4到32位的数据帧格式,有独立的发送和接收FIFO缓冲区,还支持多主机和多从机的通讯组网;OSPIM全称是OSPI I/O管理器,支持对OSPI全IO矩阵引脚进行分配管理,它支持2个SPI的单线、双线、四线和八线接口方式,支持两个端口进行引脚分配,完全可编程IO矩阵,可按功能能引脚进行配置

 

6.原理图

    GD32H759I-EVAL板载了一颗8线SPI接口的SPI FLASH芯片,型号为GD25X512MEBIRY;与MCU的OSPI接口连接通讯,分配的引脚如下所示:

 

7.移植SFUD

  • /*
  • * 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 <string.h>
  • #include "gd32h7xx.h"
  • #include "platform.h"
  • static char log_buf[256];
  • void sfud_log_debug(const char *file, const long line, const char *format, ...);
  • typedef struct
  • {
  • uint32_t spix;
  • uint32_t cs_gpiox;
  • uint32_t cs_gpio_pin;
  • } spi_user_data, *spi_user_data_t;
  • spi_user_data spi4 =
  • {
  • .spix = SPI4,
  • .cs_gpiox = GPIOF,
  • .cs_gpio_pin = GPIO_PIN_6,
  • };
  • static void spi_lock(const sfud_spi *spi)
  • {
  • }
  • static void spi_unlock(const sfud_spi *spi)
  • {
  • }
  • static void retry_delay_1ms(void)
  • {
  • PLATFORM_DelayMs(1);
  • }
  • /**
  • * 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 = 0, read_data = 0;
  • spi_user_data_t spi_dev = (spi_user_data_t)spi->user_data;
  • /**
  • * add your spi write and read code
  • */
  • if (write_size)
  • {
  • SFUD_ASSERT(write_buf);
  • }
  • if (read_size)
  • {
  • SFUD_ASSERT(read_buf);
  • }
  • spi_nss_output_enable(spi_dev->spix);
  • if (write_size)
  • {
  • for (size_t i = 0; i < write_size; i++)
  • {
  • while (RESET == spi_i2s_flag_get(spi_dev->spix, SPI_FLAG_TP))
  • {
  • }
  • spi_i2s_data_transmit(spi_dev->spix, write_buf[i]);
  • while (RESET == spi_i2s_flag_get(spi_dev->spix, SPI_FLAG_RP))
  • {
  • }
  • read_data = spi_i2s_data_receive(spi_dev->spix);
  • }
  • }
  • if (read_size)
  • {
  • memset((uint8_t *)read_buf, 0xFF, read_size);
  • for (size_t i = 0; i < read_size; i++)
  • {
  • while (RESET == spi_i2s_flag_get(spi_dev->spix, SPI_FLAG_TP))
  • {
  • }
  • spi_i2s_data_transmit(spi_dev->spix, send_data);
  • while (RESET == spi_i2s_flag_get(spi_dev->spix, SPI_FLAG_RP))
  • {
  • }
  • read_buf[i] = spi_i2s_data_receive(spi_dev->spix);
  • }
  • }
  • spi_nss_output_disable(spi_dev->spix);
  • return (result);
  • }
  • #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 */
  • 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
  • */
  • if (!strcmp(flash->spi.name, "SPIx"))
  • {
  • rcu_periph_clock_enable(RCU_GPIOF);
  • rcu_periph_clock_enable(RCU_GPIOH);
  • rcu_periph_clock_enable(RCU_SPI4);
  • rcu_spi_clock_config(IDX_SPI4, RCU_SPISRC_PLL0Q);
  • gpio_af_set(GPIOF, GPIO_AF_5, GPIO_PIN_6 | GPIO_PIN_9);
  • gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_9);
  • gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6 | GPIO_PIN_9);
  • gpio_af_set(GPIOH, GPIO_AF_5, GPIO_PIN_6 | GPIO_PIN_7);
  • gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);
  • gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6 | GPIO_PIN_7);
  • spi_parameter_struct spi_init_struct;
  • spi_i2s_deinit(spi4.spix);
  • spi_struct_para_init(&spi_init_struct);
  • spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
  • spi_init_struct.device_mode = SPI_MASTER;
  • spi_init_struct.data_size = SPI_DATASIZE_8BIT;
  • spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
  • spi_init_struct.nss = SPI_NSS_SOFT;
  • spi_init_struct.prescale = SPI_PSC_16;
  • spi_init_struct.endian = SPI_ENDIAN_MSB;
  • spi_init(spi4.spix, &spi_init_struct);
  • spi_byte_access_enable(spi4.spix);
  • flash->spi.wr = spi_write_read;
  • flash->spi.lock = spi_lock;
  • flash->spi.unlock = spi_unlock;
  • flash->spi.user_data = &spi4;
  • flash->retry.delay = retry_delay_1ms;
  • flash->retry.times = 60 * 1000;
  • }
  • 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);
  • }

 

8.移植FlashDB

  • /*
  • * Copyright (c) 2006-2018, RT-Thread Development Team
  • *
  • * SPDX-License-Identifier: Apache-2.0
  • *
  • * Change Logs:
  • * Date Author Notes
  • * 2018-01-26 armink the first version
  • */
  • #include <fal.h>
  • #include <sfud.h>
  • #ifdef FAL_USING_SFUD_PORT
  • #ifndef FAL_USING_NOR_FLASH_DEV_NAME
  • #define FAL_USING_NOR_FLASH_DEV_NAME "spiflash"
  • #endif
  • 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 sfud_dev = NULL;
  • struct fal_flash_dev spiflash =
  • {
  • .name = FAL_USING_NOR_FLASH_DEV_NAME,
  • .addr = 0,
  • .len = 8 * 1024 * 1024,
  • .blk_size = 4096,
  • .ops = { init, read, write, erase },
  • .write_gran = 1
  • };
  • static int init(void)
  • {
  • /* bare metal platform */
  • extern sfud_flash sfud_spiflash;
  • sfud_dev = &sfud_spiflash;
  • if (NULL == sfud_dev)
  • {
  • return (-1);
  • }
  • /* update the flash chip information */
  • spiflash.blk_size = sfud_dev->chip.erase_gran;
  • spiflash.len = sfud_dev->chip.capacity;
  • return (0);
  • }
  • static int read(long offset, uint8_t *buf, size_t size)
  • {
  • assert(sfud_dev);
  • assert(sfud_dev->init_ok);
  • sfud_read(sfud_dev, spiflash.addr + offset, size, buf);
  • return (size);
  • }
  • static int write(long offset, const uint8_t *buf, size_t size)
  • {
  • assert(sfud_dev);
  • assert(sfud_dev->init_ok);
  • if (sfud_write(sfud_dev, spiflash.addr + offset, size, buf) != SFUD_SUCCESS)
  • {
  • return (-1);
  • }
  • return (size);
  • }
  • static int erase(long offset, size_t size)
  • {
  • assert(sfud_dev);
  • assert(sfud_dev->init_ok);
  • if (sfud_erase(sfud_dev, spiflash.addr + offset, size) != SFUD_SUCCESS)
  • {
  • return (-1);
  • }
  • return (size);
  • }
  • #endif

 

9.FlashDB应用

  • #include "bsp_spiflash.h"
  • #include "sfud.h"
  • #include "flashdb.h"
  • sfud_flash sfud_spiflash =
  • {
  • .name = "spiflash",
  • .spi.name = "SPI4",
  • .chip = { "W25Q64",SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L * 1024L * 1024L, SFUD_WM_PAGE_256B, 4096, 0x20 },
  • };
  • struct tsdb_param
  • {
  • uint8_t status;
  • uint8_t buffer[12];
  • };
  • struct fdb_kvdb kvdb = {0};
  • struct fdb_tsdb tsdb = {0};
  • fdb_time_t fdb_time_stamp = 0;
  • fdb_time_t fdb_time_start = 1;
  • uint32_t fdb_count = 0;
  • static void fdb_lock(fdb_db_t db)
  • {
  • }
  • static void fdb_unlock(fdb_db_t db)
  • {
  • }
  • static fdb_time_t get_time(void)
  • {
  • return (++fdb_time_stamp);
  • }
  • static bool query_cb(fdb_tsl_t tsl, void *arg)
  • {
  • struct fdb_blob blob;
  • struct tsdb_param param;
  • fdb_tsdb_t db = arg;
  • fdb_blob_read((fdb_db_t)db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, ¶m, sizeof(param))));
  • printf("\r\n[%s][%d] : status: %d, buffer: %s\n", __FUNCTION__, tsl->time, param.status, param.buffer);
  • return (false);
  • }
  • void bsp_SpiFlashInit(void)
  • {
  • sfud_init();
  • if (sfud_device_init(&sfud_spiflash) == SFUD_SUCCESS)
  • {
  • printf("\r\n%s Success!\r\n", __FUNCTION__);
  • }
  • else
  • {
  • printf("\r\n%s Failed!!\r\n", __FUNCTION__); return;
  • }
  • struct fdb_blob blob;
  • fdb_err_t result;
  • struct tsdb_param param;
  • fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)fdb_lock);
  • fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)fdb_unlock);
  • result = fdb_kvdb_init(&kvdb, "kvdb", "fdb_kvdb", NULL, NULL);
  • if (result != FDB_NO_ERR)
  • {
  • printf("\r\nkvdb error!!!");
  • }
  • else
  • {
  • fdb_kv_get_blob(&kvdb, "count", fdb_blob_make(&blob, &fdb_count, sizeof(fdb_count)));
  • if (blob.saved.len == 0)
  • {
  • fdb_count = 0;
  • fdb_kv_set_blob(&kvdb, "count", fdb_blob_make(&blob, &fdb_count, sizeof(fdb_count)));
  • }
  • else
  • {
  • fdb_count++;
  • fdb_kv_set_blob(&kvdb, "count", fdb_blob_make(&blob, &fdb_count, sizeof(fdb_count)));
  • printf("\r\nkvdb count : %d", fdb_count);
  • }
  • }
  • fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)fdb_lock);
  • fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)fdb_unlock);
  • result = fdb_tsdb_init(&tsdb, "tsdb", "fdb_tsdb", get_time, 15, NULL);
  • if (result != FDB_NO_ERR)
  • {
  • printf("\r\ntsdb error!!!");
  • }
  • else
  • {
  • if (fdb_count == 0)
  • {
  • fdb_tsl_clean(&tsdb);
  • }
  • fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &fdb_time_stamp);
  • param.status = fdb_count;
  • memcpy(param.buffer, "tsdb demo", 9);
  • fdb_tsl_append(&tsdb, fdb_blob_make(&blob, ¶m, sizeof(param)));
  • fdb_tsl_iter(&tsdb, query_cb, &tsdb);
  • }
  • }

 

10.运行结果

    GD32H759I-EVAL板载了一颗8线SPI接口的SPI FLASH芯片,编程方式与我们之前的2线传统SPI接口的编程方式不同,而本次要实现的FlashDB数据库的移植,主要是基于SFUD开源库和FlashDB开源库实现的,当前还没有支持开发板上的这一个颗SPI FLASH芯片,上述的代码是基于普通SPI接口去操作SPI FLASH实现的,在其它项目已经应用实践,主要是分享一下移植的重点和应用部分;后续有机会,在搭载有普通SPI接口操作SPI FLASH的开发板上,可以进行一下测试,看一下运行结果。

 

11.软件工程

Project_20250217.zip (938.78 KB, 下载次数: 0)
查看本帖全部内容,请登录或者注册

最新回复

大佬,这个spi是QSPI接口的FLASH芯片吗?看了GD的命名和一些方式,国内的好些厂商的风格都差不多,象灵动好象也是开机打印一下频率等一些基础信息。   详情 回复 发表于 2025-2-17 15:11

赞赏

1

查看全部赞赏

点赞 关注
个人签名We are a team and we work as a team !
 
 

回复
举报

250

帖子

0

TA的资源

纯净的硅(初级)

沙发
 

SFUD: 一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库

SFUD是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。

个人签名We are a team and we work as a team !
 
 
 

回复

250

帖子

0

TA的资源

纯净的硅(初级)

板凳
 

链接已隐藏,如需查看请登录或者注册

FlashDB是一款超轻量级的嵌入式数据库,专注于提供嵌入式产品的数据存储方案。FlashDB 不仅支持传统的基于文件系统的数据库模式,而且结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命。

个人签名We are a team and we work as a team !
 
 
 

回复

7211

帖子

11

TA的资源

版主

4
 

大佬,这个spi是QSPI接口的FLASH芯片吗?看了GD的命名和一些方式,国内的好些厂商的风格都差不多,象灵动好象也是开机打印一下频率等一些基础信息。

点评

“这个spi是QSPI接口的FLASH芯片吗?” 不是,板载的OSPI 8线的SPI FLASH,不在SFUD支持的列表中;我按照之前项目上的经验和GD的例程进行移植的,后面有机会使用其它的普通的4线SPI接口的SPI FLASH再测  详情 回复 发表于 2025-2-17 15:36
 
 
 

回复

250

帖子

0

TA的资源

纯净的硅(初级)

5
 
lugl4313820 发表于 2025-2-17 15:11 大佬,这个spi是QSPI接口的FLASH芯片吗?看了GD的命名和一些方式,国内的好些厂商的风格都差不多,象灵动好 ...

“这个spi是QSPI接口的FLASH芯片吗?”

不是,板载的OSPI 8线的SPI FLASH,不在SFUD支持的列表中;我按照之前项目上的经验和GD的例程进行移植的,后面有机会使用其它的普通的4线SPI接口的SPI FLASH再测试一下

个人签名We are a team and we work as a team !
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
【干货上新】电源解决方案和技术第二趴 | DigiKey 应用探索站
当月好物、电源技术资源、特色活动、DigiKey在线实用工具,干货多多~

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 11

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表