The DMA functionality of the UART using STM32 is summarized below:
First on the code, here the STM32 USART1 as the Demo,rx DMA for the DMA1_CHANNEL5,TX DMA is dma1_channel4. Initialize as follows, red flags need to be noted:
RX-DMA initialization
1 //DMA Rx2 Usart_dmacmd (usart1,usart_dmareq_rx,enable); 3 Dma_cmd (dma1_channel5,disable);4Dma_initstruct.dma_peripheralbaseaddr = (u32) (&USART1->DR);5DMA_INITSTRUCT.DMA_MEMORYBASEADDR =(u32) RxBuf0;6Dma_initstruct.dma_dir =dma_dir_peripheralsrc;7Dma_initstruct.dma_buffersize =Ten;8Dma_initstruct.dma_peripheralinc =dma_peripheralinc_disable;9Dma_initstruct.dma_memoryinc =dma_memoryinc_enable;TenDma_initstruct.dma_peripheraldatasize =Dma_peripheraldatasize_halfword; OneDma_initstruct.dma_memorydatasize =Dma_peripheraldatasize_byte; A dma_initstruct.dma_mode = dma_mode_circular; -Dma_initstruct.dma_priority =Dma_priority_high; -DMA_INITSTRUCT.DMA_M2M =dma_m2m_disable; theDma_init (dma1_channel5,&dma_initstruct); - Dma_cmd (dma1_channel5,enable);
The initialization of interrupts is as follows:
Dma_itconfig (dma1_channel5,dma_it_tc,enable); Nvic_initstruct.nvic_irqchannel=dma1_channel5_irqn; Nvic_initstruct.nvic_irqchannelpreemptionpriority=0; Nvic_initstruct.nvic_irqchannelsubpriority=0; Nvic_initstruct.nvic_irqchannelcmd=ENABLE; Nvic_init (&nvic_initstruct); //ENABLE DMA TX ISRDma_itconfig (dma1_channel4,dma_it_tc,enable); Nvic_initstruct.nvic_irqchannel=dma1_channel4_irqn; Nvic_initstruct.nvic_irqchannelpreemptionpriority=0; Nvic_initstruct.nvic_irqchannelsubpriority=2; Nvic_initstruct.nvic_irqchannelcmd=ENABLE; Nvic_init (&NVIC_INITSTRUCT);
The TX send function is as follows:
1 voidUSART1_SENDDMA (uint8_t* buf,intlen)2 {3 Dma_inittypedef dma_initstruct;
5 Dma_itconfig (dma1_channel4,dma_it_tc,enable);6 7 Dma_cmd (dma1_channel4,disable);
8 9Dma_initstruct.dma_peripheralbaseaddr = (u32) (&USART1->DR);TenDMA_INITSTRUCT.DMA_MEMORYBASEADDR =(u32) buf; OneDma_initstruct.dma_dir =DMA_DIR_PERIPHERALDST; ADma_initstruct.dma_buffersize = Len; -Dma_initstruct.dma_peripheralinc =dma_peripheralinc_disable; -Dma_initstruct.dma_memoryinc =dma_memoryinc_enable; theDma_initstruct.dma_peripheraldatasize =Dma_peripheraldatasize_halfword; -Dma_initstruct.dma_memorydatasize =Dma_peripheraldatasize_byte; -Dma_initstruct.dma_mode =Dma_mode_normal; -Dma_initstruct.dma_priority =Dma_priority_veryhigh; +DMA_INITSTRUCT.DMA_M2M =dma_m2m_disable; -Dma_init (dma1_channel4,&dma_initstruct); + A Dma_cmd (dma1_channel4,enable); at}
The two service functions are as follows:
RX-DMA Interrupt function to implement RX's dual buffer function. It is important to note that when your DMA is set to normal mode, you have to set dmabuffersize in the interrupt function, you should complete a transfer for normal mode, buffersize direct zeroing, set into circle mode will not exist this problem, The following interrupts are set to circle mode.
voidDma1_channel5_irqhandler () {if(Dma_getitstatus (DMA1_IT_TC5)) {if(using_buf0 = =0) {Dma1_channel5->cmar = (u32) RxBuf0; using_buf0=1; } Else{Dma1_channel5->cmar = (u32) RxBuf1; using_buf0=0;} recv_flag=1;dma_clearitpendingbit (DMA1_IT_TC5); } }
TX-DMA Interrupt function
void Dma1_channel4_irqhandler () { if(Dma_getitstatus (DMA1_IT_TC4)) { //todo: ADD codehere dma_clearitpendingbit (DMA1_IT_TC4); } }
A few notes
1) The use of a double buffer in this way, for the large amount of time is very effective, when processing a buffer data, another buffer can normally receive data
2) TX DMA interrupt, can be similar to the operation of the operating system mutex, when an array is still sent, another array if the detection of a send, it is not able to send, otherwise the child data will be confused;
3) If the DMA receives the way to adopt the circular buffer, the RX-DMA can be set directly to circle mode, then the data will automatically realize the function of the ring buffer on the hardware, save a lot of time.
4) When the DMA is in normal mode, when a task is completed, the dma->dma_buffersize automatically zero, and the DMA automatically stops. If you want to set the DMA buffersize again, you must do the following:
Step1:dma_cmd (dmax_channely,disable);
Step2: Set Dma_bufferlen
Step3:dma_cmd (dmax_channely,enable)
5) When the DMA is in circle mode, the buffersize is still saved after sending or receiving, and the DMA is in the enabled state, continuous operation until the user stops the DMA
STM32 's serial port DMA transceiver and the implementation of the double buffer