串行 Flash 通用驅動庫——SFUD

本文搬運自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.hSFUD_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_SFDPSFUD_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_INDEXSFUD_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 idcapacity idGD25Q64B 對應這兩個 ID 分別爲 0x400x17 。上面要求的其他 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 文件內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章