Implementation of STM32F4 serial port dma+ ring buffer

Source: Internet
Author: User
Tags abstract reserved
The following is the implementation of the serial port dma+ ring buffer, the data transmit and receive is asynchronous, do not need death.
about ring Buffers reference:

http://blog.csdn.net/jieffantfyan/article/details/53572103 Implementation Principle

The program is designed on the basis of the serial interrupt sending and receiving mode, and the application layer is read through the ring buffer, and the ring buffer is the first level buffer, and the DMA is increased as level two cache. Relative interrupt mode This design can reduce the number of serial ports entering the interrupt, especially in the case of high-speed baud rate. Since the use of DMA to send and receive data, you must preset the sending/receiving address, length and other information, the software for DMA opened 16 byte array as a buffer. When there is data in the Send ring buffer to send, the program copies the first 16 bytes (if insufficient copy the actual length and reset the DMA send length) to the DMA send buffer and initiates the send, after the data is sent, the remaining data is copied to the DMA send buffer in the same way until the data is sent. For receiving, processing is more cumbersome than sending, requiring two interrupt service programs to mate, and when the DMA receives 16 bytes, the software writes the data to the receive ring buffer for the application to read. Because the DMA receive cache length is set to 16 bytes in the software, that is, the DMA must receive 16 bytes continuously to enter the interrupt service program, but in most cases the length of the data received cannot be a multiple of 16 bytes, for example, the MCU receives only 10 bytes for a period of time and no longer receive data. For this case can use timer Mate detection, once found that the long time to receive the serial port data will be the DMA received buffer data are all extracted. Since the STM32 SCM provides idle interrupt, we can use this mechanism to solve the above problem, when the idle interrupt is generated, it means that no data has been received, this time the DMA receive buffer data extracted. external Interface Declaration

The following is the initialization of the serial port, read, write interface abstraction out.

/****************************************************************************** * Copyright (C), Roger * All
 Rights reserved. * File name: Tty.h * Abstract: Console driver * Current version: 3.0 * Author: Roger * Completion Date: 2016-09-24 * * superseded version Ben: 2.0 * Original Author: Roger * Completion date: 2015-07-08 ****************************************************************************** /#ifndef _tty_h_ #define _TTY_H_ #define TTY_BAUDRATE 115200/* baud rate------------*/#define                       Tty_txbuf_size 256/* Send buffer length-----*/#define TTY_RXBUF_SIZE 256        /* Receive buffer length-----*/#define Tty_dma_tx_len/*DMA Send buffer----*/#define Tty_dma_rx_len /*DMA Receive buffer----*/#define TTY_USE_DMA 1/* Enable DMA----------- */* Exported Structs---------------------------------------------------------*/typedef struct {void (*init) (void);     /* Initialize--------*/unsigned int (*write) (void *buf, unsigned int len);     /* Data Write--------*/unsigned int (*read) (void *buf, unsigned int len);                          /* Read Data--------*/void (*puts) (const char *STR);                                      /* Enter a String */void (*CLR) (void);                           /* Clear the Receive buffer */unsigned int (*buflen) (void);                /* The length of the receive buffer */void (*printf) (const char *format, ...);


/* Format Print----*/}tty_t;


/* Exported Variables-------------------------------------------------------*/extern const tty_t TTY;  
 #endif
Interface Implementation # # '
/****************************************************************************** * Copyright (C), Roger * All
 Rights reserved. * File name: TTY.C * Abstract: Print serial Drive * * Current version: 3.0 * Author: Roger * Completion Date: 2016-09-24 * * Replace Version: 2.0 * Original Author: Roger * Completion date: 2015-07-08 ***************************************************************************** */* Includes------------------------------------------------------------------*/#include "tty.h" #include "

Ringbuffer.h "#include" stm32f4xx.h "#include <stdarg.h> #include <stdio.h> #include <string.h>         static unsigned char rxbuf[tty_txbuf_size];         /* Receive buffer------------*/static unsigned char txbuf[tty_rxbuf_size];       /* Send buffer------------*/static ring_buf_t ringbuf_send, RINGBUF_RECV;
    /* Transmit Buffer management---------*/#if TTY_USE_DMA = = 1 static unsigned char DMA_TX_BUF[TTY_DMA_TX_LEN];/*DMA send buffer---------*/ Static unsigned char DMA_RX_BUF[TTY_DMA_RX_LEN];/*DMA receive buffer---------*/      
#endif/******************************************************************************* * Function Name: port_conf * Function Description: Print serial configuration (PD8-&GT;USART3_TX, PD9-&GT;USART3_RX) * Input parameters: None * return value: None * Author: Roger.luo ***************************** /static void port_conf (void) {Gpio_inittypedef gpio_initstructure
    ; /*console Serial PIN Configuration----------------------------------------------------*/Rcc_ahb1periphclockcmd (rcc_ahb1periph_
    Gpiod, ENABLE);
    Gpio_pinafconfig (Gpiod, Gpio_pinsource8, GPIO_AF_USART3);
    Gpio_pinafconfig (Gpiod, Gpio_pinsource9, GPIO_AF_USART3);
    Gpio_initstructure.gpio_pin = Gpio_pin_8;
    Gpio_initstructure.gpio_mode = GPIO_MODE_AF;
    Gpio_initstructure.gpio_speed = Gpio_speed_50mhz;
    GPIO_INITSTRUCTURE.GPIO_PUPD = gpio_pupd_up;    
    Gpio_initstructure.gpio_otype = gpio_otype_pp;  
    Gpio_init (Gpiod, &gpio_initstructure);
    Gpio_initstructure.gpio_pin = Gpio_pin_9; Gpio_init (Gpiod, &AMP;GPIo_initstructure); }/******************************************************************************* * Function name: DMA_Conf * Function Description: Serial DMA configuration ( DMA1_CHANNEL4_STREAM1-&GT;USART3_RX, * dma1_channel4_stream3->usart3_tx) * input parameter: None * return value: N One * Author: roger.luo ******************************************************************************/#if TTY_USE_DMA =
    = 1 static void dma_conf (void) {dma_inittypedef dma_structure;

    Nvic_inittypedef nvic_initstructure;    
    /* Enable DMA clock */Rcc_ahb1periphclockcmd (RCC_AHB1PERIPH_DMA1, enable);
    Dma_deinit (DMA1_STREAM1);
    Dma_deinit (DMA1_STREAM3);  while (Dma_getcmdstatus (dma1_stream1)! = DISABLE) {} while (Dma_getcmdstatus (DMA1_STREAM3)! = DISABLE) {}/* Configure serial 3 receive stream                    */Dma_structure.dma_channel = Dma_channel_4;
    /*DMA1 Channel 4*/dma_structure.dma_peripheralbaseaddr = (uint32_t) (&AMP;USART3-&GT;DR);
    Dma_structure.dma_memory0baseaddr = (uint32_t) dma_rx_buf; Dma_structUre.           Dma_dir = dma_dir_peripheraltomemory;
    /* Peripheral to memory */dma_structure.dma_buffersize = sizeof (DMA_RX_BUF);
    Dma_structure.dma_peripheralinc = dma_peripheralinc_disable;
    Dma_structure.dma_memoryinc = dma_memoryinc_enable;
    Dma_structure.dma_peripheraldatasize = Dma_peripheraldatasize_byte;
    Dma_structure.dma_memorydatasize = Dma_memorydatasize_byte;                   Dma_structure.dma_mode = Dma_mode_circular;
    /* Cycle mode */dma_structure.dma_priority = Dma_priority_low;         
    Dma_structure.dma_fifomode = dma_fifomode_disable;
    Dma_structure.dma_fifothreshold = Dma_fifothreshold_full;
    Dma_structure.dma_memoryburst = Dma_memoryburst_single;
    Dma_structure.dma_peripheralburst = Dma_peripheralburst_single; 

    Dma_init (dma1_stream1, &dma_structure);
    /* Configure serial Port 3 Send stream */dma_structure.dma_peripheralbaseaddr = (uint32_t) (&AMP;USART3-&GT;DR);
    Dma_structure.dma_memory0baseaddr = (uint32_t) dma_tx_buf; Dma_structure.dma_dir = Dma_dir_memorYtoperipheral;
    /* Memory to peripherals */dma_structure.dma_buffersize = sizeof (DMA_TX_BUF);                      Dma_structure.dma_mode = Dma_mode_normal; 

    /* Normal mode-*/dma_init (DMA1_STREAM3, &dma_structure);    
    /* Enable DMA Stream Transfer Complete Interrupt */Dma_itconfig (DMA1_STREAM1, DMA_IT_TC, enable);
    Dma_itconfig (DMA1_STREAM3, DMA_IT_TC, ENABLE);                                 /* DMA Stream Enable */Dma_cmd (dma1_stream1, enable);
    /* Enable receive stream */* enable the DMA stream IRQ Channel */nvic_initstructure.nvic_irqchannel = DMA1_STREAM1_IRQN;
    nvic_initstructure.nvic_irqchannelpreemptionpriority = 1;
    nvic_initstructure.nvic_irqchannelsubpriority = 1;
    Nvic_initstructure.nvic_irqchannelcmd = ENABLE;  
    Nvic_init (&nvic_initstructure);
    nvic_initstructure.nvic_irqchannelpreemptionpriority = 0;
    Nvic_initstructure.nvic_irqchannel = DMA1_STREAM3_IRQN;  
Nvic_init (&nvic_initstructure); } #endif/*********************** Function Name: uart_conf * Function Description: TTY serial configuration * Input parameters: None * return value: None * Author: roger.luo ******************************************************************************/static void uart_conf
(void)
    {Usart_inittypedef usart_initstructure;
    Nvic_inittypedef nvic_initstructure;
    Usart_deinit (USART3);
    Rcc_apb1periphclockcmd (Rcc_apb1periph_usart3, ENABLE);  
    Usart_initstructure.usart_baudrate = tty_baudrate;
    Usart_initstructure.usart_wordlength = usart_wordlength_8b;
    Usart_initstructure.usart_stopbits = Usart_stopbits_1;
    usart_initstructure.usart_parity = Usart_parity_no;
    Usart_initstructure.usart_hardwareflowcontrol = Usart_hardwareflowcontrol_none; Usart_initstructure.usart_mode = Usart_mode_rx |
    Usart_mode_tx;

    Usart_init (USART3, &usart_initstructure);
    Nvic_initstructure.nvic_irqchannel = USART3_IRQN;
    nvic_initstructure.nvic_irqchannelpreemptionpriority = 0; Nvic_initstructure.nvic_irqchannelsubpriority = 0;
    Nvic_initstructure.nvic_irqchannelcmd = ENABLE; 

    Nvic_init (&nvic_initstructure); Ring_buf_create (&ringbuf_send, Txbuf, sizeof (TXBUF));/* Initialize the ring buffer--*/ring_buf_create (&AMP;RINGBUF_RECV, Rxbuf,     

sizeof (RXBUF));         #if TTY_USE_DMA = = 1 Usart_dmacmd (usart3,usart_dmareq_rx,enable);   
    /* Turn on DMA request--------*/Usart_dmacmd (usart3,usart_dmareq_tx,enable);       Usart_itconfig (USART3, Usart_it_idle, ENABLE);
/* Open idle Interrupt processing DMA receive-------*/#else Usart_itconfig (USART3, Usart_it_rxne, ENABLE);    
    #endif usart_itconfig (USART3, Usart_it_err, ENABLE);    
Usart_cmd (USART3, ENABLE); }/******************************************************************************* * Function name: init * Function Description: Print driver initialization * Input parameters: None * return value: None * Author: Roger.luo ******************************************************************************/St
    atic void init (void) {port_conf ();
Uart_conf (); #if TTY_USE_DMA = = 1 DMa_conf (); #endif}/******************************************************************************* * Function name: Send * Function Description: to the serial port
 Write data in Send buffer * input parameters: buf-buffer * Len-buffer length * return value: Actual write Length (if the buffer is full at this time, Len) * Author: Roger.luo /static unsigned int send (void *buf,
    unsigned int len) {#if TTY_USE_DMA = = 1 unsigned int ret;  
    ret = Ring_buf_put (&ringbuf_send, buf, Len);  
    Usart_itconfig (USART3, USART_IT_TC, ENABLE);
return ret;
    #else unsigned int ret;       
    ret = Ring_buf_put (&ringbuf_send, (unsigned char *) buf, Len);    
    Usart_itconfig (USART3, Usart_it_txe, ENABLE);        
return ret; #endif}/******************************************************************************* * Function name: recv * Function Description: Read TTY connection            Data from buffer * Input parameters: buf-buffer * Len-buffer length * return value: (actual read length) returns Len if the valid data for the receive buffer is greater than Len otherwise returns the buffer * The length of valid data in the zoneDegree * Author: roger.luo ******************************************************************************/unsigned int recv (v

OID *buf, unsigned int len) {return Ring_buf_get (&AMP;RINGBUF_RECV, (unsigned char *) buf, len);} #if TTY_USE_DMA = = 1/******************************************************************************* * Function name: DMA1_ Stream1_irqhandler * Function Description: TTY serial DMA receive complete interrupt * input parameter: None * return value: None **************************************************** /void Dma1_stream1_irqhandler (void) {if (Dma_getitstatus (DMA1_STREAM1, dma_it_tcif1)! = RE
        SET) {ring_buf_put (&ringbuf_recv, Dma_rx_buf, sizeof (DMA_RX_BUF));
    Dma_clearitpendingbit (dma1_stream1, DMA_IT_TCIF1); }}/******************************************************************************* * Function name: DMA1_Stream3_ Irqhandler * Function Description: TTY serial DMA send complete interrupt * input parameter: None * return value: None ************************************************************ //*void dma1_sTream3_irqhandler (void) {unsigned int len;   
        if (Dma_getitstatus (DMA1_STREAM3, dma_it_tcif3)! = RESET) {dma_clearitpendingbit (dma1_stream3, DMA_IT_TCIF3);                
            if (len = Ring_buf_get (&ringbuf_send, Dma_tx_buf, sizeof (DMA_TX_BUF)))) {        
            Dma_setcurrdatacounter (DMA1_STREAM3, Len);
            Dma_cmd (DMA1_STREAM3, ENABLE);
        Usart_dmacmd (usart3,usart_dmareq_tx,enable);
    } else sending = 0; }}*/#endif/******************************************************************************* * Function Name: USART3_IRQHand Ler * Function Description: Serial 1 Transmit/Receive interrupt * input parameter: None * return value: None **************************************************************************
    /void Usart3_irqhandler (void) {#if TTY_USE_DMA = = 1 uint16_t len, retry = 0; 
        if (Usart_getitstatus (USART3, usart_it_idle)! = RESET | | Usart_getitstatus (USART3, usart_it_fe)! = RESET) {/* Gets the valid data length within the DMA buffer--------------------------------------*/len = sizeof (DMA_RX_BUF)-Dma_getcurrdatacounter (DMA1_STREAM1);  
        Dma_cmd (dma1_stream1, DISABLE);    Ring_buf_put (&ringbuf_recv,dma_rx_buf, Len); /* Put data into the receive buffer */while (Dma_getcmdstatus (dma1_stream1)! = DISABLE && retry++ < 100) {}/* reset DM A current counter value------------------------------------------------*/dma_setcurrdatacounter (dma1_stream1, sizeof (dma_rx_buf
        ));         
        Dma_cmd (dma1_stream1, ENABLE);    Dma_clearflag (dma1_stream1, DMA_FLAG_TCIF1);                               /* Clear the transmit finish flag, otherwise it will enter the transfer complete interrupt */len = usart3->dr; /* Clear the Interrupt flag-------*/} if (Usart_getitstatus (USART3, USART_IT_TC)! = RESET) {if (len = Ring_buf_get ( 
            &ringbuf_send, Dma_tx_buf, sizeof (DMA_TX_BUF))) {Dma_cmd (dma1_stream3, DISABLE);
            Dma_clearflag (DMA1_STREAM3, DMA_FLAG_TCIF3);       Dma_setcurrdatacounter (DMA1_STREAM3, Len); 
            Dma_cmd (DMA1_STREAM3, ENABLE);       
        } else {usart_itconfig (USART3, USART_IT_TC, DISABLE);
    }} #else unsigned char data;
        if (Usart_getitstatus (USART3, usart_it_rxne)! = RESET) {data = Usart_receivedata (USART3);           Ring_buf_put (&ringbuf_recv,&data, 1); /* Put data into the receive buffer */} if (Usart_getitstatus (USART3, usart_it_txe)! = RESET) {if (Ring_buf_get (&ring            
 Buf_send, &data, 1)/* Remove the data from the buffer---*/{usart_senddata (USART3, data);

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.