DMA(Direct Memory Access),直接存儲器訪問。DMA傳輸方式無需CPU直接控制傳輸,通過硬體為RAM與I/O設備開闢一條直接傳送數據的通路,使CPU效率大大提高。stm32f103有2個DMA控制器,DMA1有7個通道,DMA2有5個通道,專門用來管理來自外設對存儲器的訪問請求 ...
DMA(Direct Memory Access),直接存儲器訪問。DMA傳輸方式無需CPU直接控制傳輸,通過硬體為RAM與I/O設備開闢一條直接傳送數據的通路,使CPU效率大大提高。stm32f103有2個DMA控制器,DMA1有7個通道,DMA2有5個通道,專門用來管理來自外設對存儲器的訪問請求,還有一個仲裁器來協調各個DMA請求的優先權。
1.DMA各通道請求
從外設產生的DMA請求通過邏輯"或"輸入到DMA控制器,這就意味著同時只能有一個請求有效。
例如,串口1發送的DMA,就要用到DMA1的通道4。
2.DMA1通道4(串口1發送)配置步驟
①設置外設地址
設置外設地址通過DMA1_CPAR4來設置,在這個寄存器裡面寫入&USART1_DR的值。該地址將作為DMA傳輸的目標地址。
DMA通道x外設地址寄存器(DMA_CPARx)(x = 1…7)
Eg:DMA_CHx->CPAR=cpar; //DMA1 外設地址
DMA_CHx->CPAR=&USART1_DR;
②設置存儲器地址
設置存儲器地址通過DMA1_CMAR4來設置,假設要把數組SendBuf作為存儲器,在該寄存器寫入&SendBuf的值。該地址將作為DMA傳輸的源地址
Eg:DMA_CHx->CMAR=(u32)cmar; //DMA1,存儲器地址
③設置傳輸數據量
寫入此次要傳輸的數據量,也就是SendBuf的大小。該寄存器在DMA啟動後自減,每次新的DMA傳輸都重新向該寄存器寫入要傳輸的數據量。
DMA通道x傳輸數量寄存器(DMA_CNDTRx)(x = 1…7)
Eg:DMA_CHx->CNDTR=cndtr; //DMA1,傳輸數據量
④設置通道4的配置信息
若有多個通道,則要設置優先順序,編號越小優先順序越高。
DMA通道x配置寄存器(DMA_CCRx)(x = 1…7)
⑤使能DMA1通道4,啟動傳輸
DMAx_CCRx 最低位開啟DMA傳輸。註意要設置USART1的使能DMA傳輸位,通過USART1->CR3的第七位設置,這樣就可以啟動一次USART1的DMA傳輸了。
3.DMA中斷狀態顯示及清除
DMA中斷狀態寄存器(DMA_ISR)
DMA中斷標誌清除寄存器(DMA_IFCR)
Eg:if(DMA1->ISR&(1<<13))//等待通道4傳輸完成
{
DMA1->IFCR|=1<<13;//清除通道4傳輸完成標誌
break;
}
4.DMA1通道4(串口1發送)應用
1 u16 DMA1_MEM_LEN;//保存DMA每次數據傳送的長度 2 //DMA1的各通道配置 3 //這裡的傳輸形式是固定的,這點要根據不同的情況來修改 4 //從存儲器->外設模式/8位數據寬度/存儲器增量模式 5 //DMA_CHx:DMA通道CHx 6 //cpar:外設地址 7 //cmar:存儲器地址 8 //cndtr:數據傳輸量 9 void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr) 10 { 11 RCC->AHBENR|=1<<0; //開啟DMA1時鐘 12 delay_ms(5); //等待DMA時鐘穩定 13 DMA_CHx->CPAR=cpar; //DMA1 外設地址 14 DMA_CHx->CMAR=(u32)cmar; //DMA1,存儲器地址 15 DMA1_MEM_LEN=cndtr; //保存DMA傳輸數據量 16 DMA_CHx->CNDTR=cndtr; //DMA1,傳輸數據量 17 DMA_CHx->CCR=0X00000000; //複位 18 DMA_CHx->CCR|=1<<4; //從存儲器讀 19 DMA_CHx->CCR|=0<<5; //普通模式 20 DMA_CHx->CCR|=0<<6; //外設地址非增量模式 21 DMA_CHx->CCR|=1<<7; //存儲器增量模式 22 DMA_CHx->CCR|=0<<8; //外設數據寬度為8位 23 DMA_CHx->CCR|=0<<10; //存儲器數據寬度8位 24 DMA_CHx->CCR|=1<<12; //中等優先順序 25 DMA_CHx->CCR|=0<<14; //非存儲器到存儲器模式 26 } 27 //開啟一次DMA傳輸 28 void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx) 29 { 30 DMA_CHx->CCR&=~(1<<0); //關閉DMA傳輸 31 DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,傳輸數據量 32 DMA_CHx->CCR|=1<<0; //開啟DMA傳輸 33 }DMA.c
1 const u8 TEXT_TO_SEND[]={"STM32 DMA USART1"}; 2 #define TEXT_LENTH sizeof(TEXT_TO_SEND)-1 //TEXT_TO_SEND字元串長度(不包含結束符) 3 u8 SendBuff[(TEXT_LENTH+2)*100]; 4 5 int main(void) 6 { 7 u16 i; 8 u8 t=0; 9 float pro=0; //進度 10 Stm32_Clock_Init(9); //系統時鐘設置 11 uart_init(72,9600); //串口初始化為9600 12 delay_init(72); //延時初始化 13 LED_Init(); //初始化與LED連接的硬體介面 14 LCD_Init(); //初始化LCD 15 KEY_Init(); //按鍵初始化 16 MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,(TEXT_LENTH+2)*100);//DMA1通道4,外設為串口1,存儲器為SendBuff,長(TEXT_LENTH+2)*100. 17 POINT_COLOR=RED;//設置字體為紅色 18 //顯示提示信息 19 for(i=0;i<(TEXT_LENTH+2)*100;i++)//填充ASCII字元集數據 20 { 21 if(t>=TEXT_LENTH)//加入換行符 22 { 23 SendBuff[i++]=0x0d; 24 SendBuff[i]=0x0a; 25 t=0; 26 }else SendBuff[i]=TEXT_TO_SEND[t++];//複製TEXT_TO_SEND語句 27 } 28 POINT_COLOR=BLUE;//設置字體為藍色 29 i=0; 30 while(1) 31 { 32 t=KEY_Scan(0); 33 if(t==KEY0_PRES)//KEY0按下 34 { 35 LCD_ShowString(60,150,200,16,16,"Start Transimit...."); 36 LCD_ShowString(60,170,200,16,16," %");//顯示百分號 37 printf("\r\nDMA DATA:\r\n "); 38 USART1->CR3=1<<7; //使能串口1的DMA發送 39 MYDMA_Enable(DMA1_Channel4);//開始一次DMA傳輸! 40 //等待DMA傳輸完成,此時我們來做另外一些事,點燈 41 //實際應用中,傳輸數據期間,可以執行另外的任務 42 while(1) 43 { 44 if(DMA1->ISR&(1<<13))//等待通道4傳輸完成 45 { 46 DMA1->IFCR|=1<<13;//清除通道4傳輸完成標誌 47 break; 48 } 49 pro=DMA1_Channel4->CNDTR;//得到當前還剩餘多少個數據 50 pro=1-pro/((TEXT_LENTH+2)*100);//得到百分比 51 pro*=100; //擴大100倍 52 LCD_ShowNum(60,170,pro,3,16); 53 } 54 LCD_ShowNum(60,170,100,3,16);//顯示100% 55 LCD_ShowString(60,150,200,16,16,"Transimit Finished!");//提示傳送完成 56 } 57 i++; 58 delay_ms(10); 59 if(i==20) 60 { 61 LED0=!LED0;//提示系統正在運行 62 i=0; 63 } 64 } 65 }main.c