Lesson23 DMA操作
这里是一个最简单的DMA传输的例子。DMA包括:
外设到存储器,存储器到外设,存储器到存储器之间的传输。传输的通道和数据流是有限定的,可查看数据手册的通道分配表格确定。
具体的工程见D:\02 Learn\02 UC_OS\mypro\Lesson 23 DMA
//我们采用的是存储器到外设UART1的传输.只能选择DMA2的通道7.根据数据手册的DMA章节的通道表格 //DMA_Streamx: 数据流 DMA1_Stream0~7/DMA2_Stream0~7 //chx:通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7 //par:外设地址 //mar:存储器地址· //ndtr:传输数据个数 void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr) { DMA_InitTypeDef myDMA; //判断是哪个通道,使能相应的时钟 if((u32)DMA_Streamx>(u32)DMA2) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); else RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); // myDMA.DMA_BufferSize=ndtr; //DMA_SxNDTR[15:0] 数据传输量,只有禁止传输的时候,才能写入。启动传输后,表示剩余数据量 myDMA.DMA_Channel= DMA_Channel_4; //DMA_SxCR[27:25] 通道选择 myDMA.DMA_DIR=DMA_DIR_MemoryToPeripheral; //DMA_SxCR[7:6] 传输方向 存储器到外设 myDMA.DMA_FIFOMode=DMA_FIFOMode_Disable; //DMA_SxFCR[2] 使能直接模式 myDMA.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;//DMA_SxFCR[1:0] 使用直接模式,这个配不配都可以 myDMA.DMA_Memory0BaseAddr=mar; // DMA_SxM0AR[] 存储器地址 myDMA.DMA_MemoryBurst=DMA_MemoryBurst_Single; // DMA_SxCR[24:23] 突发传输配置 myDMA.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//DMA_SxCR[14:13] 存储器数据大小 myDMA.DMA_MemoryInc=DMA_MemoryInc_Enable; //DMA_SxCR[10] 存储器地址递增 myDMA.DMA_Mode= DMA_Mode_Normal ; //DMA_SxCR[8] 禁止循环模式 myDMA.DMA_PeripheralBaseAddr=par; //外设地址 DMA_SxPAR myDMA.DMA_PeripheralBurst= DMA_PeripheralBurst_Single; ////DMA_SxCR[22:21] 外设突发配置 myDMA.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; //DMA_SxCR[12:11] 外设数据大小 myDMA.DMA_PeripheralInc= DMA_PeripheralInc_Disable; //DMA_SxCR[9] 外设地址固定 myDMA.DMA_Priority= DMA_Priority_Medium;//中等优先级 DMA_SxCR[17:16] DMA_Init(DMA_Streamx, &myDMA); //初始化 } // 完成一次传输 void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) { DMA_Cmd(DMA_Streamx,DISABLE); //关闭DMA传输 DMA_SxCR[0] EN位 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //重新读EN位,确保关闭 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //DMA_SxNDTR[15:0] 关闭后才能配置传输数量 DMA_Cmd(DMA_Streamx,ENABLE); //使能 }
1
2
3
#define SEND_BUF_SIZE 8200 //传输的数据量 u8 SendBuff[SEND_BUF_SIZE]; // 开一个RAM空间 const u8 TEXT_TO_SEND[]={"123456789abcde"}; int main(void) { u8 b; u16 i; u8 t=0; u8 j,mask=0; float pro=0;// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// delay_init(168); // uart_init(115200); // LED_Init(); // LCD_Init(); // KEY_Init(); // MYDMA_Config(DMA2_Stream7,DMA_Channel_4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA2,STEAM7,CH4,串口1 //把开辟的RAM空间填满 j=sizeof(TEXT_TO_SEND)+1; for(i=0;i<SEND_BUF_SIZE;i++) { b= i% j; if(b==j-2) SendBuff[i]=0x0d; if(b==j-1) SendBuff[i]=0x0a; if(b<j-2) SendBuff[i]=TEXT_TO_SEND[b]; } i=0; while(1) { t=KEY_Scan(0); if(t==KEY0_PRES) { printf("start to transfer date from ram to uart by DMA\r\n"); USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //配置串口的CR3寄存器,这个很重要,让串口支持DMA MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE); while(1) { if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET) //等待传输结束 { DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7); //结束后要清除标志位 break; } pro=DMA_GetCurrDataCounter(DMA2_Stream7); pro=1-pro/SEND_BUF_SIZE; pro=pro*100; //delay_ms(20); //printf("have already transfer %f percent data",pro); } printf("\r\n transfer finish"); } }