1. 程式人生 > >stm32學習筆記 F1系列DMA

stm32學習筆記 F1系列DMA

DMA 全稱Direct Memory Access,即直接儲存器訪問。
DMA傳輸將資料從一個地址空間複製到另一個地址空間。當CPU初始化這個傳輸動作,傳輸動作本身是由DMA控制器來實現和完成的。
DMA傳輸方式無需CPU直接控制傳輸,也沒有中斷處理方式那樣保留現場和恢復現場過程,通過硬體為RAM和IO裝置開闢一條直接傳輸資料的通道,使得CPU的效率大大提高。
DMA作用:為CPU減負。
STM32最多有2個DMA控制器(DMA2僅存在大容量產品中),DMA1有7個通道。DMA2有5個通道。每個通道專門用來管理來自於一個或多個外設對儲存器訪問的請求。還有一個仲裁起來協調各個DMA請求的優先權。

STM32的DMA有以下一些特性: 
①每個通道都直接連線專用的硬體DMA請求,都支援軟體觸發,這些通過軟體來配置。
②在七個請求間的優先權可以通過軟體程式設計設定(共有四級:很高、高、中等和低),假如在相等優先權時由硬體決定(請求0優先於請求1,依此類推) 。 
③ 獨立的源和目標資料區的傳輸寬度(位元組、半字、全字),模擬打包和拆包的過程。源    和目標地址必須按資料傳輸寬度對齊。 
④ 支援迴圈的緩衝器管理 
⑤ 每個通道都有3個事件標誌(DMA 半傳輸,DMA傳輸完成和DMA傳輸出錯),這3個事件標誌邏輯或成為一個單獨的中斷請求。 
⑥ 外設和儲存器,儲存器和外設的傳輸 ,儲存器和儲存器間的傳輸
⑦ 快閃記憶體、SRAM、外設的SRAM、APB1 APB2和AHB外設均可作為訪問的源和目標。 
⑧ 可程式設計的資料傳輸數目:最大為65536
從外設(TIMx、ADC、SPIx、I2Cx 和 USARTx)產生的 DMA 請求,通過邏輯或輸入到DMA 控制器,這就意味著同時只能有一個請求有效。外設的 DMA 請求,可以通過設定相應的外設暫存器中的控制位,被獨立地開啟或關閉。

下面是配置DMA通道x的過程(x代表通道號):
1. 在DMA_CPARx暫存器中設定外設暫存器的地址。發生外設資料傳輸請求時,這個地址將是資料傳輸的源或目標。
2. 在DMA_CMARx暫存器中設定資料儲存器的地址。發生外設資料傳輸請求時,傳輸的資料將從這個地址讀出或寫入這個地址。
3. 在DMA_CNDTRx暫存器中設定要傳輸的資料量。在每個資料傳輸後,這個數值遞減。
4. 在DMA_CCRx暫存器的PL[1:0]位中設定通道的優先順序。
5. 在DMA_CCRx暫存器中設定資料傳輸的方向、迴圈模式、外設和儲存器的增量模式、外設和儲存器的資料寬度、傳輸一半產生中斷或傳輸完成產生中斷。
6. 設定DMA_CCRx暫存器的ENABLE位,啟動該通道。
一旦啟動了DMA通道,它既可響應連到該通道上的外設的DMA請求。當傳輸一半的資料後,半傳輸標誌(HTIF)被置1,當設定了允許半傳輸中斷位(HTIE)時,將產生一箇中斷請求。在資料傳輸結束後,傳輸完成標誌(TCIF)被置1,當設定了允許傳輸完成中斷位(TCIE)時,將產生一箇中斷請求。


常用的外設DMA使能庫函式
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq,FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void DAC_DMACmd(uint32_t DAC_Channel, FunctionalState NewState);
void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
void SDIO_DMACmd(FunctionalState NewState);
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq,FunctionalState NewState);
void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase,uint16_t TIM_DMABurstLength)

void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource,FunctionalState NewState);

常用的DMA庫函式

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)

typedef struct
{
  uint32_t DMA_PeripheralBaseAddr; //外設基地址
  uint32_t DMA_MemoryBaseAddr; //儲存器基地址
  uint32_t DMA_DIR;         //資料傳輸方向
  uint32_t DMA_BufferSize;  //通道傳輸資料量
  uint32_t DMA_PeripheralInc;//外設增量模式
  uint32_t DMA_MemoryInc;  //儲存器增量模式
  uint32_t DMA_PeripheralDataSize; //外設資料寬度
  uint32_t DMA_MemoryDataSize; //儲存器資料寬度
  uint32_t DMA_Mode;  //模式:是否迴圈
  uint32_t DMA_Priority; //優先順序
  uint32_t DMA_M2M;    //是否儲存器到儲存器方式     

}DMA_InitTypeDef;

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx,FunctionalState NewState);

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx,uint32_t DMA_IT, FunctionalState NewState);

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx,uint16_t DataNumber); 

uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);

void DMA_ClearFlag(uint32_t DMAy_FLAG);

ITStatus DMA_GetITStatus(uint32_t DMAy_IT);

void DMA_ClearITPendingBit(uint32_t DMAy_IT);


DMA配置程式過程
① 使能DMA時鐘
   RCC_AHBPeriphClockCmd();
② 初始化DMA通道引數
   DMA_Init();
③使能串列埠DMA傳送,串列埠DMA使能函式:
   USART_DMACmd();
④使能DMA1通道,啟動傳輸。
   DMA_Cmd();
⑤查詢DMA傳輸狀態
  DMA_GetFlagStatus();
⑥獲取/設定通道當前剩餘資料量:
  DMA_GetCurrDataCounter();
  DMA_SetCurrDataCounter();