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