【分享】如何使用 SFUD 库来操作 SPI Flash 设备

发布于 2017-09-07 08:52:32
SFUD 是一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库,目前 RT-Thread 2.1.0 之后已经支持。这使得 RTT 可以驱动 更多型号的 SPI Flash 。同时使用该驱动支持多 Flash 对象实例, 能够让用户 同时驱动多片 SPI Flash 。主要使用方法如下:

1. 配置
在 rtconfig.h 可增加如下配置信息,每个配置的功能详见 rt-thread/components/drivers/spi/sfud/inc/sfud_cfg.h

#define RT_USING_SFUD //必选
#define RT_DEBUG_SFUD 1 //可选
#define RT_SFUD_USING_SFDP //可选
#define RT_SFUD_USING_FLASH_INFO_TABLE //可选

2. 使用
以往的方式只需输入 SPI Flash 的设备名称及对应的 SPI 设备名称即可

w25qxx_init("flash", "spi10");

dfs_mount("flash", "/", "elm", 0, 0);

现在使用方法也类似,只不过初始化成功后会返回 SPI flash 对象,这是一个动态 SPI flash 对象,支持对该 SPI flash 设备的删除。

static rt_spi_flash_device_t w25q64, sst25vf016b;
/* 创建两个 SPI Flash 设备,分别从 spi10 及 spi30 两个 spi 设备探测 */
w25q64 = rt_sfud_flash_probe("flash0", "spi10");
sst25vf016b = rt_sfud_flash_probe("flash1", "spi30");

dfs_mount("flash0", "/", "elm", 0, 0);

rt_sfud_flash_delete(sst25vf016b);

3、sf (SPI Flash 操作) 测试命令
在 spi_flash_sfud.c 定义有 SPI Flash 操作命令,可以通过 MSH 命令来手动操作 SPI Flash ,简单使用方法如下:
msh >sf
Usage:
sf probe [spi_device] - probe and init SPI flash by given 'spi_device'
sf read addr size - read 'size' bytes starting at 'addr'
sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'
sf erase addr size - erase 'size' bytes starting at 'addr'
sf status [ ] - read or write '1:volatile|0:non-volatile' 'status'
sf bench - full chip benchmark. DANGER: It will erase full chip!

msh >sf probe spi10
8 MB W25Q64 is current selected device.

msh >sf read 0 64
Read the W25Q64 flash data success. Start from 0x00000000, size is 64. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000000] 54 00 00 00 90 8F E3 A7 69 61 70 5F 6E 65 65 64
[00000010] 5F 63 6F 70 79 5F 61 70 70 3D 30 00 69 61 70 5F
[00000020] 63 6F 70 79 5F 61 70 70 5F 73 69 7A 65 3D 30 00
[00000030] 73 74 6F 70 5F 69 6E 5F 62 6F 6F 74 6C 6F 61 64

msh >sf write 10 1 2 3 4 5
Write the W25Q64 flash data success. Start from 0x0000000A, size is 5.
Write data: 1 2 3 4 5 .

msh >sf erase 0 8192
Erase the W25Q64 flash data success. Start from 0x00000000, size is 8192

msh >sf status
The W25Q64 flash status register current value is 0x00.

msh >sf status 1 28
Write the W25Q64 flash status register to 0x1C success.

msh >sf bench yes
Erasing the W25Q64 8388608 bytes data, waiting...
Erase benchmark success, total time: 20.591S.
Writing the W25Q64 8388608 bytes data, waiting...
Write benchmark success, total time: 32.768S.
Reading the W25Q64 8388608 bytes data, waiting...
Read benchmark success, total time: 16.129S.

查看更多

关注者
0
被浏览
11.4k
41 个回答
bernard
bernard 2017-09-07
这个部分,
>> w25q64 = rt_sfud_flash_probe("W25Q64", "spi10");
>> sst25vf016b = rt_sfud_flash_probe("SST25VF016B", "spi30");

感觉有些多余,能否flash0 = rt_sfud_flash_probe("flash0", "spi10"); 然后就自动识别?还有一个需要考虑的,分区表怎么整合起来?
armink
armink 2017-09-07
这个部分,
>> w25q64 = rt_sfud_flash_probe("W25Q64", "spi10");
>> sst25vf016b = rt_sfud_flash_probe("SST25VF016B", "spi30");

感觉有些多余,能否flash0 = rt_sfud_flash_probe("flash0", "spi10"); 然后就自动识别?还有一个需要考虑的,分区表怎么整合起来?


熊大,你可能理解错意思了,底层是自动识别的。rt_sfud_flash_probe 这个函数的第一个入参是返回对象的名称,跟 rt_thread_create 的第一个入参概念是一样的。

你是指的你的那个 partition 组件吗?
bernard
bernard 2017-09-07
我觉得也是,所以我实际上建议你给的例子能够统一、抽象化些比较好,然后可以给出注释出来。

SFUD应该更类似flash底层的操作吧?如果程序固件本身占用一部分,那么必然会引入分区的部分。partition组件是一种可能
armink
armink 2017-09-07
我觉得也是,所以我实际上建议你给的例子能够统一、抽象化些比较好,然后可以给出注释出来。

SFUD应该更类似flash底层的操作吧?如果程序固件本身占用一部分,那么必然会引入分区的部分。partition组件是一种可能


对的,SFUD 是以字符模式操作 flash 的,这点跟块设备有区别。

分区这个功能感觉是可选的,作为 RTT 的一个 package 也不错。
勇士FF
勇士FF 2018-07-02
我使用的是3.0.4 build Jun 24 2018

bsp/stm32f429-apollo
编译下载 ,出现如下问题:
[SFUD]Warning: Read SFDP parameter header information failed. The W25Q256 is not support JEDEC SFDP.
[SFUD]Warning: This flash device is not found or not support.
[SFUD]Error: W25Q256 flash device is initialize fail.
ERROR: SPI flash probe failed by SPI device spi50.

我检查了好久没有找到答案,我猜想rtt官网再app中使用并且driver都已测试,我直接下载就可以使用,想测试下效果出现如上错误,

probe:
if (RT_NULL == rt_sfud_flash_probe("W25Q256", "spi50"))
{
return RT_ERROR;
};

挂:
result = rt_spi_bus_attach_device(&spi_device, "spi50", "spi5", (void*)&spi_cs);

msh />list_device
device type ref count
------ -------------------- ----------
e0 Network Interface 0
spi50 SPI Device 0
spi5 SPI Bus 0
i2c0 I2C Bus 1
nand0 MTD Device 0
rtc RTC 0
uart2 Character Device 0
uart1 Character Device 2


sf probe spi50
[SFUD]Warning: Read SFDP parameter header information failed. The sf_cmd is not support JEDEC SFDP.
[SFUD]Warning: This flash device is not found or not support.
[SFUD]Error: sf_cmd flash device is initialize fail.
ERROR: SPI flash probe failed by SPI device spi50.
msh />
msh />

烦请知道的人员赐教下 谢谢
whj467467222
whj467467222 认证专家 2018-07-03
勇士FF 发表于 2018-7-2 22:38
我使用的是3.0.4 build Jun 24 2018

bsp/stm32f429-apollo


找不到帖子链接地址了。以前W25Q256是不支持SFUD的,前几天刚更新的SFUD已经支持了,你更新一下驱动看看。https://github.com/armink/SFUD
whj467467222
whj467467222 认证专家 2018-07-05
@armink

现在使用SFUD驱动AT45DB321E,sfud本来不支持,参考您的添加方法加进去了AT45DB321E,能识别到该FLASH,现在有几个问题请问一下。
1,在官方的datesheet
User configurable page size
 512 bytes per page
 528 bytes per page (default)
 Page size can be factory pre-configured for 512 bytes
默认为528,
在其他论坛看到其他网友的普遍做法是每次读528,写的时候就是512,通过这种操作来实现读写
而在SFUD设置的AT45是512,看datesheet里面修改每页字节大小是otp,只能修改一次
2,SFUD只是FLASH驱动,如果要进行读 写 擦除 就可以使用您开源的easyflash了吧
whj467467222
whj467467222 认证专家 2018-07-06
armink 发表于 2017-9-7 11:06
对的,SFUD 是以字符模式操作 flash 的,这点跟块设备有区别。

分区这个功能感觉是可选的,作为 RTT 的 ...


armink,老大,我在使用SFUD的遇到了这样几个问题
rt_sfud_flash_probe 这个函数是探测FLASH型号,并返回一个设备指针
那么我在使用sfud_read 操作时,编译器报错,因为sfud_read的参数类型是const类型

下载了您提供的demo里面有一个裸机版的例程,里面有一个测试程序

测试程序sfud_get_device_table来获取
static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;


enum {
SFUD_AT45_DEVICE_INDEX = 0,
};

#define SFUD_FLASH_DEVICE_TABLE \
{ \
[SFUD_AT45_DEVICE_INDEX] ={.name = "AT45DB321E", .spi.name = "SPI1"}, \
}


这样可以指针指向这里的时候是没有flash容量数据的,会出现地址超出

如果我在上面加入芯片的chip,在进行读操作的时候,运行sfud_read_status的时候回死机
NikolaDi
NikolaDi 2018-07-18
SFUD 能读出 厂商ID,读出来也是正确的,SPI FLASH 也支持 SFDP ,为啥读出来的错误呢?
SPI FLASH 用的是 IS25LP256D
TIM截图20180718142707.png
whj467467222
whj467467222 认证专家 2018-07-18
NikolaDi 发表于 2018-7-18 14:29
SFUD 能读出 厂商ID,读出来也是正确的,SPI FLASH 也支持 SFDP ,为啥读出来的错误呢?
SPI FLASH 用的是 ...


我看了下SFUD提供支持的FLASH里面没有你这款,所以你需要自己添加
如何添加库里没有的FLASH
kklili
kklili 2018-12-26
请教一下楼主,每次sfud都是 check error,我把最新的table加上之后,ID能找到对应的FLASH,但是还是找不到SFDP的signature,最后显示挂载SPI FLASH失败,用的是阿波罗的F429开发板,有可能是什么问题呢?[img]d:\1.png[/img]

1.png
armink
armink 2018-12-26
kklili 发表于 2018-12-26 09:14
请教一下楼主,每次sfud都是 check error,我把最新的table加上之后,ID能找到对应的FLASH,但是还是找不到 ...


这个问题挺常见的。不排除 Flash 出厂日期过早还未支持 SFDP 标准,还有可能是假货。

方便给拍个照片吗?可以大致看到一些出厂信息
Liam
Liam 2019-01-26
    本帖最后由 Liam 于 2019-1-26 15:48 编辑


求助一下楼主,我工程在main线程中运行到w25qxx_init()的时候就报了互斥量不存在,是打开的驱动有问题么?应该怎么修改呢.我硬件flash是w25q64_bv
int main()
{
rt_kprintf("SPI test.\r\n");
w25qxx_init("flash", "spi1");
//w25qxx_init(W25Q_SPI_DEVICE_NAME, "spi1");

dfs_mount("flash", "/", "elm", 0, 0);
return 0;
}



mutex_error.jpg
menuconfig.jpg
armink
armink 2019-01-26
Liam 发表于 2019-1-26 15:45
求助一下楼主,我工程在main线程中运行到w25qxx_init()的时候就报了互斥量不存在,是打开的驱动有问题么? ...


SFUD 与 下面那个 w25q 驱动不是一个东西,你好像搞混了
yaomo718
yaomo718 2019-01-27
勇士FF 发表于 2018-7-2 22:38
我使用的是3.0.4 build Jun 24 2018

bsp/stm32f429-apollo


我在429上是可以使用的,软件版本为3.0.3,falsh也是W25Q128。
从flash里读取失败,请先确认你的spi引脚有没有正确配置,先确认审批总线没有问题,然后可以跟踪一下从flash里有没有读取出来什么数据。
armink
armink 2019-01-27
kklili 发表于 2018-12-26 09:14
请教一下楼主,每次sfud都是 check error,我把最新的table加上之后,ID能找到对应的FLASH,但是还是找不到 ...


问题后来解决了吗?

记得有个网友定位过该问题,好像是 CS 引脚初始化过晚会出现该问题。
Liam
Liam 2019-02-01
请教楼主一个问题,我在使用SPI flash的时候可以正常工作,测试同一个SPI总线上的SD卡时不能正常工作。
两者只是片选信号不一样,在挂载时已修正。请问一下这个现象是我SD卡、TF卡的问题么?

flash.jpg
SD.jpg
armink
armink 2019-02-02
Liam 发表于 2019-2-1 11:32
请教楼主一个问题,我在使用SPI flash的时候可以正常工作,测试同一个SPI总线上的SD卡时不能正常工作。
两 ...


不太清楚,把你的问题单独发帖吧
yangyang
yangyang 2019-03-21
勇士FF 发表于 2018-7-2 22:38
我使用的是3.0.4 build Jun 24 2018

bsp/stm32f429-apollo


你好,我编译的时候也是这样的问题。请问你找到解决方法了吗?
quandevil
quandevil 2019-06-18
yangyang 发表于 2019-3-21 17:01
你好,我编译的时候也是这样的问题。请问你找到解决方法了吗?


坑。。还没有解决
storm
storm 2019-08-23
分享一下我今天使用SFUD 一些心得
首先 配置env后,自动添加了一个spi_flash_init.C文件里面有
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4);

if (RT_NULL == rt_sfud_flash_probe("W25Q32", "spi10"))
{
return -RT_ERROR;
};

return RT_EOK;
}

然后在主函数里面调用
sfud_flash *sfud_dev =NULL;
sfud_dev=rt_sfud_flash_find_by_dev_name("W25Q32");然后就可以开心的玩耍了
result=sfud_erase(sfud_dev, 0, 1024);
result=sfud_read(sfud_dev, 0, 32, data);
memset(dataBufW,1,31);
result=sfud_write(sfud_dev,0,32,dataBufW);
result=sfud_read(sfud_dev, 0, 32, data);

ps:
armink大神可能认为调用这些神马的都是些基本工,
但是对于刚接触这个框架的人来说真的很难找到怎么单独的读写flash啊,sf命令里来回来去的调用看的人眼花缭乱不如直接上具体该怎么应用这个接口框架
beli
beli 2019-08-23
storm 发表于 2019-8-23 15:19
分享一下我今天使用SFUD 一些心得
首先 配置env后,自动添加了一个spi_flash_init.C文件里面有
static int ...


https://www.rt-thread.org/qa/thread-421528-1-1.html
我也遇到了些问题,能帮我看下吗。
storm
storm 2019-08-23
beli 发表于 2019-8-23 16:40
https://www.rt-thread.org/qa/thread-421528-1-1.html
我也遇到了些问题,能帮我看下吗。 ...


不好意思,我还没看到文件系统那里,不过看你的日志应该已经成功探测到了flash
你可以用
sf probe spi50
然后
sf erase
sf read
sf write
这几个命令试试看写数据和读数据是否正常
beli
beli 2019-08-23
storm 发表于 2019-8-23 17:10
不好意思,我还没看到文件系统那里,不过看你的日志应该已经成功探测到了flash
你可以用
sf probe spi50 ...


就是这几个命令不正常。但是用easyflash命令测试读写是正常的。
armink
armink 2019-08-23
storm 发表于 2019-8-23 15:19
分享一下我今天使用SFUD 一些心得
首先 配置env后,自动添加了一个spi_flash_init.C文件里面有
static int ...

感谢分享,另外单独操作 SFUD flash 的函数是不是可以看下 SFUD 文档上的介绍呢

https://github.com/armink/SFUD#2 ... -%E6%95%B0%E6%8D%AE
storm
storm 2019-08-26
armink 发表于 2019-8-23 19:52
感谢分享,另外单独操作 SFUD flash 的函数是不是可以看下 SFUD 文档上的介绍呢

https://github.com/armi ...


感谢大神回复 我研究一下
zsurge
zsurge 2019-10-09
armink 发表于 2017-9-7 09:07
熊大,你可能理解错意思了,底层是自动识别的。rt_sfud_flash_probe 这个函数的第一个入参是返回对象的名 ...


龙哥,我使用您的SFUD+easyFlash+FreeRTOS,使用ef_set_env和ef_et_env 这两句话需要6秒时间?想请教下,您认为大概是那方面问题?
armink
armink 2019-10-10
zsurge 发表于 2019-10-9 20:27
龙哥,我使用您的SFUD+easyFlash+FreeRTOS,使用ef_set_env和ef_et_env 这两句话需要6秒时间?想请教下, ...


用的是 GitHub 上的最新版吗?
瑞尧
瑞尧 2019-11-11
kklili 发表于 2018-12-26 09:14
请教一下楼主,每次sfud都是 check error,我把最新的table加上之后,ID能找到对应的FLASH,但是还是找不到 ...


你好,请问你说的table是指的mount table吗?
翌雨芩风
翌雨芩风 2019-11-26
各位大神,如何用SFUD实16位/32位读写,而不是现在的8位。:)
freedom195
freedom195 2020-02-14
@armink 大神,在调SFUD中遇到问题了,源码看了很久,感觉我想的可能不对,但实际的结果就是错的,特来问下。



https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=423563&extra=page%3D1%26filter%3Dtypeid%26typeid%3D60
熊喵炖香菇
熊喵炖香菇 2020-03-04
请问使用 sf probe探测设备 控制台就卡住不动了 看了程序一直卡在 while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)); 请问各位大佬,可能是什么原因?
1583324143(1).jpg
1583324487(1).jpg
weizixiu
weizixiu 2020-04-18
Liam 发表于 2019-1-26 15:45
求助一下楼主,我工程在main线程中运行到w25qxx_init()的时候就报了互斥量不存在,是打开的驱动有问题么? ...


兄弟,你这个问题解决了吗?
木成舟
木成舟 2020-05-10
我想问下,我用了ota之后,sfud就无法重新初始化成功了,这个是什么问题呢?

test1.png
whj467467222
whj467467222 认证专家 2020-05-10
木成舟 发表于 2020-5-10 00:10
我想问下,我用了ota之后,sfud就无法重新初始化成功了,这个是什么问题呢?
...


你OTA之前也没成功啊
木成舟
木成舟 2020-05-10
whj467467222 发表于 2020-5-10 09:24
你OTA之前也没成功啊


OTA之前成功的,可以从远程下载进去w25q64,而且可以跳转,但是一跳转执行app分区的程序,就提示sfud失败。
木成舟
木成舟 2020-05-10
whj467467222 发表于 2020-5-10 09:24
你OTA之前也没成功啊


我想问下,我用的是stm32f103ret6 spi3,这个是不是对于ota有影响?
Nanne
Nanne 2020-05-18
    本帖最后由 Nanne 于 2020-5-18 15:49 编辑


1.png
如上图,此处既然已经注册设备了,为什么采用这样的方式调用呢?
// sfud_flash *sfud_dev =NULL;
// sfud_dev=rt_sfud_flash_find_by_dev_name("W25Q32"); //然后就可以开心的玩耍了
// result=sfud_erase(sfud_dev, 0, 1024);
// result=sfud_read(sfud_dev, 0, 32, data);
// memset(dataBufW,1,31);
// result=sfud_write(sfud_dev,0,32,dataBufW);
// result=sfud_read(sfud_dev, 0, 32, data);



我在应用的时候,如果按照注册设备的方式应用,则会出现报错:
g_rtt_sfud_flash_dev->flash_device.read((rt_device_t)sfud_dev, 0, (void *)data_buff_recv, 100);


是我的应用方法有问题,还是当前确实就是这样?@armink


Nanne
Nanne 2020-05-18
    本帖最后由 Nanne 于 2020-5-18 21:54 编辑


另外,以下宏定义的最大速度,是最大只能50MHz吗?
#define RT_SFUD_SPI_MAX_HZ 50000000

我的STM32H750IB板卡,实测50MHz会读取失败:
在【state = HAL_SPI_Receive(spi_handle, (uint8_t *)recv_buf, send_length, 1000)】处报错。
如果将频率降低到40MHz,则可以正常读写,这个可能是什么原因呢?
益达_fighting
益达_fighting 2020-06-27
storm 发表于 2019-8-23 15:19
分享一下我今天使用SFUD 一些心得
首先 配置env后,自动添加了一个spi_flash_init.C文件里面有
static int ...


昨天不知道SFUD,参照裸机32的代码用spi transfermessage那些API实现读写,心累哦
myLLgf
myLLgf 2020-09-02

您好,请问一下,我使用 at45db161e 这个芯片,和 rt_thread_studio 环境。现在遇到了一些问题:

我发现在 sfud_def.h 中,对 SFUD_CMD_XXXX 等指令的宏定义,都是和 at45db 系列的不一样的,和 w25 系列的芯片一样,除了 SFUD_CMD_JEDEC_ID 这个指令定义。

这样的话,如果想要 at45db 系列的也能工作起来,是否要把 SFUD_CMD_XXXX 等宏定义都按照 at45db 系列重写呢?

比如状态获取指令,at45db 系列是 0xD7, 而 sfud_def.h 中定义是 0x05。

非常期待您的回复和帮助!

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览