串行外設(shè)接口(Serial Peripheral Interface,縮寫為 SPI) 提供了基于SPI 協(xié)議的數(shù)據(jù)發(fā)送和接收功能, 可以工作于主機(jī)或從機(jī)模式。 SPI 接口支持具有硬件 CRC 計算和校驗的全雙工和單工模式。
8.1.SPI 基礎(chǔ)知識
SPI 物理層
SPI接口采用主從模式(Master Slave)架構(gòu);支持一主一從模式和一主多從模式,但不支持多主模式。它是一種同步高速全雙工的通信總線,總體結(jié)構(gòu)如下圖常見的SPI通訊系統(tǒng)所示。
一個主機(jī)連接四個從機(jī),其中一個SPI總線一般有四個信號分為:
SCLK:時鐘信號,由主機(jī)產(chǎn)生并控制。
MOSI:主機(jī)數(shù)據(jù)輸出,從機(jī)數(shù)據(jù)輸入。
MISO:主機(jī)數(shù)據(jù)輸入,從機(jī)數(shù)據(jù)輸出。
SS/NSS:從機(jī)片選使能信號,由主機(jī)控制。在一主對多從的模式下,每一個從機(jī)都需要獨(dú)占一個SS,也就是說有多少個從機(jī)就有多少個片選信號。
SPI 協(xié)議層
SPI的協(xié)議定義了通信的起始信號、停止信號、數(shù)據(jù)有效性、時鐘同步等環(huán)節(jié)。下面我們分析一下兩個設(shè)備通過SPI總線通信的過程,SPI通信時序圖如下圖通訊時序所示:
SPI 通訊時序
這個是一個主機(jī)的通信時序,信號線 NSS、SCK、MOSI 都是由主機(jī)控制,MISO 是由從機(jī)進(jìn)行控制。其中 MOSI 和 MISO 上的數(shù)據(jù)僅在 NSS 為低時才有效,并且每個SCK 時鐘周期只交換一位數(shù)據(jù)。
起始信號和停止信號:如_SPI通訊時序圖_中①和⑥分別表示通信的起始和結(jié)束,這些信號的產(chǎn)生是通過主機(jī)將片選信號(NSS)置低和置高實現(xiàn)的。NSS 除了是開始和結(jié)束信號的產(chǎn)生者,它也是主機(jī)和從機(jī)通信的選擇者,當(dāng)一個主機(jī)對多個從機(jī)通信時,主機(jī)通過置低從機(jī)的 NSS 信號線來選擇與哪個從機(jī)進(jìn)行通信。
時鐘同步:SPI 總線是一個同步全雙工的通信總線,所以 SPI 的數(shù)據(jù)傳輸是需要 SCK 時鐘信號嚴(yán)格同步的,每一個 SCK 周期只傳輸一位數(shù)據(jù),這一個周期里要完成數(shù)據(jù)的準(zhǔn)備和采樣,且數(shù)據(jù)的輸入和輸出是同時進(jìn)行的。MSB 先行或 LSB先行協(xié)議中是沒有硬性規(guī)定,只需通信雙方保持統(tǒng)一即可。SPI 每次數(shù)據(jù)傳輸可以是 8 位或 16 位為單位,每次傳輸?shù)膯挝粩?shù)不受限制。
數(shù)據(jù)有效性:SPI 在 SCK 時鐘的同步下進(jìn)行數(shù)據(jù)的準(zhǔn)備和采樣,過程如圖 1-2 的②③④⑤所示。在 NSS 為低的情況時,在 SCK 的上升沿時 MISO 和 MOSI 進(jìn)行數(shù)據(jù)準(zhǔn)備,SCK 的下降沿時讀取 MISO 和 MOSI 上的數(shù)據(jù)。在 NSS 為高時,MISO 和MOSI 上的數(shù)據(jù)無效。
SPI 工作模式:如_SPI通訊時序圖_只是 SPI 的一種工作模式,SPI 一共有四種工作模式。他們的區(qū)別是總線空閑時 SCK 的電平狀態(tài)和數(shù)據(jù)采樣時刻。這四種模式的配置是通過配置“時鐘極 性 CKPL”和“時鐘相位 CKPH”的電平來實現(xiàn)的。
CKPL=0 時,SCK 引腳在空閑狀態(tài)保持低電平;
CKPL=1 時,SCK 引腳在空閑狀態(tài)保持高電平;
CKPH=0 時,SCK 時鐘的第一個邊沿進(jìn)行采樣;
CKPH =1 時,SCK 時鐘的第二個邊沿進(jìn)行采樣。
四種模式如下圖SPI通訊模式所示:
SPI 數(shù)據(jù)傳輸流程
前面我們了解了SPI協(xié)議的物理連接方式和SPI的具體協(xié)議和SPI的四種工作模式,下面我們從整體上分析一下SPI通信的流程。通過前面的內(nèi)容可知,在一個SCK周期內(nèi),SPI會完成如下操作:
主機(jī)通過MOSI線發(fā)送1位數(shù)據(jù),從機(jī)通過該線讀取這1位數(shù)據(jù)。
從機(jī)通過MISO線發(fā)送1位數(shù)據(jù),主機(jī)通過該線讀取這1位數(shù)據(jù)。
這是通過移位寄存器來實現(xiàn)的。如下圖所示,主機(jī)和從機(jī)各有一個移位寄存器,且二者連接成環(huán)。隨著時鐘脈沖,數(shù)據(jù)按照從高位到低位的方式依次移出主機(jī)寄存器和從機(jī)寄存器,并且依次移入從機(jī)寄存器和主機(jī)寄存器。當(dāng)寄存器中的內(nèi)容全部移出時,相當(dāng)于完成了兩個寄存器內(nèi)容的交換。通信流程如圖所示:
8.2.GD32 SPI 外設(shè)原理簡介
因篇幅有限,本文無法詳細(xì)介紹GD32所有系列SPI外設(shè)接口,下面以GD32F30x為列,著重介紹下GD32F30x的SPI外設(shè)簡介和結(jié)構(gòu)框圖,后介紹下各個系列的差異。
GD32 SPI 主要特性
? 具有全雙工和單工模式的主從操作;
? 16位寬度,獨(dú)立的發(fā)送和接收緩沖區(qū);
? 8位或16位數(shù)據(jù)幀格式;
? 低位在前或高位在前的數(shù)據(jù)位順序;
? 軟件和硬件NSS管理;
? 硬件CRC計算、發(fā)送和校驗;
? 發(fā)送和接收支持DMA模式;
? 支持SPI TI模式;
? 支持SPI NSS脈沖模式;
? 支持SPI四線功能的主機(jī)模式(僅在SPI0中)。
GD32的SPI外設(shè)還支持I2S功能,I2S功能是一種音頻串行通訊協(xié)議,如果需要學(xué)習(xí)請參考各個系列的User_Manual,本文不做過多的介紹。
SPI 結(jié)構(gòu)框圖介紹
SPI 通訊模式
通訊引腳:如_SPI通訊模式圖_的①所示,GD32硬件接口SCK、NSS、MOSI、MISO為標(biāo)準(zhǔn)的SPI協(xié)議的四條信號線;IO2、IO3為GD32的SPI四線模式使用到的引腳,分別為:發(fā)送或接收數(shù)據(jù)2線和3線(在GD32F30x中僅SPI0支持四線主機(jī)模式)。各個系列的SPI個數(shù)不同,SPI接口和芯片I/O口的對應(yīng)關(guān)系,可查閱各個系列的Datasheet。
時鐘生成器:如_SPI通訊模式圖_的②所示,SCK線的時鐘信號,是由波特率發(fā)生器根據(jù)“控制寄存器0(SPI_CTL0)”中的PSC[2:0]位控制的。具體分頻選擇如下
000:PCLK/2 100:PCLK/32
001:PCLK/4 101:PCLK/64
010:PCLK/8 110:PCLK/128
011:PCLK/16 111:PCLK/256
當(dāng)使用SPI0時,PCLK=PCLK2,當(dāng)使用SPI1和SPI2時,PCLK=PCLK1。
數(shù)據(jù)通訊單元:如_SPI通訊模式圖_的③所示,SPI的MOSI及MISO都連接到數(shù)據(jù)移位寄存器上,數(shù)據(jù)移位寄存器的數(shù)據(jù)來源及目標(biāo)接收、發(fā)送緩沖區(qū)以及MISO、MOSI線。當(dāng)向外發(fā)送數(shù)據(jù)的時候,數(shù)據(jù)移位寄存器以“發(fā)送緩沖區(qū)”為數(shù)據(jù)源,把數(shù)據(jù)一位一位地通過數(shù)據(jù)線發(fā)送出去;當(dāng)從外部接收數(shù)據(jù)的時候,數(shù)據(jù)移位寄存器把數(shù)據(jù)線采樣到的數(shù)據(jù)一位一位地存儲到“接收緩沖區(qū)”中。
通過寫SPI的“數(shù)據(jù)寄存器(SPI_DATA)”把數(shù)據(jù)填充到發(fā)送緩沖區(qū)中,通訊讀“數(shù)據(jù)寄存器(SPI_DATA)”,可以獲取接收緩沖區(qū)中的內(nèi)容。其中數(shù)據(jù)幀長度可以通過“控制寄存器0(SPI_CTL0)”的“FF16位”配置成8位及16位模式;配置“LF位”可選擇MSB先行還是LSB先行。
下面以SPI作為主機(jī)MSB先行收發(fā)數(shù)據(jù)來分析一下通訊流程:
控制NSS信號線進(jìn)入低電平,選中從器件發(fā)出通信開始信號;
檢查“發(fā)送緩沖區(qū)”是否為空(SPI_STAT的TBE是否為1),如果為空,將所需要發(fā)送的數(shù)據(jù)寫入“發(fā)送緩沖區(qū)”;
“發(fā)送緩沖區(qū)”里的數(shù)據(jù)一次性寫入“移位寄存器”,一旦“發(fā)送緩沖區(qū)”里的數(shù)據(jù)寫入“移位寄存器”SPI通信正式開始;
“移位寄存器”通過MOSI信號線從高位一位一位的發(fā)送到接收方,由于SPI的通信時全雙工的,所以MOSI每發(fā)出一位MISO就接收一位存入移位寄存器;
直到一個數(shù)據(jù)單元發(fā)完(數(shù)據(jù)單元大小8位/16位可配置)?!耙莆患拇嫫鳌崩锝邮栈貋淼臄?shù)據(jù)將一次性寫入“接收緩沖區(qū)”,這時SPI_STAT的RBNE位將置1。也就是說“接收緩沖區(qū)”已有數(shù) 據(jù)。這時就可以讀取數(shù)據(jù)了。
如果要發(fā)多組數(shù)據(jù)或者收多組數(shù)據(jù),只需重復(fù)第2,3,4,5步。注意如果只收不發(fā)時,只需發(fā)送0xFF即可;
當(dāng)所有數(shù)據(jù)都通信完成控制NSS信號進(jìn)入高電平,通信正式結(jié)束。
各系列 SPI 功能差異
GD32系列MCU有關(guān)SPI外設(shè)各系列功能差異如下表所示
8.3.硬件連接說明
SPI 串行 Flash 硬件連接圖
如圖所示,為典型的SPI外設(shè)硬件連接圖:GD25Q40是一種使用 SPI通訊協(xié)議的NOR FLASH存儲器,它的CS/SCLK/SI/SO引腳分別連接到了GD32對應(yīng)的SPI引腳NSS/SCK/MOSI/MISO上,其中GD32的NSS引腳是一個普通的GPIO,不是SPI的專用NSS引腳,所以程序中我們要使用軟件控制的方式。若硬件設(shè)計中為SPI_NSS可以程序里可以配置為硬件控制方式。
讀者可以根據(jù)典型硬件連接圖和相應(yīng)系列的Datasheet設(shè)計出自己的硬件連接方式。
8.4.軟件配置說明
本小節(jié)講解SPI_Example歷程中SPI模塊的配置說明,主要包括外設(shè)時鐘配置、GPIO引腳配置、SPI外設(shè)配置、主函數(shù)介紹以及運(yùn)行結(jié)果。本例程主要介紹GD32 MCU各系列SPI0模塊的數(shù)據(jù)發(fā)送,有關(guān)SPI其他功能例程可參考各系列固件庫例程。
外設(shè)時鐘配置
外設(shè)時鐘配置如代碼清單例程時鐘配置所示,在GD32全系列MCU中需打開GPIOA和SPI0的時鐘,由于使用到PA3/PA5/PA7引腳以及SPI0模塊,另外,在GD32F10X、GD32F20X、GD32F30X、GD32E10X中需要打開AF時鐘。
void rcu_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_SPI0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif #endif }
GPIO 引腳配置
GPIO引腳配置如代碼清單SPI例程GPIO引腳配置所示,GD32F10X、GD32F30X、GD32F20X、GD32E10X系列GPIO配置相同,PA5、PA7需配置為復(fù)用推挽輸出、PA6需配置為浮空輸入、PA3作為片選控制引腳配置為推挽輸出模式;GD32F1X0、GD32F4XX、GD32F3X0、 GD32E23X系列GPIO配置基本相同,不同在于PA5/PA6/PA7引腳的AF復(fù)用功能配置不同,在GD32F1X0、GD32F3X0和GD32E23X上,需要配置為AF0模式,在GD32F4XX上需要配置為AF5模式。GPIO配置完成后,例程中將CS片選信號拉高。
void gpio_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */ gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7); gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6); /* PA3 as NSS */ gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */ gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); #elif defined GD32F4XX gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); #endif gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); #endif SET_SPI0_NSS_HIGH }
SPI 外設(shè)配置
SPI外設(shè)配置如代碼清單SPI例程SPI外設(shè)配置所示。GD32全系列MCU中SPI外設(shè)配置基本相同,在本例程中,SPI0作為主機(jī)全雙工模式,GD32標(biāo)準(zhǔn)庫提供了SPI初始化結(jié)構(gòu)體及初始化函數(shù)來配置SPI外設(shè),其初始化結(jié)構(gòu)體說明如表 0-13 SPI初始化結(jié)構(gòu)體說明列表所示,SPI初始化結(jié)構(gòu)體填充完成后,調(diào)用spi_init函數(shù)進(jìn)行SPI外設(shè)配置,配置完成后,調(diào)用spi_enable使能SPI外設(shè)。
void spi_config(void) { #if defined GD32F10X_HD|| GD32F30X_HD || GD32F1X0 || GD32F20X_CL || GD32F4XX || GD32F3X0 || GD32E10X || GD32E23X spi_parameter_struct spi_init_struct; /* SPI0 parameter config */ spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; spi_init_struct.device_mode = SPI_MASTER; spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; spi_init_struct.nss = SPI_NSS_SOFT; spi_init_struct.prescale = SPI_PSC_256; spi_init_struct.endian = SPI_ENDIAN_MSB; spi_init(SPI0, &spi_init_struct); spi_enable(SPI0); #endif }
SPI 初始化結(jié)構(gòu)體說明列表
主函數(shù)說明
主函數(shù)如代碼清單SPI例程主函數(shù)所示,該主函數(shù)主要分成四部分,RCU時鐘配置、 GPIO 配置、SPI外設(shè)配置和while(1)主函數(shù),前三部分已在前三小節(jié)介紹,在while(1)主循環(huán)中采用查詢的方法循環(huán)發(fā)送SPI數(shù)據(jù),單次循環(huán)數(shù)據(jù)填充完成后,查詢RBNE和TRANS標(biāo)志位判斷數(shù)據(jù)發(fā)送 完成,然后拉高CS片選,完成單次循環(huán)發(fā)送。
int main(void) { /* peripheral clock enable */ rcu_config(); /* GPIO config */ gpio_config(); /* SPI config */ spi_config(); while(1) { SET_SPI0_NSS_LOW /* wait for transmit complete */ while(send_n < arraysize){ while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)); spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]); } while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)); while(RESET != spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS)) {} SET_SPI0_NSS_HIGH send_n = 0; } }
運(yùn)行結(jié)果
將SPI_Example例程按照對應(yīng)的芯片工程編譯完成后,下載到對應(yīng)芯片中,采用示波器或者邏輯分析儀查看SPI_CS、SPI_CLK、SPI_MOSI引腳波形,如下圖SPI發(fā)送邏輯分析儀抓取波形圖所示,通過協(xié)議解析后,SPI數(shù)據(jù)發(fā)送正確。
8.5.SPI 使用注意事項
(1) 在切換SPI時鐘前要關(guān)閉SPI,切換完成后再使能SPI。
(2) 在采用SPI發(fā)送數(shù)據(jù)時,發(fā)送buf空標(biāo)志TBE置位,并不代表數(shù)據(jù)發(fā)送完成,僅代表數(shù)據(jù)從發(fā)送數(shù)據(jù)寄存器移到發(fā)送移位寄存器中,如果通過查詢TBE標(biāo)志來拉高CS片選,由于GD32系列MCU代碼執(zhí)行效率較高,當(dāng)發(fā)送速率較低時可能會出現(xiàn)當(dāng)TBE置位時,拉高CS片選,此時數(shù)據(jù)還未完成發(fā)送,造成從機(jī)接受數(shù)據(jù)出錯。可以通過查詢接收數(shù)據(jù)寄存器非空RBNE和TRANS標(biāo)志位來判斷數(shù)據(jù)發(fā)送完成,然后再拉高CS片選。
(3) SPI的MISO管腳需配置為浮空輸入模式,否則有可能數(shù)據(jù)接收異常。
本教程由GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關(guān)注聚沃科技官網(wǎng)
-
單片機(jī)
+關(guān)注
關(guān)注
6035文章
44554瀏覽量
634629 -
mcu
+關(guān)注
關(guān)注
146文章
17123瀏覽量
350979 -
SPI
+關(guān)注
關(guān)注
17文章
1706瀏覽量
91502
發(fā)布評論請先 登錄
相關(guān)推薦
評論