SPI 的 DMA 發送與接收


一、概述
在項目開發中,需要用到SPI接口來進行大量數據的傳輸,為了能節省CPU的工作時間,采用DMA來進行數據發送則是明智之舉。
二、工作模式描述
 1、發送方作為主機發送數據,接收方作為從機接收數據,基本的硬件連接為:
主機——從機
NSS ——NSS
SCK——SCK
MOSI——MOSI
MISO——MISO
GND——GND(注意一定要共地,否則數據會錯很多)
2、關於主從機NSS管腳各自功能的說明
主機的NSS作為GPIO口使用,在進行SPI初始化時設置為SPI_NSS_Soft。
從機的NSS由主機NSS管腳的輸出狀態決定,在進行SPI初始化時設置為SPI_NSS_Hard。
三、主機(發送數據)代碼詳解

1、結構體變量定義

SPI_InitTypeDef  SPI_InitStructure;//SPI初始化結構體
DMA_InitTypeDef  DMA_InitStructure;//DMA初始化結構體
GPIO_InitTypeDef GPIO_InitStructure;//GPIO初始化結構體
NVIC_InitTypeDef NVIC_InitStructure;//NVIC初始化結構體
2、開相關設備時鍾
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//GPIO、AFIO時鍾使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI2時鍾
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA1時鍾
3、SPI接口GPIO初始化
由於只用到SPI接口的三個信號線,故只需進行三個GPIO口的初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//將SCK和MOSI管腳設置為復用推挽輸出    
GPIO_Init(GPIOB, &GPIO_InitStructure);
    
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//NSS作為GPIO口使用,設置為推挽輸出  
GPIO_Init(GPIOB, &GPIO_InitStructure);
4、SPI初始化
SPI_Cmd(SPI2, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;  
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;  
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;  
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
5、DMA初始化
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x4000380C;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Data;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = ADC_DATASIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
 
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);//使能DMA1通道5中斷,注意一定要是“DMA_IT_TC”,否則會出現進不了中斷的問題。
6、NVIC初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
7、使能SPI2、DMA1、SPI2 DMA發送
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);//使能SPI2 DMA發送功能
SPI_Cmd(SPI2, ENABLE);//使能SPI2
DMA_Cmd(DMA1_Channel5,ENABLE);//使能SPI2 DMA發送通道
8、DMA發送中斷服務程序
注意進入中斷服務程序,需要先關閉相應通道的DMA功能,再修改CNDTR的值,修改完成后再打開並清除中斷標志位。
void DMA1_Channel5_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC5)==SET)
    {
        DMA_Cmd(DMA1_Channel5,DISABLE);
        DMA1_Channel5->CNDTR = ADC_DATASIZE;
        DMA_Cmd(DMA1_Channel5,ENABLE);
        DMA_ClearITPendingBit(DMA1_IT_TC5);
    }
}
四、從機(接收數據)代碼詳解
1、結構體變量定義
SPI_InitTypeDef SPI_InitStructure;//SPI初始化結構體
DMA_InitTypeDef DMA_InitStructure;//DMA初始化結構體
GPIO_InitTypeDef GPIO_InitStructure;//GPIO初始化結構體
NVIC_InitTypeDef NVIC_InitStructure;//NVIC初始化結構體
2、開相關設備時鍾
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//GPIO、AFIO時鍾使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI2時鍾
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA1時鍾
3、SPI接口GPIO初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
GPIO_Init(GPIOB, &GPIO_InitStructure);
4、SPI初始化
SPI_Cmd(SPI2, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;       
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;   
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;       
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; 
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;     
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
5、DMA初始化
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x4000380C;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Data;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADC_DATASIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
 
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
6、NVIC初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
7、使能SPI2、DMA1、SPI2 DMA接收
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx,ENABLE);
SPI_Cmd(SPI2, ENABLE);
DMA_Cmd(DMA1_Channel4,ENABLE);
8、DMA接收中斷服務程序
void DMA1_Channel4_IRQHandler(void)
{
    if(DMA_GetFlagStatus(DMA1_IT_TC4) == SET)
    {
        DMA_Cmd(DMA1_Channel4,DISABLE);
        DMA1_Channel4->CNDTR = ADC_DATASIZE;
        DMA_Cmd(DMA1_Channel4,ENABLE);
        DMA_ClearITPendingBit(DMA1_IT_TC4);
   }
}
五、總結
在產品開發中需要進行大量數據傳輸的場合,DMA是很好的選擇,用好DMA功能能使程序設計效率大大提高


免責聲明!

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



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