第一步写好了FAL移植,那么进行第二步 SFUD 移植

【FlashDB】第一步 FlashDB 移植到 STM32L475 使用QSPI驱动外部 flash W25Q64之FAL移植

准备工作

1. SFUD 介绍

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

  • 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
  • 资源占用
    标准占用:RAM:0.2KB ROM:5.5KB
    最小占用:RAM:0.1KB ROM:3.6KB
  • 设计思路:
  1. 什么是 SFDP :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B (点击这里查看)。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
  2. 不支持 SFDP 怎么办 :如果该 Flash 不支持 SFDP 标准,SFUD会查询配置文件 ( /sfud/inc/sfud_flash_def.h ) 中提供的 Flash 参数信息表 中是否支持该款Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 2.5 添加库目前不支持Flash)。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。

想实际了解请点击以下链接:
https://gitee.com/Armink/SFUD

2.打开STM32CubeMX配置单片机的QSPI相关驱动

配置如下图:

注意:红框中的Flash Size 一项中是可查询的flash地址位数减一
例如:我使用的是W25Q64,最大地址是0x800000,一共占据了24位,那么24-1就是Flash Size的长度,Flash Size最大到32位寻址

3. 将SFUD相关文件放入到MDK中


3.1 打开 sfud_port.c 文件,将一下内容替换

/** This file is part of the Serial Flash Universal Driver Library.** Copyright (c) 2018, zylx, <qgyhd1234@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: 2018-11-23*/#include <sfud.h>
#include <stdarg.h>
#include <stdio.h>
#include <stm32l4xx_hal.h>
#include <stm32l4xx_hal_gpio.h>
#include <string.h>void sfud_log_info(const char *format, ...);
sfud_err qspi_send_then_recv(const void *send_buf, size_t send_length, void *recv_buf, size_t recv_length);
extern QSPI_HandleTypeDef hqspi;typedef struct
{QSPI_HandleTypeDef *spix;GPIO_TypeDef *cs_gpiox;uint16_t cs_gpio_pin;
} spi_user_data, *spi_user_data_t;static char log_buf[256];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;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);}/* reset cs pin */if (spi_dev->cs_gpiox != NULL)HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin, GPIO_PIN_RESET);if (write_size && read_size){/* read data */qspi_send_then_recv(write_buf, write_size, read_buf, read_size);}else if (write_size){/* send data */qspi_send_then_recv(write_buf, write_size, NULL, NULL);}/* set cs pin */if (spi_dev->cs_gpiox != NULL)HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin, GPIO_PIN_SET);return result;
}/*** QSPI fast read data*/
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;QSPI_CommandTypeDef Cmdhandler;extern QSPI_HandleTypeDef hqspi;/* set cmd struct */Cmdhandler.Instruction = qspi_read_cmd_format->instruction;if(qspi_read_cmd_format->instruction_lines == 0){Cmdhandler.InstructionMode = QSPI_INSTRUCTION_NONE;}else if(qspi_read_cmd_format->instruction_lines == 1){Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;}else if(qspi_read_cmd_format->instruction_lines == 2){Cmdhandler.InstructionMode = QSPI_INSTRUCTION_2_LINES;}else if(qspi_read_cmd_format->instruction_lines == 4){Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;}Cmdhandler.Address = addr;Cmdhandler.AddressSize = QSPI_ADDRESS_24_BITS;if(qspi_read_cmd_format->address_lines == 0){Cmdhandler.AddressMode = QSPI_ADDRESS_NONE;}else if(qspi_read_cmd_format->address_lines == 1){Cmdhandler.AddressMode = QSPI_ADDRESS_1_LINE;}else if(qspi_read_cmd_format->address_lines == 2){Cmdhandler.AddressMode = QSPI_ADDRESS_2_LINES;}else if(qspi_read_cmd_format->address_lines == 4){Cmdhandler.AddressMode = QSPI_ADDRESS_4_LINES;}Cmdhandler.AlternateBytes = 0;Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;Cmdhandler.AlternateBytesSize = 0;Cmdhandler.DummyCycles = qspi_read_cmd_format->dummy_cycles;Cmdhandler.NbData = read_size;if(qspi_read_cmd_format->data_lines == 0){Cmdhandler.DataMode = QSPI_DATA_NONE;}else if(qspi_read_cmd_format->data_lines == 1){Cmdhandler.DataMode = QSPI_DATA_1_LINE;}else if(qspi_read_cmd_format->data_lines == 2){Cmdhandler.DataMode = QSPI_DATA_2_LINES;}else if(qspi_read_cmd_format->data_lines == 4){Cmdhandler.DataMode = QSPI_DATA_4_LINES;}Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE;Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);if (HAL_QSPI_Receive(&hqspi, read_buf, 5000) != HAL_OK){sfud_log_info("qspi recv data failed(%d)!", hqspi.ErrorCode);hqspi.State = HAL_QSPI_STATE_READY;result = SFUD_ERR_READ;}return result;
}/* about 100 microsecond delay */
static void retry_delay_100us(void)
{uint32_t delay = 2400;while (delay--);
}static spi_user_data spi1 = { .spix = &hqspi, .cs_gpiox = NULL, .cs_gpio_pin = NULL };sfud_err sfud_spi_port_init(sfud_flash *flash)
{sfud_err result = SFUD_SUCCESS;switch (flash->index){case SFUD_W25_DEVICE_INDEX:{/* set the interfaces and data */flash->spi.wr = spi_write_read;flash->spi.qspi_read = qspi_read;flash->spi.lock = spi_lock;flash->spi.unlock = spi_unlock;flash->spi.user_data = &spi1;/* about 100 microsecond delay */flash->retry.delay = retry_delay_100us;/* adout 60 seconds timeout */flash->retry.times = 60 * 10000;break;}}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\r\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\r\n", log_buf);va_end(args);
}/*** This function can send or send then receive QSPI data.*/
sfud_err qspi_send_then_recv(const void *send_buf, size_t send_length, void *recv_buf, size_t recv_length)
{assert_param(send_buf);assert_param(recv_buf);assert_param(send_length != 0);QSPI_CommandTypeDef Cmdhandler;unsigned char *ptr = (unsigned char *)send_buf;size_t count = 0;sfud_err result = SFUD_SUCCESS;/* get instruction */Cmdhandler.Instruction = ptr[0];Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;count++;/* get address */if (send_length > 1){if (send_length >= 4){/* address size is 3 Byte */Cmdhandler.Address = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);Cmdhandler.AddressSize = QSPI_ADDRESS_24_BITS;count += 3;}else{return SFUD_ERR_READ;}Cmdhandler.AddressMode = QSPI_ADDRESS_1_LINE;}else{/* no address stage */Cmdhandler.Address = 0 ;Cmdhandler.AddressMode = QSPI_ADDRESS_NONE;Cmdhandler.AddressSize = 0;}Cmdhandler.AlternateBytes = 0;Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;Cmdhandler.AlternateBytesSize = 0;Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE;Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;if (send_buf && recv_buf){/* recv data *//* set dummy cycles */if (count != send_length){Cmdhandler.DummyCycles = (send_length - count) * 8;}else{Cmdhandler.DummyCycles = 0;}/* set recv size */Cmdhandler.DataMode = QSPI_DATA_1_LINE;Cmdhandler.NbData = recv_length;HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);if (recv_length != 0){if (HAL_QSPI_Receive(&hqspi, recv_buf, 5000) != HAL_OK){sfud_log_info("qspi recv data failed(%d)!", hqspi.ErrorCode);hqspi.State = HAL_QSPI_STATE_READY;result = SFUD_ERR_READ;}}return result;}else{/* send data *//* set dummy cycles */Cmdhandler.DummyCycles = 0;/* determine if there is data to send */if (send_length - count > 0){Cmdhandler.DataMode = QSPI_DATA_1_LINE;}else{Cmdhandler.DataMode = QSPI_DATA_NONE;}/* set send buf and send size */Cmdhandler.NbData = send_length - count;HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);if (send_length - count > 0){if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)(ptr + count), 5000) != HAL_OK){sfud_log_info("qspi send data failed(%d)!", hqspi.ErrorCode);hqspi.State = HAL_QSPI_STATE_READY;result = SFUD_ERR_WRITE;}}return result;}
}

3.2 注意188行-214行

注意:箭头所指是,HAL库初始化QSPI时所定义的宏,根据实际情况填写

3.3 打开 sfud_cfg.h 文件

.name flash 设备名字
.spi.name 驱动名字,无关紧要,填写对应的驱动方式即可
.chip 片子的驱动信息,重要,要填对,具体的驱动信息在 sfud_flash_def.h 122行,复制粘贴即可

至此SFUD移植完成。

4. SFUD 测试代码

void sfud_demo(uint32_t addr, size_t size, uint8_t *data);#define SFUD_DEMO_TEST_BUFFER_SIZE                     1024
static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];int main(){if (sfud_init() == SFUD_SUCCESS){/* enable qspi fast read mode, set four data lines width */sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25_DEVICE_INDEX), 4);sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);}while(1);}
/*** SFUD demo for the first flash device test.** @param addr flash start address* @param size test flash size* @param size test flash data buffer*/
void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{sfud_err result = SFUD_SUCCESS;extern sfud_flash *sfud_dev;const sfud_flash *flash = sfud_get_device(SFUD_W25_DEVICE_INDEX);size_t i;/* prepare write data */for (i = 0; i < size; i++){data[i] = i;}/* erase test */result = sfud_erase(flash, addr, size);if (result == SFUD_SUCCESS){printf("Erase the %s flash data finish. Start from 0x%08X, size is %zu.\r\n", flash->name, addr, size);}else{printf("Erase the %s flash data failed.\r\n", flash->name);return;}/* write test */result = sfud_write(flash, addr, size, data);if (result == SFUD_SUCCESS){printf("Write the %s flash data finish. Start from 0x%08X, size is %zu.\r\n", flash->name, addr, size);}else{printf("Write the %s flash data failed.\r\n", flash->name);return;}memset(data, 0, size);/* read test */result = sfud_read(flash, addr, size, data);if (result == SFUD_SUCCESS){printf("Read the %s flash data success. Start from 0x%08X, size is %zu. The data is:\r\n", flash->name, addr, size);printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");for (i = 0; i < size; i++){if (i % 16 == 0){printf("[%08X] ", addr + i);}printf("%02X ", data[i]);if (((i + 1) % 16 == 0) || i == size - 1){printf("\r\n");}}printf("\r\n");}else{printf("Read the %s flash data failed.\r\n", flash->name);}/* data check */for (i = 0; i < size; i++){if (data[i] != i % 256){printf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);break;}}if (i == size){printf("The %s flash test is success.\r\n", flash->name);}
}

【FlashDB】第二步 FlashDB 移植 STM32L475 使用QSPI驱动外部 flash W25Q64之 SFUD 移植相关推荐

  1. MicroPython支持SPI驱动外部Flash了

    2019独角兽企业重金招聘Python工程师标准>>> 今天MicroPython添加了一个重要更新,可以通过SPI方式驱动外部Flash. 而STM32L476DISC开发板作为第 ...

  2. STM32F103 硬件SPI驱动外部FLASH W25X16

    之前学习过使用,汇顶和盛源达的蓝牙芯片驱动外部FLASH,从外部FLASH中读出图片原始数据,并刷新到OLED上,最开始入门的芯片也是STM321但是在学校的时候基本没有使用STM32来驱动外部FLA ...

  3. micropython移植stm32f746_STM32L476和STM32F746的外部Flash复制文件速度对比

    1.STM32L476使用的是GPIO模拟的SPI,自然速度要慢.STM32F746使用硬件QSPI,会快很多. 2.但也不能简单从你测的这个时间上得出M7性能比M4强的结论(当然M7确实比M4强). ...

  4. STM32F429使用touchGFX驱动外部flash存储资源

    起源 做单片机开发的时候,总会遇到单片机内存不够,图片需要存储到外部flash的情况. 开始 开发环境: 1.开发板:安富莱V6 2.显示屏:LCD7寸,480*800分辨率 3.外部flash:W2 ...

  5. LoRa 之一 旧版驱动(sx12xxDrivers-V2.1.0)移植及驱动架构详解

      在之前的项目中,一直使用 LoRa 通信.很早之前就想写写文章记录一下学习过程.怎奈一直是一知半解的状态,想写不敢写!LoRa 这个东西在国内用的貌似不是太多.   对于无线通信,各个国家或者地区 ...

  6. 移植SFUD,驱动SPI FLASH ZD25WQ80

    1.关于SFUD SFUD (Serial Flash Universal Driver) 串行 Flash 通用驱动库,支持众多spi flash,关于SFUD的详细资料可参考:https://gi ...

  7. Exynos4412 内核移植(五)—— 驱动的移植

    以移植自己制作的驱动,学习内核移植中的驱动移植,及 驱动程序的动态编译和静态编译 硬件环境: Linux 内核版本:Linux 3.14 主机:Ubuntu 12.04发行版 目标机:FS4412平台 ...

  8. c++驱动键鼠源码_Android移植FM芯片RDA5807M驱动指导

    文档说明 本文档以SC826为例(MSM8953平台,Android 7),描述如何移植FM芯片RDA5807M驱动. 移植修改 1):rdafm_drv.c rdafm_drv.h 放到kernel ...

  9. 2440 6.0BSP 移植过程之显示驱动篇

    2440 6.0BSP 移植过程之显示驱动篇 //--------------------------------------------------------------------------- ...

最新文章

  1. Java 面试知识点解析(六)——数据库篇
  2. 手工卸载oracle,升级和卸载Oracle数据库软件的命令整理
  3. 如何编写 Cloud9 JavaScript IDE 的功能扩展
  4. webgis从基础到开发实践_ArcGIS API For Javascript 开发笔记(四)
  5. mysql程序设计教程_MySQL教程_编程入门教程_牛客网
  6. Linux 系统的运行级别(Run Level)
  7. LESS是一个CSS预处理器,跨浏览器友好,提供诸如变量,函数, mixins 和操作等功能,可以构建动态CSS...
  8. oppok3如何刷机_OPPO K3怎么刷机?
  9. android uboot boot 区别,uboot fastboot原理
  10. 【单片机学习笔记】上传一整年的自学电子笔记,互相交流,共同进步。
  11. java 开源论坛框架/java web 论坛框架
  12. c语言写流水灯程序,用汇编和C语言 写流水灯程序
  13. Excel 自动计算房贷、月供 (附模板)
  14. 几何分布的期望和方差公式推导_学习笔记:几种特殊分布之间的关系
  15. I3D【Inflated 3D ConvNet】——膨胀卷积网络用于行为识别
  16. 激活win10专业版最简单的方法
  17. Fragstats计算景观格局指数不出结果和分维数PAFRAC出现N/A的问题
  18. 『ACM』ACM部分训练日记(以此纪念和队友与FLS一起度过的快乐时光)
  19. 根据cron表达式获取最近几次执行的时间
  20. Vulkan Samples 阅读 -- Extensions(二)

热门文章

  1. cocos creator(12)
  2. Android App签名的那些事
  3. 数据透视:Excel数据透视和Python数据透视
  4. SLAM中多目三角化
  5. 计算机毕业设计之云日记设计与实现
  6. 【转】以太坊 2.0 中的验证者经济模型
  7. 获取股票简单数据:腾讯、新浪、东方财富。。。
  8. duilib设置透明窗口_使用duilib开发半透明异形窗体程序(补充)
  9. Python海龟绘图入门篇
  10. 题目描述: 某城市有一个火车站,铁轨铺设如图所示。 有n节车厢从A方向驶入车站,按进站顺序编号1~n。 现让这些火车按照某种特定的顺序进入B方向的铁轨并驶出车站。 为了重组车厢,可以借助中转站C。