? ? ? ? DMA 是為CPU分擔(dān)數(shù)據(jù)轉(zhuǎn)移的工作。因為DMA的存在CPU才被解放出來,它可以在 DMA 轉(zhuǎn)移數(shù)據(jù)的過程中同時進行數(shù)據(jù)運算、響應(yīng)中斷,大大提高效率。
1、DMA工作分析
? ? ? ? 數(shù)據(jù)傳輸?shù)倪^程中,不需要內(nèi)核的全程參與,所以內(nèi)核可以同時進行數(shù)據(jù)運算。DMA 方式是點到點的數(shù)據(jù)轉(zhuǎn)移,而不使用 DMA 方式還要以內(nèi)核來作為中轉(zhuǎn)站,顯然 DMA 傳輸方式的效率更高。
? ? ? ? 要使用 DMA,需要確定一系列的控制參數(shù),如外設(shè)數(shù)據(jù)的地址、內(nèi)存地址、傳輸方向等,在開啟 DMA 傳輸前還要先發(fā)出 DMA 請求。
?
2、 初始化DMA?
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;
(1)DMA_PeripheralBaseAddr:這個成員保存的是外設(shè)數(shù)據(jù)寄存器的基地址,這個地址作為傳輸?shù)脑椿蚰繕?。DMA 具有地址自增的功能,地址自增功使得可以方便地讀取連續(xù)的 數(shù)據(jù)單元 ?,F(xiàn)在給這個成員的賦USART1_DR_Base,是一個自定義的宏:
#define USART1_DR_Base 0x40013804【串口外設(shè)會自動把數(shù)據(jù)寄存器中的數(shù)據(jù),送入它的移位寄存器,然后由硬件按照串口協(xié)議把該數(shù)據(jù)發(fā)送出去。】
(2)DMA_MemoryBaseAddr:保存了內(nèi)存的基地址,同樣,這個地址可作為傳輸?shù)脑椿蚰繕恕T谑褂脮r通常會給這個成員賦值為某個數(shù)組的基地址,然后利用 DMA 的地址自增功能把數(shù)組一個個地填滿。在本代碼中向這個成員賦值為 SendBuff,這是一個自定義的數(shù)組變量名。
(3)DMA_DIR:保存了 DMA 數(shù)據(jù)傳輸方向,可以選擇是外設(shè)到內(nèi)存還是內(nèi)存到外設(shè)。
(4)DMA_BufferSize:保存了 DMA 要傳輸?shù)臄?shù)據(jù)總大小,其單位為后面結(jié)構(gòu)體成員。
(5)DMA_PeripheralInc/DMA_MemoryInc:分別為外設(shè)和內(nèi)存的地址是否開啟自增功能。
(6)DMA_PeripheralDataSize/ DMA_MemoryDataSize:分別為外設(shè)和內(nèi)存的數(shù)據(jù)單元大小??梢詾樽止?jié)、半字和字。
(7)DMA_Mode:保存了 DMA 的模式,可以為循環(huán)模式或正常模式,循環(huán)模式即在傳輸完一輪數(shù)據(jù)之后再重新傳輸,這種方式很適合 ADC 不斷采集數(shù)據(jù)的場合。
(8)DMA_Priority:DMA 通道的優(yōu)先級,總線矩陣根據(jù)其 DMA 通道的優(yōu)先級進行總線協(xié)調(diào)分配。
(9)DMA_M2M:保存了是否內(nèi)存到內(nèi)存的 DMA 傳輸。DMA 傳輸可以在外設(shè)與內(nèi)存、外設(shè)與外設(shè)以及內(nèi)存與內(nèi)存之間進行。
?
//?初始化DMA主要是開啟外設(shè)時鐘、填充初始化結(jié)構(gòu)體以及使能外設(shè)。 void?USART1_DMA_Config(void) { ??DMA_InitTypeDef?DMA_InitStructure; ??RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,?ENABLE);?/*開啟?DMA?時鐘*/ ??DMA_InitStructure.DMA_PeripheralBaseAddr?=?USART1_DR_Base;?/*設(shè)置?DMA?源:串口數(shù)據(jù)寄存器地址*/ ??DMA_InitStructure.DMA_MemoryBaseAddr?=?(u32)SendBuff;?/*內(nèi)存地址(要傳輸?shù)淖兞康闹羔?*/ ??DMA_InitStructure.DMA_DIR?=?DMA_DIR_PeripheralDST;?/*方向:從內(nèi)存到外設(shè)*/ ??DMA_InitStructure.DMA_BufferSize?=?SENDBUFF_SIZE;?/*傳輸大小DMA_BufferSize=SENDBUFF_SIZE*/ ??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è)數(shù)據(jù)單位*/ ??DMA_InitStructure.DMA_MemoryDataSize?=?DMA_MemoryDataSize_Byte;?/*內(nèi)存數(shù)據(jù)單位?8bit*/ ??DMA_InitStructure.DMA_Mode?=?DMA_Mode_Circular;?/*DMA?模式:不斷循環(huán)*/ ??DMA_InitStructure.DMA_Priority?=?DMA_Priority_Medium;?/*優(yōu)先級:中*/ ??DMA_InitStructure.DMA_M2M?=?DMA_M2M_Disable;?/*禁止內(nèi)存到內(nèi)存的傳輸?*/ ??/*配置?DMA1?的?4?通道??根據(jù)?DMA?的請求映像來設(shè)置?*/ ??DMA_Init(DMA1_Channel4,?&DMA_InitStructure); ??DMA_Cmd?(DMA1_Channel4,?ENABLE);??/*使能?DMA*/ //DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//配置?DMA?發(fā)送完成后產(chǎn)生中斷 }