【海東青電子原創(chuàng)文章,轉(zhuǎn)載請注明出處:http://www.itdecent.cn/p/f22afca42c57】
(文中代碼下載地址:https://github.com/haidongqing/qspi-readid)
STM32F746G-DISCO開發(fā)板上,通過QaudSPI接口連接了一片MICRON公司的NOR FLASH,型號為?N25Q128A13EF840E 。這里涉及了2個方面的技術(shù)問題:
1)Qaud SPI 總線接口;
2)ST MCU如何通過Qaud SPI 接口讀寫NOR FLASH。
先來看看什么是Qaud SPI,它是SPI的“升級版”,也有簡寫成QSPI的,稱為四線SPI,可以理解為在傳統(tǒng)的SPI總線上,擴充了4條“雙向”數(shù)據(jù)線。這樣,Qaud SPI就有6根線:片選信號CS、時鐘CLK、數(shù)據(jù)線D0-D3(SPI是4根線:CS、CLK、MISO、MOSI)。功能的增強一定帶來新的復(fù)雜性,QSPI也不例外 ---- 相比較SPI而言,QSPI不再是只按照CLK的時鐘時序讀或?qū)憯?shù)據(jù)那么簡單了,而是需要先發(fā)送“命令”才能讀寫數(shù)據(jù)。所以,QSPI總線的驅(qū)動、編程要復(fù)雜一些。
為了簡化QSPI的編程、使用,STM32系列MCU在內(nèi)部增加了一個QSPI控制器,通過一些相關(guān)的寄存器控制對QSPI的操作。總體而言,QSPI有3種工作模式:單線(Single,或Extended)、雙線(Daul)和四線(Qaud),其中四線SPI最常用(顯然,這種模式下數(shù)據(jù)吞吐率最大、效率最高),這也是我們下面要討論的重點。
上圖是STM32F746用戶手冊中QaudSPI功能框圖(單BANK的情形,746也支持雙BANK模式,此處不作討論),可見MCU與FLASH之間就是6根信號線。
既然我們關(guān)心的是如果讀寫FLASH,就得先看看FLASH這個外部器件對讀寫數(shù)據(jù)有哪些要求(時序,讀寫命令等)。
首先,F(xiàn)LASH在進(jìn)入“常規(guī)工作”狀態(tài)之前,需要先進(jìn)行“配置”,即參數(shù)初始化,比如QSPI總線模式、讀數(shù)據(jù)延遲周期等。N25Q內(nèi)部有2種類型的配置寄存器:Nonvolatile Configuration Register 和?Volatile Configuration Register,前者是非易失的,后者是易失的。讀配置寄存器有相應(yīng)的命令:
這是很簡單的讀取命令,MCU通過QSPI總線發(fā)送一個命令字 B5 ,F(xiàn)LASH接收到之后,在數(shù)據(jù)線上送出配置寄存器中的內(nèi)容。寫配置寄存器如下:
發(fā)送2個字節(jié):命令字 B1 + 一字節(jié)配置內(nèi)容,總共16 bit。讀寫配置寄存器的時序圖比較簡單,但這個是基礎(chǔ),讀懂了圖二、圖四的時序圖,就能讀懂下面稍復(fù)雜一些的時序圖。
第二,讀出數(shù)據(jù)的具體操作。最簡單的,是先讀出FLASH的ID。任何一個廠家的FLASH器件,內(nèi)部都有一個device id,以及一些擴展信息,說明這個FLASH的生產(chǎn)商、芯片容量等基礎(chǔ)參數(shù)。
測試時,使用了READ ID(9E) 命令,它只能用于Extended模式。注意上圖的 Notes 2 :

表明此命令不需要地址,讀延遲周期(Dummy clock cycles)為0,即不需要。請注意?Dummy clock cycles 這個參數(shù),這是個非常重要的參數(shù),在讀取FLAHS數(shù)據(jù)時,從發(fā)出讀命令,到FLASH將數(shù)據(jù)送上數(shù)據(jù)線,是需要一定時間的,這個時間就是?Dummy clock cycles,后面講到對FLASH讀數(shù)據(jù)時還會重點提到。正確讀出ID的結(jié)果會是這樣的:
讀ID ,得到的數(shù)據(jù)(前3個)是:20h,BAh,18h。
(注:JEDEC,Joint Electron Device Engineering Council,JEDEC固態(tài)技術(shù)協(xié)會,EIA的分支,F(xiàn)LASH廠家的ID應(yīng)該是由這個標(biāo)準(zhǔn)化組織分配的)
好了,我們就只先做最簡單的一步:如何讀出FLAHS的ID。MCU這一端的工作,主要是使用CubeMX正確配置QaudSPI,并編寫代碼訪問FLASH。先看看STM32F746G-DISCO 開發(fā)板的原理圖、確定QSPI用到的pin:
運行STM32Cube,選擇STM32F746NG芯片,配置RCC、SYS和時鐘:
最后是主角:QaudSPI:
上圖中,
1、選擇QSPI的四線模式。
2、FLASH的時鐘頻率,選擇對HCLK 2分頻,就是 216/(1+1) = 108 MHz,正好是N25Q芯片的最高可用頻率(見;N25Q數(shù)據(jù)手冊)。---- 之前這個參數(shù)設(shè)置成了2,是錯誤的,感謝網(wǎng)友 “海鴉” 的提醒??!
3、QSPI針對讀寫數(shù)據(jù)設(shè)計了FIFO緩沖區(qū),這是緩沖區(qū)長度。
4、選擇延遲半個時鐘采樣周期、利于適應(yīng)FLASH的可能延遲,見圖十五。
5、N25Q容量是128Mbit,即16MByte,那么按字節(jié)尋址的話有16M個地址,16M = 2的24次方,所以填寫24。
6、連續(xù)2個命令之間需要的延遲間隔時間(時鐘周期)。QSPI每次向FLASH發(fā)送命令,片選信號CS都有一個拉低、再拉高的過程,2個命令之間CS保持高電平(無效狀態(tài)),這個高電平保持多久,稱為 Chip Select High Time(見圖十六)。N25Q要求這個時間最小是50ns(見圖十七),F(xiàn)LASH時鐘是108MHz,50ns/(1/108MHz) = 5.4,即最小需要5.4個時鐘周期,所以這里選擇了6。
7、Clock Mode,空閑時CLK的電平狀態(tài),似無大礙,這里選了low(模式0;如果high,是模式3)。
QaudSPI的配置還沒完事,還需要檢查GPIO的復(fù)用功能是否配置正確(這是有血的教訓(xùn)的,見這里)。CubeMX默認(rèn)的QSPI管腳配置是:
需要按下圖重新分配pin:
生成KEIL代碼。main.c中,函數(shù)?MX_QUADSPI_Init() 是CubeMX生成的QSPI的初始化函數(shù)。
先定義一個常數(shù)數(shù)組,包含了N25Q的ID信息:
const uint8_t bN25Q_ID[BUFFERSIZE] = {0x20, 0xBA, 0x18}; ? ? ? ? ? ? ? //Manufacturer ID, Memory Type, Memory Capacity
然后讀FLASH:
sCommand 是 QSPI_CommandTypeDef 類型的結(jié)構(gòu)體,負(fù)責(zé)配置命令模式、命令字、數(shù)據(jù)格式、數(shù)據(jù)長度等關(guān)鍵信息,然后調(diào)用?HAL_QSPI_Command() 發(fā)送命令。在 ?HAL_QSPI_Command() 內(nèi)部又調(diào)用了 QSPI_Config(),通過寫QSPI相關(guān)的一些寄存器最終實現(xiàn)發(fā)送命令的操作。在調(diào)用 QSPI_Config() 時,使用了一個重要的參數(shù):QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE,它約定了QSPI在此次與FLASH的會話中,使用的是QSPI的“間接操作模式”(QSPI有三種操作模式,詳情將在下一講中介紹,預(yù)留鏈接)。
讀出ID結(jié)果如下:
讀出的數(shù)值確實是?20h,BAh,18h;開發(fā)板背面的LED慢閃,表明讀取ID正確(如果出錯,LED將快閃)。
本例的代碼下載地址:https://github.com/haidongqing/qspi-readid。
下一節(jié)將介紹QSPI的三種操作模式、并實現(xiàn)讀FLASH數(shù)據(jù):《STM32硬件基礎(chǔ)--QaudSPI總線讀寫片外FLASH(二)》。
補充:關(guān)于QaudSPI的時鐘頻率
分頻系數(shù)數(shù)值+1,是真正的分頻倍數(shù)。為了2分頻,應(yīng)該將 PRESCALER 參數(shù)設(shè)置為1;如果設(shè)置為2,就是3分頻了,QaudSPI時鐘頻率更低了,程序仍能正常執(zhí)行,只不過讀寫速率降低了、效率低了。經(jīng)測試,如果將 PRESCALER 參數(shù)設(shè)置為0,QaudSPI時鐘頻率==HCLK 了,超出了最大頻率范圍,讀出的ID是錯誤的。