(一)裸机使用
1. SFUD SFDP
SFUD :SPI通用驱动库
SFDP : 固态技术协会技术标准
2. 宏配置 占用大小
两个宏定义都打开,但是优先支持SFDP。
18864 + 3060 = 21924
关闭#define SFUD_USING_SFDP
Program Size: Code=15708 RO-data=2036 RW-data=104 ZI-data=2568
15708 + 2036 = 17744
比上面少了4180
关闭#define SFUD_USING_FLASH_INFO_TABLE
Program Size: Code=15568 RO-data=1312 RW-data=104 ZI-data=2568
15568 + 1312 = 16880
比上面少了864
#ifndef _SFUD_CFG_H_
#define _SFUD_CFG_H_
// 调试模式
#define SFUD_DEBUG_MODE
//SFUD会对支持SFDP的标准FLASH进行初始化
//支持SFDP的FLASH设备会把'S'、'F'、'D'、'P'这四个字符以及SFDP的版本号按顺序放在FLASH的某8个字节空间里
//#define SFUD_USING_SFDP
//是否使用该库自带的 Flash 参数信息表
//SFUD会根据用户在sfud_flash_def中SFUD_FLASH_CHIP_TABLE中定义的FLASH参数表来完成对FLASH的初始化
#define SFUD_USING_FLASH_INFO_TABLE
// QSPI 模式
//#define SFUD_USING_QSPI
//FLASH设备表
enum {
SFUD_W25_DEVICE_INDEX = 0,
};
#define SFUD_FLASH_DEVICE_TABLE \
{ \
[SFUD_W25_DEVICE_INDEX] = {.name = "W25Q16", .spi.name = "SPI1"}, \
}
#endif /* _SFUD_CFG_H_ */
3. 信息表内容
使用的W25Q16信息
读ID(0x9F),这里可以读出三种ID,第一个是制造商ID,第二个是存储器类型ID,第三个是容量ID
| 名称 | 制造商 ID | 类型 ID | 容量 ID | 容量 | 写模式 | 擦除粒度(擦除的最小单位) | 擦除粒度对应的命令 | 。
SFUD_WM_PAGE_256B = 1 << 0, /**< write 1 to 256 bytes per page */
#define SFUD_MF_ID_WINBOND 0xEF
{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},
0xEF 0X40 0X15
4. 移植注意:
- sfud_port.c 里面的接口文件
移植文件位于 /sfud/port/sfud_port.c ,文件中的 sfud_err sfud_spi_port_init(sfud_flash *flash) 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件 - sfud_cfg.h 里面的宏定义开关
主函数初始化和使用
/* SFUD initialize */
if (sfud_init() == SFUD_SUCCESS) {
sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
}
注意这个,第一次读ID之前需要判断是否繁忙
/* read JEDEC ID include manufacturer ID, memory type ID and flash capacity ID */
//读ID之前判断忙
wait_busy(flash);
result = read_jedec_id(flash);
接口文件里实现的读写
switch (flash->index) {
case SFUD_W25_DEVICE_INDEX: {
/* 同步 Flash 移植所需的接口及数据 */
flash->spi.wr = spi_write_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = &user_spi;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_nop;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 10000;
break;
}
}
用户延时函数
/* delay */
static void retry_delay_nop(void) {
uint32_t delay1 = 1000*1000;
while(delay1--)
{
__NOP();
}
}
片选拉低后需要给点时间
HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin, GPIO_PIN_RESET);
retry_delay_nop();
更改上面两个文件后可以使用
实际使用
未添加工程 10.7K
添加SFUD初始化和读写 21.54K
可以看到这个占用还是很大的
这个容量在BOOT中是不接受的
成功放弃
使用普通的自定义驱动函数
实现读写擦除等 14.66K
4K左右
可以接受
使用这种方式
关于DSPI QSPI
SPI : 4线,MOSI MISO 输出输入
DSPI : 4线, MOSI MISO 两个可做输出也可做输入, 例如输出+输出
QSPI: 6线,WP和HOLD线,也变成了数据线,
参考链接
链接地址
(二) RT_thread使用
- 配置软件包参数
- 在CUBEMX配置SPI 1的参数,使用软件片选,片选引脚不配置
- 在board.h中配置开启 #define BSP_USING_SPI1
- 在drv_spi.c中看到SPI的配置
在RTthread资源文件目录使用文件搜索工具
找一个spi_config.h的文件添加到工程里面
- 在开机初始化时候会调用rt_hw_spi_init
函数中主要将spi1 注册到spi_bus中 - 在drv_spi.c中还有rt_hw_spi_device_attach函数。
- 这个函数需要传入总线名称、设备名称、SPI的CS脚信息
总结:先注册spi1 总线设备,然后注册spi中层设备,然后设置片选引脚
然后把spi1总线和spi中层设备绑定
最后使用SFUD把spi中层设备绑定
第一层 spi设备
第二层 spi使用设备
第三层 SFUD
rt_sfud_flash_probe("W25Q", "spi1.0"))
>
rt_sfud_flash_probe_ex
>
/* initialize SFUD device */
if (sfud_device_init(sfud_dev) != SFUD_SUCCESS)
>
hardware_init
>
sfud_spi_port_init
>
- sfud_init
- sfud_device_init(&flash_table[i]);
- hardware_init(flash);+ software_init(flash);
- sfud_spi_port_init(flash);
case SFUD_W25_DEVICE_INDEX: {
/* 同步 Flash 移植所需的接口及数据 */
flash->spi.wr = spi_write_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = &user_spi;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_nop;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 10000;
break;
}