SFUD 是一款開源的串行SPI Flash 通用驅動庫。由於現有市面的串行Flash 種類居多,各個Flash 的規格及命令存在差異, SFUD 就是為了解決這些Flash 的差異現狀而設計,讓我們的產品能夠支持不同品牌及規格的Flash,提高了涉及到Flash 功能的軟件的可重用性及可擴展性,同時也可以規避Flash 缺貨或停產給產品所帶來的風險。
/sfud/inc/sfud_flash_def.h ) 中提供的Flash 參數信息表中是否支持該款Flash。如果不支持,則可以在配置文件中添加該款Flash 的參數信息(添加方法詳細見2.5 添加庫目前不支持的Flash)。獲取到了Flash 的規格參數後,就可以實現對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 | 支持 | 雙線 | |
| MX25L3233F | Macronix | 32Mb | 133MHz | 支持 | 未測試 | by JiapengLi |
| 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 |
| GD25Q32C | GigaDevice | 32Mb | 120Mhz | 不支持 | 未測試 | by gaupen1186 |
| 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 串行閃存產品線 |
| NM25Q128EV | Nor_Mem | 128Mb | 未測試 | 不支持 | 未測試 | SFDP可能會讀取到信息後識別為超過32Gb |
| P25D40H | PUYA | 4Mb | 未測試 | 支持 | 未測試 | by Shan |
| P25Q80H | PUYA | 8Mb | 未測試 | 支持 | 未測試 | by Shan |
注:QSPI 模式中,雙線表示支持雙線快讀,四線表示支持四線快讀。
一般情況下,支持四線快讀的FLASH 也支持雙線快讀。
先說明下本庫主要使用的一個結構體sfud_flash 。其定義位於/sfud/inc/sfud_def.h 。每個SPI Flash 會對應一個該結構體,該結構體指針下面統稱為Flash 設備對象。初始化成功後在sfud_flash->chip結構體中會存放SPI Flash 的常見參數。如果SPI Flash 還支持SFDP ,還可以通過sfud_flash->sfdp看到更加全面的參數信息。以下很多函數都將使用Flash 設備對像作為第一個入參,實現對指定SPI Flash 的操作。
將會調用sfud_device_init ,初始化Flash 設備表中的全部設備。如果只有一個Flash 也可以只使用sfud_device_init進行單一初始化。
注意:初始化完的SPI Flash 默認都已取消寫保護狀態,如需開啟寫保護,請使用sfud_write_status 函數修改SPI Flash 狀態。
sfud_err sfud_init ( void ) sfud_err sfud_device_init ( sfud_flash * flash )| 參數 | 描述 |
|---|---|
| flash | 待初始化的Flash 設備 |
當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 |
在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 設備表中的索引值 |
sfud_err sfud_read ( const sfud_flash * flash , uint32_t addr , size_t size , uint8_t * data )| 參數 | 描述 |
|---|---|
| flash | Flash 設備對象 |
| addr | 起始地址 |
| size | 從起始地址開始讀取數據的總大小 |
| data | 讀取到的數據 |
注意:擦除操作將會按照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 | 從起始地址開始擦除數據的總大小 |
sfud_err sfud_chip_erase ( const sfud_flash * flash )| 參數 | 描述 |
|---|---|
| flash | Flash 設備對象 |
sfud_err sfud_write ( const sfud_flash * flash , uint32_t addr , size_t size , const uint8_t * data )| 參數 | 描述 |
|---|---|
| flash | Flash 設備對象 |
| addr | 起始地址 |
| size | 從起始地址開始寫入數據的總大小 |
| data | 待寫入的數據 |
注意:擦除操作將會按照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 | 待寫入的數據 |
sfud_err sfud_read_status ( const sfud_flash * flash , uint8_t * status )| 參數 | 描述 |
|---|---|
| flash | Flash 設備對象 |
| status | 當前狀態寄存器值 |
sfud_err sfud_write_status ( const sfud_flash * flash , bool is_volatile , uint8_t status )| 參數 | 描述 |
|---|---|
| flash | Flash 設備對象 |
| is_volatile | 是否為易閃失的,true: 易閃失的,及斷電後會丟失 |
| status | 當前狀態寄存器值 |
所有配置位於/sfud/inc/sfud_cfg.h ,請參考下面的配置介紹,選擇適合自己項目的配置。
打開/關閉SFUD_DEBUG_MODE宏定義
打開/關閉SFUD_USING_SFDP宏定義
注意:關閉後只會查詢該庫在
/sfud/inc/sfud_flash_def.h中提供的Flash 信息表。這樣雖然會降低軟件的適配性,但減少代碼量。
打開/關閉SFUD_USING_FAST_READ宏定義。許多Flash的讀模式可能並不能滿足較高的SPI頻率(具體可查閱各Flash的數據手冊交流特性部分),此時需要使能快速讀模式。
注意:由於快速讀模式在讀時插入了默認一個空字節,在SPI速率較慢時可能相較於讀模式速度更慢。
打開/關閉SFUD_USING_FLASH_INFO_TABLE宏定義
注意:關閉後該庫只驅動支持SFDP 規範的Flash,也會適當的降低部分代碼量。另外2.3.2 及2.3.3 這兩個宏定義至少定義一種,也可以兩種方式都選擇。
為了進一步降低代碼量, 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 );
......如果產品中存在多個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()方法獲取到設備表,再配合這個索引值來訪問指定的設備。
打開/關閉SFUD_USING_QSPI宏定義
開啟後,SFUD 也將支持使用QSPI 總線連接的Flash。
移植文件位於/sfud/port/sfud_port.c ,文件中的sfud_err sfud_spi_port_init(sfud_flash *flash)方法是庫提供的移植方法,在裡面完成各個設備SPI 讀寫驅動(必選)、重試次數(必選)、重試接口(可選)及SPI 鎖(可選)的配置。更加詳細的移植內容,可以參考demo 中的各個平台的移植文件。
這裡需要修改/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的支持。
目前已支持如下平台下的Demo
| 路徑 | 平台描述 |
|---|---|
| /demo/stm32f10x_non_os | STM32F10X 裸機平台 |
| /demo/stm32f2xx_rtt | STM32F2XX + RT-Thread 操作系統平台 |
| /demo/stm32l475_non_os_qspi | STM32L475 + QSPI 模式裸機平台 |
| /demo/esp32_ext_spi_flash | ESP32C3 + SPI外部Flash ESP-IDF框架 |
採用MIT 開源協議,細節請閱讀項目中的LICENSE 文件內容。