STM32 GD32 标准库移植SFUD
创始人
2024-01-30 06:07:58

本次移植是在官方源码的基础上进行移植的

本次介绍的两个软件包SFUD/FAL都与FLASH有关,并且都可以独立使用或者结合在一起使用,两个软件包都对操作系统无依赖,可以使用裸机移植,也很方便移植到各种系统。
这两个软件包的作者都是armink,armink的开源仓库地址:https://github.com/armink,更多好玩的软件,请到作者仓库查询。
 

下面给出官方源码的下载链接 

https://gitee.com/Armink/SFUD

0.SFUD 是什么

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
  • 设计思路:
    • 什么是 SFDP :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B (点击这里查看)。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
    • 不支持 SFDP 怎么办 :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( /sfud/inc/sfud_flash_def.h ) 中提供的 Flash 参数信息表 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 2.5 添加库目前不支持的 Flash)。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。

1、为什么选择 SFUD

  • 避免项目因 Flash 缺货、Flash 停产或产品扩容而带来的风险;
  • 越来越多的项目将固件存储到串行 Flash 中,例如:ESP8266 的固件、主板中的 BIOS 及其他常见电子产品中的固件等等,但是各种 Flash 规格及命令不统一。使用 SFUD 即可避免,在相同功能的软件平台基础下,无法适配不同 Flash 种类的硬件平台的问题,提高软件的可重用性;
  • 简化软件流程,降低开发难度。现在只需要配置好 SPI 通信,即可畅快的开始玩串行 Flash 了;
  • 可以用来制作 Flash 编程器/烧写器

相关的说明大家可以进去链接详细的看一下

目前支持的FLASH类型列表
在这里插入图片描述

总结一下:SFUD就是一个SPI-FLASH的底层驱动,只要是遵循 JEDEC (固态技术协会)的芯片都是可以适配的,目前我理解的好处就是如果更换了硬件,只要是这个表里面的,就不需要改代码!!!

 

RT-Thread中flash管理 — [SFUD组件 和 FAL驱动组件介绍]

本来项目上是想用FlashDB  

在移植嵌入式数据库的基础 上   首先第一步大多数都是先移植SFUD

使用rtthread移植

        在移植过程中一定要参考两个资料:项目的readme文档和demo工程。 对于使用rtthread完整版来说,作者已经把SFUD制作成了rtthread的内置组件了,对于使用者只需要勾选就可以了:

标准库移植:

工具准备
STM32CubeMX:用于配置QSPI外设和串口外设,并生成 MDK 工程;

本文采用的模板是固件库版本
Keil MDK:用于编译和下载工程;
串口助手:用于查看开发板串口调试信息输出;
裸机工程准备
下载完源码后    直接将源码中的SFUD相关的.c  .h文件  添加到你准备的工程模板文件中

  • 先去下载库,然后放入自己的工程中(先不动),基本上就是这个样子的
    在这里插入图片描述
  • 接着就是修改头文件了
    基本上不需要修改什么,先把配置文件改一下

 

 

sfud_cfg.h

填写相关枚举与宏。因为事例工程所使用的芯片STM32F429IG并没有QSPI功能,可以注释掉。

如果Flash型号支持SFDP,可以注释SFUD_USING_SFDP。可以减少需要编译的代码量。

/** This file is part of the Serial Flash Universal Driver Library.** Copyright (c) 2016-2018, Armink, ** 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_//#define SFUD_DEBUG_MODE		//使能SFUD的打印日志#define SFUD_USING_SFDP		//使能SFDP:JEDEC标准(JESD216)标准接口	注意:关闭后只会查询该库在 /sfud/inc/sfud_flash_def.h 中提供的 Flash 信息表。\
这样虽然会降低软件的适配性,但减少代码量。#define SFUD_USING_FLASH_INFO_TABLE	//是否使用该库自带的 Flash 参数信息表注意:关闭后该库只驱动支持 SFDP 规范的 Flash,也会适当的降低部分代码量。\
另外 2.3.2 及 2.3.3 这两个宏定义至少定义一种,也可以两种方式都选择//支持多路外设enum
{SFUD_W25Q64_DEVICE_INDEX = 0,
};
//把实际使用的硬件和外设接口对应配置好
#define SFUD_FLASH_DEVICE_TABLE                                                \
{                                                                              \[SFUD_W25Q64_DEVICE_INDEX] = {.name = "W25Q64JV", .spi.name = "SPI1"},           \
}#define SFUD_USING_QSPI#endif /* _SFUD_CFG_H_ */

判断芯片支持SFUD

1.FLASH芯片支持SFDP标准;(在芯片datesheet中全局搜索SFDP)。
2.如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( \sfud\inc\sfud_flash_def.h ) 中提供的 Flash 参数信息表 是否支持该款 Flash。

#ifdef SFUD_USING_FLASH_INFO_TABLE
/* SFUD supported flash chip information table. If the flash not support JEDEC JESD216 standard,* then the SFUD will find the flash chip information by this table. You can add other flash to here then*  notice me for update it. The configuration information name and index reference the sfud_flash_chip structure.* | name | mf_id | type_id | capacity_id | capacity | write_mode | erase_gran | erase_gran_cmd |*/
#define SFUD_FLASH_CHIP_TABLE                                                                                       \
{                                                                                                                   \{"AT45DB161E", SFUD_MF_ID_ATMEL, 0x26, 0x00, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_DUAL_BUFFER, 512, 0x81},      \{"W25Q40BV", SFUD_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q32BV", SFUD_MF_ID_WINBOND, 0x40, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q64CV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q64DW", SFUD_MF_ID_WINBOND, 0x60, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q128BV", SFUD_MF_ID_WINBOND, 0x40, 0x18, 16L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                  \{"W25Q256FV", SFUD_MF_ID_WINBOND, 0x40, 0x19, 32L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                  \{"SST25VF080B", SFUD_MF_ID_SST, 0x25, 0x8E, 1L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \{"SST25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \{"M25P32", SFUD_MF_ID_MICRON, 0x20, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                  \{"M25P80", SFUD_MF_ID_MICRON, 0x20, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                  \{"M25P40", SFUD_MF_ID_MICRON, 0x20, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                      \{"EN25Q32B", SFUD_MF_ID_EON, 0x30, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"GD25Q64B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                 \{"GD25Q16B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                 \{"S25FL216K", SFUD_MF_ID_CYPRESS, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                   \{"S25FL032P", SFUD_MF_ID_CYPRESS, 0x02, 0x15, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                   \{"A25L080", SFUD_MF_ID_AMIC, 0x30, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"F25L004", SFUD_MF_ID_ESMT, 0x20, 0x13, 512L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},                     \{"PCT25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \
}
#endif /* SFUD_USING_FLASH_INFO_TABLE */


 

但是在添加spi来读取外部FLASH的时候,遇到了一些情况。

例如,找不到设备,或者说无法读取FLASH的ID。

读出的设备ID、厂商ID等是正确的,但是检测出来不符合SFDP标准。

[SFUD](..\..\..\sfud\src\sfud.c:116) Start initialize Serial Flash Universal Driver(SFUD) V1.1.0.
[SFUD](..\..\..\sfud\src\sfud.c:117) You can get the latest version on https://github.com/armink/SFUD .
[SFUD](..\..\..\sfud\src\sfud.c:861) The flash device manufacturer ID is 0xEF, memory type ID is 0x40, capacity ID is 0x16.
[SFUD](..\..\..\sfud\src\sfud_sfdp.c:122) Error: Check SFDP signature error. It's must be 50444653h('S' 'F' 'D' 'P').
[SFUD]Warning: Read SFDP parameter header information failed. The W25Q32BV is not support JEDEC SFDP.
[SFUD]Find a Winbond W25Q32BV flash chip. Size is 4194304 bytes.
[SFUD](..\..\..\sfud\src\sfud.c:840) Flash device reset success.
[SFUD]W25Q32BV flash device is initialize success.
[SFUD]Error: Can't enable write status.
Erase the W25Q32BV flash data failed.

sfud_port.c 修改引脚

 以上全部修改完之后

在主函数添加测试代码

static void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{sfud_err result = SFUD_SUCCESS;const sfud_flash *flash = sfud_get_device_table() + 0;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){RTT_Printf("Erase the %s flash data finish. Start from 0x%08X, size is %ld.\r\n", flash->name, addr,size);}else{RTT_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){RTT_Printf("Write the %s flash data finish. Start from 0x%08X, size is %ld.\r\n", flash->name, addr,size);}else{RTT_Printf("Write the %s flash data failed.\r\n", flash->name);return;}/* read test */result = sfud_read(flash, addr, size, data);if (result == SFUD_SUCCESS){RTT_Printf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\r\n", flash->name, addr,size);RTT_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){RTT_Printf("[%08X] ", addr + i);}RTT_Printf("%02X ", data[i]);if (((i + 1) % 16 == 0) || i == size - 1){RTT_Printf("\r\n");}}RTT_Printf("\r\n");}else{RTT_Printf("Read the %s flash data failed.\r\n", flash->name);}/* data check */for (i = 0; i < size; i++){if (data[i] != i % 256){RTT_Printf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);break;}}if (i == size){RTT_Printf("The %s flash test is success.\r\n", flash->name);}
}

打印的结果显示

 

 关于HAL库移植SFUD 参考以下的文章

SFUD移植 - 简书

本文中所使用的裸机工程是基于HAL库的,在SFUD源码的Demo中也有一份HAL库的工程,因为基于HAL库的移植接口实现都是一样的,所以我直接将Demo中的sfud_port.c文件复制过来替换:

推荐看官方文档SFUD: 一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库 (gitee.com)

FLASH芯片型号:W25Q64JVSSIQ
RTOS:liteos-m
MCU:STM32F407ZGT6 HAL库

判断芯片支持SFUD

1.FLASH芯片支持SFDP标准;(在芯片datesheet中全局搜索SFDP)。
2.如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( \sfud\inc\sfud_flash_def.h ) 中提供的 Flash 参数信息表 是否支持该款 Flash。

#ifdef SFUD_USING_FLASH_INFO_TABLE
/* SFUD supported flash chip information table. If the flash not support JEDEC JESD216 standard,* then the SFUD will find the flash chip information by this table. You can add other flash to here then*  notice me for update it. The configuration information name and index reference the sfud_flash_chip structure.* | name | mf_id | type_id | capacity_id | capacity | write_mode | erase_gran | erase_gran_cmd |*/
#define SFUD_FLASH_CHIP_TABLE                                                                                       \
{                                                                                                                   \{"AT45DB161E", SFUD_MF_ID_ATMEL, 0x26, 0x00, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_DUAL_BUFFER, 512, 0x81},      \{"W25Q40BV", SFUD_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q32BV", SFUD_MF_ID_WINBOND, 0x40, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q64CV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q64DW", SFUD_MF_ID_WINBOND, 0x60, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                    \{"W25Q128BV", SFUD_MF_ID_WINBOND, 0x40, 0x18, 16L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                  \{"W25Q256FV", SFUD_MF_ID_WINBOND, 0x40, 0x19, 32L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                  \{"SST25VF080B", SFUD_MF_ID_SST, 0x25, 0x8E, 1L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \{"SST25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \{"M25P32", SFUD_MF_ID_MICRON, 0x20, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                  \{"M25P80", SFUD_MF_ID_MICRON, 0x20, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                  \{"M25P40", SFUD_MF_ID_MICRON, 0x20, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8},                      \{"EN25Q32B", SFUD_MF_ID_EON, 0x30, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"GD25Q64B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                 \{"GD25Q16B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                 \{"S25FL216K", SFUD_MF_ID_CYPRESS, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                   \{"S25FL032P", SFUD_MF_ID_CYPRESS, 0x02, 0x15, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                   \{"A25L080", SFUD_MF_ID_AMIC, 0x30, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},                        \{"F25L004", SFUD_MF_ID_ESMT, 0x20, 0x13, 512L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},                     \{"PCT25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20},              \
}
#endif /* SFUD_USING_FLASH_INFO_TABLE */

3.如果列表中还没有你用的芯片,按照格式要求在表的末尾添加自己的芯片即可。

接口适配

1.\sfud\inc\sfud_cfg.h

 

#ifndef _SFUD_CFG_H_
#define _SFUD_CFG_H_#define SFUD_DEBUG_MODE#define SFUD_USING_SFDP// #define SFUD_USING_FLASH_INFO_TABLEenum {SFUD_W25Q64JV_DEVICE_INDEX = 0,
};#define SFUD_FLASH_DEVICE_TABLE                                                \
{                                                                              \[SFUD_W25Q64JV_DEVICE_INDEX] = {.name = "W25Q64JV", .spi.name = "SPI2"},           \
}// #define SFUD_USING_QSPI#endif /* _SFUD_CFG_H_ */

我这里用的是FLASH芯片支持SFDP标准,用的是SPI通信。所以可以屏蔽掉SFUD_USING_FLASH_INFO_TABLE和SFUD_USING_QSPI两个宏。
SFUD_FLASH_DEVICE_TABLE中定义了自己使用的FLASH芯片。

2.spi.c

配置完成后,需要初始化spi。我这里使用cubemx生成spi初始化代码。并增加spi_cs的初始化代码。为了让SFUD能支持一个MCU通过任意SPI接任意数量的FLASH芯片,增加spi_cs_low()spi2_cs_high()。源码如下:

/* Includes ------------------------------------------------------------------*/
#include "spi.h"/* USER CODE BEGIN 0 */
#define SPI2_CS_PIN GPIO_PIN_0
#define SPI2_CS_GPIO_PORT GPIOC
/* USER CODE END 0 */SPI_HandleTypeDef hspi2;/* SPI2 init function */
void MX_SPI2_Init(void)
{/* USER CODE BEGIN SPI2_Init 0 *//* USER CODE END SPI2_Init 0 *//* USER CODE BEGIN SPI2_Init 1 *//* USER CODE END SPI2_Init 1 */hspi2.Instance = SPI2;hspi2.Init.Mode = SPI_MODE_MASTER;hspi2.Init.Direction = SPI_DIRECTION_2LINES;hspi2.Init.DataSize = SPI_DATASIZE_8BIT;hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;hspi2.Init.NSS = SPI_NSS_SOFT;hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi2.Init.TIMode = SPI_TIMODE_DISABLE;hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi2.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi2) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI2_Init 2 *//* USER CODE END SPI2_Init 2 */
}void HAL_SPI_MspInit(SPI_HandleTypeDef *spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if (spiHandle->Instance == SPI2){/* USER CODE BEGIN SPI2_MspInit 0 *//* USER CODE END SPI2_MspInit 0 *//* SPI2 clock enable */__HAL_RCC_SPI2_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**SPI2 GPIO ConfigurationPC2     ------> SPI2_MISOPC3     ------> SPI2_MOSIPB10     ------> SPI2_SCK*/GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* USER CODE BEGIN SPI2_MspInit 1 */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);/*Configure GPIO pin : SPI_FLASH_CS_Pin */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/* USER CODE END SPI2_MspInit 1 */}
}void HAL_SPI_MspDeInit(SPI_HandleTypeDef *spiHandle)
{if (spiHandle->Instance == SPI2){/* USER CODE BEGIN SPI2_MspDeInit 0 *//* USER CODE END SPI2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_SPI2_CLK_DISABLE();/**SPI2 GPIO ConfigurationPC2     ------> SPI2_MISOPC3     ------> SPI2_MOSIPB10     ------> SPI2_SCK*/HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10);/* USER CODE BEGIN SPI2_MspDeInit 1 *//* USER CODE END SPI2_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */
void spi2_cs_low(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
}void spi2_cs_high(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
}
/* USER CODE END 1 */

3.\sfud\port\sfud_port.c

为了让SFUD能支持一个MCU通过任意SPI接任意数量的FLASH芯片,定义了结构体sfud_port_t
sfud_spi_port_init()sfud_port_t初始化。源码如下:

#include 
#include 
#include "main.h"
#include "los_mux.h"
#include "los_task.h"
#include "los_memory.h"
#include "string.h"
#include "spi.h"
static char log_buf[256];typedef struct
{SPI_HandleTypeDef *hspi;UINT32 lock;void (*cs_low)(void);void (*cs_high)(void);
} sfud_port_t;void sfud_log_debug(const char *file, const long line, const char *format, ...);static void spi_lock(const struct __sfud_spi *spi)
{sfud_port_t *sfud_port = (sfud_port_t *)(spi->user_data);LOS_MuxPend(sfud_port->lock, 1000);
}static void spi_unlock(const struct __sfud_spi *spi)
{sfud_port_t *sfud_port = (sfud_port_t *)(spi->user_data);LOS_MuxPost(sfud_port->lock);
}/*** 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;sfud_port_t *sfud_port = (sfud_port_t *)(spi->user_data);// uint8_t send_data, read_data;/*** add your spi write and read code*/sfud_port->cs_low();if (HAL_SPI_Transmit(sfud_port->hspi, (uint8_t *)write_buf, write_size, 3000) != HAL_OK){// sfud_log_debug(__FILE__, __LINE__, "spi write fail.");result = SFUD_ERR_WRITE;goto ERR;}if ((read_buf != NULL) && (read_size != 0)){if (HAL_SPI_Receive(sfud_port->hspi, read_buf, read_size, 3000) != HAL_OK){// sfud_log_debug(__FILE__, __LINE__, "spi read fail.");result = SFUD_ERR_READ;}}// return result;
ERR:sfud_port->cs_high();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 */static void retry_delay(void)
{LOS_TaskDelay(1);
}sfud_err sfud_spi_port_init(sfud_flash *flash)
{sfud_err result = SFUD_SUCCESS;sfud_port_t *sfud_port = NULL;/*** 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*//*Configure GPIO pin Output Level */if (strcmp(flash->spi.name, "SPI2") == 0){MX_SPI2_Init();sfud_port = LOS_MemAlloc(m_aucSysMem0, sizeof(sfud_port_t));if (sfud_port == NULL){sfud_log_debug(__FILE__, __LINE__, "memory alloc fail.");goto ERR_MEMALLOC;}if (LOS_MuxCreate(&sfud_port->lock) != LOS_OK){sfud_log_debug(__FILE__, __LINE__, "mux create fail.");result = SFUD_ERR_NOT_FOUND;goto ERR_MUX;}sfud_port->hspi = &hspi2;sfud_port->cs_high = spi2_cs_high;sfud_port->cs_low = spi2_cs_low;flash->spi.wr = spi_write_read; // Requiredflash->spi.lock = spi_lock;flash->spi.unlock = spi_unlock;flash->spi.user_data = sfud_port;flash->retry.delay = retry_delay;flash->retry.times = 10000; // Required}else{result = SFUD_ERR_NOT_FOUND;}return result;ERR_MUX:LOS_MemFree(m_aucSysMem0, sfud_port);
ERR_MEMALLOC:HAL_SPI_DeInit(sfud_port->hspi);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);
}

跑起来

业务层/应用层只需要关注sfud.h中的api。初始化过程如下:

sfud_flash *w25q64_handle;sfud_init();
// SFUD_W25Q64JV_DEVICE_INDEX在sfud_cfg.h中自己定义。
w25q64_handle = sfud_get_device(SFUD_W25Q64JV_DEVICE_INDEX);

获得句柄w25q64_handle后,就调用读、写、擦除等API了。
测试结果如下:

[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud.c:116) Start initialize Serial Flash Universal Driver(SFUD) V1.1.0.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud.c:117) You can get the latest version on https://github.com/armink/SFUD .
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud.c:861) The flash device manufacturer ID is 0xEF, memory type ID is 0x40, capacity ID is 0x17.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:131) Check SFDP header is OK. The reversion is V1.5, NPN is 0.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:173) Check JEDEC basic flash parameter header is OK. The table id is 0, reversion is V1.5, length is 16, parameter table pointer is 0x000080.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:203) JEDEC basic flash parameter table info:
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:204) MSB-LSB  3    2    1    0
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0001] 0xFF 0xF9 0x20 0xE5
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0002] 0x03 0xFF 0xFF 0xFF
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0003] 0x6B 0x08 0xEB 0x44
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0004] 0xBB 0x42 0x3B 0x08
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0005] 0xFF 0xFF 0xFF 0xFE
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0006] 0x00 0x00 0xFF 0xFF
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0007] 0xEB 0x40 0xFF 0xFF
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0008] 0x52 0x0F 0x20 0x0C
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:206) [0009] 0x00 0x00 0xD8 0x10
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:215) 4 KB Erase is supported throughout the device. Command is 0x20.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:234) Write granularity is 64 bytes or larger.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:245) Target flash status register is non-volatile.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:271) 3-Byte only addressing.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:305) Capacity is 8388608 Bytes.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:311) Flash device supports 4KB block erase. Command is 0x20.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:311) Flash device supports 32KB block erase. Command is 0x52.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud_sfdp.c:311) Flash device supports 64KB block erase. Command is 0xD8.
[SFUD]Find a Winbond flash chip. Size is 8388608 bytes.
[SFUD](E:/project/ohos_tunnel/code/ohos_tunnel_dev/third_party/sfud/src/sfud.c:840) Flash device reset success.
[SFUD]W25Q64JV flash device is initialize success.

参考文章

关于万能SPI-Flash驱动库SFUD移植心得

万能SPI-Flash驱动库SFUD移植心得 (amobbs.com 阿莫电子论坛 - 东莞阿莫电子网站)

 SFUD | 一款串行 Flash 通用驱动库

SFUD | 一款串行 Flash 通用驱动库_Mculover666的博客-CSDN博客

SFUD简介和移植感受_¥风笛¥的博客-CSDN博客

【学习笔记】RT-Thread中flash管理 — [SFUD组件 和 FAL驱动组件介绍]_黄逸芬的博客-CSDN博客

上一篇:四川人的话

下一篇:vulnhub靶机corrosion1

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
最安全的匿名举报方式 匿名12... 来源:中安在线8月9日,河北邢台小伙张钊(化名)在河北政务服务网12345平台举报楼上邻居涉嫌非法开...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
中国光棍有多少人 2020年9... 我国是世界上人口最多的国家,庞大的人口基数为我国的发展带来了许多的益处。但是同时,我国也是出生人口性...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...