DMA簡介:
在硬件系統(tǒng)中,主要由CPU(內(nèi)核),外設(shè),內(nèi)存(SRAM),總線等結(jié)構(gòu)組成,數(shù)據(jù)就經(jīng)常要在內(nèi)存與外設(shè)之間傳輸轉(zhuǎn)移,或者是從外設(shè)A轉(zhuǎn)移到外設(shè)B.
DMA(Direct Memory Access)直接存儲器存儲,是一種可以大大減輕CPU工作量的數(shù)據(jù)存儲方式.
數(shù)據(jù)轉(zhuǎn)移的一般方式:
例如當(dāng)CPU需要處理由ADC外設(shè)采集回來的數(shù)據(jù)時(shí),CPU首先要把數(shù)據(jù)從ADC外設(shè)的寄存器讀取到內(nèi)存中(變量),然后進(jìn)行運(yùn)算處理.
(但是,因?yàn)樵谵D(zhuǎn)移數(shù)據(jù)的過程中會占用CPU十分寶貴的資源,所以希望CPU更多地被用在數(shù)據(jù)運(yùn)算或響應(yīng)中斷之中,而數(shù)據(jù)轉(zhuǎn)移的工作交由其它部件完成。)
DMA的方式:
DMA可以為CPU分擔(dān)了數(shù)據(jù)轉(zhuǎn)移的工作。因?yàn)镈MA的存在,CPU被解放出來,它可以在DMA轉(zhuǎn)移數(shù)據(jù)的過程中同時(shí)進(jìn)行數(shù)據(jù)運(yùn)算,響應(yīng)中斷,大大提高效率.
DMA的工作:
在STM32中文手冊可以找到STM32的系統(tǒng)結(jié)構(gòu)圖,可以很清晰的看到STM32內(nèi)核,存儲器,外設(shè)以及DMA的連接
所有這些硬件結(jié)構(gòu)最終都通過各種各樣的線連接到總線矩陣之中,硬件結(jié)構(gòu)之間的數(shù)據(jù)轉(zhuǎn)移都經(jīng)過總線矩陣的協(xié)調(diào),使各個外設(shè)都能夠和諧地使用總線來傳輸數(shù)據(jù).
例如:
在不使用DMA的情況下,內(nèi)核通過DCode經(jīng)過總線矩陣協(xié)調(diào),使用AHB把外設(shè)ADC采集的數(shù)據(jù)讀取到內(nèi)核,然后內(nèi)核DCode再通過總線矩陣協(xié)調(diào),把數(shù)據(jù)存放到內(nèi)存SRAM中。
而在使用DMA之后,由DMA控制器的DMA總線與總線矩陣協(xié)調(diào),使用AHB把外設(shè)ADC的數(shù)據(jù)經(jīng)由DMA通道存放到內(nèi)存SRAM。在這個數(shù)據(jù)傳輸?shù)倪^程中,不需要內(nèi)核的全程參與,所以內(nèi)核可以同時(shí)進(jìn)行數(shù)據(jù)運(yùn)算,而且DMA的方式是點(diǎn)到點(diǎn)的數(shù)據(jù)轉(zhuǎn)移,而不使用DMA的方式還要以內(nèi)核來作為中轉(zhuǎn)站,顯然是DMA的傳輸方式的效率更高。(所以”直接“是很強(qiáng)的東西?。。?/p>
DMA的控制參數(shù):
要使用DMA,需要確定一系列的控制參數(shù):
如外設(shè)數(shù)據(jù)的地址,內(nèi)存地址,傳輸方向等,在開啟DMA傳輸前還要先發(fā)出DMA請求。
DMA實(shí)例main函數(shù):
main函數(shù)功能:
實(shí)際上是利用DMA把數(shù)據(jù)(數(shù)組)從內(nèi)存轉(zhuǎn)移到外設(shè)(串口)。外設(shè)工作的時(shí)候,除了轉(zhuǎn)移數(shù)據(jù),實(shí)質(zhì)是不需要內(nèi)核干預(yù)的,而數(shù)據(jù)轉(zhuǎn)移的工作現(xiàn)在交給了DMA,所以在串口發(fā)送數(shù)據(jù)的時(shí)候,內(nèi)核同時(shí)還可以進(jìn)行其它操作,比如點(diǎn)亮LED燈(類似一個線程動作)。
頭文件忽略………..
extern uint8_t SendBuff[SENDBUFF_SIZE];
uint16_t i;
int main(void)
{
/USART1_Config 115200 8-N-1/
USART1_Config();
DMA_Config();
LED_GPIO_Config();
r(i=0;i { SendBuff[i] = 0xff; } /*串口向DMA發(fā)出請求 */ USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//在DMA傳送未完成時(shí),CPU會繼續(xù)執(zhí)行main函數(shù)中的代碼 LED1(ON);//先點(diǎn)亮LED,而同時(shí)DMA在向串口運(yùn)送數(shù)據(jù),當(dāng)DMA發(fā)送完成時(shí),在中斷函數(shù)關(guān)閉LED while(1); } main函數(shù)里面配置好了串口1,DMA,以及LED外設(shè),使能DMA的發(fā)送請求.其中串口配置以及LEDGPIO的配置這里就不講解了,前面的博客都有說,配置的內(nèi)容都一樣. DMA的配置: void DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//開啟 DMA 時(shí)鐘 NVIC_Config(); //配置 DMA 中斷 /*設(shè)置 DMA 源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址*/ DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; /*內(nèi)存地址(要傳輸?shù)淖兞康闹羔?*/ DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; /*方向:從內(nèi)存到外設(shè)*/ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; /*傳輸大小 DMA_BufferSize=SENDBUFF_SIZE*/ DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; /*外設(shè)地址不增*/ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /*內(nèi)存地址自增*/ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /*外設(shè)數(shù)據(jù)單位*/ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; /*內(nèi)存數(shù)據(jù)單位 8bit*/ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; /*DMA 模式:一次傳輸,循環(huán)*/ DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /*優(yōu)先級:中*/ DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; /*禁止內(nèi)存到內(nèi)存的傳輸 */ DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /*配置 DMA1 的 4 通道*/ DMA_Init(DMA1_Channel4, &DMA_InitStructure); DMA_Cmd (DMA1_Channel4,ENABLE); //使能 DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //配置 DMA 發(fā)送完之后產(chǎn)生中斷 } DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; ps:外設(shè)數(shù)據(jù)寄存器的地址可以在《STM32參考手冊》中找到一個存儲器映射表(部分)(圖截的不是很好看?。。。?nbsp; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure); 填充好結(jié)構(gòu)體后,就使能DMA了,這里用到DMA1_Channel4(DMA1的通道4),這個通道不是隨便選擇的,是根據(jù)DMA的請求映射來選擇的,在《STM32參考手冊》可以找到。 DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); DMA的中斷: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置DMA通道的優(yōu)先級組1 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;//中斷通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 這里的是調(diào)用了NVIC_PriorityGroupConfig()DMA的中斷優(yōu)先級為組1,中斷通道配置為DMA1_Channel4_IRQn. 中斷服務(wù)函數(shù): void DMA1_Channel4_IRQHandler(void) { if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)//判斷是否為 DMA 發(fā)送完成中斷 { LED1(OFF);//LED 關(guān)閉 DMA_ClearFlag(DMA1_FLAG_TC4); //清除DMA中斷標(biāo)志位 } } 這個中斷服務(wù)函數(shù)名在啟動文件startup_stm32f10x_hd.s中找到(以前說過,這里再說一次),這里就是檢查中斷標(biāo)志位,關(guān)閉LED燈,清除中斷標(biāo)志位 在main函數(shù)里USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); 使能或者關(guān)閉串口的DMA接口,這里配置的是串口1的USART_DMAReq_Tx(串口發(fā)送請求),也可以是USART_DMAReq_Rx(串口接收請求). 調(diào)用這個庫函數(shù)允許串口外設(shè)向 DMA 發(fā)出請求,請求DMA傳輸數(shù)據(jù)。調(diào)用了這個函數(shù)之后,DMA開始響應(yīng)串口的請求,根據(jù)DMA配置,把數(shù)組中的數(shù)據(jù)一個個地轉(zhuǎn)移到串口數(shù)據(jù)寄存器,并由串口向外發(fā)送這些數(shù)據(jù)。在調(diào)用了USART_DMACmd()函數(shù)之后,接下來在main函數(shù)就把LED點(diǎn)亮了. PS: 實(shí)際上,在DMA還沒傳輸完成數(shù)據(jù)的時(shí)候,因?yàn)閮?nèi)核并不參與DMA數(shù)據(jù)傳輸?shù)娜^程,所以內(nèi)核在這個時(shí)候執(zhí)行了點(diǎn)亮LED1的代碼。而當(dāng)DMA傳輸完成時(shí),進(jìn)入了中斷,再把LED1關(guān)閉.
保存外設(shè)數(shù)據(jù)寄存器的基地址,這個地址作為傳輸?shù)脑椿蚰繕?biāo)(DMA具有地址自增的功能,地址自增可以方便地讀取連續(xù)的單元)
這里面用的USART1_DR_Base宏實(shí)際是#define USART1_DR_Base 0x40013804,從《 STM32 參考手冊》可知,串口外設(shè)會自動地把數(shù)據(jù)寄存器中的數(shù)據(jù),送入它的移位寄存器,然后由硬件按照串口協(xié)議把該數(shù)據(jù)發(fā)送出去。
在這個實(shí)例中,把數(shù)據(jù)寄存器的地址作為外設(shè)的地址,那么由DMA通道轉(zhuǎn)移過來的內(nèi)存數(shù)據(jù)就會被保護(hù)到這個寄存器中,然后串口就會自動進(jìn)行發(fā)送了.
可以看到,USART1(串口1)的外設(shè)基地址為0x40013800,同時(shí)我們在查找《STM32數(shù)據(jù)手冊》手冊可以找到USART的數(shù)據(jù)寄存器,了解到偏移量是0x04,那么USART1的外設(shè)基地址加上數(shù)據(jù)寄存器的地址偏移就是在DMA傳輸中需要的目標(biāo)地址了。
0x4001 3804 = 0x4001 3800 + 0x04;
保存了內(nèi)存的基地址,這個地址也可以作為傳輸源或目標(biāo).在使用時(shí)通常會給這個成員賦值為某個數(shù)組的基地址,然后利用DMA的地址自增功能把數(shù)組一個個地填滿.
(在C語言中數(shù)組名就是該數(shù)組的基地址,而數(shù)組(變量)是被保存到內(nèi)存(SRAM)上的,所以我們實(shí)質(zhì)上給.DMA_MemoryBaseAddr 這個結(jié)構(gòu)體成員賦予了一個內(nèi)存地址。)
DMA數(shù)據(jù)傳輸方向,可以選擇是外設(shè)到內(nèi)存還是內(nèi)存到外設(shè)。DMA_DIR_PeripheralDST是內(nèi)存到外設(shè)
DMA要傳輸?shù)臄?shù)據(jù)總大小, DMA_BufferSize=SENDBUFF_SIZE=5000,這里要傳輸5000個數(shù)據(jù)
外設(shè)地址不增,因?yàn)橛玫氖峭庠O(shè)地址是固定的.
內(nèi)存地址自增,數(shù)組自增把數(shù)據(jù)一個個都傳到數(shù)據(jù)寄存器.
外設(shè)傳輸數(shù)據(jù)單元大小,可以為字節(jié),半字節(jié),字.
內(nèi)存?zhèn)鬏敂?shù)據(jù)單元大小,可以為字節(jié),半字節(jié),字,這里是8bit.
DMA的模式,可以為循環(huán)模式或者正常模式,在循環(huán)模式下傳輸完一輪數(shù)據(jù)之后再重新傳輸,適合ADC不斷采集數(shù)據(jù)等場合,這里是正常模式,也就是一次.
配置DMA通道的優(yōu)先級,總線矩陣根據(jù)DMA通道的優(yōu)先級進(jìn)行總線協(xié)調(diào)分配,這里配置為DMA_Priority_Medium(中等優(yōu)先級).
(在使用1個DMA通道時(shí),配置任何優(yōu)先級都沒有區(qū)別)
使能內(nèi)存到內(nèi)存的DMA傳輸。DMA傳輸可以在外設(shè)與內(nèi)存,外設(shè)與外設(shè),還可以在內(nèi)存與內(nèi)存之間進(jìn)行傳輸。
這里用的是內(nèi)存到外設(shè) ,使用DMA_M2M_Disable(禁止內(nèi)存到內(nèi)存的傳輸).
DMA_Cmd (DMA1_Channel4,ENABLE);
(DMA請求是指外設(shè)在需要使用DMA前需要向DMA控制器發(fā)送請求信息,DMA在接收到請求后才會根據(jù)DMA配置進(jìn)行數(shù)據(jù)轉(zhuǎn)移。)
PS:
從圖中可以看到即使同樣是外設(shè)串口1,串口1的發(fā)送數(shù)據(jù) DMA 請求和串口1的接收數(shù)據(jù)DMA請求通道都是不一樣的,分別為DMA1通道4和DMA1的通道5。
把DMA配置成DMA_IT_TC(DMA發(fā)送完成標(biāo)志)中斷.DMA_ITConfig是用于外設(shè)中斷的函數(shù).
中斷配置:
在DMA_Config()中調(diào)用了NVIC_Config()進(jìn)行DMA中斷配置
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
上一篇:STM32之SPI_FLASH
下一篇:STM32之USART(串口通信)
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 東芝推出輸出耐壓1800V的車載光繼電器
- 中國制定的全球首項(xiàng)鋰離子電池硅基負(fù)極材料國際標(biāo)準(zhǔn)發(fā)布
- 智能汽車合成數(shù)據(jù)架構(gòu)與應(yīng)用實(shí)踐分享
- 15家車企的固態(tài)電池汽車及供應(yīng)商一覽!
- 8月交付!鋰電巨頭全固態(tài)電池商業(yè)化“快進(jìn)”
- 白皮書點(diǎn)破汽車智駕營銷現(xiàn)象:六個“不等于”揭示真實(shí)的輔助駕駛
- Unity引擎在智能座艙項(xiàng)目流程之深入優(yōu)化與未來技術(shù)
- Unity引擎在智能座艙項(xiàng)目流程之未來技術(shù)趨勢與高級整合
- Stellantis宣布終止氫燃料電池技術(shù)開發(fā)
- 汽車攝像頭模塊中敏感和動態(tài)電源軌的紋波降低技術(shù)