寒假学习之stm32(15)----DMA(direct memory access)
DMA的基礎科普
老規矩,最先進行的是基礎知識的科普?
DMA(百度百科):?
http://baike.baidu.com/subview/32471/5048463.htm
DMA 傳輸將數據從一個地址空間復制到另外一個地址空間。當CPU 初始化這個傳輸動作,傳輸動作本身是由 DMA 控制器來實行和完成。典型的例子就是移動一個外部內存的區塊到芯片內部更快的內存區。像是這樣的操作并沒有讓處理器工作拖延,反而可以被重新排程去處理其他的工作。DMA 傳輸對于高效能 嵌入式系統算法和網絡是很重要的。
在實現DMA傳輸時,是由DMA控制器直接掌管總線,因此,存在著一個總線控制權轉移問題。即DMA傳輸前,CPU要把總線控制權交給DMA控制器,而在結束DMA傳輸后,DMA控制器應立即把總線控制權再交回給CPU。一個完整的DMA傳輸過程必須經過DMA請求、DMA響應、DMA傳輸、DMA結束4個步驟。
1. DMA請求 CPU對DMA控制器初始化,并向I/O接口發出操作命令,I/O接口提出DMA請求。2. DMA響應 DMA控制器對DMA請求判別優先級及屏蔽,向總線裁決邏輯提出總線請求。當CPU執行完當前總線周期即可釋放總線控制權。此時,總線裁決邏輯輸出總線應答,表示DMA已經響應,通過DMA控制器通知I/O接口開始DMA傳輸。
3. DMA傳輸 DMA控制器獲得總線控制權后,CPU即刻掛起或只執行內部操作,由DMA控制器輸出讀寫命令,直接控制RAM與I/O接口進行DMA傳輸。 在DMA控制器的控制下,在存儲器和外部設備之間直接進行數據傳送,在傳送過程中不需要中央處理器的參與。開始時需提供要傳送的數據的起始位置和數據長度。
4. DMA結束 當完成規定的成批數據傳送后,DMA控制器即釋放總線控制權,并向I/O接口發出結束信號。當I/O接口收到結束信號后,一方面停 止I/O設備的工作,另一方面向CPU提出中斷請求,使CPU從不介入的狀態解脫,并執行一段檢查本次DMA傳輸操作正確性的代碼。最后,帶著本次操作結果及狀態繼續執行原來的程序。
由此可見,DMA傳輸方式無需CPU直接控制傳輸,也沒有中斷處理方式那樣保留現場和恢復現場的過程,通過硬件為RAM與I/O設備開辟一條直接傳送數據的通路,使CPU的效率大為提高。
stm32的DMA特性
聊完了總的性質,接下來該談談DMA在stm32上的特性了
stm32下的 DMA主要特性?
1. 12個獨立的可配置的通道(請求): DMA1有7個通道, DMA2有5個通道?
每個通道對應的具體外設如中文參考手冊所給出的圖所示:?
DMA1:?
DMA2:?
每個通道都直接連接專用的硬件DMA請求,每個通道都同樣支持軟件觸發。這些功能通過?
軟件來配置。
在同一個DMA模塊上,多個請求間的優先權可以通過軟件編程設置(共有四級:很高、高、?
中等和低),優先權設置相等時由硬件決定(請求0優先于請求1,依此類推) 。
獨立數據源和目標數據區的傳輸寬度(字節、半字、全字),模擬打包和拆包的過程。源和目?
標地址必須按數據傳輸寬度對齊。
支持循環的緩沖器管理
每個通道都有3個事件標志(DMA半傳輸、 DMA傳輸完成和DMA傳輸出錯),這3個事件標志邏輯或成為一個單獨的中斷請求。
存儲器和存儲器間的傳輸
外設和存儲器、存儲器和外設之間的傳輸
閃存、 SRAM、外設的SRAM、 APB1、 APB2和AHB外設均可作為訪問的源和目標。
可編程的數據傳輸數目:最大為65535
祭出DMA的程序框圖,先看看總體印象:?
庫函數的配置過程:
1.CPU對IO的初始化指令:
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);CPU對DMA的初始化指令以及 2.DMA響應的過程:
時鐘的初始化:?
由圖片可以看出,stm32的dma是在AHB總線上的,所以在時鐘初始化的時候:?
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA初始化:
DMA_DeInit(DMA_CHx); //將DMA的通道x寄存器重設為缺省值 DMA_Init(DMA_CHx,&DMA_InitStruct); 其中,DMA_InitStruct的結構體成員如下:1. DMA_PeripheralBaseAddr:外設的基地址(寄存器的地址) 2. DMA_MemoryBaseAddr: 內存的基地址(可以是代碼中定義的數組的地址) 3. DMA_BufferSize : 傳送數據的數量,其有效參數需要自己設置(0~65535) 4. DMA_DIR :DMA的數據傳輸方向,其有效參數為:DMA_DIR_PeripheralDST(外設作為數據發送的目的地)或者DMA_DIR_PeripheralSRC(外設作為數據發送的源頭) 5. DMA_PeripheralInc:外設的自增模式(每次傳輸一個數據之后,指針自動+1),有效的參數為:DMA_PeripheralInc_Enable,DMA_PeripheralInc_Disable 6. DMA_MemoryInc:內存的自增模式,有效參數同5類似 7. DMA_PeripheralDataSize:外設的每個數據的大小,其有效參數為:DMA_MemoryDataSize_Byte, DMA_MemoryDataSize_HalfWord, DMA_MemoryDataSize_Word 8. DMA_MemoryDataSize,內存的每個數據大小,其概念類似于7 9. DMA_Mode:DMA的數據傳輸模式,DMA_Mode_Circular(循環傳遞),DMA_Mode_Normal(只傳遞一次) 10. DMA_Priority:DMA的數據傳遞優先級別,其有效參數為:DMA_Priority_VeryHigh(非常高),DMA_Priority_High(高),DMA_Priority_Medium(中),DMA_Priority_Low(低)使能DMA(在每次數據傳輸結束以后,數據傳輸數量都會被清零,所以,每次傳輸數據,都必須使能一次DMA)
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx) { DMA_Cmd(DMA_CHx, DISABLE ); //關閉USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA緩存的大小DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 }3.DMA傳輸,4.DMA傳輸結束
while(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET) //判斷通道4傳輸完成{DMA_ClearFlag(DMA1_FLAG_TC4);//清除通道4傳輸完成標志break; }pro=DMA_GetCurrDataCounter(DMA1_Channel4);//得到當前還剩余多少個數據pro=1-pro/SEND_BUF_SIZE;//得到百分比 pro*=100; //擴大100倍,得到真正的數據}總體的過程:
DMA_InitTypeDef DMA_InitStructure;u16 DMA1_MEM_LEN;//保存DMA每次數據傳送的長度 //DMA1的各通道配置 //這里的傳輸形式是固定的,這點要根據不同的情況來修改 //從存儲器->外設模式/8位數據寬度/存儲器增量模式 //DMA_CHx:DMA通道CHx //cpar:外設地址 //cmar:存儲器地址 //cndtr:數據傳輸量 void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr) {RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA傳輸DMA_DeInit(DMA_CHx); //將DMA的通道1寄存器重設為缺省值DMA1_MEM_LEN=cndtr;DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外設基地址DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA內存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //數據傳輸方向,從內存讀取發送到外設DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA緩存的大小DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址寄存器不變DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內存地址寄存器遞增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //數據寬度為8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //數據寬度為8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x擁有中優先級 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x沒有設置為內存到內存傳輸DMA_Init(DMA_CHx, &DMA_InitStructure); //根據DMA_InitStruct中指定的參數初始化DMA的通道//USART1_Tx_DMA_Channel所標識的寄存器} //開啟一次DMA傳輸 void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx) { DMA_Cmd(DMA_CHx, DISABLE ); //關閉USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA緩存的大小DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 }總結
以上是生活随笔為你收集整理的寒假学习之stm32(15)----DMA(direct memory access)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript event
- 下一篇: String类得常用方法