【軟件中如何設置SPI的極性和相位】SPI分主設備和從設備,兩者通過SPI協(xié)議通訊。而設置SPI的模式,是從設備的模式,決定了主設備的模式。所以要先去搞懂從設備的SPI是何種模式,然后再將主設備的SPI的模式,設置和從設備相同的模式,即可正常通訊。對于從設備的SPI是什么模式,有兩種:(1)固定的,有SPI從設備硬件決定的SPI從設備,具體是什么模式,相關的datasheet中會有描述,需要自己去datasheet中找到相關的描述,即:關于SPI從設備,在空閑的時候,是高電平還是低電平,即決定了CPOL是0還是1;然后再找到關于設備是在上升沿還是下降沿去采樣數(shù)據(jù),這樣就是,在定了CPOL的值的前提下,對應著可以推算出CPHA是0還是1了。舉例1:CC2500-Low-CostLow-Power2.4GHzRFTransceiver的datasheet中SPI的時序圖是:
從圖中可以看到,最開始的SCLK和結(jié)束時候的SCLK,即空閑時刻的SCLK,是低電平,推導出CPOL=0,然后可以看到數(shù)據(jù)采樣的時候,即數(shù)據(jù)最中間的那一點,對應的是SCLK的第一個邊沿,所以CPHA=0(此時對應的是上升沿)。舉例2:SSD1289-240RGBx320TFTLCDControllerDriver的datasheet中提到:“SDIisshiftedinto8-bitshiftregisteroneveryrisingedgeofSCKintheorderofdatabit7,databit6……databit0.”意思是,數(shù)據(jù)是在上升沿采樣,所以可以斷定是CPOL=0,CPHA=0,或者CPOL=1,CPHA=1的模式,但是至于是哪種模式。按理來說,接下來應該再去確定SCLK空閑時候是高電平還是低電平,用以確定CPOL是0還是1,但是datasheet中沒有提到這點。所以,此處,目前不太確定,是兩種模式都支持,還是需要額外找證據(jù)卻確定CPOL是0還是1.(2)可配置的,由軟件自己設定從設備也是一個SPI控制器,4種模式都支持,此時只要自己設置為某種模式即可。然后知道了從設備的模式后,再去將SPI主設備的模式,設置為和從設備模式一樣,即可。 對于如何配置SPI的CPOL和CPHA的話,不多細說,多數(shù)都是直接去寫對應的SPI控制器中對應寄存器中的CPOL和CPHA那兩位,寫0或?qū)?即可。舉例:C8051F347中的SPI就是一個SPI的controller控制器,即支持軟件配置CPOL和CPHA的值,四種模式都支持,此處C8051F347作為SPI從設備,設置了CPOL=1,CPHA=0的模式,因此,此處對應主芯片中的SPI控制器,作為Master主設備,其SPI的模式也要設置為CPOL=1,CPHA=0,即可。
【SPI的讀寫程序設計】文中標紅的是特別注意看的地方主要是熟悉flash芯片的指令集,以及存儲芯片扇區(qū)和塊的理解,最重要的是擦除都是以扇區(qū)擦除的方式。
本節(jié)將利用SPI來實現(xiàn)對外部FLASH(W25X16)的讀寫,并將結(jié)果顯示在TFTLCD模塊上。本節(jié)分為如下幾個部分:
3.17.1 SPI簡介
3.17.2硬件設計
3.17.3軟件設計
3.17.4下載與測試
1 SPI簡介
SPI是英語Serial Peripheralinterface的縮寫,顧名思義就是串行外圍設備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。SPI接口主要應用在EEPROM,F(xiàn)LASH,實時時鐘,AD轉(zhuǎn)換器,還有數(shù)字信號處理器和數(shù)字信號解碼器之間。SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時為PCB的布局上節(jié)省空間,提供方便,正是出于這種簡單易用的特性,現(xiàn)在越來越多的芯片集成了這種通信協(xié)議,STM32也有SPI接口。
SPI接口一般使用4條線:
MISO主設備數(shù)據(jù)輸入,從設備數(shù)據(jù)輸出。
MOSI主設備數(shù)據(jù)輸出,從設備數(shù)據(jù)輸入。
SCLK時鐘信號,由主設備產(chǎn)生。
CS從設備片選信號,由主設備控制。
SPI主要特點有:可以同時發(fā)出和接收串行數(shù)據(jù);可以當作主機或從機工作;提供頻率可編程時鐘;發(fā)送結(jié)束中斷標志;寫沖突保護;總線競爭保護等。
SPI總線四種工作方式SPI模塊為了和外設進行數(shù)據(jù)交換,根據(jù)外設工作要求,其輸出串行同步時鐘極性和相位可以進行配置,時鐘極性(CPOL)對傳輸協(xié)議沒有重大的影響。如果CPOL=0,串行同步時鐘的空閑狀態(tài)為低電平;如果CPOL=1,串行同步時鐘的空閑狀態(tài)為高電平。時鐘相位(CPHA)能夠配置用于選擇兩種不同的傳輸協(xié)議之一進行數(shù)據(jù)傳輸。如果CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)數(shù)據(jù)被采樣;如果CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)數(shù)據(jù)被采樣。SPI主模塊和與之通信的外設備時鐘相位和極性應該一致。
不同時鐘相位下的總線數(shù)據(jù)傳輸時序見下圖:
圖3.17.1.1不同時鐘相位下的總線傳輸時序(CPHA=0/1)
STM32的SPI功能很強大,SPI時鐘最多可以到18Mhz,支持DMA,可以配置為SPI協(xié)議或者I2S協(xié)議。
本節(jié),我們將利用STM32的SPI來讀取外部SPIFLASH芯片(W25X16),實現(xiàn)類似上節(jié)的功能。這里對SPI我們只簡單介紹一下SPI的使用,STM32的SPI詳細介紹請參考《STM32參考手冊》第422頁,22節(jié)。然后我們再介紹下SPIFLASH芯片。
這節(jié),我們使用STM32的SPI1的主模式,下面就來看看SPI1部分的設置步驟吧,STM32的主模式配置步驟如下:
1)配置相關引腳的復用功能,使能SPI1時鐘。
我們要用SPI1,第一步就要是能SPI1的時鐘,SPI1的時鐘通過APB2ENR的第12位來設置。其次要設置SPI1的相關引腳為復用輸出,這樣才會連接到SPI1上否則這些IO口還是默認的狀態(tài),也就是標準輸入輸出口。這里我們使用的是PA5、6、7這3個(SCK.、MISO、MOSI,CS使用軟件管理方式),所以設置這三個為復用IO。
2)設置SPI1工作模式。
這一步全部是通過SPI1_CR1來設置,我們設置SPI1為主機模式,設置數(shù)據(jù)格式為8位,然后通過CPOL和CPHA位來設置SCK時鐘極性及采樣方式。并設置SPI1的時鐘頻率(最大18Mhz),以及數(shù)據(jù)的格式(MSB在前還是LSB在前)。
3)使能SPI1。
這一步通過SPI1_CR1的bit6來設置,以啟動SPI1,在啟動之后,我們就可以開始SPI通訊了。
SPI1的使用就介紹到這里,接下來介紹一下W25X16。W25X16是華邦公司推出的繼W25X10/20/40/80(從1Mb~8Mb)后容量更大的FLASH產(chǎn)品,W25X16的容量為16Mb,還有容量更大的W25X32/64,ALIENTEK所選擇的W25X16容量為16Mb,也就是2M字節(jié),同AT45DB161是一樣大小的。
W25X16將2M的容量分為32個塊(Block),每個塊大小為64K字節(jié),每個塊又分為16個扇區(qū)(Sector),每個扇區(qū)4K個字節(jié)。W25X16的最少擦除單位為一個扇區(qū),也就是每次必須擦除4K個字節(jié)。這樣我們需要給W25X16開辟一個至少4K的緩存區(qū),這樣對SRAM要求比較高(相對于AT45DB161來說),但是它有價格及供貨上的優(yōu)勢。
W25X16的差些周期為10000次,具有20年的數(shù)據(jù)保存期限,支持電壓為2.7~3.6V,W25X16支持標準的SPI,還支持雙輸出的SPI,最大SPI時鐘可以到75Mhz(雙輸出時相當于150Mhz),更多的W25X16的介紹,請參考W25X16的DATASHEET。
2硬件設計
本節(jié)實驗功能簡介:開機的時候先檢測W25X16是否存在,然后在主循環(huán)里面用1個按鍵用來執(zhí)行寫入W25X16的操作,另外一個按鍵用來執(zhí)行讀出操作,在TFTLCD模塊上顯示相關信息。同時用DS0提示程序正在運行。
所要用到的硬件資源如下:
1)STM32F103RBT6。
2)DS0(外部LED0)。
3)KEY0和KEY2。
4)TFTLCD液晶模塊。
5)W25X16。
前面4部分的資源,我們前面已經(jīng)介紹了,請大家參考相關章節(jié)。這里只介紹W25X16與STM32的連接,板上的W25X16是直接連在STM32F103RBT6上的,連接關系如下圖:
圖3.17.2.1STM32F103RBT6與W25X16連接電路圖
3軟件設計
打開上一節(jié)的工程,首先在HARDWARE文件夾下新建一個FLASH的文件夾和SPI的文件夾。然后新建一個flash.c和flash.h的文件保存在FLASH文件夾下,新建spi.c和spi.h的文件,保存在SPI文件夾下,并將這兩個文件夾加入頭文件包含路徑。
打開spi.c文件,輸入如下代碼:
#include"spi.h"
//SPI口初始化
//這里針是對SPI1的初始化
voidSPIx_Init(void)
{
RCC->APB2ENR"=1<<2; //PORTA時鐘使能
RCC->APB2ENR|=1<<12; //SPI1時鐘使能
//這里只針對SPI口初始化
GPIOA->CRL&=0X000FFFFF;
GPIOA->CRL|=0XBBB00000;//PA5.6.7復用
GPIOA->ODR|=0X7<<5; //PA5.6.7上拉
SPI1->CR1|=0<<10;//全雙工模式
SPI1->CR1|=1<<9; //軟件nss管理
SPI1->CR1|=1<<8;