QSPI(Quad Serial Peripheral Interface) 是一種高速串行通信接口,在標準SPI(Serial Peripheral Interface)的基礎上擴展至4條數(shù)據(jù)線(Quad Mode),顯著提升數(shù)據(jù)傳輸速率。它廣泛應用于Flash存儲器、傳感器和微控制器之間的通信。AS32系列MCU芯片開發(fā)板集成了一塊S25FL512SAGMFVG13型號的QSPI FLASH,本文我們將介紹該系列芯片使用簡潔單線模式操作QSPI FLASH。

代碼詳解:
1、扇區(qū)擦除函數(shù)

根據(jù)指導手冊我們知道,在進行扇區(qū)擦除命令之前必須先給一個WREN 命令,該命令會將狀態(tài)寄存器中的寫使能鎖存器(WEL)置位,以允許任何寫入操作。此外,本文用例使用3字節(jié)地址,根據(jù)時序圖可知,應先發(fā)送指令(長度可配置)接著發(fā)送一個24位地址。
我們開始講解扇區(qū)擦除函數(shù),代碼如下:
#define WRITE_ENABLE_INST 0x06
#define WRITE_DISBALE_INST 0x04
#define ERASE_SECTOR_INST 0xD8
#define READ_RIGISTER1_INST 0x05
#define PAGE_PROGRAME_INST 0x02
#define READ_FLASH_INST 0x03
void QSPI_FlashErase(uint32_t block_start, uint32_t sector_num)
{
uint32_t dst;
uint32_t SR_Status;
uint8_t erase_status = 1;
dst = block_start;
uint32_t num = sector_num-1;
if (dst + num * 0x3FFFF> 0xFFFFFF)
{
Printf("error :Exceeds the erase range.rn");
}
QSPI_Reset();
QSPI_Deinit();
QSPI_StructInitenable();
QSPI_WriteEnable();
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
for (uint32_t i = 0; i < num; i++)
{
QSPI_SectorErase();
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
QSPI_SetAddr(dst + num*0x3FFFF);
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
}
while (erase_status)
{
QSPI_SetDataLength(0);
QSPI_ReadStatus_Rigister1();
delay_ms(10);
erase_status = QSPI_ReadData();
}
QSPI_ReadFlash(dst, PROGRAME_SIZE, QSPI_BUFFER );
}
首先看第16行,對QSPI結(jié)構體初始化,分別配置片選高電平時間,QSPI時鐘信號在指令之間的電平,QSPI時鐘分頻。

接著第17行,發(fā)送寫使能命令。該函數(shù)主要配置QSPI->CCR寄存器,主要配置指令寫使能指令和簡介寫模式,其余配置讀者可查閱AS32X601設計手冊的QSPI章節(jié),這里不做過多贅述。

第22行,進行扇區(qū)擦除,和寫使能函數(shù)一致,區(qū)別在于配置不同的指令,第24行設置需要擦除區(qū)域的首地址。

第30行,配置QSPI數(shù)據(jù)長度寄存器(DLR)為0,我們需要讀取1字節(jié),即SR1寄存器8位。第31行,我們發(fā)送讀取QSPI FLASH的SR1寄存器指令。第33行,讀取QSPI FLASH返回的8位數(shù)據(jù),直到erase_status = 0時,我們擦除操作完成。這里是間接讀取模式,還可使用輪詢模式,減少CPU等待時間,完全交給QSPI FLASH來處理數(shù)據(jù)。

以下是讀取SR1寄存器的相關配置,和擦除函數(shù)一致,區(qū)別在于指令,當然讀者可以自行配置QSPI 為2線或4線。

2、讀QSPI FLASH
接上節(jié),我們在最后調(diào)用了QSPI_ReadFlash函數(shù),本章節(jié)詳細講解該函數(shù),先看FLASH手冊,

該指令允許從存儲器陣列的任意字節(jié)地址開始讀取。每輸出一個字節(jié)數(shù)據(jù)后,地址會自動遞增至下一個更高地址(按順序連續(xù)遞增)。因此,只需提供起始地址000000h并發(fā)送一次讀指令,即可連續(xù)讀取整個存儲器的內(nèi)容。當?shù)竭_最高地址后,地址計數(shù)器將自動回繞至000000h,從而支持無限循環(huán)的連續(xù)讀取操作。
函數(shù)如下:
void QSPI_ReadFlash(uint32_t block_start, uint32_t byte_num, uint32_t buffer[])
{
uint32_t FIFO_LEVEL = 0;
QSPI_WriteEnable();
QSPI_SetDataLength(byte_num);
QSPI_Read_Flash();
QSPI_SetAddr(block_start);
delay_ms(10);
FIFO_LEVEL = QSPI_GetFIFOLevel();
while (FIFO_LEVEL != 0)
{
for (uint32_t i=0;i
{
buffer[i] = QSPI_ReadData();
Printf("%xt",buffer[i]);
}
FIFO_LEVEL = QSPI_GetFIFOLevel();
}
QSPI_WriteDisable();
}
同樣在讀數(shù)據(jù)之前需要解鎖QSPI FLASH,并在操作完成后上鎖。第5行,設置讀取需要讀取的字節(jié)數(shù),第6行,調(diào)用QSPI_READ_FLASH(),函數(shù)如下,第9行,獲取FIFO中有效字節(jié)數(shù),當FIFO非空時,讀QSPI->DR寄存器獲取數(shù)據(jù),直到FIFO為空。

3、下板驗證
程序初始化后,調(diào)用QSPI_FlashErase(0x00, 1),從0地址開始,擦除1個扇區(qū),觀察打印信息,并截取了邏輯分析儀片段。


4、頁編程函數(shù)

主要內(nèi)容:若地址的最低9位(A8-A0)不全為0,則超出當前頁末尾的傳輸數(shù)據(jù)將從同一頁的起始地址(即最低9位全為0的地址)開始編程,即地址會在頁對齊的邊界內(nèi)回繞。這是因為用戶只需輸入單個頁地址即可覆蓋整個頁邊界。
如果發(fā)送給設備的數(shù)據(jù)不足一頁,這些數(shù)據(jù)字節(jié)將從所提供地址開始按順序編程,而不會影響同一頁內(nèi)的其他字節(jié)。
為優(yōu)化時序,使用頁編程(PP)命令在頁邊界內(nèi)加載整個頁大小的編程緩沖器,相比于加載不足一頁的數(shù)據(jù)到編程緩沖器,將節(jié)省總體編程時間。
int QSPI_FlashWrite(uint32_t block_start,uint32_t offset_into_block, uint32_t count, uint32_t buffer[])
{
uint32_t dst;
uint32_t ii;
uint32_t num;
dst = block_start + offset_into_block;
num = count;
if (dst%4 != 0)
{
Printf( "the addr must 4-byte alignmentrn");
return 0;
}
QSPI_Deinit();
if ((dst%256) == 0)
{ int loop = 0;
Printf( "the first packge is 256 bytesrn");
while (num > 256)
{
QSPI_StructInitenable();
QSPI_SetDataLength(0xff);
QSPI_WriteEnable();
QSPI_PageProgram();
QSPI_SetAddr(dst);
for (ii = loop256/4; ii < loop256/4+64; ii++)
{
QSPI->DR = buffer[ii];
}
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
dst += 256;
num -= 256;
delay_ms(20);
loop++;
}
QSPI_StructInitenable();
QSPI_SetDataLength(block_start + offset_into_block + count - dst -1);
QSPI_WriteEnable();
QSPI_PageProgram();
QSPI_SetAddr(dst);
for (ii = 256loop/4; ii < (256loop+block_start + offset_into_block + count - dst)/4; ii++)
{
QSPI->DR = buffer[ii];
}
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
dst += block_start + offset_into_block + count – dst;
}
else
{
QSPI_StructInitenable();
QSPI_WriteEnable();
QSPI_PageProgram();
QSPI_SetAddr(dst);
QSPI_SetDataLength(256-(dst%256));
for (ii = 0; ii < (256-(dst%256))/4; ii++)
{
QSPI->DR = buffer[ii];
}
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
dst += 256-(dst%256);
while (num > 256)
{
QSPI_StructInitenable();
QSPI_WriteEnable();
QSPI_PageProgram();
QSPI_SetAddr(dst);
QSPI_SetDataLength(256-1);
for (ii = 0; ii < 64; ii++)
{
QSPI->DR = buffer[ii];
}
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
dst += 256;
num -= 256;
}
QSPI_StructInitenable();
QSPI_WriteEnable();
QSPI_PageProgram();
QSPI_SetAddr(dst);
QSPI_SetDataLength(block_start + offset_into_block + count - dst -1);
for (ii = 0; ii < (block_start + offset_into_block + count - dst)/4; ii++)
{
QSPI->DR = buffer[ii];
}
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
dst += block_start + offset_into_block + count - dst;
}
QSPI_WriteDisable();
while ( (QSPI_GetFlagStatus(QSPI_FLAG_BUSY) == 1));
QSPI_ReadFlash(block_start,PROGRAME_SIZE,QSPI_BUFFER);
return 0; //RESULT_OK
}
第1至13行定義了函數(shù)參數(shù)并計算目標地址,同時檢查地址是否4字節(jié)對齊,若未對齊則報錯返回。第14行對QSPI控制器進行復位。第15至48行處理目標地址256字節(jié)對齊的情況:第16至35行循環(huán)寫入完整的256字節(jié)數(shù)據(jù)頁,每次寫入前初始化硬件、設置數(shù)據(jù)長度、使能寫入、發(fā)送頁編程命令并設置地址,隨后通過循環(huán)寫入64個32位數(shù)據(jù),等待操作完成后更新地址和剩余計數(shù);第36至47行處理剩余不足256字節(jié)的數(shù)據(jù)尾部,采用類似的流程但數(shù)據(jù)長度根據(jù)剩余量動態(tài)計算。第49至88行處理目標地址未256字節(jié)對齊的情況:第51至60行先寫入從起始地址到下一個256字節(jié)邊界的首部數(shù)據(jù)片段;第61至75行循環(huán)寫入后續(xù)完整的256字節(jié)頁;第76至87行處理最后的尾部數(shù)據(jù)。
5、下板驗證
準備寫入1024個數(shù),0-0x3FF,共4K,從0地址開始,觀察打印信息



審核編輯 黃宇
-
FlaSh
+關注
關注
10文章
1747瀏覽量
155480 -
QSPI
+關注
關注
0文章
55瀏覽量
13355 -
MCU芯片
+關注
關注
3文章
260瀏覽量
12878
發(fā)布評論請先 登錄
編譯可在QSPI Flash上運行的程序
在軟件SDK中選擇不同的下載模式時,是哪個部件更改了QSPI0中寄存器的值?
STM32H750 QSPI flash重映射模式下有方法能實現(xiàn)讀寫操作嗎?
STM32 QSPI怎么退出映射模式?
xilinx-A7 fpga 使用QSPI模式啟動,項目需要用MCU做FPGA程序升級,請問MCU怎么操作SPIFLASH?
如何對STM32 QSPI進行調(diào)試
如何制作適用于MM32F5270系列MCU的QSPI Flash下載算法呢?
什么是QSPI?如何使用QSPI與QSPI Flash進行通信呢?
先楫hpm6000的SPI外設使用四線模式操作讀寫華邦flash
AT32系列MCU flash具體操作說明
如何使用QSPI Flash控制器開發(fā)板上的 QSPI Flash進行寫讀操作
微控制器外置QSPI Flash選型的注意事項
FreeRTOS 在 AS32系列RISC-V 架構MCU電機驅(qū)動中的應用實踐與優(yōu)化
AS32系列MCU芯片中CRC計算模塊的應用介紹
如何利用AS32系列MCU芯片使用簡潔單線模式操作QSPI FLASH?
評論