STM32F4 SPI 學習筆記


SPI 全稱Serial Peripheral Interface

SPI的最高時鍾高達45MHZ

下圖表達了SPI的工程原理,通過兩根線(MISO和MOSI)進行數據傳輸,數據的讀寫同步進行,通過移位寄存器完成數據的交換。

SPI的4條通訊線:

MISO: Master Input Slave Output

MOSI: Master Output Slave Input

CS: Chip Select

SCLK: System Clock

前兩根線是數據傳輸線,最后一跟 是系統時鍾線 ,主要看第三根線CS,信號片選:

這是別人寫的一個不錯的解釋  https://blog.csdn.net/STL1634614466/article/details/69375138

總結如下:

CS在也叫NSS(Number Slave Select),分為軟件和硬件控制,如果用硬件NSS,只能通過PF6這個口控制,因此只能於一台Slave連接。因此一般用軟件NSS,通過普通IO輸出數字電平到Slave的片選端口,如果是低電平,則工作,如果是高電平則不連接。

SPI的相關配置如下:

1. 時鍾極性:CPOL = 0 -> 時鍾空閑為低電平; CPOL = 1 -> 時鍾空閑為高電平;

2. 時鍾相位:CPHA = 0 -> 時鍾第一個跳變沿采集數據; CPHA = 1 -> 時鍾第二個跳變沿采集數據;(兩種不同的傳輸協議)

提醒:主從機的時鍾極性和時鍾相位應保持一致。

3. MODE: 可以配置為Master 或者 Slave,主從模式的區別在於時鍾來源於主機

4. 傳輸方向:只讀,雙向單線,雙向雙線

5. SPI波特率分頻系數

6. 開始位:MSB 或者 LSB

7. NSS軟件控制還是硬件控制

8. 幀格式:SPI Motorola 或者 TI

9. 是否開啟CRC校驗

10. 如果開啟CRC,測需要設置CRC多項式

關於SPI的配置,差不多就這些了,需要配置相關的寄存器。當然,HAL庫早就將其封裝好了,直接調用就行了。

下面就是STM32中SPI的使用過程了:

STEP1:打開SPI時鍾

__HAL_RCC_SPI5_CLK_ENABLE();

STEP2:對SPI進行相關的配置

HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);

  上面的代碼中相關的配置很多,具體已經在之前羅列了,大概就10個相關的配置。

STEP3:使能SPI

__HAL_SPI_ENABLE(&SPI5_Handler);

STEP4:數據傳輸

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);

以上部分大多參考正點原子的資料整理的。下面我們來通過CUBEMX配置自己的SPI,通過SPI連接到一個FLASH,並實現批量數據的傳輸。

 首先打開在CUBEMX上的配置:

選擇全雙工,並且禁止硬件NSS。接下來就是在Configuration界面配置SPI的一些參數,下面我隨便配置了一下,注意主機和從機一些參數要保持一致,DMA和中斷我們就先不用了。

配置好了,接下來我們生成工程文件吧!

 打開生成好的文件,找到Application/User目錄下spi.c,里面有個函數就是用於配置我們在圖形界面配置的參數。

void MX_SPI5_Init(void)
{

  hspi5.Instance = SPI5;
  hspi5.Init.Mode = SPI_MODE_MASTER;
  hspi5.Init.Direction = SPI_DIRECTION_2LINES;
  hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi5.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi5.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi5.Init.NSS = SPI_NSS_SOFT;
  hspi5.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi5.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi5) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(spiHandle->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspInit 0 */

  /* USER CODE END SPI5_MspInit 0 */
    /* SPI5 clock enable */
    __HAL_RCC_SPI5_CLK_ENABLE();
  
    /**SPI5 GPIO Configuration    
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI5_MspInit 1 */

  /* USER CODE END SPI5_MspInit 1 */
  }
}

這個函數在main.c里已經幫你調用了,CUBEMX真棒!

接下來我們就用STM32這個主機與一塊FLASH從機進行通訊吧!

我們在這里調用一下正點原子整理的兩個文件spi.c和w25qxx.c以及他們的頭文件。通過一個定時器不斷掃描按鍵狀態,並且在while(1)里面寫入:

  while (1)
  {
        switch (SPI_KEY) {
            case KEY0_PRES:
                W25QXX_Write((u8*)"showtimewalker", 0x00, 14);
                LED0 = !LED0;
                break;
            case KEY1_PRES:
                W25QXX_Write((u8*)"ShowTimeWalker", 0x00, 14);
                LED0 = !LED0;
                break;
            case KEY2_PRES:
                W25QXX_Read(DisPlayString, 0x00, 14);
                POINT_COLOR = BLUE;
                LCD_ShowString(10 + DisPlayCutoffX,60 + DisPlayCutoffY,300,16,16,(char*)DisPlayString);
                DisPlayCutoffY += 18;
                if (DisPlayCutoffY == 198){
                    DisPlayCutoffX += 120;
                    DisPlayCutoffY = 0;
                }
                LED0 = !LED0;
                delay_ms(50);
                break;
        }

編譯通過,然后我們按下KEY0,寫入“showtimewalker”,按下KEY1,寫入“ShowTimeWalker”,按下KEY2,讀出數據,並且顯示到顯示屏上。看一下實際測試結果吧:

OK,調試成功,值得一提的是,FLASH中的數據是掉電不消失的哦,因此可以用於存儲一下特殊數據。

有疑問歡迎大家討論。謝謝閱讀。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM