4135 views|0 replies

538

Posts

3

Resources
The OP
 

[GD32L233C-START Review] 4. USART uses idle interrupts and DMA to receive data of variable length [Copy link]

For serial port data reception, there are many occasions where it is necessary to receive data of indefinite length. It would be very troublesome to receive indefinite length data only through receiving interrupt.

Fortunately, the USART of GD32's L233 MCU provides an idle interrupt function.

Idle interrupt combined with DMA reception is a very classic method for receiving variable-length data, and it is also a very basic and commonly used method.

The basic idea:

1. Ensure that a frame of data is received through idle interrupt

2. Get the length of the received data through DMA.

3. Get data of specified length from the buffer for application processing

Regarding DMA, it may be a little different from what we used before. I didn’t find a correspondence table between peripherals and DMA channels.

Directly use DMA channel 1 as the receiving channel of USART and find that it can be used normally.

The example program also provides an example of combining DMA in idle mode, and the example program uses USART1.

With a little modification, it can be changed to other USARTs.

This time I will use USART0 to implement the DMA receiving function in idle.

USART0 is directly brought out through the UART to USB interface on the development board hardware, and only one USB cable is needed to communicate with the PC.

The pins used are PA9 (TX), PA10 (RX)

as follows:

The program is mainly divided into several parts:

1. Initialization of usart0: pin configuration, enable sending and receiving, enable idle interrupt, etc.;

2. Receive DMA configuration

3. Configuration of idle interrupt

4. Implementation of interrupt handling function of usart0

details as follows:

1. Initialization of usart0:

void uart0_init(void)
{
		nvic_irq_enable(USART0_IRQn, 0);
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* connect port to USART TX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
    /* connect port to USART RX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    /* configure USART TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);

    /* configure USART RX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);

    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_dma_receive_config(USART0, USART_DENR_ENABLE);
    //usart_dma_transmit_config(USART1, USART_DENT_ENABLE);
    usart_enable(USART0);	
}

2. Receive DMA configuration:

void uart0_dma_init(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* initialize DMA channel 1 */
    dma_deinit(DMA_CH1);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART0_RX;
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr  = (uint32_t)usart0_rec_buf;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = UART0_DMA_REC_LEN;
    dma_init_struct.periph_addr  = (uint32_t)&USART_RDATA(USART0);
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH1, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH1);
    dma_memory_to_memory_disable(DMA_CH1);
    /* disable the DMAMUX_MUXCH1 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH1);

    /* enable DMA channel 1 */
    dma_channel_enable(DMA_CH1);
}

3. Configuration of idle interrupt:

void uart0_idle_init(void)
{
    /*wait IDLEF set and clear it*/
    while(RESET == usart_flag_get(USART0, USART_FLAG_IDLE)) {
    }
    usart_flag_clear(USART0, USART_FLAG_IDLE);
    usart_interrupt_enable(USART0, USART_INT_IDLE);	
}

4. Implementation of interrupt handling function of usart0:

void USART0_IRQHandler(void)
{
    if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)){
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);

        /* number of data received */
        Usart0RecLen = UART0_DMA_REC_LEN - (dma_transfer_number_get(DMA_CH1));
        memcpy(usart0_rec_pro_buf,usart0_rec_buf,Usart0RecLen);
        usart0_rec_comp_flag = 1;

        /* disable DMA and reconfigure */
        dma_channel_disable(DMA_CH1);
        dma_transfer_number_config(DMA_CH1, UART0_DMA_REC_LEN);
        dma_channel_enable(DMA_CH1);
		}
}

Compile, download, debug:

The serial port assistant sends 1234:

The above tests achieved the expected results!

The source code is as follows:

gd_finger.zip (606.14 KB, downloads: 73)

This post is from GD32 MCU
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list