SPI Flash驅(qū)動(dòng)包括兩層:硬件訪(fǎng)問(wèn)層(HAL/QSPI)和RT-Thread的適配層。
HAL 提供基本的 QSPI API 來(lái)訪(fǎng)問(wèn) QSPI 外設(shè)的寄存器。 有關(guān)詳細(xì)信息,請(qǐng)參閱 QSPI HAL 的 API 文檔。
適配層提供常見(jiàn)的 SPI-Flash 訪(fǎng)問(wèn)功能。 用戶(hù)無(wú)需操作系統(tǒng)即可直接使用。 它還為RT-Thread注冊(cè)到MTD,可以被文件系統(tǒng)訪(fǎng)問(wèn)。 Flash 控制器也默認(rèn)支持 FIFO DMA 模式和 QSPI 模式,可以通過(guò)配置頭文件關(guān)閉它們。 主要功能包括:
- 多實(shí)例支持多達(dá) 4 個(gè)
- FIFO DMA 支持讀/寫(xiě)
- 對(duì)閃存讀取的 DMA 支持
- SPI/QSPI 支持
- NOR/NAND 支持
- Sector、block32、block64、NOR的全芯片擦除和NAND的塊擦除
驅(qū)動(dòng)配置
硬件驅(qū)動(dòng)程序可以使用多個(gè)實(shí)例(硬件限制最多 4 個(gè)實(shí)例)??梢允褂?menuconfig 工具為每個(gè)項(xiàng)目選擇它,并且通常保存在 C 頭文件中。默認(rèn)情況下,配置保存為 rtconfig.h。
下面的例子顯示了一個(gè)項(xiàng)目頭文件中定義的標(biāo)志,項(xiàng)目是啟用FLASH控制器,SPI-FLASH模式啟用,使用QSPI控制器1的NOR模式和QSPI22的NAND模式,以及大小為2MB的FLASH1,使用128MB的FLASH2。步驟選擇配置:
- 在項(xiàng)目下的命令中輸入“menuconfig”
- 選擇“RTOS —>”
- 選擇“On-chip Peripheral Driver—>”
- 選擇“Enable QSPI —>” 使用 QSPI 驅(qū)動(dòng),定義宏BSP_USING_QSPI
- 選擇“Enable QSPI Driver” 使用 spi flash控制器,定義宏BSP_USING_SPI_FLASH
- 選擇“QSPI Controller 1 Enable —>” 使用 QSPI1 控制器,定義宏BSP_ENABLE_QSPI1
- 輸入“QSPI1 Mode” 選擇 QSPI1 為 Nor/Nand flash,定義宏BSP_QSPI1_MODE
- 輸入“QSPI1 Mem Size (MB)” 以MB為單位設(shè)置flash1內(nèi)存大小,定義宏BSP_QSPI1_MEM_SIZE
- 回到 QSPI 控制器啟用:
- 選擇“QSPI Controller 2 Enable —>” 使用 QSPI2 控制器r,定義宏BSP_ENABLE_QSPI2
- 輸入“QSPI2 Mode:” 選擇QSPI2為Nor/Nand flash,定義宏BSP_QSPI1_MODE
- 輸入“QSPI2 Mem Size (MB)” 以MB為單位設(shè)置flash2內(nèi)存大小,定義宏BSP_QSPI2_MEM_SIZE
#define BSP_USING_QSPI
#define BSP_USING_SPI_FLASH
#define BSP_ENABLE_QSPI1
#define BSP_QSPI1_USING_DMA
#define BSP_QSPI1_MODE 0
#define BSP_QSPI1_MEM_SIZE 2
#define BSP_ENABLE_QSPI2
#define BSP_QSPI2_USING_DMA
#define BSP_QSPI2_MODE 1
#define BSP_QSPI2_MEM_SIZE 128
如果您想將閃存用于文件系統(tǒng)或?qū)⑵溆米?rt-device,則應(yīng)啟用 MTD,它還使用 menuconfig 工具并包含在頭文件中。 啟用 RT-DEVICE flash 界面的步驟(在 menuconfig 主菜單中):
- 選擇“RTOS”—>
- 選擇“RT-Thread Components—>”
- 選擇“Device Driver—>”
- 啟用“Using MTD Nor Flash device drivers” 將 Nor Flash 注冊(cè)到 MTD 設(shè)備,定義宏 RT_USING_MTD_NOR
- 選擇“Enable Nor Flash file syste” 在 Flash 上使用文件系統(tǒng),定義宏 RT_USING_NOR_FS
- 輸入“Base sector for file system” Flash 上文件系統(tǒng)的起始地址(按扇區(qū))
#define RT_USING_MTD_NOR
#define RT_USING_NOR_FS
#define RT_NOR_FS_BASE_SEC 4096
配置完成后,用戶(hù)需要在所有需要訪(fǎng)問(wèn)驅(qū)動(dòng)程序的源代碼中包含頭文件
內(nèi)存地址和設(shè)備名稱(chēng)
當(dāng)使用閃存作為內(nèi)存時(shí),它的基地址定義在內(nèi)存映射中:
#define QSPI1_MEM_BASE (0x10000000)
#define QSPI2_MEM_BASE (0x64000000)
#define QSPI3_MEM_BASE (0x68000000)
#define QSPI4_MEM_BASE (0x12000000)
#define FLASH_BASE_ADDR (QSPI1_MEM_BASE)
#define FLASH2_BASE_ADDR (QSPI2_MEM_BASE)
#ifdef BSP_QSPI2_MEM_SIZE
#define FLASH2_SIZE (BSP_QSPI2_MEM_SIZE*1024*1024)
#else
#define FLASH2_SIZE (0)
#endif
#define FLASH3_BASE_ADDR (QSPI3_MEM_BASE)
#ifdef BSP_QSPI3_MEM_SIZE
#define FLASH3_SIZE (BSP_QSPI3_MEM_SIZE*1024*1024)
#else
#define FLASH3_SIZE (0)
#endif
#define FLASH4_BASE_ADDR (QSPI4_MEM_BASE)
#ifdef BSP_QSPI4_MEM_SIZE
#define FLASH4_SIZE (BSP_QSPI4_MEM_SIZE*1024*1024)
#else
#define FLASH4_SIZE (0)
#endif
注冊(cè)到 RT-DEVICE 的 FLASH 設(shè)備名稱(chēng)是固定的。 對(duì)于 FLASH1,它的設(shè)備名稱(chēng)是 "flash1" 。 對(duì)于 FLASH2,它的設(shè)備名稱(chēng)是 "flash2" 。
非操作系統(tǒng)閃存 API
int rt_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size);
int rt_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size);
rt_err_t rt_flash_erase(rt_uint32_t addr, size_t size);
使用 SPI 或閃存
適配器層注冊(cè) RT-Thread 請(qǐng)求的硬件支持功能,并使用 HAL 實(shí)現(xiàn)這些功能。 對(duì)于使用 RT-Thread 的用戶(hù),可以使用以下代碼作為示例(對(duì)于塊設(shè)備進(jìn)程,它的地址和大小是基于扇區(qū)的):
rt_device_t fdev = rt_device_find("flash1");
rt_err_t err = rt_device_open(fdev, RT_DEVICE_FLAG_RDWR);
char * buf = malloc(4096);
int size = rt_device_read(fdev, 0, buf, 1);
size = rt_device_write(fdev, 0, buf, 1);
unsigned long param[2];
param[0] = 0;
param[1] = 1;
rt_device_control(fdev, RT_DEVICE_CTRL_BLK_ERASE, param);
...
用戶(hù)也可以在沒(méi)有系統(tǒng)的情況下使用帶有驅(qū)動(dòng)程序接口的閃存訪(fǎng)問(wèn)(地址和大小是基于字節(jié)的,地址應(yīng)該是絕對(duì)地址),如下所示:
char * buf = malloc(4096);
unsigned long address = FLASH_BASE_ADDR;
int size = rt_flash_read(address, buf, 4096);
size = rt_flash_write(address, buf, 4096);
rt_flash_erase(address, 4096);
...