SPI
一、SPI簡介
SPI(Serial Peripheral Interface )是串行外圍接口設備,是一種高速的,全雙工,同步的通信總線,並且在芯片上只占用四根線,節約了芯片的管腳,同時為PCB的布局上節省空間,提供方便,正是處於這種簡單易用的特性,現在越來越多的芯片集成了這種協議。
SPI 是一個環形總線結構,由 ss(cs)、 sck、 sdi、 sdo 構成,其時序其實很簡單,主要是在 sck 的控制下,兩個雙向移位寄存器進行數據交換。
因為是全雙工同步通信,所以在傳輸數據時,左邊主機的數據從移位寄存器進入MOSI線上進入右邊的從機,並存入最低位,同時從機的最高位通過MISO傳輸到主機的最低位,當第二位數據進行發送時,最低位的數據會向左移一位並將新數據存入最低位。
二、通信協議
1、物理層
motorola公司 首先提出的全雙工三線同步串行外圍接口,采用主從模式( Master Slave)架構;支持多 slave 模式應用,一般僅支持單Master(單主機模式)。
管腳
三線SPI:SCLK(時鍾線),MISO(主機接收從機發送),MOSI(主機發送從機接收)
四線SPI:CS(片選線),SCLK,MISO,MOSI
片選:被選,確定該設備處於何種工作模式
連接方式
2、數據鏈路層
SPI采用位協議,------高位在前,低位在后
SPI有四種工作模式,SPI0 SPI1 SPI2 SPI3
SPI 模塊為了和外設進行數據交換,根據外設工作要求,其輸出串行同步時鍾極性和相位可以進行配置,時鍾極性(CPOL)對傳輸協
議沒有重大的影響。如果 CPOL=0,串行同步時鍾的空閑狀態為低電平;如果 CPOL=1,串行同步時鍾的空閑狀態為高電平。時鍾相位(CPHA)
能夠配置用於選擇兩種不同的傳輸協議之一進行數據傳輸。如果 CPHA=0,在串行同步時鍾的第一個跳變沿(上升或下降)數據被采樣;如
果 CPHA=1,在串行同步時鍾的第二個跳變沿(上升或下降)數據被采樣。 SPI 主模塊和與之通信的外設音時鍾相位和極性應該一致。
SPI 時序圖詳解---SPI 接口在模式 0 下輸出第一位數據的時刻
三、STM32中SPI控制器
數量:2個 SPI1 SPI2
特性:全雙工同步通信
8/16是傳輸幀選擇
主從結構
8個主模式波特率預分頻系數
主模式和從模式下均可以由軟件或硬件進行NSS管理
可編程的時鍾極性和相位
可編程的數據順序, MSB在前或LSB在前
四、配置工作模式
1、NSS管理
SPI可以工作為主機模式和從機模式,可以通過軟件模式和硬件模式進行管理。
SPI的NSS引腳分為內部引腳和外部引腳,當內部引腳檢測到高電平的時候,設備會工作在主機模式,檢測到低電平,工作在從機模式。
先說軟件模式,軟件模式可以通過SPI_CR1寄存器的SSM為進行設置,當SSM位為1時,SPI的模式管理為軟件管理模式,且當SSI位為1時(SSI位僅在SSM位為1時有效),內部的NSS會被驅動為高電平,該設備就設置為主機模式且外部NSS引腳會輸出一個低電平信號,當其他的設備檢測到低電平信號時,會自動進入從機模式。
硬件模式:
NSS輸出使能通過CR2的SSOE位進行控制,一旦該位被使能,NSS引腳作為一個輸出引腳,若SPI工作為主機模式,NSS會輸出一個低電平,當其他設備的NSS引腳接到主設備的引腳,會檢測到一個低電平,並會自動進入從設備狀態。當配置為主模式,NSS配置為輸入引腳,(MSTR=1,SSOE=0)時,如果NSS被拉低,則配置為主模式水白,會自動進入從工作模式。
若向通過硬件管理工作模式,只需將需要配置為主模式的NSS引腳接高電平,從模式的NSS接低電平即可。
更詳細的NSS工作模式介紹見:https://blog.csdn.net/andylauren/article/details/52259703
五、SPI配置過程
1、查看原理圖確定引腳,以及各個引腳的工作模式
這里spi的四個引腳分別對應pa4,pa5,pa6,pa7,SPI作為主機,MOSI,cs,clk應給配置為輸出模式,miso配置為輸入。
所以為了將SPI的功能復用到IO扣上,pa5,pa7要用作復用推挽輸出。(pa4為什么配置為通用推挽輸出現在我還沒弄明白,等明白了再改回來)
2、確定spi的時鍾相位以及時鍾極性等工作模式
因為時鍾相位和時鍾極性可以配置出4種spi的模式,而spi的工作模式與數據的采集以及輸出有關,所以我們這里要根據外設來確當spi的工作模式。
#include "spi.h" void SPI_Config(void) { /* pa4 sf cs 通用推挽輸出 pa5 sc clk 復用推挽輸出 pa6 miso 浮空輸入 pa7 mosi 復用推挽輸出 */ //GPIO GPIO_InitTypeDef GPIOInitStruct; //SPI SPI_InitTypeDef SPIInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1,ENABLE); //pa4 通用推挽輸出 GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIOInitStruct.GPIO_Pin = GPIO_Pin_4; GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIOInitStruct); //pa5 pa7 復用推挽輸出 GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIOInitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_Init(GPIOA,&GPIOInitStruct); //pa6 浮空輸入 GPIOInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIOInitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_Init(GPIOA,&GPIOInitStruct); //SPI SPIInitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //分頻 SPIInitStruct.SPI_CPHA = SPI_CPHA_1Edge; //時鍾相位 SPIInitStruct.SPI_CPOL = SPI_CPOL_Low; //時鍾極性 SPIInitStruct.SPI_DataSize = SPI_DataSize_8b; //數據寬度 SPIInitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全雙工 SPIInitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前 SPIInitStruct.SPI_Mode = SPI_Mode_Master; //主機 SPIInitStruct.SPI_NSS = SPI_NSS_Soft; //軟件模式 SPI_Init(SPI1,&SPIInitStruct); //使能SPI SPI_Cmd(SPI1,ENABLE); }