您好,登錄后才能下訂單哦!
小編給大家分享一下STM32 SPI是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
SPI 規定了兩個 SPI 設備之間通信必須由主設備 (Master) 來控制次設備 (Slave). 一個 Master 設備可以通過提供 Clock 以及對 Slave 設備進行片選 (Slave Select) 來控制多個 Slave 設備, SPI 協議還規定 Slave 設備的 Clock 由 Master 設備通過 SCK 管腳提供給 Slave 設備, Slave 設備本身不能產生或控制 Clock, 沒有 Clock 則 Slave 設備不能正常工作。
采用主-從模式(Master-Slave) 的控制方式。
SPI 規定了兩個 SPI 設備之間通信必須由主設備 (Master) 來控制次設備 (Slave). 一個 Master 設備可以通過提供 Clock 以及對 Slave 設備進行片選 (Slave Select) 來控制多個 Slave 設備, SPI 協議還規定 Slave 設備的 Clock 由 Master 設備通過 SCK 管腳提供給 Slave 設備, Slave 設備本身不能產生或控制 Clock, 沒有 Clock 則 Slave 設備不能正常工作。
采用同步方式(Synchronous)傳輸數據
Master 設備會根據將要交換的數據來產生相應的時鐘脈沖(Clock Pulse), 時鐘脈沖組成了時鐘信號(Clock Signal) , 時鐘信號通過時鐘極性 (CPOL) 和 時鐘相位 (CPHA) 控制著兩個 SPI 設備間何時數據交換以及何時對接收到的數據進行采樣, 來保證數據在兩個設備之間是同步傳輸的。
SPI數據交換框圖
上圖只是對 SPI 設備間通信的一個簡單的描述, 下面就來解釋一下圖中所示的幾個組件(Module):
SSPBUF,Synchronous Serial Port Buffer, 泛指 SPI 設備里面的內部緩沖區, 一般在物理上是以 FIFO 的形式, 保存傳輸過程中的臨時數據;
SSPSR, Synchronous Serial Port Register, 泛指 SPI 設備里面的移位寄存器(Shift Regitser), 它的作用是根據設置好的數據位寬(bit-width) 把數據移入或者移出 SSPBUF;
Controller, 泛指 SPI 設備里面的控制寄存器, 可以通過配置它們來設置 SPI 總線的傳輸模式。
SPI 設備間的數據傳輸之所以又被稱為數據交換, 是因為 SPI 協議規定一個 SPI 設備不能在數據通信過程中僅僅只充當一個 "發送者(Transmitter)" 或者 "接收者(Receiver)". 在每個 Clock 周期內, SPI 設備都會發送并接收一個 bit 大小的數據, 相當于該設備有一個 bit 大小的數據被交換了. 一個 Slave 設備要想能夠接收到 Master 發過來的控制信號, 必須在此之前能夠被 Master 設備進行訪問 (Access). 所以, Master 設備必須首先通過 SS/CS pin 對 Slave 設備進行片選, 把想要訪問的 Slave 設備選上. 在數據傳輸的過程中, 每次接收到的數據必須在下一次數據傳輸之前被采樣. 如果之前接收到的數據沒有被讀取, 那么這些已經接收完成的數據將有可能會被丟棄, 導致 SPI 物理模塊最終失效. 因此, 在程序中一般都會在 SPI 傳輸完數據后, 去讀取 SPI 設備里的數據, 即使這些數據(Dummy Data)在我們的程序里是無用的。
上升沿、下降沿、前沿、后沿觸發。當然也有MSB和LSB傳輸方式.
SPI的極性Polarity和相位Phase,最常見的寫法是CPOL和CPHA,不過也有一些其他寫法,簡單總結如下:
(1) CKPOL (Clock Polarity) = CPOL = POL = Polarity = (時鐘)極性
(2) CKPHA (Clock Phase) = CPHA = PHA = Phase = (時鐘)相位
(3) SCK=SCLK=SPI的時鐘
(4) Edge=邊沿,即時鐘電平變化的時刻,即上升沿(rising edge)或者下降沿(falling edge)
對于一個時鐘周期內,有兩個edge,分別稱為:
Leading edge=前一個邊沿=第一個邊沿,對于開始電壓是1,那么就是1變成0的時候,對于開始電壓是0,那么就是0變成1的時候;
Trailing edge=后一個邊沿=第二個邊沿,對于開始電壓是1,那么就是0變成1的時候(即在第一次1變成0之后,才可能有后面的0變成1),對于開始電壓是0,那么就是1變成0的時候;
先說什么是SCLK時鐘的空閑時刻,其就是當SCLK在數發送8個bit比特數據之前和之后的狀態,于此對應的,SCLK在發送數據的時候,就是正常的工作的時候,有效active的時刻了。
先說英文,其精簡解釋為:Clock Polarity = IDLE state of SCK。
再用中文詳解:
SPI的CPOL,表示當SCLK空閑idle的時候,其電平的值是低電平0還是高電平1:
CPOL=0,時鐘空閑idle時候的電平是低電平,所以當SCLK有效的時候,就是高電平,就是所謂的active-high;
CPOL=1,時鐘空閑idle時候的電平是高電平,所以當SCLK有效的時候,就是低電平,就是所謂的active-low;
首先說明一點,capture strobe = latch = read = sample,都是表示數據采樣,數據有效的時刻。相位,對應著數據采樣是在第幾個邊沿(edge),是第一個邊沿還是第二個邊沿,0對應著第一個邊沿,1對應著第二個邊沿。
對于:
CPHA=0,表示第一個邊沿:
對于CPOL=0,idle時候的是低電平,第一個邊沿就是從低變到高,所以是上升沿;
對于CPOL=1,idle時候的是高電平,第一個邊沿就是從高變到低,所以是下降沿;
CPHA=1,表示第二個邊沿:
對于CPOL=0,idle時候的是低電平,第二個邊沿就是從高變到低,所以是下降沿;
圖例1
圖例2
SPI分主設備和從設備,兩者通過SPI協議通訊。
而設置SPI的模式,是從設備的模式,決定了主設備的模式。
所以要先去搞懂從設備的SPI是何種模式,然后再將主設備的SPI的模式,設置和從設備相同的模式,即可正常通訊。
對于從設備的SPI是什么模式,有兩種:
1.固定的,有SPI從設備硬件決定的
SPI從設備,具體是什么模式,相關的datasheet中會有描述,需要自己去datasheet中找到相關的描述,即:
關于SPI從設備,在空閑的時候,是高電平還是低電平,即決定了CPOL是0還是1;
然后再找到關于設備是在上升沿還是下降沿去采樣數據,這樣就是,在定了CPOL的值的前提下,對應著可以推算出CPHA是0還是1了。
2.可配置的,由軟件自己設定
從設備也是一個SPI控制器,4種模式都支持,此時只要自己設置為某種模式即可。
然后知道了從設備的模式后,再去將SPI主設備的模式,設置為和從設備模式一樣,即可。
對于如何配置SPI的CPOL和CPHA的話,不多細說,多數都是直接去寫對應的SPI控制器中對應寄存器中的CPOL和CPHA那兩位,寫0或寫1即可。
SPI是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。SPI接口主要應用在EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為PCB的布局上節省空間,提供方便,正是出于這種簡單易用的特性,現在越來越多的芯片集成了這種通信協議,STM32也有SPI接口。
SPI接口一般使用4條線通信:
MISO 主設備數據輸入,從設備數據輸出。
MOSI 主設備數據輸出,從設備數據輸入。
SCLK 時鐘信號,由主設備產生。
CS 從設備片選信號,由主設備控制。
SPI主要特點有:可以同時發出和接收串行數據;可以當作主機或從機工作;提供頻率可編程時鐘;發送結束中斷標志;寫沖突保護;總線競爭保護等。
STM32的SPI功能很強大,SPI時鐘最多可以到18Mhz,支持DMA,可以配置為SPI協議或者I2S協議
關于SPI,從數據手冊查到
STM32F207VCT6共有3個SPI。
從下表查出每個SPI對應的管腳
STM32標準外設庫SPI_InitTypeDef的定義
typedef struct { uint16_t SPI_Direction; // 設置SPI 的通信方式,可以選擇為半雙工,全雙工,以及串行發和串行收方式 uint16_t SPI_Mode; // 設置SPI 的主從模式 uint16_t SPI_DataSize; // 為8 位還是16 位幀格式選擇項 uint16_t SPI_CPOL; // 設置時鐘極性 uint16_t SPI_CPHA; // 設置時鐘相位 uint16_t SPI_NSS; //設置NSS 信號由硬件(NSS管腳)還是軟件控制 uint16_t SPI_BaudRatePrescaler; //設置SPI 波特率預分頻值 uint16_t SPI_FirstBit; //設置數據傳輸順序是MSB 位在前還是LSB 位在前 uint16_t SPI_CRCPolynomial; //設置CRC 校驗多項式,提高通信可靠性,大于1 即可 }SPI_InitTypeDef;
第一個參數SPI_Direction 是用來設置SPI的通信方式,可以選擇為半雙工,全雙工,以及串行發和串行收方式,這里我們選擇全雙工模式SPI_Direction_2Lines_FullDuplex。
第二個參數SPI_Mode用來設置SPI的主從模式,這里我們設置為主機模式 SPI_Mode_Master,當然有需要你也可以選擇為從機模式 SPI_Mode_Slave。
第三個參數SPI_DataSiz為8位還是16位幀格式選擇項,這里我們是8位傳輸,選擇SPI_DataSize_8b。
第四個參數SPI_CPOL用來設置時鐘極性,我們設置串行同步時鐘的空閑狀態為高電平所以我們選擇SPI_CPOL_High。
第五個參數SPI_CPHA 用來設置時鐘相位,也就是選擇在串行同步時鐘的第幾個跳變沿(上升或下降)數據被采樣,可以為第一個或者第二個條邊沿采集,這里我們選擇第二個跳變沿,所以選擇 SPI_CPHA_2Edge
第六個參數SPI_NSS設置NSS信號由硬件(NSS管腳)還是軟件控制,這里我們通過軟件控制NSS關鍵,而不是硬件自動控制,所以選擇 SPI_NSS_Soft。
第七個參數 SPI_BaudRatePrescaler很關鍵,就是設置 SPI 波特率預分頻值也就是決定 SPI 的時鐘的參數,從不分頻道256分頻8個可選值,初始化的時候我們選擇256分頻值SPI_BaudRatePrescaler_256,傳輸速度為36M/256=140.625KHz。
第八個參數 SPI_FirstBit設置數據傳輸順序是 MSB 位在前還是LSB位在前,這里我們選擇SPI_FirstBit_MSB高位在前。
第九個參數 SPI_CRCPolynomial是用來設置CRC校驗多項式,提高通信可靠性,大于1即可。
示例代碼:
void SPIInit( void ) { SPI_InitTypeDef SPI_InitStructure; FLASH_GPIO_Init(); /*!< Deselect the FLASH: Chip Select high */ GPIO_SetBits( GPIOA, GPIO_Pin_4 ); /*!< SPI configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; /* 雙線雙向全雙工 */ SPI_InitStructure.SPI_Mode = SPI_Mode_Master; /* 主 SPI */ SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; /* SPI 發送接收 8 位幀結構 */ SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; /* 串行同步時鐘的空閑狀態為高電平 */ SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; /* 第二個跳變沿數據被采樣 */ SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; /* NSS 信號由軟件控制 */ SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; /* 預分頻 16 */ SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; /* 數據傳輸從 MSB 位開始 */ SPI_InitStructure.SPI_CRCPolynomial = 7; /* CRC 值計算的多項式 */ SPI_Init( SPI1, &SPI_InitStructure ); /*!< Enable the sFLASH_SPI */ SPI_Cmd( SPI1, ENABLE ); }
看到這里,可能覺的前面講原理并沒有太大的用處,因為STM32集成了SPI控制器,配置一下即可。
一方面我們學習原理是為了更好的理解SPI,用于對接不同的SPI設備,像norflash的spi驅動網上有大量的例子,不容易出錯。但并不是特別常見的,spi驅動SD卡,SPI驅動網絡PHY,SPI驅動ESP8266,甚至在設計兩個IC通信時,由于沒有過多GPIO,又覺的IIC通信速度慢的話,可以設計兩個IC之間使用SPI通信,顯然這些場景就需要了解SPI的原理
另外一方面,實際應用中,有可能因為芯片其他管腳用于特殊功能,留下的管腳沒有硬件SPI功能,只能模擬實現,這個時候學習SPI原理就很有必要了。
SPI的常用應用NorFlash
從數據手冊上看到,SPI傳輸:CKPOL=1 , CKPHA=1
所以STM32的SPI讀取NorFlash的配置如下
抓取的波形如下
讀取norflash
使用STM32F207硬件SPI模塊
/** * @brief Initializes the peripherals used by the SPI FLASH driver. * @param None * @retval None */ void FLASH_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /*!< Enable the SPI clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /*!< Enable GPIO clocks */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); /*!< SPI pins configuration *************************************************/ /*!< Connect SPI pins to AF5 */ GPIO_PinAFConfig(GPIOA, 5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, 6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOB, 5, GPIO_AF_SPI1); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//GPIO_PuPd_DOWN; /*!< SPI SCK pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOA, &GPIO_InitStructure); /*!< SPI MISO pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_Init(GPIOA, &GPIO_InitStructure); /*!< SPI MOSI pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOB, &GPIO_InitStructure); /*!< Configure sFLASH Card CS pin in output pushpull mode */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOE, &GPIO_InitStructure); } /** * @brief Initializes the peripherals used by the SPI FLASH driver. * @param None * @retval None */ void FLASH_SPIInit(void) { SPI_InitTypeDef SPI_InitStructure; FLASH_GPIO_Init(); /*!< Deselect the FLASH: Chip Select high */ GPIO_SetBits(GPIOE,GPIO_Pin_12); /*!< SPI configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//雙線雙向全雙工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主 SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;// SPI 發送接收 8 位幀結構 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//串行同步時鐘的空閑狀態為高電平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二個跳變沿數據被采樣 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS 信號由軟件控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;//預分頻 16 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//數據傳輸從 MSB 位開始 SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC 值計算的多項式 SPI_Init(SPI1, &SPI_InitStructure); /*!< Enable the sFLASH_SPI */ SPI_Cmd(SPI1, ENABLE); }
軟件模擬SPI協議
/** * @brief Sends a byte through the SPI interface and return the byte received * from the SPI bus. * @param byte: byte to send. * @retval The value of the received byte. */ uint8_t SPI_ReadWriteByte(uint8_t data) { uint8_t i,data_read = 0; if(data!=0xA5){ for(i=0;i<8;i++){ MSPI_CLK_L(); if(data&0x80){ MSPI_MOSI_H(); }else{ MSPI_MOSI_L(); } MSPI_DELAY(); data = data<<1; MSPI_CLK_H(); MSPI_DELAY(); } return data_read; }else{ for(i=0;i<8;i++){ MSPI_CLK_L(); MSPI_DELAY(); data_read = data_read<<1; MSPI_CLK_H(); if(MSPI_READ_IN()){ data_read |= 0x01; } MSPI_DELAY(); } return data_read; } } /** * @brief Initializes the peripherals used by the SPI FLASH driver. * @param None * @retval None */ void FLASH_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /*!< Enable GPIO clocks */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); /*!< Configure sFLASH Card CS pin in output pushpull mode */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOE, &GPIO_InitStructure); /*!< SPI SCK pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOA, &GPIO_InitStructure); MSPI_CLK_H(); /*!< SPI MOSI pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOB, &GPIO_InitStructure); MSPI_MOSI_H(); /*!< SPI MISO pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_Init(GPIOA, &GPIO_InitStructure); } /** * @brief Initializes the peripherals used by the SPI FLASH driver. * @param None * @retval None */ void FLASH_SPIInit(void) { FLASH_GPIO_Init(); /*!< Deselect the FLASH: Chip Select high */ GPIO_SetBits(GPIOE,GPIO_Pin_12); }
開源地址:
https://github.com/strongercjd/STM32F207VCT6
以上是“STM32 SPI是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。