STM32 's serial port DMA transceiver and the implementation of the double buffer

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.