本文搬運自SFUD開源項目的相關說明,僅供學習、參考,不涉及任何商業行爲。此外,向所有曾參與該開源項目的開發者致敬。
0、SFUD 是什麼
SFUD(Serial Flash Universal Driver) 是一款開源的串行 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 (點擊這裏查看)。該標準規定了,每個 Flash 中會存在一個參數表,該表中會存放 Flash 容量、寫粒度、擦除命令、地址模式等 Flash 規格參數。目前,除了部分廠家舊款 Flash 型號會不支持該標準,其他絕大多數新出廠的 Flash 均已支持 SFDP 標準。所以該庫在初始化時會優先讀取 SFDP 表參數。
- 不支持 SFDP 怎麼辦 :如果該 Flash 不支持 SFDP 標準,SFUD 會查詢配置文件 (
/sfud/inc/sfud_flash_def.h
) 中提供的 Flash 參數信息表 中是否支持該款 Flash。如果不支持,則可以在配置文件中添加該款 Flash 的參數信息(添加方法詳細見 2.5 添加庫目前不支持的 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|OSChina|Coding) 。
如果覺得這個開源項目很贊,可以點擊 項目主頁 右上角的 Star ,同時把它推薦給更多有需要的朋友。
型號 | 製造商 | 容量 | 最高速度 | SFDP 標準 | QSPI 模式 | 備註 |
---|---|---|---|---|---|---|
W25Q40BV | Winbond | 4Mb | 50Mhz | 不支持 | 雙線 | 已停產 |
W25Q80DV | Winbond | 8Mb | 104Mhz | 支持 | 雙線 | |
W25Q16BV | Winbond | 16Mb | 104Mhz | 不支持 | 雙線 | by slipperstree |
W25Q16CV | Winbond | 16Mb | 104Mhz | 支持 | 未測試 | |
W25Q16DV | Winbond | 16Mb | 104Mhz | 支持 | 未測試 | by slipperstree |
W25Q32BV | Winbond | 32Mb | 104Mhz | 支持 | 雙線 | |
W25Q64CV | Winbond | 64Mb | 80Mhz | 支持 | 四線 | |
W25Q128BV | Winbond | 128Mb | 104Mhz | 支持 | 四線 | |
W25Q256FV | Winbond | 256Mb | 104Mhz | 支持 | 四線 | |
MX25L3206E | Macronix | 32Mb | 86MHz | 支持 | 雙線 | |
KH25L4006E | Macronix | 4Mb | 86Mhz | 支持 | 未測試 | by JiapengLi |
KH25L3206E | Macronix | 32Mb | 86Mhz | 支持 | 雙線 | |
SST25VF016B | Microchip | 16Mb | 50MHz | 不支持 | 不支持 | SST 已被 Microchip 收購 |
M25P40 | Micron | 4Mb | 75Mhz | 不支持 | 未測試 | by redocCheng |
M25P80 | Micron | 8Mb | 75Mhz | 不支持 | 未測試 | by redocCheng |
M25P32 | Micron | 32Mb | 75Mhz | 不支持 | 不支持 | |
EN25Q32B | EON | 32Mb | 104MHz | 不支持 | 未測試 | |
GD25Q16B | GigaDevice | 16Mb | 120Mhz | 不支持 | 未測試 | by TanekLiang |
GD25Q64B | GigaDevice | 64Mb | 120Mhz | 不支持 | 雙線 | |
S25FL216K | Cypress | 16Mb | 65Mhz | 不支持 | 雙線 | |
S25FL032P | Cypress | 32Mb | 104Mhz | 不支持 | 未測試 | by yc_911 |
S25FL164K | Cypress | 64Mb | 108Mhz | 支持 | 未測試 | |
A25L080 | AMIC | 8Mb | 100Mhz | 不支持 | 雙線 | |
A25LQ64 | AMIC | 64Mb | 104Mhz | 支持 | 支持 | |
F25L004 | ESMT | 4Mb | 100Mhz | 不支持 | 不支持 | |
PCT25VF016B | PCT | 16Mb | 80Mhz | 不支持 | 不支持 | SST 授權許可,會被識別爲 SST25VF016B |
AT45DB161E | 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 狀態。
sfud_err sfud_init(void)
2.2.2 初始化指定的 Flash 設備
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 擴展信息表 中匹配最合適的、速度最快的快速讀命令,之後用戶在調用 sfud_read() 時,會使用 QSPI 模式的傳輸函數發送該命令。
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)。本方法通過 Flash 設備位於設備表中索引值來返回 Flash 設備對象,超出設備表範圍返回 NULL
。
sfud_flash *sfud_get_device(size_t index)
參數 | 描述 |
---|---|
index | Flash 設備位於 FLash 設備表中的索引值 |
2.2.5 讀取 Flash 數據
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 芯片的擦除粒度對齊,否則執行擦除操作後,將會導致其他數據丟失。
sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size)
參數 | 描述 |
---|---|
flash | Flash 設備對象 |
addr | 起始地址 |
size | 從起始地址開始擦除數據的總大小 |
2.2.7 擦除 Flash 全部數據
sfud_err sfud_chip_erase(const sfud_flash *flash)
參數 | 描述 |
---|---|
flash | Flash 設備對象 |
2.2.8 往 Flash 寫數據
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 芯片的擦除粒度對齊,否則執行擦除操作後,將會導致其他數據丟失。
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 狀態
sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status)
參數 | 描述 |
---|---|
flash | Flash 設備對象 |
status | 當前狀態寄存器值 |
2.2.11 寫(修改) Flash 狀態
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
對該設備進行初始化。參考如下代碼:
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
這個宏定義,示例如下:
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 | STM32F10X 裸機平臺 |
/demo/stm32f2xx_rtt | STM32F2XX + RT-Thread 操作系統平臺 |
/demo/stm32l475_non_os_qspi | STM32L475 + QSPI 模式 裸機平臺 |
2.7 許可
採用 MIT 開源協議,細節請閱讀項目中的 LICENSE 文件內容。