commit
a87914b535
|
@ -169,6 +169,10 @@ config RT_USING_SPI
|
||||||
default n
|
default n
|
||||||
|
|
||||||
if RT_USING_SPI
|
if RT_USING_SPI
|
||||||
|
config RT_USING_QSPI
|
||||||
|
bool "Enable QSPI mode"
|
||||||
|
default n
|
||||||
|
|
||||||
config RT_USING_SPI_MSD
|
config RT_USING_SPI_MSD
|
||||||
bool "Using SD/TF card driver with spi"
|
bool "Using SD/TF card driver with spi"
|
||||||
select RT_USING_DFS
|
select RT_USING_DFS
|
||||||
|
@ -186,6 +190,11 @@ config RT_USING_SPI
|
||||||
bool "Using defined supported flash chip information table"
|
bool "Using defined supported flash chip information table"
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config RT_SFUD_USING_QSPI
|
||||||
|
bool "Using QSPI mode support"
|
||||||
|
select RT_USING_QSPI
|
||||||
|
default n
|
||||||
|
|
||||||
config RT_DEBUG_SFUD
|
config RT_DEBUG_SFUD
|
||||||
bool "Show more SFUD debug information"
|
bool "Show more SFUD debug information"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -144,8 +144,8 @@ struct rt_qspi_configuration
|
||||||
rt_uint32_t medium_size;
|
rt_uint32_t medium_size;
|
||||||
/* double data rate mode */
|
/* double data rate mode */
|
||||||
rt_uint8_t ddr_mode;
|
rt_uint8_t ddr_mode;
|
||||||
/* the number of lines connected to the hardware */
|
/* the data lines max width which QSPI bus supported, such as 1, 2, 4 */
|
||||||
rt_uint8_t qspi_hw_lines;
|
rt_uint8_t qspi_dl_width ;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rt_qspi_device
|
struct rt_qspi_device
|
||||||
|
|
|
@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c']
|
||||||
CPPPATH = [cwd, cwd + '/../include']
|
CPPPATH = [cwd, cwd + '/../include']
|
||||||
LOCAL_CCFLAGS = ''
|
LOCAL_CCFLAGS = ''
|
||||||
|
|
||||||
|
if GetDepend('RT_USING_QSPI'):
|
||||||
|
src += ['qspi_core.c']
|
||||||
|
|
||||||
src_device = []
|
src_device = []
|
||||||
|
|
||||||
if GetDepend('RT_USING_SPI_WIFI'):
|
if GetDepend('RT_USING_SPI_WIFI'):
|
||||||
|
|
|
@ -25,7 +25,7 @@ rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configu
|
||||||
qspi_device->config.parent.reserved = cfg->parent.reserved;
|
qspi_device->config.parent.reserved = cfg->parent.reserved;
|
||||||
qspi_device->config.medium_size = cfg->medium_size;
|
qspi_device->config.medium_size = cfg->medium_size;
|
||||||
qspi_device->config.ddr_mode = cfg->ddr_mode;
|
qspi_device->config.ddr_mode = cfg->ddr_mode;
|
||||||
qspi_device->config.qspi_hw_lines = cfg->qspi_hw_lines;
|
qspi_device->config.qspi_dl_width = cfg->qspi_dl_width;
|
||||||
|
|
||||||
result = rt_spi_configure(&device->parent, &cfg->parent);
|
result = rt_spi_configure(&device->parent, &cfg->parent);
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
|
|
||||||
[SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
|
[SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
|
||||||
|
|
||||||
- 主要特点:面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
|
- 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
|
||||||
- 资源占用
|
- 资源占用
|
||||||
- 标准占用:RAM:0.2KB ROM:5.5KB
|
- 标准占用:RAM:0.2KB ROM:5.5KB
|
||||||
- 最小占用:RAM:0.1KB ROM:3.6KB
|
- 最小占用:RAM:0.1KB ROM:3.6KB
|
||||||
- 设计思路:这里要首先跟大家介绍一个标准: **SFDP** ,它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数,如果该 Flash 不支持 SFDP,则查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/master/sfud/inc/sfud_flash_def.h#L110-L122) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
|
- 设计思路:
|
||||||
|
- **什么是 SFDP** :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
|
||||||
|
- **不支持 SFDP 怎么办** :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/4bee2d0417a7ce853cc7aa3639b03fe825611fd9/sfud/inc/sfud_flash_def.h#L116-L142) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。
|
||||||
|
|
||||||
## 1、为什么选择 SFUD
|
## 1、为什么选择 SFUD
|
||||||
|
|
||||||
|
@ -23,37 +25,43 @@
|
||||||
|
|
||||||
### 2.1 已支持 Flash
|
### 2.1 已支持 Flash
|
||||||
|
|
||||||
下表为所有在 Demo 平台上进行过真机测试的 Flash。目前 SFUD 提供的 **Flash 参数信息表** 只包括下表中 **不支持** SFDP 标准的 Flash,其他不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
|
下表为所有已在 Demo 平台上进行过真机测试过的 Flash。显示为 **不支持** SFDP 标准的 Flash 已经在 Flash 参数信息表中定义,更多不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。
|
||||||
|
|
||||||
|型号|制造商|容量|最高速度|SFDP 标准|备注|
|
如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
|
||||||
|:--:|:----:|:--:|:--:|:--:|:--:|
|
|
||||||
|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|已停产|
|
|型号|制造商|容量|最高速度|SFDP 标准|QSPI 模式|备注|
|
||||||
|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持||
|
|:--:|:----:|:--:|:--:|:--:|:--:|----|
|
||||||
|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持| by [slipperstree](https://github.com/slipperstree)|
|
|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|双线|已停产|
|
||||||
|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持||
|
|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持|双线||
|
||||||
|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持| by [slipperstree](https://github.com/slipperstree)|
|
|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持|双线| by [slipperstree](https://github.com/slipperstree)|
|
||||||
|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持||
|
|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|未测试||
|
||||||
|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持||
|
|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持|未测试| by [slipperstree](https://github.com/slipperstree)|
|
||||||
|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持||
|
|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持|双线||
|
||||||
|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持||
|
|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|四线||
|
||||||
|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持||
|
|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|四线||
|
||||||
|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持| by [JiapengLi](https://github.com/JiapengLi)|
|
|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|四线||
|
||||||
|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持||
|
|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|双线||
|
||||||
|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持| SST 已被 Microchip 收购|
|
|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持|未测试| by [JiapengLi](https://github.com/JiapengLi)|
|
||||||
|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
|
|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|双线||
|
||||||
|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)|
|
|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持|不支持| SST 已被 Microchip 收购|
|
||||||
|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持||
|
|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
|
||||||
|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持||
|
|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)|
|
||||||
|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持| by [TanekLiang](https://github.com/TanekLiang) |
|
|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|不支持||
|
||||||
|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持||
|
|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|未测试||
|
||||||
|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持||
|
|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持|未测试| by [TanekLiang](https://github.com/TanekLiang) |
|
||||||
|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持| by [yc_911](https://gitee.com/yc_911) |
|
|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|双线||
|
||||||
|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持||
|
|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|双线||
|
||||||
|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持||
|
|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持|未测试| by [yc_911](https://gitee.com/yc_911) |
|
||||||
|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持||
|
|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|未测试||
|
||||||
|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持||
|
|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|双线||
|
||||||
|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|SST 授权许可,会被识别为 SST25VF016B|
|
|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|支持||
|
||||||
|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|ADESTO 收购 Atmel 串行闪存产品线|
|
|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持|不支持||
|
||||||
|
|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|不支持|SST 授权许可,会被识别为 SST25VF016B|
|
||||||
|
|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|不支持|ADESTO 收购 Atmel 串行闪存产品线|
|
||||||
|
|
||||||
|
> 注:QSPI 模式中,双线表示支持双线快读,四线表示支持四线快读。
|
||||||
|
>
|
||||||
|
> 一般情况下,支持四线快读的 FLASH 也支持两线快读。
|
||||||
|
|
||||||
### 2.2 API 说明
|
### 2.2 API 说明
|
||||||
|
|
||||||
|
@ -63,7 +71,7 @@
|
||||||
|
|
||||||
将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
|
将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
|
||||||
|
|
||||||
> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
|
> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_init(void)
|
sfud_err sfud_init(void)
|
||||||
|
@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_flash *flash)
|
||||||
|:----- |:----|
|
|:----- |:----|
|
||||||
|flash |待初始化的 Flash 设备|
|
|flash |待初始化的 Flash 设备|
|
||||||
|
|
||||||
#### 2.2.3 获取 Flash 设备对象
|
#### 2.2.3 使能快速读模式(仅当 SFUD 开启 QSPI 模式后可用)
|
||||||
|
|
||||||
|
当 SFUD 开启 QSPI 模式后,SFUD 中的 Flash 驱动支持使用 QSPI 总线进行通信。相比传统的 SPI 模式,使用 QSPI 能够加速 Flash 数据的读取,但当数据需要写入时,由于 Flash 本身的数据写入速度慢于 SPI 传输速度,所以 QSPI 模式下的数据写入速度提升并不明显。
|
||||||
|
|
||||||
|
所以 SFUD 对于 QSPI 模式的支持仅限于快速读命令。通过该函数可以配置 Flash 所使用的 QSPI 总线的实际支持的数据线最大宽度,例如:1 线(默认值,即传统的 SPI 模式)、2 线、4 线。
|
||||||
|
|
||||||
|
设置后,SFUD 会去结合当前设定的 QSPI 总线数据线宽度,去 [QSPI Flash 扩展信息表](https://github.com/armink/SFUD/blob/069d2b409ec239f84d675b2c3d37894e908829e6/sfud/inc/sfud_flash_def.h#L149-L177) 中匹配最合适的、速度最快的快速读命令,之后用户在调用 sfud_read() 时,会使用 QSPI 模式的传输函数发送该命令。
|
||||||
|
|
||||||
|
```C
|
||||||
|
sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 描述 |
|
||||||
|
| :-------------- | :------------------------------------------- |
|
||||||
|
| flash | Flash 设备 |
|
||||||
|
| data_line_width | QSPI 总线支持的数据线最大宽度,例如:1、2、4 |
|
||||||
|
|
||||||
|
#### 2.2.4 获取 Flash 设备对象
|
||||||
|
|
||||||
在 SFUD 配置文件中会定义 Flash 设备表,负责存放所有将要使用的 Flash 设备对象,所以 SFUD 支持多个 Flash 设备同时驱动。设备表的配置在 `/sfud/inc/sfud_cfg.h` 中 `SFUD_FLASH_DEVICE_TABLE` 宏定义,详细配置方法参照 [2.3 配置方法 Flash](#23-配置方法))。本方法通过 Flash 设备位于设备表中索引值来返回 Flash 设备对象,超出设备表范围返回 `NULL` 。
|
在 SFUD 配置文件中会定义 Flash 设备表,负责存放所有将要使用的 Flash 设备对象,所以 SFUD 支持多个 Flash 设备同时驱动。设备表的配置在 `/sfud/inc/sfud_cfg.h` 中 `SFUD_FLASH_DEVICE_TABLE` 宏定义,详细配置方法参照 [2.3 配置方法 Flash](#23-配置方法))。本方法通过 Flash 设备位于设备表中索引值来返回 Flash 设备对象,超出设备表范围返回 `NULL` 。
|
||||||
|
|
||||||
|
@ -91,7 +116,7 @@ sfud_flash *sfud_get_device(size_t index)
|
||||||
|:----- |:----|
|
|:----- |:----|
|
||||||
|index |Flash 设备位于 FLash 设备表中的索引值|
|
|index |Flash 设备位于 FLash 设备表中的索引值|
|
||||||
|
|
||||||
#### 2.2.4 读取 Flash 数据
|
#### 2.2.5 读取 Flash 数据
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
|
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
|
||||||
|
@ -104,7 +129,7 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
|
||||||
|size |从起始地址开始读取数据的总大小|
|
|size |从起始地址开始读取数据的总大小|
|
||||||
|data |读取到的数据|
|
|data |读取到的数据|
|
||||||
|
|
||||||
#### 2.2.5 擦除 Flash 数据
|
#### 2.2.6 擦除 Flash 数据
|
||||||
|
|
||||||
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
|
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
|
||||||
|
|
||||||
|
@ -118,7 +143,7 @@ sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
|
||||||
|addr |起始地址|
|
|addr |起始地址|
|
||||||
|size |从起始地址开始擦除数据的总大小|
|
|size |从起始地址开始擦除数据的总大小|
|
||||||
|
|
||||||
#### 2.2.6 擦除 Flash 全部数据
|
#### 2.2.7 擦除 Flash 全部数据
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_chip_erase(const sfud_flash *flash)
|
sfud_err sfud_chip_erase(const sfud_flash *flash)
|
||||||
|
@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash)
|
||||||
|:----- |:----|
|
|:----- |:----|
|
||||||
|flash |Flash 设备对象|
|
|flash |Flash 设备对象|
|
||||||
|
|
||||||
#### 2.2.7 往 Flash 写数据
|
#### 2.2.8 往 Flash 写数据
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
|
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
|
||||||
|
@ -141,7 +166,7 @@ sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const u
|
||||||
|size |从起始地址开始写入数据的总大小|
|
|size |从起始地址开始写入数据的总大小|
|
||||||
|data |待写入的数据|
|
|data |待写入的数据|
|
||||||
|
|
||||||
#### 2.2.8 先擦除再往 Flash 写数据
|
#### 2.2.9 先擦除再往 Flash 写数据
|
||||||
|
|
||||||
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
|
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
|
||||||
|
|
||||||
|
@ -156,7 +181,7 @@ sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, c
|
||||||
|size |从起始地址开始写入数据的总大小|
|
|size |从起始地址开始写入数据的总大小|
|
||||||
|data |待写入的数据|
|
|data |待写入的数据|
|
||||||
|
|
||||||
#### 2.2.9 读取 Flash 状态
|
#### 2.2.10 读取 Flash 状态
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
|
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
|
||||||
|
@ -167,7 +192,7 @@ sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
|
||||||
|flash |Flash 设备对象|
|
|flash |Flash 设备对象|
|
||||||
|status |当前状态寄存器值|
|
|status |当前状态寄存器值|
|
||||||
|
|
||||||
#### 2.2.10 写(修改) Flash 状态
|
#### 2.2.11 写(修改) Flash 状态
|
||||||
|
|
||||||
```C
|
```C
|
||||||
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
|
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
|
||||||
|
@ -234,6 +259,12 @@ enum {
|
||||||
|
|
||||||
上面定义了两个 Flash 设备(大部分产品一个足以),两个设备的名称为 `"W25Q64CV"` 及 `"GD25Q64B"` ,分别对应 `"SPI1"` 及 `"SPI3"` 这两个 SPI 设备名称(在移植 SPI 接口时会用到,位于 `/sfud/port/sfud_port.c` ), `SFUD_W25Q16CV_DEVICE_INDEX` 与 `SFUD_GD25Q64B_DEVICE_INDEX` 这两个枚举定义了两个设备位于设备表中的索引,可以通过 `sfud_get_device_table()` 方法获取到设备表,再配合这个索引值来访问指定的设备。
|
上面定义了两个 Flash 设备(大部分产品一个足以),两个设备的名称为 `"W25Q64CV"` 及 `"GD25Q64B"` ,分别对应 `"SPI1"` 及 `"SPI3"` 这两个 SPI 设备名称(在移植 SPI 接口时会用到,位于 `/sfud/port/sfud_port.c` ), `SFUD_W25Q16CV_DEVICE_INDEX` 与 `SFUD_GD25Q64B_DEVICE_INDEX` 这两个枚举定义了两个设备位于设备表中的索引,可以通过 `sfud_get_device_table()` 方法获取到设备表,再配合这个索引值来访问指定的设备。
|
||||||
|
|
||||||
|
#### 2.3.6 QSPI 模式
|
||||||
|
|
||||||
|
打开/关闭 `SFUD_USING_QSPI` 宏定义
|
||||||
|
|
||||||
|
开启后,SFUD 也将支持使用 QSPI 总线连接的 Flash。
|
||||||
|
|
||||||
### 2.4 移植说明
|
### 2.4 移植说明
|
||||||
|
|
||||||
移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。
|
移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。
|
||||||
|
@ -258,6 +289,7 @@ enum {
|
||||||
|:----- |:----|
|
|:----- |:----|
|
||||||
|[/demo/stm32f10x_non_os](https://github.com/armink/SFUD/tree/master/demo/stm32f10x_non_os) |STM32F10X 裸机平台|
|
|[/demo/stm32f10x_non_os](https://github.com/armink/SFUD/tree/master/demo/stm32f10x_non_os) |STM32F10X 裸机平台|
|
||||||
|[/demo/stm32f2xx_rtt](https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt) |STM32F2XX + [RT-Thread](http://www.rt-thread.org/) 操作系统平台|
|
|[/demo/stm32f2xx_rtt](https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt) |STM32F2XX + [RT-Thread](http://www.rt-thread.org/) 操作系统平台|
|
||||||
|
|[/demo/stm32l475_non_os_qspi](https://github.com/armink/SFUD/tree/master/demo/stm32l475_non_os_qspi) |STM32L475 + QSPI 模式 裸机平台|
|
||||||
|
|
||||||
### 2.7 许可
|
### 2.7 许可
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Serial Flash Universal Driver Library.
|
* This file is part of the Serial Flash Universal Driver Library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
|
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
@ -75,6 +75,23 @@ size_t sfud_get_device_num(void);
|
||||||
*/
|
*/
|
||||||
const sfud_flash *sfud_get_device_table(void);
|
const sfud_flash *sfud_get_device_table(void);
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/**
|
||||||
|
* Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
|
||||||
|
*
|
||||||
|
* it will find the appropriate fast-read instruction to replace the read instruction(0x03)
|
||||||
|
* fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
|
||||||
|
*
|
||||||
|
* @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
|
||||||
|
*
|
||||||
|
* @param flash flash device
|
||||||
|
* @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
|
||||||
|
*
|
||||||
|
* @return result
|
||||||
|
*/
|
||||||
|
sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width);
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read flash data
|
* read flash data
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,6 +45,13 @@
|
||||||
#define SFUD_USING_SFDP
|
#define SFUD_USING_SFDP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SFUD will support QSPI mode.
|
||||||
|
*/
|
||||||
|
#ifdef RT_SFUD_USING_QSPI
|
||||||
|
#define SFUD_USING_QSPI
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE
|
* Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Serial Flash Universal Driver Library.
|
* This file is part of the Serial Flash Universal Driver Library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
|
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
@ -78,7 +78,7 @@ if (!(EXPR)) \
|
||||||
else {if (__delay_temp) {__delay_temp();} retry --;}
|
else {if (__delay_temp) {__delay_temp();} retry --;}
|
||||||
|
|
||||||
/* software version number */
|
/* software version number */
|
||||||
#define SFUD_SW_VERSION "1.0.6"
|
#define SFUD_SW_VERSION "1.1.0"
|
||||||
/*
|
/*
|
||||||
* all defined supported command
|
* all defined supported command
|
||||||
*/
|
*/
|
||||||
|
@ -118,6 +118,22 @@ if (!(EXPR)) \
|
||||||
#define SFUD_CMD_READ_DATA 0x03
|
#define SFUD_CMD_READ_DATA 0x03
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SFUD_CMD_DUAL_OUTPUT_READ_DATA
|
||||||
|
#define SFUD_CMD_DUAL_OUTPUT_READ_DATA 0x3B
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SFUD_CMD_DUAL_IO_READ_DATA
|
||||||
|
#define SFUD_CMD_DUAL_IO_READ_DATA 0xBB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SFUD_CMD_QUAD_IO_READ_DATA
|
||||||
|
#define SFUD_CMD_QUAD_IO_READ_DATA 0xEB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SFUD_CMD_QUAD_OUTPUT_READ_DATA
|
||||||
|
#define SFUD_CMD_QUAD_OUTPUT_READ_DATA 0x6B
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID
|
#ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID
|
||||||
#define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90
|
#define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90
|
||||||
#endif
|
#endif
|
||||||
|
@ -183,6 +199,21 @@ typedef enum {
|
||||||
SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */
|
SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */
|
||||||
} sfud_err;
|
} sfud_err;
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/**
|
||||||
|
* QSPI flash read cmd format
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t instruction;
|
||||||
|
uint8_t instruction_lines;
|
||||||
|
uint8_t address_size;
|
||||||
|
uint8_t address_lines;
|
||||||
|
uint8_t alternate_bytes_lines;
|
||||||
|
uint8_t dummy_cycles;
|
||||||
|
uint8_t data_lines;
|
||||||
|
} sfud_qspi_read_cmd_format;
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
/* SPI bus write read data function type */
|
/* SPI bus write read data function type */
|
||||||
typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size);
|
typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size);
|
||||||
|
|
||||||
|
@ -219,6 +250,11 @@ typedef struct __sfud_spi {
|
||||||
/* SPI bus write read data function */
|
/* SPI bus write read data function */
|
||||||
sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
|
sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
|
||||||
size_t read_size);
|
size_t read_size);
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* QSPI fast read function */
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
/* lock SPI bus */
|
/* lock SPI bus */
|
||||||
void (*lock)(const struct __sfud_spi *spi);
|
void (*lock)(const struct __sfud_spi *spi);
|
||||||
/* unlock SPI bus */
|
/* unlock SPI bus */
|
||||||
|
@ -243,6 +279,10 @@ typedef struct {
|
||||||
} retry;
|
} retry;
|
||||||
void *user_data; /**< some user data */
|
void *user_data; /**< some user data */
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
sfud_qspi_read_cmd_format read_cmd_format; /**< fast read cmd format */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SFUD_USING_SFDP
|
#ifdef SFUD_USING_SFDP
|
||||||
sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */
|
sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Serial Flash Universal Driver Library.
|
* This file is part of the Serial Flash Universal Driver Library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2017, Armink, <armink.ztl@gmail.com>
|
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
@ -64,6 +64,16 @@ typedef struct {
|
||||||
uint8_t erase_gran_cmd; /**< erase granularity size block command */
|
uint8_t erase_gran_cmd; /**< erase granularity size block command */
|
||||||
} sfud_flash_chip;
|
} sfud_flash_chip;
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* QSPI flash chip's extended information compared with SPI flash */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t mf_id; /**< manufacturer ID */
|
||||||
|
uint8_t type_id; /**< memory type ID */
|
||||||
|
uint8_t capacity_id; /**< capacity ID */
|
||||||
|
uint8_t read_mode; /**< supported read mode on this qspi flash chip */
|
||||||
|
} sfud_qspi_flash_ext_info;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SFUD support manufacturer JEDEC ID */
|
/* SFUD support manufacturer JEDEC ID */
|
||||||
#define SFUD_MF_ID_CYPRESS 0x01
|
#define SFUD_MF_ID_CYPRESS 0x01
|
||||||
#define SFUD_MF_ID_FUJITSU 0x04
|
#define SFUD_MF_ID_FUJITSU 0x04
|
||||||
|
@ -131,6 +141,42 @@ typedef struct {
|
||||||
}
|
}
|
||||||
#endif /* SFUD_USING_FLASH_INFO_TABLE */
|
#endif /* SFUD_USING_FLASH_INFO_TABLE */
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* This table saves flash read-fast instructions in QSPI mode,
|
||||||
|
* SFUD can use this table to select the most appropriate read instruction for flash.
|
||||||
|
* | mf_id | type_id | capacity_id | qspi_read_mode |
|
||||||
|
*/
|
||||||
|
#define SFUD_FLASH_EXT_INFO_TABLE \
|
||||||
|
{ \
|
||||||
|
/* W25Q40BV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* W25Q80JV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* W25Q16BV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* W25Q32BV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* W25Q64JV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||||
|
/* W25Q128JV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||||
|
/* W25Q256FV */ \
|
||||||
|
{SFUD_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||||
|
/* EN25Q32B */ \
|
||||||
|
{SFUD_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO}, \
|
||||||
|
/* S25FL216K */ \
|
||||||
|
{SFUD_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* A25L080 */ \
|
||||||
|
{SFUD_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO}, \
|
||||||
|
/* A25LQ64 */ \
|
||||||
|
{SFUD_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO}, \
|
||||||
|
/* MX25L3206E and KH25L3206E */ \
|
||||||
|
{SFUD_MF_ID_MICRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
/* GD25Q64B */ \
|
||||||
|
{SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||||
|
}
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Serial Flash Universal Driver Library.
|
* This file is part of the Serial Flash Universal Driver Library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
|
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
|
@ -46,6 +46,22 @@ static const sfud_mf mf_table[] = SFUD_MF_TABLE;
|
||||||
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
|
static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/**
|
||||||
|
* flash read data mode
|
||||||
|
*/
|
||||||
|
enum sfud_qspi_read_mode {
|
||||||
|
NORMAL_SPI_READ = 1 << 0, /**< mormal spi read mode */
|
||||||
|
DUAL_OUTPUT = 1 << 1, /**< qspi fast read dual output */
|
||||||
|
DUAL_IO = 1 << 2, /**< qspi fast read dual input/output */
|
||||||
|
QUAD_OUTPUT = 1 << 3, /**< qspi fast read quad output */
|
||||||
|
QUAD_IO = 1 << 4, /**< qspi fast read quad input/output */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* QSPI flash chip's extended information table */
|
||||||
|
static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
static sfud_err software_init(const sfud_flash *flash);
|
static sfud_err software_init(const sfud_flash *flash);
|
||||||
static sfud_err hardware_init(sfud_flash *flash);
|
static sfud_err hardware_init(sfud_flash *flash);
|
||||||
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
|
static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
|
||||||
|
@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) {
|
||||||
return flash_table;
|
return flash_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
|
||||||
|
uint8_t dummy_cycles, uint8_t data_lines) {
|
||||||
|
/* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */
|
||||||
|
if (flash->chip.capacity <= 0x1000000) {
|
||||||
|
flash->read_cmd_format.instruction = ins;
|
||||||
|
flash->read_cmd_format.address_size = 24;
|
||||||
|
} else {
|
||||||
|
flash->read_cmd_format.instruction = ins + 1;
|
||||||
|
flash->read_cmd_format.address_size = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash->read_cmd_format.instruction_lines = ins_lines;
|
||||||
|
flash->read_cmd_format.address_lines = addr_lines;
|
||||||
|
flash->read_cmd_format.alternate_bytes_lines = 0;
|
||||||
|
flash->read_cmd_format.dummy_cycles = dummy_cycles;
|
||||||
|
flash->read_cmd_format.data_lines = data_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
|
||||||
|
*
|
||||||
|
* it will find the appropriate fast-read instruction to replace the read instruction(0x03)
|
||||||
|
* fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
|
||||||
|
*
|
||||||
|
* @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
|
||||||
|
*
|
||||||
|
* @param flash flash device
|
||||||
|
* @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
|
||||||
|
*
|
||||||
|
* @return result
|
||||||
|
*/
|
||||||
|
sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
|
||||||
|
size_t i = 0;
|
||||||
|
uint8_t read_mode = NORMAL_SPI_READ;
|
||||||
|
sfud_err result = SFUD_SUCCESS;
|
||||||
|
|
||||||
|
SFUD_ASSERT(flash);
|
||||||
|
SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
|
||||||
|
|
||||||
|
/* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
|
||||||
|
for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
|
||||||
|
if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
|
||||||
|
&& (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
|
||||||
|
&& (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
|
||||||
|
read_mode = qspi_flash_ext_info_table[i].read_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine qspi supports which read mode and set read_cmd_format struct */
|
||||||
|
switch (data_line_width) {
|
||||||
|
case 1:
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (read_mode & DUAL_IO) {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2);
|
||||||
|
} else if (read_mode & DUAL_OUTPUT) {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
|
||||||
|
} else {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (read_mode & QUAD_IO) {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
|
||||||
|
} else if (read_mode & QUAD_OUTPUT) {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
|
||||||
|
} else {
|
||||||
|
qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hardware initialize
|
* hardware initialize
|
||||||
*/
|
*/
|
||||||
static sfud_err hardware_init(sfud_flash *flash) {
|
static sfud_err hardware_init(sfud_flash *flash) {
|
||||||
extern sfud_err sfud_spi_port_init(sfud_flash *flash);
|
extern sfud_err sfud_spi_port_init(sfud_flash * flash);
|
||||||
|
|
||||||
sfud_err result = SFUD_SUCCESS;
|
sfud_err result = SFUD_SUCCESS;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* set default read instruction */
|
||||||
|
flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
|
|
||||||
/* SPI write read function must be initialize */
|
/* SPI write read function must be initialize */
|
||||||
SFUD_ASSERT(flash->spi.wr);
|
SFUD_ASSERT(flash->spi.wr);
|
||||||
/* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
|
/* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
|
||||||
|
@ -315,11 +414,18 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
|
||||||
result = wait_busy(flash);
|
result = wait_busy(flash);
|
||||||
|
|
||||||
if (result == SFUD_SUCCESS) {
|
if (result == SFUD_SUCCESS) {
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
|
||||||
|
result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
cmd_data[0] = SFUD_CMD_READ_DATA;
|
cmd_data[0] = SFUD_CMD_READ_DATA;
|
||||||
make_adress_byte_array(flash, addr, &cmd_data[1]);
|
make_adress_byte_array(flash, addr, &cmd_data[1]);
|
||||||
cmd_size = flash->addr_in_4_byte ? 5 : 4;
|
cmd_size = flash->addr_in_4_byte ? 5 : 4;
|
||||||
result = spi->wr(spi, cmd_data, cmd_size, data, size);
|
result = spi->wr(spi, cmd_data, cmd_size, data, size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* unlock SPI */
|
/* unlock SPI */
|
||||||
if (spi->unlock) {
|
if (spi->unlock) {
|
||||||
spi->unlock(spi);
|
spi->unlock(spi);
|
||||||
|
@ -328,7 +434,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* erase all flash data
|
* erase all flash data
|
||||||
*
|
*
|
||||||
|
@ -715,8 +820,16 @@ static sfud_err reset(const sfud_flash *flash) {
|
||||||
SFUD_ASSERT(flash);
|
SFUD_ASSERT(flash);
|
||||||
|
|
||||||
cmd_data[0] = SFUD_CMD_ENABLE_RESET;
|
cmd_data[0] = SFUD_CMD_ENABLE_RESET;
|
||||||
|
result = spi->wr(spi, cmd_data, 1, NULL, 0);
|
||||||
|
if (result == SFUD_SUCCESS) {
|
||||||
|
result = wait_busy(flash);
|
||||||
|
} else {
|
||||||
|
SFUD_INFO("Error: Flash device reset failed.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_data[1] = SFUD_CMD_RESET;
|
cmd_data[1] = SFUD_CMD_RESET;
|
||||||
result = spi->wr(spi, cmd_data, 2, NULL, 0);
|
result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
|
||||||
|
|
||||||
if (result == SFUD_SUCCESS) {
|
if (result == SFUD_SUCCESS) {
|
||||||
result = wait_busy(flash);
|
result = wait_busy(flash);
|
||||||
|
|
|
@ -31,6 +31,16 @@
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
#define RT_SFUD_DEFAULT_QSPI_CFG \
|
||||||
|
{ \
|
||||||
|
RT_SFUD_DEFAULT_SPI_CFG, \
|
||||||
|
.medium_size = 0x800000, \
|
||||||
|
.ddr_mode = 0, \
|
||||||
|
.qspi_dl_width = 4, \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static char log_buf[RT_CONSOLEBUF_SIZE];
|
static char log_buf[RT_CONSOLEBUF_SIZE];
|
||||||
|
|
||||||
void sfud_log_debug(const char *file, const long line, const char *format, ...);
|
void sfud_log_debug(const char *file, const long line, const char *format, ...);
|
||||||
|
@ -116,14 +126,31 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si
|
||||||
sfud_err result = SFUD_SUCCESS;
|
sfud_err result = SFUD_SUCCESS;
|
||||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
struct rt_qspi_device *qspi_dev = RT_NULL;
|
||||||
|
#endif
|
||||||
if (write_size) {
|
if (write_size) {
|
||||||
RT_ASSERT(write_buf);
|
RT_ASSERT(write_buf);
|
||||||
}
|
}
|
||||||
if (read_size) {
|
if (read_size) {
|
||||||
RT_ASSERT(read_buf);
|
RT_ASSERT(read_buf);
|
||||||
}
|
}
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
|
||||||
|
qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
|
||||||
|
if (write_size && read_size) {
|
||||||
|
if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) == 0) {
|
||||||
|
result = SFUD_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
} else if (write_size) {
|
||||||
|
if (rt_qspi_send(qspi_dev, write_buf, write_size) == 0) {
|
||||||
|
result = SFUD_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
if (write_size && read_size) {
|
if (write_size && read_size) {
|
||||||
if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
|
if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
|
||||||
result = SFUD_ERR_TIMEOUT;
|
result = SFUD_ERR_TIMEOUT;
|
||||||
|
@ -137,10 +164,52 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si
|
||||||
result = SFUD_ERR_TIMEOUT;
|
result = SFUD_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/**
|
||||||
|
* QSPI fast read data
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
struct rt_qspi_message message;
|
||||||
|
sfud_err result = SFUD_SUCCESS;
|
||||||
|
|
||||||
|
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||||
|
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||||
|
struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
|
||||||
|
|
||||||
|
/* set message struct */
|
||||||
|
message.instruction.content = qspi_read_cmd_format->instruction;
|
||||||
|
message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
|
||||||
|
|
||||||
|
message.address.content = addr;
|
||||||
|
message.address.size = qspi_read_cmd_format->address_size;
|
||||||
|
message.address.qspi_lines = qspi_read_cmd_format->address_lines;
|
||||||
|
|
||||||
|
message.alternate_bytes.content = 0;
|
||||||
|
message.alternate_bytes.size = 0;
|
||||||
|
message.alternate_bytes.qspi_lines = 0;
|
||||||
|
|
||||||
|
message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
|
||||||
|
|
||||||
|
message.parent.send_buf = RT_NULL;
|
||||||
|
message.parent.recv_buf = read_buf;
|
||||||
|
message.parent.length = read_size;
|
||||||
|
message.parent.cs_release = 1;
|
||||||
|
message.parent.cs_take = 1;
|
||||||
|
message.qspi_data_lines = qspi_read_cmd_format->data_lines;
|
||||||
|
|
||||||
|
if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
|
||||||
|
result = SFUD_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void spi_lock(const sfud_spi *spi) {
|
static void spi_lock(const sfud_spi *spi) {
|
||||||
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
|
||||||
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
|
||||||
|
@ -203,6 +272,9 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
|
||||||
|
|
||||||
/* port SPI device interface */
|
/* port SPI device interface */
|
||||||
flash->spi.wr = spi_write_read;
|
flash->spi.wr = spi_write_read;
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
flash->spi.qspi_read = qspi_read;
|
||||||
|
#endif
|
||||||
flash->spi.lock = spi_lock;
|
flash->spi.lock = spi_lock;
|
||||||
flash->spi.unlock = spi_unlock;
|
flash->spi.unlock = spi_unlock;
|
||||||
flash->spi.user_data = flash;
|
flash->spi.user_data = flash;
|
||||||
|
@ -214,7 +286,6 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
|
||||||
/* 60 seconds timeout */
|
/* 60 seconds timeout */
|
||||||
flash->retry.times = 60 * 10000;
|
flash->retry.times = 60 * 10000;
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +317,10 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
|
||||||
* @note you also can change the SPI to other configuration after initialized finish */
|
* @note you also can change the SPI to other configuration after initialized finish */
|
||||||
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
|
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
|
||||||
extern sfud_err sfud_device_init(sfud_flash *flash);
|
extern sfud_err sfud_device_init(sfud_flash *flash);
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
|
||||||
|
struct rt_qspi_device *qspi_dev = RT_NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
RT_ASSERT(spi_flash_dev_name);
|
RT_ASSERT(spi_flash_dev_name);
|
||||||
RT_ASSERT(spi_dev_name);
|
RT_ASSERT(spi_dev_name);
|
||||||
|
@ -277,6 +352,16 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
sfud_dev->spi.name = spi_dev_name_bak;
|
sfud_dev->spi.name = spi_dev_name_bak;
|
||||||
|
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* set the qspi line number and configure the QSPI bus */
|
||||||
|
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
|
||||||
|
qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
|
||||||
|
qspi_cfg.qspi_dl_width = qspi_dev->config.qspi_dl_width;
|
||||||
|
rt_qspi_configure(qspi_dev, &qspi_cfg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
|
rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
|
||||||
}
|
}
|
||||||
/* SFUD flash device initialize */
|
/* SFUD flash device initialize */
|
||||||
|
@ -296,6 +381,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const
|
||||||
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
|
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
|
||||||
rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
|
rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
|
||||||
rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
|
rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
|
||||||
|
#ifdef SFUD_USING_QSPI
|
||||||
|
/* reconfigure the QSPI bus for medium size */
|
||||||
|
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
|
||||||
|
qspi_cfg.medium_size = sfud_dev->chip.capacity;
|
||||||
|
rt_qspi_configure(qspi_dev, &qspi_cfg);
|
||||||
|
if(qspi_dev->enter_qspi_mode != RT_NULL)
|
||||||
|
qspi_dev->enter_qspi_mode(qspi_dev);
|
||||||
|
}
|
||||||
|
/* set data lines width */
|
||||||
|
sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
|
||||||
|
#endif /* SFUD_USING_QSPI */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register device */
|
/* register device */
|
||||||
|
|
Loading…
Reference in New Issue