STM32 SPI DMA 的使用

  一是想總結一下SPI總線的特色與注意點,二是總結一下SPI DMA的使用性能

1、SPI信號線說明ui

  一般SPI經過4個引腳與外部器件相連:spa

  • MISO:主設備輸入/從設備輸出引腳。該引腳在從模式下發送數據,在主模式下接收數據。
  • MOSI:主設備輸出/從設備輸入引腳。該引腳在主模式下發送數據,在從模式下接收數據。
  • SCK:串口時鐘,做爲主設備的輸出,從設備的輸入
  • NSS:從設備選擇。這是一個可選的引腳,用來選擇主/從設備。它的功能是用來做爲「片選引腳」,讓主設備能夠單獨地與特定從設備通信,避免數據線上的衝突。

2、原理3d

  MOSI腳相互鏈接,MISO腳相互鏈接。這樣,數據在主和從之間串行地傳輸(MSB位在前)。code

  通訊老是由主設備發起。主設備經過MOSI腳把數據發送給從設備,從設備經過MISO引腳回傳數據。這意味全雙工通訊的數據輸出和數據輸入是用同一個時鐘信號同步的;時鐘信號由主設備經過SCK腳提供。orm

 
3、NSS說明與注意點
 
 

  NSS分爲內部引腳和外部引腳。xml

  NSS外部引腳能夠做爲輸入信號或者輸出信號,輸入信號通常用做硬件方式從機的片選,而輸出信號通常用於主SPI去片選與之相連的從SPI。blog

  NSS從設備選擇有兩種模式:ip

一、軟件模式內存

  能夠經過設置SPI_CR1寄存器的SSM位來使能這種模式,當它爲1時,NSS引腳上的電平由SSI決定。在這種模式下NSS外部引腳能夠用做它用,而內部NSS信號電平能夠經過寫SPI_CR1的SSI位來驅動。  

二、硬件模式

兩種方式:

(1)對於主SPI,NSS能夠直接接高電平,對於從SPI,能夠直接接低電平。  

(2)當STM32F10xxx工做爲主SPI,而且NSS輸出已經經過SPI_CR2寄存器的SSOE位使能,這時主機的NSS講做爲輸出信號,引腳信號被拉低,全部NSS引腳與這個主SPI的NSS引腳相連並配置爲硬件NSS的SPI設備,將自動變成從SPI設備。

  此時兩個的NSS信號線能夠接個上拉電阻直連。

4、DMA說明

  DMAAMBA的先進高性能總線(AHB)上的設備,它有2AHB端口:一個是從端口,用於配置DMA,另外一個是主端口,使得DMA能夠在不一樣的從設備之間傳輸數據。

  DMA的做用是在沒有Cortex-M3核心的干預下,在後臺完成數據傳輸。在傳輸數據的過程當中,主處理器能夠執行其它任務,只有在整個數據塊傳輸結束後,須要處理這些數據時纔會中斷主處理器的操做。它能夠在對系統性能產生較小影響的狀況下,實現大量數據的傳輸。

 5、SPI_DMA的通訊過程

  • 設置外設地址
  • 設置存儲器地址
  • 設置傳輸數據量
  • 設置通道的配置信息
  • 使能DMA通道,啓動傳輸

 

  •  發送時,在每次TXE被設置爲’1’時發出DMA請求,DMA控制器則寫數據至SPI_DR寄存器,TXE標誌所以而被清除。
  •  接收時,在每次RXNE被設置爲’1’時發出DMA請求,DMA控制器則從SPI_DR寄存器讀出數據,RXNE標誌所以而被清除。

6、相關代碼

這裏使用的是SPI1

SPI_DMA配置

 1 /*******************************************************************************
 2 * Function Name  : SPI1_DMA_Configuration
 3 * Description    : 配置SPI1_RX的DMA通道2,SPI1_TX的DMA通道3
 4 * Input          : None
 5 * Output         : None
 6 * Return         : None
 7 * Attention             : 
 8 *******************************************************************************/
 9 void SPI1_DMA_Configuration( void )
10 {
11     DMA_InitTypeDef DMA_InitStructure;
12     
13     /* DMA1 Channel2 (triggered by SPI1 Rx event) Config */
14   DMA_DeInit(DMA1_Channel2);  
15   DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;                          //設置 SPI1 發送外設(0x4001300C) 地址(目的地址)
16   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_RX_Buff;                    //設置 SRAM 存儲地址(目的地址)
17   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                //傳輸方向 外設-內存
18   DMA_InitStructure.DMA_BufferSize = SPI1_ReciveBufferSize;                         //設置 SPI1 發送長度
19   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
20   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
21   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
22   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
23   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
24   DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
25   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
26   DMA_Init(DMA1_Channel2, &DMA_InitStructure);
27   
28   DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
29   /* Enable SPI1 DMA RX request */
30   SPI1->CR2 |= 1<<0;                                                                 //接收緩衝區DMA使能
31   DMA_Cmd(DMA1_Channel2, ENABLE);
32     
33     
34     /* DMA1 Channel3 (triggered by SPI1 Tx event) Config */
35   DMA_DeInit(DMA1_Channel3);  
36   DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;                          //設置  接收外設(0x4001300C) 地址(源地址)
37   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_TX_Buff;                    //設置 SRAM 存儲地址(源地址)
38   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                //傳輸方向 內存-外設
39   DMA_InitStructure.DMA_BufferSize = SPI1_SendBufferSize;                           //設置 SPI1 接收長度
40   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                  //外設地址增量(不變)
41   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                           //內存地址增量(變化)
42   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;           //外設傳輸寬度(字節)
43   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                   //內存傳輸寬度(字節)
44   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                     //傳輸方式,一次傳輸完中止,不從新加載
45   DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                           //中斷方式-高(三級)
46   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                      //內存到內存方式禁止
47   DMA_Init(DMA1_Channel3, &DMA_InitStructure);
48   
49   DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);                                   //開啓 DMA1_Channel3 傳輸完成中斷
50   DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE);                                   //開啓 DMA1_Channel3 傳輸錯誤中斷
51   /* Enable SPI1 DMA TX request */
52   SPI1->CR2 |= 1<<1;                                                                //發送緩衝區DMA使能
53   DMA_Cmd(DMA1_Channel3, DISABLE);                                                  //開啓 DMA 通道 DMA1_Channel3
54 }

SPI發送

 1 /*******************************************************************************
 2 * Function Name  : SPI1_Send
 3 * Description    : SPI1的DMA方式發送
 4 * Input          : SPI1_TX_Buff[SPI1_SendBufferSize]
 5 * Output         : None
 6 * Return         : None
 7 * Attention             : 關閉DMA通道3以前必須等待TXE爲1,等待忙標誌爲0
 8 *******************************************************************************/
 9 void SPI1_Send( u8 *buff, u32 len )
10 {
11     DMA1_Channel3->CPAR = SPI1_DR_Addr; //外設地址
12     DMA1_Channel3->CMAR = (u32) buff; //mem地址
13     DMA1_Channel3->CNDTR = len ; //傳輸長度
14     DMA1_Channel3->CCR = (0 << 14) | // 非存儲器到存儲器模式
15             (2 << 12) | // 通道優先級高
16             (0 << 11) | // 存儲器數據寬度8bit
17             (0 << 10) | // 存儲器數據寬度8bit
18             (0 <<  9) | // 外設數據寬度8bit
19             (0 <<  8) | // 外設數據寬度8bit
20             (1 <<  7) | // 存儲器地址增量模式
21             (0 <<  6) | // 外設地址增量模式(不增)
22             (0 <<  5) | // 非循環模式
23             (1 <<  4) | // 從存儲器讀
24             (1 <<  3) | // 容許傳輸錯誤中斷
25             (0 <<  2) | // 容許半傳輸中斷
26             (1 <<  1) | // 容許傳輸完成中斷
27             (1);        // 通道開啓
28 }

SPI接收

 1 /*******************************************************************************
 2 * Function Name  : SPI1_Recive
 3 * Description    : SPI1的DMA方式接收
 4 * Input          : None
 5 * Output         : SPI1_RX_Buff[SPI1_ReciveBufferSize]
 6 * Return         : None
 7 * Attention             : 必需要先關閉通道2,而後再配置通道2的參數
 8 *******************************************************************************/
 9 void SPI1_Recive( u8 *buff, u32 len )
10 {
11     DMA1_Channel2->CCR &= ~( 1 << 0 );          //關閉DMA通道2
12     
13     DMA1_Channel2->CPAR = SPI1_DR_Addr; //外設地址
14     DMA1_Channel2->CMAR = (uint32_t)buff; //mem地址
15     DMA1_Channel2->CNDTR = len ; //傳輸長度
16     DMA1_Channel2->CCR = (0 << 14) | // 非存儲器到存儲器模式
17             (2 << 12) | // 通道優先級高
18             (0 << 11) | // 存儲器數據寬度8bit
19             (0 << 10) | // 存儲器數據寬度8bit
20             (0 <<  9) | // 外設數據寬度8bit
21             (0 <<  8) | // 外設數據寬度8bit
22             (1 <<  7) | // 存儲器地址增量模式
23             (0 <<  6) | // 外設地址增量模式(不增)
24             (0 <<  5) | // 非循環模式
25             (0 <<  4) | // 傳輸方向 外設-內存
26             (0 <<  3) | // 容許傳輸錯誤中斷
27             (0 <<  2) | // 容許半傳輸中斷
28             (1 <<  1) | // 容許傳輸完成中斷
29             (1);        // 通道開啓
30 }
相關文章
相關標籤/搜索