Serial Peripheral Interface Bus(SPI)
目錄
- 前言
- 一、SPI協議簡介
- SPI物理層
- SPI協議層
- 一、基本通訊程序
- 2. 通訊的攔截和停止信號
- 3.資料有效性
- 4. CPOL/CPHA 及通訊模式
- 二、STM32cubeMX設定
- 三、STM32 HAL庫中的SPI
- 1.SPI初始化結構體
一、SPI協議簡介
SPI 協議是由摩托羅拉公司提出的通訊協議(Serial Peripheral Interface),即通訊外圍設備面是全高速雙工的通訊協議,它被廣泛地在通訊設備與MCU之間使用,它被廣泛地在ADC、LCD等設備與MCU之間使用,3 條總線分別為SCK、MOSI、MISO,觸發選用SS
SPI物理層
- SS(Slave Select) SS(從設備選擇信號線,常稱為選片信號線,也稱為NSS、CS,以下用NSS表示,當有多個SPI從設備與SPI主機連接時,設備的選擇其他信號線) SCK 及任何一條信號線,我在每一個設備的SPI、MISO 線上,即從設備上,都共同使用這3 條信號;而從設備本身的這個NS NS 上有多少條信號線,本協議的多少個設備通過路由,有多少個從設備上選址,即線路上的設備地址,即上的設備並進行通訊協議;沒有設備地址,使用NSS信號線來探測,當主機要選擇從設備的時候,該從設備的信號線設置為低調它,即從該設備被選中有效片選,接著開始與被人的設備進行SPI通訊,所以SPI通訊以NSS線置NSS低作為被線信號,以簡單的說此PIN是主人使用Slave要接收訊號以及Master去跟Slave要數據需要觸發的腳位(類似I2C的地址概念)
- SCK(Serial Clock):信號線時鐘,用於通訊數據同步,它由通訊主機設備產生,決定通訊的頻率,不同的支持的最高頻率不一樣,如STM32的SPI時鐘頻率最大為fpclk/2 ,兩個設備之間通訊時,通訊設備之間的通訊低速
- MOSI(主設備輸出/從輸入)主輸出:主設備輸出線,主機資源的資料設備從鏈路信號,從機由線索線輸入讀入發送的資料,即這條線索的方向為主機到從機
- MISO Master Input,,Slave Output):從主設備輸出的資料輸入(從線索輸入設備,從線索輸入)方向為從機到主機
二、SPI協議層
一、基本通訊程序
是一個機器與信號源的信號源都來自主機,NSS、CK、MOS I 由主機控制產生而 MISO 的由主機產生,通過信號線讀取從機的信號線,MOSI (SS) 為各種稀有的 MISO 時間段才有效,我和 MISO 傳輸一個短期的資料
CPOL/CPHA 及通訊模式
SPI 的一些寫法,不過簡單概括如下:
- CKPOL (時鐘極性) = CPOL = POL = Polarity = (時鐘)
- CKPHA(時鐘相位)= CPHA = PHA = Phase = (時鐘)相位
- SCK=SCLK=SPI的時鐘
- Edge=邊沿,即隨時沿用的時刻,即上升沿或下降沿(下降沿)週期,有兩個沿,分別稱為:
- 前沿=前一個邊沿=第一個邊沿,對於開始電壓是1,那麼就是1變成0的時候,對於開始電壓是0,那麼就是0變成1的時候;
- 後沿=後一個沿=第二個邊沿,對於開始電壓是1,就是開始變成1的時候(同樣是在第一次1變成0之後,才可能有後面的0變成1),對於開始電壓是0,那麼就是1變成0的時候;
PS:這個CPOL/CP這個需要規範或者看正確處使用的傳感器的傳感器等產品的HA用於互通通信
AS5047P以為例
此處有明確的才能
三、STM32CubeMX建出SPI
所以下圖因為這個使用的原因會導致1因此會這樣可以用來代替上圖是84MHz,用於把SPI CLK 284/256MHz的速度來使用
四、STM32 HAL庫中的SPI
1.SPI初始化結構體
其他外設一樣,STM32 HAL庫提供了SPI初始化結構體及初始化函式來配置SPI外設,初始化結構體及式定義在庫檔案
STM32F4xx_hal_spi.h
STM32F4xx_hal_spi.c
從STM32CubeMX建檔出來會含初始化部分
static void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;//這邊是選用SPI2
hspi2.Init.Mode = SPI_MODE_MASTER;/*設定SPI 的主/從機端模式*/
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_16BIT;*設定SPI 的資料幀長度,可選8/16 位*/
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;//這邊看需求設定可用內建
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;//這個是直接關西到傳輸速度
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
2.介面函式
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);
PS:這邊在接收部分需要使用物件Datasheet 怎麼傳輸AS5047P號後可以像封包一樣看到我發送的消息,由第2個接收到的,所以如果是使用TransmitReceive
本方的大小試填入2
SPI_DMA範例
這邊比較推薦寫法如下
在HAL_SPI_TransmitReceive_DMA涵式內找到/* Enable the SPI Error Interrupt Bit */下面位置加上CS腳位拉High或拉Low來達成訊息同步
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,uint16_t Size)
******************以上省略***********
/* Enable the SPI Error Interrupt Bit */
__HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR));
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
/* Enable Tx DMA Request */
SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN);
error :
/* Process Unlocked */
__HAL_UNLOCK(hspi);
return errorcode;
並且在Callback涵式中把腳位拉起來
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
}