diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 94af3524102bafc951b6f124dfa489db50e39e22..9e97aac3c39f5f7bbb603637afe813b9dc4bdd5a 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -168,7 +168,11 @@ config RT_USING_SPI bool "Using SPI Bus/Device device drivers" 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 bool "Using SD/TF card driver with spi" select RT_USING_DFS @@ -185,6 +189,11 @@ config RT_USING_SPI config RT_SFUD_USING_FLASH_INFO_TABLE bool "Using defined supported flash chip information table" default y + + config RT_SFUD_USING_QSPI + bool "Using QSPI mode support" + select RT_USING_QSPI + default n config RT_DEBUG_SFUD bool "Show more SFUD debug information" diff --git a/components/drivers/include/drivers/spi.h b/components/drivers/include/drivers/spi.h index 7394710581aebcbf7c5829d1b7cf213e1903eeb3..04a65421a53cada4a3227e8f6a8f343f76452598 100644 --- a/components/drivers/include/drivers/spi.h +++ b/components/drivers/include/drivers/spi.h @@ -144,8 +144,8 @@ struct rt_qspi_configuration rt_uint32_t medium_size; /* double data rate mode */ rt_uint8_t ddr_mode; - /* the number of lines connected to the hardware */ - rt_uint8_t qspi_hw_lines; + /* the data lines max width which QSPI bus supported, such as 1, 2, 4 */ + rt_uint8_t qspi_dl_width ; }; struct rt_qspi_device diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index ee423c33db428305c8dae0cd1684e9f330630115..b88671ebc93e8a554bf262efbf495663f98dbb1a 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c'] CPPPATH = [cwd, cwd + '/../include'] LOCAL_CCFLAGS = '' +if GetDepend('RT_USING_QSPI'): + src += ['qspi_core.c'] + src_device = [] if GetDepend('RT_USING_SPI_WIFI'): diff --git a/components/drivers/spi/qspi_core.c b/components/drivers/spi/qspi_core.c index 7676764b59465b92e854d09fe878d67d3600725c..c9ff6a963799a9b179d907236fb044029f20b843 100644 --- a/components/drivers/spi/qspi_core.c +++ b/components/drivers/spi/qspi_core.c @@ -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.medium_size = cfg->medium_size; 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); diff --git a/components/drivers/spi/sfud/README.md b/components/drivers/spi/sfud/README.md index 7394321243522852bf7ad1274383701aaee2bb5b..c732d06dbe6773ebda1a00c4536240877ec06869 100644 --- a/components/drivers/spi/sfud/README.md +++ b/components/drivers/spi/sfud/README.md @@ -6,11 +6,13 @@ [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.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 @@ -23,37 +25,43 @@ ### 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** ,同时把它推荐给更多有需要的朋友。 - -|型号|制造商|容量|最高速度|SFDP 标准|备注| -|:--:|:----:|:--:|:--:|:--:|:--:| -|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|已停产| -|[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)| -|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|| -|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.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|支持|| -|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|| -|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|| -|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|| -|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|| -|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持| by [JiapengLi](https://github.com/JiapengLi)| -|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|| -|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持| SST 已被 Microchip 收购| -|[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)| -|[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)| -|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|| -|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|| -|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持| by [TanekLiang](https://github.com/TanekLiang) | -|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|| -|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|| -|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持| by [yc_911](https://gitee.com/yc_911) | -|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|| -|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|| -|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|| -|[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 串行闪存产品线| +下表为所有已在 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))** 。 + +如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。 + +|型号|制造商|容量|最高速度|SFDP 标准|QSPI 模式|备注| +|:--:|:----:|:--:|:--:|:--:|:--:|----| +|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|双线|已停产| +|[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)| +|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|未测试|| +|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.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|支持|双线|| +|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|四线|| +|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|四线|| +|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|四线|| +|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|双线|| +|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持|未测试| by [JiapengLi](https://github.com/JiapengLi)| +|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|双线|| +|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持|不支持| SST 已被 Microchip 收购| +|[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)| +|[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)| +|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|不支持|| +|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|未测试|| +|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持|未测试| by [TanekLiang](https://github.com/TanekLiang) | +|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|双线|| +|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|双线|| +|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持|未测试| by [yc_911](https://gitee.com/yc_911) | +|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|未测试|| +|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|双线|| +|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|支持|| +|[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 说明 @@ -63,7 +71,7 @@ 将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。 -> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。 +> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。 ```C sfud_err sfud_init(void) @@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_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` 。 @@ -91,7 +116,7 @@ sfud_flash *sfud_get_device(size_t index) |:----- |:----| |index |Flash 设备位于 FLash 设备表中的索引值| -#### 2.2.4 读取 Flash 数据 +#### 2.2.5 读取 Flash 数据 ```C 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 |从起始地址开始读取数据的总大小| |data |读取到的数据| -#### 2.2.5 擦除 Flash 数据 +#### 2.2.6 擦除 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 |起始地址| |size |从起始地址开始擦除数据的总大小| -#### 2.2.6 擦除 Flash 全部数据 +#### 2.2.7 擦除 Flash 全部数据 ```C sfud_err sfud_chip_erase(const sfud_flash *flash) @@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash) |:----- |:----| |flash |Flash 设备对象| -#### 2.2.7 往 Flash 写数据 +#### 2.2.8 往 Flash 写数据 ```C 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 |从起始地址开始写入数据的总大小| |data |待写入的数据| -#### 2.2.8 先擦除再往 Flash 写数据 +#### 2.2.9 先擦除再往 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 |从起始地址开始写入数据的总大小| |data |待写入的数据| -#### 2.2.9 读取 Flash 状态 +#### 2.2.10 读取 Flash 状态 ```C 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 设备对象| |status |当前状态寄存器值| -#### 2.2.10 写(修改) Flash 状态 +#### 2.2.11 写(修改) Flash 状态 ```C 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()` 方法获取到设备表,再配合这个索引值来访问指定的设备。 +#### 2.3.6 QSPI 模式 + +打开/关闭 `SFUD_USING_QSPI` 宏定义 + +开启后,SFUD 也将支持使用 QSPI 总线连接的 Flash。 + ### 2.4 移植说明 移植文件位于 `/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/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 许可 diff --git a/components/drivers/spi/sfud/inc/sfud.h b/components/drivers/spi/sfud/inc/sfud.h index be1ccb208eb63a0ff1a62f786458e0e61c86b586..2b68c38216f707f8d20ae007529ec74c4e769ef4 100644 --- a/components/drivers/spi/sfud/inc/sfud.h +++ b/components/drivers/spi/sfud/inc/sfud.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * 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); +#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 * diff --git a/components/drivers/spi/sfud/inc/sfud_cfg.h b/components/drivers/spi/sfud/inc/sfud_cfg.h index 59189a9693da402949a0ce0e356f2cf03b7aac23..051de6d577fa943a55e75262b6fce4127b81add4 100644 --- a/components/drivers/spi/sfud/inc/sfud_cfg.h +++ b/components/drivers/spi/sfud/inc/sfud_cfg.h @@ -45,6 +45,13 @@ #define SFUD_USING_SFDP #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 */ diff --git a/components/drivers/spi/sfud/inc/sfud_def.h b/components/drivers/spi/sfud/inc/sfud_def.h index 1b0e8a3986331f3d6cd2e533fecf51f348df0859..fe7876618ba6b55362fe735b5c7a5d3f765ab07a 100644 --- a/components/drivers/spi/sfud/inc/sfud_def.h +++ b/components/drivers/spi/sfud/inc/sfud_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -78,7 +78,7 @@ if (!(EXPR)) \ else {if (__delay_temp) {__delay_temp();} retry --;} /* software version number */ -#define SFUD_SW_VERSION "1.0.6" +#define SFUD_SW_VERSION "1.1.0" /* * all defined supported command */ @@ -118,6 +118,22 @@ if (!(EXPR)) \ #define SFUD_CMD_READ_DATA 0x03 #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 #define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90 #endif @@ -183,6 +199,21 @@ typedef enum { SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */ } 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 */ typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size); @@ -218,7 +249,12 @@ typedef struct __sfud_spi { char *name; /* 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, - 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 */ void (*lock)(const struct __sfud_spi *spi); /* unlock SPI bus */ @@ -243,6 +279,10 @@ typedef struct { } retry; 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 sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */ #endif diff --git a/components/drivers/spi/sfud/inc/sfud_flash_def.h b/components/drivers/spi/sfud/inc/sfud_flash_def.h index 2022a043b2fe7f70c287d10995e9b4d3390a70de..89223755573b87a422d633f2bef934e5d35f2a12 100644 --- a/components/drivers/spi/sfud/inc/sfud_flash_def.h +++ b/components/drivers/spi/sfud/inc/sfud_flash_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016-2017, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -59,11 +59,21 @@ typedef struct { uint8_t type_id; /**< memory type ID */ uint8_t capacity_id; /**< capacity ID */ uint32_t capacity; /**< flash capacity (bytes) */ - uint16_t write_mode; /**< write mode @see sfud_write_mode */ + uint16_t write_mode; /**< write mode @see sfud_write_mode */ uint32_t erase_gran; /**< erase granularity (bytes) */ uint8_t erase_gran_cmd; /**< erase granularity size block command */ } 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 */ #define SFUD_MF_ID_CYPRESS 0x01 #define SFUD_MF_ID_FUJITSU 0x04 @@ -131,6 +141,42 @@ typedef struct { } #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 } #endif diff --git a/components/drivers/spi/sfud/src/sfud.c b/components/drivers/spi/sfud/src/sfud.c index e3376555ca909f192a5180b5bfa720847c9845f4..6cfd1191ef47d35c851498ecd64f314fde970c19 100644 --- a/components/drivers/spi/sfud/src/sfud.c +++ b/components/drivers/spi/sfud/src/sfud.c @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * 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; #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 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, @@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) { 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 */ 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; size_t i; @@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) { 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 */ SFUD_ASSERT(flash->spi.wr); /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */ @@ -315,10 +414,17 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t result = wait_busy(flash); if (result == SFUD_SUCCESS) { - cmd_data[0] = SFUD_CMD_READ_DATA; - make_adress_byte_array(flash, addr, &cmd_data[1]); - cmd_size = flash->addr_in_4_byte ? 5 : 4; - result = spi->wr(spi, cmd_data, cmd_size, data, size); +#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; + make_adress_byte_array(flash, addr, &cmd_data[1]); + cmd_size = flash->addr_in_4_byte ? 5 : 4; + result = spi->wr(spi, cmd_data, cmd_size, data, size); + } } /* unlock SPI */ if (spi->unlock) { @@ -328,7 +434,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t return result; } - /** * erase all flash data * @@ -715,8 +820,16 @@ static sfud_err reset(const sfud_flash *flash) { SFUD_ASSERT(flash); 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; - result = spi->wr(spi, cmd_data, 2, NULL, 0); + result = spi->wr(spi, &cmd_data[1], 1, NULL, 0); if (result == SFUD_SUCCESS) { result = wait_busy(flash); diff --git a/components/drivers/spi/spi_flash_sfud.c b/components/drivers/spi/spi_flash_sfud.c index c0e42b3cd8fa9f08e1dc755f4fc52faf8156b3f6..0f3cba07987d1900b2441d6dca720d1bce5625e4 100644 --- a/components/drivers/spi/spi_flash_sfud.c +++ b/components/drivers/spi/spi_flash_sfud.c @@ -23,11 +23,21 @@ #ifndef RT_SFUD_DEFAULT_SPI_CFG /* read the JEDEC SFDP command must run at 50 MHz or less */ -#define RT_SFUD_DEFAULT_SPI_CFG \ -{ \ - .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \ - .data_width = 8, \ - .max_hz = 50 * 1000 * 1000, \ +#define RT_SFUD_DEFAULT_SPI_CFG \ +{ \ + .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \ + .data_width = 8, \ + .max_hz = 50 * 1000 * 1000, \ +} +#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 @@ -116,31 +126,90 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si 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); - +#ifdef SFUD_USING_QSPI + struct rt_qspi_device *qspi_dev = RT_NULL; +#endif if (write_size) { RT_ASSERT(write_buf); } if (read_size) { RT_ASSERT(read_buf); } - - 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) { - result = SFUD_ERR_TIMEOUT; - } - } else if (write_size) { - if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) { - result = SFUD_ERR_TIMEOUT; +#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 { - if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) { - result = SFUD_ERR_TIMEOUT; + } + else +#endif + { + 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) { + result = SFUD_ERR_TIMEOUT; + } + } else if (write_size) { + if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } + } else { + if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } } } 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) { sfud_flash *sfud_dev = (sfud_flash *) (spi->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 */ flash->spi.wr = spi_write_read; +#ifdef SFUD_USING_QSPI + flash->spi.qspi_read = qspi_read; +#endif flash->spi.lock = spi_lock; flash->spi.unlock = spi_unlock; flash->spi.user_data = flash; @@ -213,8 +285,7 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) { flash->retry.delay = retry_delay_100us; /* 60 seconds timeout */ flash->retry.times = 60 * 10000; - - + 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 */ struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG; 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_dev_name); @@ -277,7 +352,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const goto error; } sfud_dev->spi.name = spi_dev_name_bak; - rt_spi_configure(rtt_dev->rt_spi_device, &cfg); + +#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); } /* 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.bytes_per_sector = 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 */