本次移植是在官方源码的基础上进行移植的
本次介绍的两个软件包SFUD/FAL都与FLASH有关,并且都可以独立使用或者结合在一起使用,两个软件包都对操作系统无依赖,可以使用裸机移植,也很方便移植到各种系统。
这两个软件包的作者都是armink,armink的开源仓库地址:https://github.com/armink,更多好玩的软件,请到作者仓库查询。
下面给出官方源码的下载链接
https://gitee.com/Armink/SFUD
SFUD 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
相关的说明大家可以进去链接详细的看一下
目前支持的FLASH类型列表
总结一下:SFUD就是一个SPI-FLASH的底层驱动,只要是遵循 JEDEC (固态技术协会)的芯片都是可以适配的,目前我理解的好处就是如果更换了硬件,只要是这个表里面的,就不需要改代码!!!
本来项目上是想用FlashDB
在移植嵌入式数据库的基础 上 首先第一步大多数都是先移植SFUD
工具准备STM32CubeMX:用于配置QSPI外设和串口外设,并生成 MDK 工程;
本文采用的模板是固件库版本
Keil MDK:用于编译和下载工程;
串口助手:用于查看开发板串口调试信息输出;
裸机工程准备
下载完源码后 直接将源码中的SFUD相关的.c .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_ */ 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.

以上全部修改完之后
在主函数添加测试代码
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);}
}
打印的结果显示

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库
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.如果列表中还没有你用的芯片,按照格式要求在表的末尾添加自己的芯片即可。

#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芯片。
配置完成后,需要初始化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 */
为了让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博客
上一篇:四川人的话