Merge pull request #2006 from armink/fix_sfud

Update sfud
This commit is contained in:
Bernard Xiong 2018-11-26 18:20:20 +08:00 committed by GitHub
commit a87914b535
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 442 additions and 79 deletions

View File

@ -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

View File

@ -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

View File

@ -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'):

View File

@ -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);

View File

@ -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 许可

View File

@ -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
* *

View File

@ -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
*/ */

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 */