前言:
最近学习小熊派的demo code过程中发现,居然还有QSPI这种协议,以前使用的都是标准SPI,对于spi flash以前更是只用过标准SPI,就在想flash芯片居然有这么多协议方式,驱动开发也太难了,于是有了去gitee仓库搜索开源的通用flash驱动代码想法,偶然间发现了armlink大神写的SFUD库。仓库地址在这里: https://gitee.com/Armink/SFUD
一、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 的全部操作。
更详细的介绍请去上方的gitee仓库。
二、SFUD移植到小熊派开发板
2.1 添加SFUD库
从上方的sfud仓库下载sfud源码,添加到keil工程中
2.2 配置cubeMX QSPI参数和管脚
2.3 适配port接口
2.3.1 修改sfud_cfg.h
#define SFUD_DEBUG_MODE
#define SFUD_USING_SFDP
#define SFUD_USING_FLASH_INFO_TABLE
enum {
SFUD_W25Q64JV_DEVICE_INDEX = 0,
};
#define SFUD_FLASH_DEVICE_TABLE \
{ \
[SFUD_W25Q64JV_DEVICE_INDEX] = {.name = "W25Q64JV", .spi.name = "SPI1"}, \
}
#define SFUD_USING_QSPI
2.3.4 修改sfud_port.c
static void spi_lock(const sfud_spi *spi)
{
__disable_irq();
}
static void spi_unlock(const sfud_spi *spi)
{
__enable_irq();
}
static spi_user_data spi1 = { .spix = &hqspi, .cs_gpiox = bearPi_qspi_cs_GPIO_Port, .cs_gpio_pin = bearPi_qspi_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
*/
switch (flash->index)
{
case SFUD_W25Q64JV_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;
}
在main函数中初始化
sfud_flash * easyflash_sfud_device = sfud_get_device(SFUD_W25Q64JV_DEVICE_INDEX);
sfud_init();
sfud_qspi_fast_read_enable(easyflash_sfud_device, 2);
三、SFUD运行
运行日志如下