This commit is contained in:
2024-08-05 20:57:09 +08:00
commit 46d9ee7795
3020 changed files with 1725767 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2016-2018 Armink (armink.ztl@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,297 @@
# SFUD (Serial Flash Universal Driver) 串行 Flash 通用驱动库
---
## 0、SFUD 是什么
[SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
- 主要特点:支持 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 表参数。
- **不支持 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
- 避免项目因 Flash 缺货、Flash 停产或产品扩容而带来的风险;
- 越来越多的项目将固件存储到串行 Flash 中例如ESP8266 的固件、主板中的 BIOS 及其他常见电子产品中的固件等等,但是各种 Flash 规格及命令不统一。使用 SFUD 即可避免,在相同功能的软件平台基础下,无法适配不同 Flash 种类的硬件平台的问题,提高软件的可重用性;
- 简化软件流程,降低开发难度。现在只需要配置好 SPI 通信,即可畅快的开始玩串行 Flash 了;
- 可以用来制作 Flash 编程器/烧写器
## 2、SFUD 如何使用
### 2.1 已支持 Flash
下表为所有已在 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|支持|双线||
|[MX25L3233F](https://www.macronix.com/Lists/Datasheet/Attachments/8754/MX25L3233F,%203V,%2032Mb,%20v1.7.pdf)|Macronix|32Mb|133MHz|支持|未测试|by [JiapengLi](https://github.com/JiapengLi)|
|[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 [Liang Yongxiang](https://github.com/liangyongxiang) |
|[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 说明
先说明下本库主要使用的一个结构体 `sfud_flash` 。其定义位于 `/sfud/inc/sfud_def.h`。每个 SPI Flash 会对应一个该结构体,该结构体指针下面统称为 Flash 设备对象。初始化成功后在 `sfud_flash->chip` 结构体中会存放 SPI Flash 的常见参数。如果 SPI Flash 还支持 SFDP ,还可以通过 `sfud_flash->sfdp` 看到更加全面的参数信息。以下很多函数都将使用 Flash 设备对象作为第一个入参,实现对指定 SPI Flash 的操作。
#### 2.2.1 初始化 SFUD 库
将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。
> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。
```C
sfud_err sfud_init(void)
```
#### 2.2.2 初始化指定的 Flash 设备
```C
sfud_err sfud_device_init(sfud_flash *flash)
```
|参数 |描述|
|:----- |:----|
|flash |待初始化的 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`
```C
sfud_flash *sfud_get_device(size_t index)
```
|参数 |描述|
|:----- |:----|
|index |Flash 设备位于 FLash 设备表中的索引值|
#### 2.2.5 读取 Flash 数据
```C
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|addr |起始地址|
|size |从起始地址开始读取数据的总大小|
|data |读取到的数据|
#### 2.2.6 擦除 Flash 数据
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
```C
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|addr |起始地址|
|size |从起始地址开始擦除数据的总大小|
#### 2.2.7 擦除 Flash 全部数据
```C
sfud_err sfud_chip_erase(const sfud_flash *flash)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
#### 2.2.8 往 Flash 写数据
```C
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|addr |起始地址|
|size |从起始地址开始写入数据的总大小|
|data |待写入的数据|
#### 2.2.9 先擦除再往 Flash 写数据
> 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。
```C
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|addr |起始地址|
|size |从起始地址开始写入数据的总大小|
|data |待写入的数据|
#### 2.2.10 读取 Flash 状态
```C
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|status |当前状态寄存器值|
#### 2.2.11 写(修改) Flash 状态
```C
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status)
```
|参数 |描述|
|:----- |:----|
|flash |Flash 设备对象|
|is_volatile |是否为易闪失的true: 易闪失的,及断电后会丢失|
|status |当前状态寄存器值|
### 2.3 配置方法
所有配置位于 `/sfud/inc/sfud_cfg.h` ,请参考下面的配置介绍,选择适合自己项目的配置。
#### 2.3.1 调试模式
打开/关闭 `SFUD_DEBUG_MODE` 宏定义
#### 2.3.2 是否使用 SFDP 参数功能
打开/关闭 `SFUD_USING_SFDP` 宏定义
> 注意:关闭后只会查询该库在 `/sfud/inc/sfud_flash_def.h` 中提供的 Flash 信息表。这样虽然会降低软件的适配性,但减少代码量。
#### 2.3.3 是否使用该库自带的 Flash 参数信息表
打开/关闭 `SFUD_USING_FLASH_INFO_TABLE` 宏定义
> 注意:关闭后该库只驱动支持 SFDP 规范的 Flash也会适当的降低部分代码量。另外 2.3.2 及 2.3.3 这两个宏定义至少定义一种,也可以两种方式都选择。
#### 2.3.4 既不使用 SFDP ,也不使用 Flash 参数信息表
为了进一步降低代码量,`SFUD_USING_SFDP``SFUD_USING_FLASH_INFO_TABLE` 也可以 **都不定义**
此时,只要在定义 Flash 设备时,指定好 Flash 参数,之后再调用 `sfud_device_init` 对该设备进行初始化。参考如下代码:
```C
sfud_flash sfud_norflash0 = {
.name = "norflash0",
.spi.name = "SPI1",
.chip = { "W25Q64FV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L * 1024L * 1024L, SFUD_WM_PAGE_256B, 4096, 0x20 } };
......
sfud_device_init(&sfud_norflash0);
......
```
#### 2.3.5 Flash 设备表
如果产品中存在多个 Flash ,可以添加 Flash 设备表。修改 `SFUD_FLASH_DEVICE_TABLE` 这个宏定义,示例如下:
```C
enum {
SFUD_W25Q64CV_DEVICE_INDEX = 0,
SFUD_GD25Q64B_DEVICE_INDEX = 1,
};
#define SFUD_FLASH_DEVICE_TABLE \
{ \
[SFUD_W25Q64CV_DEVICE_INDEX] = {.name = "W25Q64CV", .spi.name = "SPI1"}, \
[SFUD_GD25Q64B_DEVICE_INDEX] = {.name = "GD25Q64B", .spi.name = "SPI3"}, \
}
```
上面定义了两个 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 中的各个平台的移植文件。
### 2.5 添加库目前不支持的 Flash
这里需要修改 `/sfud/inc/sfdu_flash_def.h` ,所有已经支持的 Flash 见 `SFUD_FLASH_CHIP_TABLE` 宏定义,需要提前准备的 Flash 参数内容分别为:| 名称 | 制造商 ID | 类型 ID | 容量 ID | 容量 | 写模式 | 擦除粒度(擦除的最小单位) | 擦除粒度对应的命令 | 。这里以添加 兆易创新 ( GigaDevice ) 的 `GD25Q64B` Flash 来举例。
此款 Flash 为兆易创新的早期生产的型号,所以不支持 SFDP 标准。首先需要下载其数据手册,找到 0x9F 命令返回的 3 种 ID 这里需要最后面两字节 ID ,即 `type id``capacity id``GD25Q64B` 对应这两个 ID 分别为 `0x40``0x17` 。上面要求的其他 Flash 参数都可以在数据手册中找到,这里要重点说明下 **写模式** 这个参数,库本身提供的写模式共计有 4 种,详见文件顶部的 `sfud_write_mode` 枚举类型,同一款 Flash 可以同时支持多种写模式,视情况而定。对于 `GD25Q64B` 而言,其支持的写模式应该为 `SFUD_WM_PAGE_256B` ,即写 1-256 字节每页。结合上述 `GD25Q64B` 的 Flash 参数应如下:
```
{"GD25Q64B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, 8*1024*1024, SFUD_WM_PAGE_256B, 4096, 0x20},
```
再将其增加到 `SFUD_FLASH_CHIP_TABLE` 宏定义末尾,即可完成该库对 `GD25Q64B` 的支持。
### 2.6 Demo
目前已支持如下平台下的 Demo
|路径 |平台描述|
|:----- |:----|
|[/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 许可
采用 MIT 开源协议,细节请阅读项目中的 LICENSE 文件内容。

View File

@@ -0,0 +1,178 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is an head file for this library. You can see all of the functions which can be called by user.
* Created on: 2016-04-23
*/
#ifndef _SFUD_H_
#define _SFUD_H_
#include "sfud_def.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ../src/sfup.c */
/**
* SFUD library initialize.
*
* @return result
*/
sfud_err sfud_init(void);
/**
* SFUD initialize by flash device
*
* @param flash flash device
*
* @return result
*/
sfud_err sfud_device_init(sfud_flash *flash);
/**
* get flash device by its index which in the flash information table
*
* @param index the index which in the flash information table @see flash_table
*
* @return flash device
*/
sfud_flash *sfud_get_device(size_t index);
/**
* get flash device total number on flash device information table @see flash_table
*
* @return flash device total number
*/
size_t sfud_get_device_num(void);
/**
* get flash device information table @see flash_table
*
* @return flash device table pointer
*/
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
*
* @param flash flash device
* @param addr start address
* @param size read size
* @param data read data pointer
*
* @return result
*/
sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data);
/**
* erase flash data
*
* @note It will erase align by erase granularity.
*
* @param flash flash device
* @param addr start address
* @param size erase size
*
* @return result
*/
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size);
/**
* write flash data (no erase operate)
*
* @param flash flash device
* @param addr start address
* @param data write data
* @param size write size
*
* @return result
*/
sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);
/**
* erase and write flash data
*
* @param flash flash device
* @param addr start address
* @param size write size
* @param data write data
*
* @return result
*/
sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);
/**
* erase all flash data
*
* @param flash flash device
*
* @return result
*/
sfud_err sfud_chip_erase(const sfud_flash *flash);
/**
* read flash register status
*
* @param flash flash device
* @param status register status
*
* @return result
*/
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status);
/**
* write status register
*
* @param flash flash device
* @param is_volatile true: volatile mode, false: non-volatile mode
* @param status register status
*
* @return result
*/
sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status);
#ifdef __cplusplus
}
#endif
#endif /* _SFUD_H_ */

View File

@@ -0,0 +1,75 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is the configure head file for this library.
* Created on: 2016-04-23
*/
#ifndef _SFUD_CFG_H_
#define _SFUD_CFG_H_
#include <rtthread.h>
/**
* It will print more information on debug mode.
* #define RT_DEBUG_SFUD open debug mode */
#ifdef RT_DEBUG_SFUD
#define SFUD_DEBUG_MODE
#endif
#ifdef RT_DEBUG_SFUD
#define DBG_LVL DBG_LOG
#define SFUD_DEBUG(fmt, ...) LOG_D("(%s:%ld) "fmt"", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define DBG_LVL DBG_INFO
#endif /* RT_DEBUG_SFUD */
#define DBG_TAG "SFUD"
#include <rtdbg.h>
#define SFUD_INFO(...) LOG_I(__VA_ARGS__)
/**
* Using probe flash JEDEC SFDP parameter.
*/
#ifdef RT_SFUD_USING_SFDP
#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
*/
#ifdef RT_SFUD_USING_FLASH_INFO_TABLE
#define SFUD_USING_FLASH_INFO_TABLE
#endif
#define SFUD_FLASH_DEVICE_TABLE {{0}}
#endif /* _SFUD_CFG_H_ */

View File

@@ -0,0 +1,296 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is the macro definition head file for this library.
* Created on: 2016-04-23
*/
#ifndef _SFUD_DEF_H_
#define _SFUD_DEF_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sfud_cfg.h>
#include "sfud_flash_def.h"
#ifdef __cplusplus
extern "C" {
#endif
/* debug print function. Must be implement by user. */
#ifdef SFUD_DEBUG_MODE
#ifndef SFUD_DEBUG
#define SFUD_DEBUG(...) sfud_log_debug(__FILE__, __LINE__, __VA_ARGS__)
#endif /* SFUD_DEBUG */
#else
#define SFUD_DEBUG(...)
#endif /* SFUD_DEBUG_MODE */
#ifndef SFUD_INFO
#define SFUD_INFO(...) sfud_log_info(__VA_ARGS__)
#endif
/* assert for developer. */
#ifdef SFUD_DEBUG_MODE
#define SFUD_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
SFUD_DEBUG("(%s) has assert failed at %s.", #EXPR, __FUNCTION__); \
while (1); \
}
#else
#define SFUD_ASSERT(EXPR)
#endif
/**
* retry process
*
* @param delay delay function for every retry. NULL will not delay for every retry.
* @param retry retry counts
* @param result SFUD_ERR_TIMEOUT: retry timeout
*/
#define SFUD_RETRY_PROCESS(delay, retry, result) \
void (*__delay_temp)(void) = (void (*)(void))delay; \
if (retry == 0) {result = SFUD_ERR_TIMEOUT;break;} \
else {if (__delay_temp) {__delay_temp();} retry --;}
/* software version number */
#define SFUD_SW_VERSION "1.1.0"
/*
* all defined supported command
*/
#ifndef SFUD_CMD_WRITE_ENABLE
#define SFUD_CMD_WRITE_ENABLE 0x06
#endif
#ifndef SFUD_CMD_WRITE_DISABLE
#define SFUD_CMD_WRITE_DISABLE 0x04
#endif
#ifndef SFUD_CMD_READ_STATUS_REGISTER
#define SFUD_CMD_READ_STATUS_REGISTER 0x05
#endif
#ifndef SFUD_VOLATILE_SR_WRITE_ENABLE
#define SFUD_VOLATILE_SR_WRITE_ENABLE 0x50
#endif
#ifndef SFUD_CMD_WRITE_STATUS_REGISTER
#define SFUD_CMD_WRITE_STATUS_REGISTER 0x01
#endif
#ifndef SFUD_CMD_PAGE_PROGRAM
#define SFUD_CMD_PAGE_PROGRAM 0x02
#endif
#ifndef SFUD_CMD_AAI_WORD_PROGRAM
#define SFUD_CMD_AAI_WORD_PROGRAM 0xAD
#endif
#ifndef SFUD_CMD_ERASE_CHIP
#define SFUD_CMD_ERASE_CHIP 0xC7
#endif
#ifndef SFUD_CMD_READ_DATA
#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
#ifndef SFUD_CMD_JEDEC_ID
#define SFUD_CMD_JEDEC_ID 0x9F
#endif
#ifndef SFUD_CMD_READ_UNIQUE_ID
#define SFUD_CMD_READ_UNIQUE_ID 0x4B
#endif
#ifndef SFUD_CMD_READ_SFDP_REGISTER
#define SFUD_CMD_READ_SFDP_REGISTER 0x5A
#endif
#ifndef SFUD_CMD_ENABLE_RESET
#define SFUD_CMD_ENABLE_RESET 0x66
#endif
#ifndef SFUD_CMD_RESET
#define SFUD_CMD_RESET 0x99
#endif
#ifndef SFUD_CMD_ENTER_4B_ADDRESS_MODE
#define SFUD_CMD_ENTER_4B_ADDRESS_MODE 0xB7
#endif
#ifndef SFUD_CMD_EXIT_4B_ADDRESS_MODE
#define SFUD_CMD_EXIT_4B_ADDRESS_MODE 0xE9
#endif
#ifndef SFUD_WRITE_MAX_PAGE_SIZE
#define SFUD_WRITE_MAX_PAGE_SIZE 256
#endif
/* send dummy data for read data */
#ifndef SFUD_DUMMY_DATA
#define SFUD_DUMMY_DATA 0xFF
#endif
/* maximum number of erase type support on JESD216 (V1.0) */
#define SFUD_SFDP_ERASE_TYPE_MAX_NUM 4
/**
* status register bits
*/
enum {
SFUD_STATUS_REGISTER_BUSY = (1 << 0), /**< busing */
SFUD_STATUS_REGISTER_WEL = (1 << 1), /**< write enable latch */
SFUD_STATUS_REGISTER_SRP = (1 << 7), /**< status register protect */
};
/**
* error code
*/
typedef enum {
SFUD_SUCCESS = 0, /**< success */
SFUD_ERR_NOT_FOUND = 1, /**< not found or not supported */
SFUD_ERR_WRITE = 2, /**< write error */
SFUD_ERR_READ = 3, /**< read error */
SFUD_ERR_TIMEOUT = 4, /**< timeout error */
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);
#ifdef SFUD_USING_SFDP
/**
* the SFDP (Serial Flash Discoverable Parameters) parameter info which used on this library
*/
typedef struct {
bool available; /**< available when read SFDP OK */
uint8_t major_rev; /**< SFDP Major Revision */
uint8_t minor_rev; /**< SFDP Minor Revision */
uint16_t write_gran; /**< write granularity (bytes) */
uint8_t erase_4k; /**< 4 kilobyte erase is supported throughout the device */
uint8_t erase_4k_cmd; /**< 4 Kilobyte erase command */
bool sr_is_non_vola; /**< status register is supports non-volatile */
uint8_t vola_sr_we_cmd; /**< volatile status register write enable command */
bool addr_3_byte; /**< supports 3-Byte addressing */
bool addr_4_byte; /**< supports 4-Byte addressing */
uint32_t capacity; /**< flash capacity (bytes) */
struct {
uint32_t size; /**< erase sector size (bytes). 0x00: not available */
uint8_t cmd; /**< erase command */
} eraser[SFUD_SFDP_ERASE_TYPE_MAX_NUM]; /**< supported eraser types table */
//TODO lots of fast read-related stuff (like modes supported and number of wait states/dummy cycles needed in each)
} sfud_sfdp, *sfud_sfdp_t;
#endif
/**
* SPI device
*/
typedef struct __sfud_spi {
/* SPI device name */
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);
#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 */
void (*unlock)(const struct __sfud_spi *spi);
/* some user data */
void *user_data;
} sfud_spi, *sfud_spi_t;
/**
* serial flash device
*/
typedef struct {
char *name; /**< serial flash name */
size_t index; /**< index of flash device information table @see flash_table */
sfud_flash_chip chip; /**< flash chip information */
sfud_spi spi; /**< SPI device */
bool init_ok; /**< initialize OK flag */
bool addr_in_4_byte; /**< flash is in 4-Byte addressing */
struct {
void (*delay)(void); /**< every retry's delay */
size_t times; /**< default times for error retry */
} 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
} sfud_flash, *sfud_flash_t;
#ifdef __cplusplus
}
#endif
#endif /* _SFUD_DEF_H_ */

View File

@@ -0,0 +1,198 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
* Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is the flash types and specification macro definition head file for this library.
* Created on: 2016-06-09
*/
#ifndef _SFUD_FLASH_DEF_H_
#define _SFUD_FLASH_DEF_H_
#include <stdint.h>
#include <sfud_cfg.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* flash program(write) data mode
*/
enum sfud_write_mode {
SFUD_WM_PAGE_256B = 1 << 0, /**< write 1 to 256 bytes per page */
SFUD_WM_BYTE = 1 << 1, /**< byte write */
SFUD_WM_AAI = 1 << 2, /**< auto address increment */
SFUD_WM_DUAL_BUFFER = 1 << 3, /**< dual-buffer write, like AT45DB series */
};
/* manufacturer information */
typedef struct {
char *name;
uint8_t id;
} sfud_mf;
/* flash chip information */
typedef struct {
char *name; /**< flash chip name */
uint8_t mf_id; /**< manufacturer ID */
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 */
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
#define SFUD_MF_ID_EON 0x1C
#define SFUD_MF_ID_ATMEL 0x1F
#define SFUD_MF_ID_MICRON 0x20
#define SFUD_MF_ID_AMIC 0x37
#define SFUD_MF_ID_NOR_MEM 0x52
#define SFUD_MF_ID_SANYO 0x62
#define SFUD_MF_ID_INTEL 0x89
#define SFUD_MF_ID_ESMT 0x8C
#define SFUD_MF_ID_FUDAN 0xA1
#define SFUD_MF_ID_HYUNDAI 0xAD
#define SFUD_MF_ID_SST 0xBF
#define SFUD_MF_ID_MACRONIX 0xC2
#define SFUD_MF_ID_GIGADEVICE 0xC8
#define SFUD_MF_ID_ISSI 0xD5
#define SFUD_MF_ID_WINBOND 0xEF
/* SFUD supported manufacturer information table */
#define SFUD_MF_TABLE \
{ \
{"Cypress", SFUD_MF_ID_CYPRESS}, \
{"Fujitsu", SFUD_MF_ID_FUJITSU}, \
{"EON", SFUD_MF_ID_EON}, \
{"Atmel", SFUD_MF_ID_ATMEL}, \
{"Micron", SFUD_MF_ID_MICRON}, \
{"AMIC", SFUD_MF_ID_AMIC}, \
{"Sanyo", SFUD_MF_ID_SANYO}, \
{"Intel", SFUD_MF_ID_INTEL}, \
{"ESMT", SFUD_MF_ID_ESMT}, \
{"Fudan", SFUD_MF_ID_FUDAN}, \
{"Hyundai", SFUD_MF_ID_HYUNDAI}, \
{"SST", SFUD_MF_ID_SST}, \
{"GigaDevice", SFUD_MF_ID_GIGADEVICE}, \
{"ISSI", SFUD_MF_ID_ISSI}, \
{"Winbond", SFUD_MF_ID_WINBOND}, \
{"Macronix", SFUD_MF_ID_MACRONIX}, \
{"NOR-MEM", SFUD_MF_ID_NOR_MEM}, \
}
#ifdef SFUD_USING_FLASH_INFO_TABLE
/* SFUD supported flash chip information table. If the flash not support JEDEC JESD216 standard,
* then the SFUD will find the flash chip information by this table. You can add other flash to here then
* notice me for update it. The configuration information name and index reference the sfud_flash_chip structure.
* | name | mf_id | type_id | capacity_id | capacity | write_mode | erase_gran | erase_gran_cmd |
*/
#define SFUD_FLASH_CHIP_TABLE \
{ \
{"AT45DB161E", SFUD_MF_ID_ATMEL, 0x26, 0x00, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_DUAL_BUFFER, 512, 0x81}, \
{"W25Q40BV", SFUD_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25X40CL", SFUD_MF_ID_WINBOND, 0x30, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25X16AV", SFUD_MF_ID_WINBOND, 0x30, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q32BV", SFUD_MF_ID_WINBOND, 0x40, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q64CV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q64DW", SFUD_MF_ID_WINBOND, 0x60, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q128BV", SFUD_MF_ID_WINBOND, 0x40, 0x18, 16L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"W25Q256FV", SFUD_MF_ID_WINBOND, 0x40, 0x19, 32L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"SST25VF080B", SFUD_MF_ID_SST, 0x25, 0x8E, 1L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20}, \
{"SST25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20}, \
{"M25P32", SFUD_MF_ID_MICRON, 0x20, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8}, \
{"M25P80", SFUD_MF_ID_MICRON, 0x20, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8}, \
{"M25P40", SFUD_MF_ID_MICRON, 0x20, 0x13, 512L*1024L, SFUD_WM_PAGE_256B, 64L*1024L, 0xD8}, \
{"EN25Q32B", SFUD_MF_ID_EON, 0x30, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"GD25Q64B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"GD25Q16B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"GD25Q32C", SFUD_MF_ID_GIGADEVICE, 0x40, 0x16, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"S25FL216K", SFUD_MF_ID_CYPRESS, 0x40, 0x15, 2L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"S25FL032P", SFUD_MF_ID_CYPRESS, 0x02, 0x15, 4L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"A25L080", SFUD_MF_ID_AMIC, 0x30, 0x14, 1L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
{"F25L004", SFUD_MF_ID_ESMT, 0x20, 0x13, 512L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20}, \
{"PCT25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, SFUD_WM_BYTE|SFUD_WM_AAI, 4096, 0x20}, \
{"NM25Q128EVB", SFUD_MF_ID_NOR_MEM, 0x21, 0x18, 16L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
}
#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|QUAD_OUTPUT|QUAD_IO}, \
/* 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_MACRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
/* MX25L51245G */ \
{SFUD_MF_ID_MACRONIX, 0x20, 0x1A, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
/* GD25Q64B */ \
{SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \
/* NM25Q128EVB */ \
{SFUD_MF_ID_NOR_MEM, 0x21, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
}
#endif /* SFUD_USING_QSPI */
#ifdef __cplusplus
}
#endif
#endif /* _SFUD_FLASH_DEF_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,387 @@
/*
* This file is part of the Serial Flash Universal Driver Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: Analyze the SFDP (Serial Flash Discoverable Parameters) which from JESD216/A/B (V1.X) standard.
* JESD216 (V1.0) document: http://www.jedec.org/sites/default/files/docs/JESD216.pdf
* JESD216A (V1.5) document: http://www.jedec.org/sites/default/files/docs/JESD216A.pdf
* JESD216B (V1.6) document: http://www.jedec.org/sites/default/files/docs/JESD216B.pdf
*
* Created on: 2016-05-26
*/
#include "../inc/sfud.h"
/**
* JEDEC Standard JESD216 Terms and definitions:
*
* DWORD: Four consecutive 8-bit bytes used as the basic 32-bit building block for headers and parameter tables.
*
* Sector: The minimum granularity - size and alignment - of an area that can be erased in the data array
* of a flash memory device. Different areas within the address range of the data array may have a different
* minimum erase granularity (sector size).
*/
#ifdef SFUD_USING_SFDP
/* support maximum SFDP major revision by driver */
#define SUPPORT_MAX_SFDP_MAJOR_REV 1
/* the JEDEC basic flash parameter table length is 9 DWORDs (288-bit) on JESD216 (V1.0) initial release standard */
#define BASIC_TABLE_LEN 9
/* the smallest eraser in SFDP eraser table */
#define SMALLEST_ERASER_INDEX 0
/**
* SFDP parameter header structure
*/
typedef struct {
uint8_t id; /**< Parameter ID LSB */
uint8_t minor_rev; /**< Parameter minor revision */
uint8_t major_rev; /**< Parameter major revision */
uint8_t len; /**< Parameter table length(in double words) */
uint32_t ptp; /**< Parameter table 24bit pointer (byte address) */
} sfdp_para_header;
static sfud_err read_sfdp_data(const sfud_flash *flash, uint32_t addr, uint8_t *read_buf, size_t size);
static bool read_sfdp_header(sfud_flash *flash);
static bool read_basic_header(const sfud_flash *flash, sfdp_para_header *basic_header);
static bool read_basic_table(sfud_flash *flash, sfdp_para_header *basic_header);
/* ../port/sfup_port.c */
extern void sfud_log_debug(const char *file, const long line, const char *format, ...);
extern void sfud_log_info(const char *format, ...);
/**
* Read SFDP parameter information
*
* @param flash flash device
*
* @return true: read OK
*/
bool sfud_read_sfdp(sfud_flash *flash) {
SFUD_ASSERT(flash);
/* JEDEC basic flash parameter header */
sfdp_para_header basic_header;
if (read_sfdp_header(flash) && read_basic_header(flash, &basic_header)) {
return read_basic_table(flash, &basic_header);
} else {
SFUD_INFO("Warning: Read SFDP parameter header information failed. The %s does not support JEDEC SFDP.", flash->name);
return false;
}
}
/**
* Read SFDP parameter header
*
* @param flash flash device
*
* @return true: read OK
*/
static bool read_sfdp_header(sfud_flash *flash) {
sfud_sfdp *sfdp = &flash->sfdp;
/* The SFDP header is located at address 000000h of the SFDP data structure.
* It identifies the SFDP Signature, the number of parameter headers, and the SFDP revision numbers. */
/* sfdp parameter header address */
uint32_t header_addr = 0;
/* each parameter header being 2 DWORDs (64-bit) */
uint8_t header[2 * 4] = { 0 };
SFUD_ASSERT(flash);
sfdp->available = false;
/* read SFDP header */
if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != SFUD_SUCCESS) {
SFUD_INFO("Error: Can't read SFDP header.");
return false;
}
/* check SFDP header */
if (!(header[0] == 'S' &&
header[1] == 'F' &&
header[2] == 'D' &&
header[3] == 'P')) {
SFUD_DEBUG("Error: Check SFDP signature error. It's must be 50444653h('S' 'F' 'D' 'P').");
return false;
}
sfdp->minor_rev = header[4];
sfdp->major_rev = header[5];
if (sfdp->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
SFUD_INFO("Error: This reversion(V%d.%d) of SFDP is not supported.", sfdp->major_rev, sfdp->minor_rev);
return false;
}
SFUD_DEBUG("Check SFDP header is OK. The reversion is V%d.%d, NPN is %d.", sfdp->major_rev, sfdp->minor_rev,
header[6]);
return true;
}
/**
* Read JEDEC basic parameter header
*
* @param flash flash device
*
* @return true: read OK
*/
static bool read_basic_header(const sfud_flash *flash, sfdp_para_header *basic_header) {
/* The basic parameter header is mandatory, is defined by this standard, and starts at byte offset 08h. */
uint32_t header_addr = 8;
/* each parameter header being 2 DWORDs (64-bit) */
uint8_t header[2 * 4] = { 0 };
SFUD_ASSERT(flash);
SFUD_ASSERT(basic_header);
/* read JEDEC basic flash parameter header */
if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != SFUD_SUCCESS) {
SFUD_INFO("Error: Can't read JEDEC basic flash parameter header.");
return false;
}
basic_header->id = header[0];
basic_header->minor_rev = header[1];
basic_header->major_rev = header[2];
basic_header->len = header[3];
basic_header->ptp = (long)header[4] | (long)header[5] << 8 | (long)header[6] << 16;
/* check JEDEC basic flash parameter header */
if (basic_header->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
SFUD_INFO("Error: This reversion(V%d.%d) of JEDEC basic flash parameter header is not supported.",
basic_header->major_rev, basic_header->minor_rev);
return false;
}
if (basic_header->len < BASIC_TABLE_LEN) {
SFUD_INFO("Error: The JEDEC basic flash parameter table length (now is %d) error.", basic_header->len);
return false;
}
SFUD_DEBUG("Check JEDEC basic flash parameter header is OK. The table id is %d, reversion is V%d.%d,"
" length is %d, parameter table pointer is 0x%06lX.", basic_header->id, basic_header->major_rev,
basic_header->minor_rev, basic_header->len, basic_header->ptp);
return true;
}
/**
* Read JEDEC basic parameter table
*
* @param flash flash device
*
* @return true: read OK
*/
static bool read_basic_table(sfud_flash *flash, sfdp_para_header *basic_header) {
sfud_sfdp *sfdp = &flash->sfdp;
/* parameter table address */
uint32_t table_addr = basic_header->ptp;
/* parameter table */
uint8_t table[BASIC_TABLE_LEN * 4] = { 0 }, i, j;
SFUD_ASSERT(flash);
SFUD_ASSERT(basic_header);
/* read JEDEC basic flash parameter table */
if (read_sfdp_data(flash, table_addr, table, sizeof(table)) != SFUD_SUCCESS) {
SFUD_INFO("Warning: Can't read JEDEC basic flash parameter table.");
return false;
}
/* print JEDEC basic flash parameter table info */
SFUD_DEBUG("JEDEC basic flash parameter table info:");
SFUD_DEBUG("MSB-LSB 3 2 1 0");
for (i = 0; i < BASIC_TABLE_LEN; i++) {
SFUD_DEBUG("[%04d] 0x%02X 0x%02X 0x%02X 0x%02X", i + 1, table[i * 4 + 3], table[i * 4 + 2], table[i * 4 + 1],
table[i * 4]);
}
/* get block/sector 4 KB erase supported and command */
sfdp->erase_4k_cmd = table[1];
switch (table[0] & 0x03) {
case 1:
sfdp->erase_4k = true;
SFUD_DEBUG("4 KB Erase is supported throughout the device. Command is 0x%02X.", sfdp->erase_4k_cmd);
break;
case 3:
sfdp->erase_4k = false;
SFUD_DEBUG("Uniform 4 KB erase is unavailable for this device.");
break;
default:
SFUD_INFO("Error: Uniform 4 KB erase supported information error.");
return false;
}
/* get write granularity */
//TODO 目前为 1.0 所提供的方式,后期支持 V1.5 及以上的方式读取 page size
switch ((table[0] & (0x01 << 2)) >> 2) {
case 0:
sfdp->write_gran = 1;
SFUD_DEBUG("Write granularity is 1 byte.");
break;
case 1:
sfdp->write_gran = 256;
SFUD_DEBUG("Write granularity is 64 bytes or larger.");
break;
}
/* volatile status register block protect bits */
switch ((table[0] & (0x01 << 3)) >> 3) {
case 0:
/* Block Protect bits in device's status register are solely non-volatile or may be
* programmed either as volatile using the 50h instruction for write enable or non-volatile
* using the 06h instruction for write enable.
*/
sfdp->sr_is_non_vola = true;
SFUD_DEBUG("Target flash status register is non-volatile.");
break;
case 1:
/* block protect bits in device's status register are solely volatile. */
sfdp->sr_is_non_vola = false;
SFUD_DEBUG("Block Protect bits in device's status register are solely volatile.");
/* write enable instruction select for writing to volatile status register */
switch ((table[0] & (0x01 << 4)) >> 4) {
case 0:
sfdp->vola_sr_we_cmd = SFUD_VOLATILE_SR_WRITE_ENABLE;
SFUD_DEBUG("Flash device requires instruction 50h as the write enable prior "
"to performing a volatile write to the status register.");
break;
case 1:
sfdp->vola_sr_we_cmd = SFUD_CMD_WRITE_ENABLE;
SFUD_DEBUG("Flash device requires instruction 06h as the write enable prior "
"to performing a volatile write to the status register.");
break;
}
break;
}
/* get address bytes, number of bytes used in addressing flash array read, write and erase. */
switch ((table[2] & (0x03 << 1)) >> 1) {
case 0:
sfdp->addr_3_byte = true;
sfdp->addr_4_byte = false;
SFUD_DEBUG("3-Byte only addressing.");
break;
case 1:
sfdp->addr_3_byte = true;
sfdp->addr_4_byte = true;
SFUD_DEBUG("3- or 4-Byte addressing.");
break;
case 2:
sfdp->addr_3_byte = false;
sfdp->addr_4_byte = true;
SFUD_DEBUG("4-Byte only addressing.");
break;
default:
sfdp->addr_3_byte = false;
sfdp->addr_4_byte = false;
SFUD_INFO("Error: Read address bytes error!");
return false;
}
/* get flash memory capacity */
uint32_t table2_temp = ((long)table[7] << 24) | ((long)table[6] << 16) | ((long)table[5] << 8) | (long)table[4];
switch ((table[7] & (0x01 << 7)) >> 7) {
case 0:
sfdp->capacity = 1 + (table2_temp >> 3);
break;
case 1:
table2_temp &= 0x7FFFFFFF;
if (table2_temp > sizeof(sfdp->capacity) * 8 + 3) {
sfdp->capacity = 0;
SFUD_INFO("Error: The flash capacity is grater than 32 Gb/ 4 GB! Not Supported.");
return false;
}
sfdp->capacity = 1L << (table2_temp - 3);
break;
}
SFUD_DEBUG("Capacity is %ld Bytes.", sfdp->capacity);
/* get erase size and erase command */
for (i = 0, j = 0; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
if (table[28 + 2 * i] != 0x00) {
sfdp->eraser[j].size = 1L << table[28 + 2 * i];
sfdp->eraser[j].cmd = table[28 + 2 * i + 1];
SFUD_DEBUG("Flash device supports %ldKB block erase. Command is 0x%02X.", sfdp->eraser[j].size / 1024,
sfdp->eraser[j].cmd);
j++;
}
}
/* sort the eraser size from small to large */
for (i = 0, j = 0; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
if (sfdp->eraser[i].size) {
for (j = i + 1; j < SFUD_SFDP_ERASE_TYPE_MAX_NUM; j++) {
if (sfdp->eraser[j].size != 0 && sfdp->eraser[i].size > sfdp->eraser[j].size) {
/* swap the small eraser */
uint32_t temp_size = sfdp->eraser[i].size;
uint8_t temp_cmd = sfdp->eraser[i].cmd;
sfdp->eraser[i].size = sfdp->eraser[j].size;
sfdp->eraser[i].cmd = sfdp->eraser[j].cmd;
sfdp->eraser[j].size = temp_size;
sfdp->eraser[j].cmd = temp_cmd;
}
}
}
}
sfdp->available = true;
return true;
}
static sfud_err read_sfdp_data(const sfud_flash *flash, uint32_t addr, uint8_t *read_buf, size_t size) {
uint8_t cmd[] = {
SFUD_CMD_READ_SFDP_REGISTER,
(addr >> 16) & 0xFF,
(addr >> 8) & 0xFF,
(addr >> 0) & 0xFF,
SFUD_DUMMY_DATA,
};
SFUD_ASSERT(flash);
SFUD_ASSERT(addr < 1L << 24);
SFUD_ASSERT(read_buf);
SFUD_ASSERT(flash->spi.wr);
return flash->spi.wr(&flash->spi, cmd, sizeof(cmd), read_buf, size);
}
/**
* get the most suitable eraser for erase process from SFDP parameter
*
* @param flash flash device
* @param addr start address
* @param erase_size will be erased size
*
* @return the eraser index of SFDP eraser table @see sfud_sfdp.eraser[]
*/
size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size) {
size_t index = SMALLEST_ERASER_INDEX, i;
/* only used when flash supported SFDP */
SFUD_ASSERT(flash->sfdp.available);
/* the address isn't align by smallest eraser's size, then use the smallest eraser */
if (addr % flash->sfdp.eraser[SMALLEST_ERASER_INDEX].size) {
return SMALLEST_ERASER_INDEX;
}
/* Find the suitable eraser.
* The largest size eraser is at the end of eraser table.
* In order to decrease erase command counts, so the find process is from the end of eraser table. */
for (i = SFUD_SFDP_ERASE_TYPE_MAX_NUM - 1;; i--) {
if ((flash->sfdp.eraser[i].size != 0) && (erase_size >= flash->sfdp.eraser[i].size)
&& (addr % flash->sfdp.eraser[i].size == 0)) {
index = i;
break;
}
if (i == SMALLEST_ERASER_INDEX) {
break;
}
}
return index;
}
#endif /* SFUD_USING_SFDP */