DMA+USART双缓冲区收发,妈妈再也不用担心丢包(附GD32L233源码)

本文介绍了如何在GD32L233X单片机上使用DMA和USART进行高波特率(921600bps)的双缓冲区收发,涉及自定义printf日志、串口空闲和DMA完成中断处理,以及DMA通道的配置和中断管理。
摘要由CSDN通过智能技术生成

DMA+USART双缓冲区收发 波特率可达921600( 以GD32L233X为例)

基本配置

#define USART_DMA_TX_BUF_LEN (128)
#define USART1_RX_BUF_LEN (130)

void USART1_Init(uint32_t baudrate)
{
    // initialize the com
    com_usart_init(baudrate);
    // configure DMA ch0 and ch1
    dma_usart_init();
}

static void com_usart_init(uint32_t baudrate)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);

    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USART TX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);

    /* connect port to USART RX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);

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

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

    /* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, baudrate);
    usart_word_length_set(USART1, USART_WL_8BIT);
    usart_parity_config(USART1, USART_PM_NONE);
    usart_stop_bit_set(USART1, USART_STB_1BIT);
    usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
    usart_data_first_config(USART1, USART_MSBF_LSB);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    /*USART enable*/
    usart_interrupt_enable(USART1, USART_INT_IDLE);
    nvic_irq_enable(USART1_IRQn, 2);
    usart_enable(USART1);
}
static void dma_usart_init(void)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel 2 */
    rcu_periph_clock_enable(RCU_DMA);
    dma_deinit(DMA_CH2);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request = DMA_REQUEST_USART1_TX;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = NULL;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = (uint32_t)USART1_TDATA_ADDRESS;
    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_CH2, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH2);
    dma_memory_to_memory_disable(DMA_CH2);
    /* disable the DMAMUX_MUXCH2 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH2);

    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);

    /* initialize DMA channel 1 */
    dma_deinit(DMA_CH1);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request = DMA_REQUEST_USART1_RX;
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = NULL;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = (uint32_t)USART1_RDATA_ADDRESS;
    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_enable(DMA_CH1);
    dma_memory_to_memory_disable(DMA_CH1);
    /* disable the DMAMUX_MUXCH1 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH1);
    /* USART DMA enable for reception */
    usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
    nvic_irq_enable(DMA_Channel1_IRQn, 0);
}

自写printf debuglog

自己写了个类似printf的串口发送,在Xcom里换行尾部加 \ r\ n


void usart_dma_printf(char* fmt, ...)
{
    char* str = (char*)malloc(200);
    memset(str, 0, 200);
    va_list ap;
    va_start(ap, fmt);
    vsprintf(str, fmt, ap);
    va_end(ap);

    uint8_t byte_size = 0;
    while(str[byte_size] != '\0')byte_size++;

    uart1_interface_send((uint8_t*)str, byte_size);

    //free str
    free(str);
    str = NULL;
}

uint32_t uart1_interface_send(uint8_t* data, uint16_t len)
{
    static volatile uint8_t uart1_lock = 0;
    static uint8_t  uart1_send_buf[USART_DMA_TX_BUF_LEN];
    static uint16_t count, send_len;

    while(uart1_lock)//多线程访问时会上锁
    {
        ;
    }

    uart1_lock = 1;

    count = 0;
    while(count < len)//若len>USART_DMA_TX_BUF_LEN,进行多包发送
    {
        while(DMA_CHCNT(DMA_CH2))//等待一次发送完成
        {
            ;
        }

        if(len - count > USART_DMA_TX_BUF_LEN)
        {
            send_len = USART_DMA_TX_BUF_LEN;
        }
        else
        {
            send_len = len - count;
        }

        memcpy(uart1_send_buf, data + count, send_len);
        dma_channel_disable(DMA_CH2);
        dma_memory_address_config(DMA_CH2, (uint32_t)&uart1_send_buf[0]);
        dma_transfer_number_config(DMA_CH2, send_len);
        dma_channel_enable(DMA_CH2);
        count += send_len;
    }

    uart1_lock = 0;

    return 0;
}

以及printf重定向

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE* f)
{
    usart_data_transmit(USART1, (uint8_t)ch);
    while(RESET == usart_flag_get(USART1, USART_FLAG_TBE))
        ;
    return ch;
}

串口空闲中断+dma完成中断,双缓冲区接收

在这里插入图片描述

uint8_t usart1_rx_flag;
uint8_t usart1_rx_buf[2][USART1_RX_BUF_LEN];
void USART1_IRQHandler(void)
{
    if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE))
    {
        static uint16_t this_time_rx_len = 0;
        // clear flag
        usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
        /* enable DMA channel 0 transfer complete interrupt */
        dma_interrupt_disable(DMA_CH1, DMA_INT_FTF);//必须先关dma中断在关dma
        dma_channel_disable(DMA_CH1);
        dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_FTF);//清标志位

        this_time_rx_len = USART1_RX_BUF_LEN - dma_transfer_number_get(DMA_CH1);;
        dma_transfer_number_config(DMA_CH1, USART1_RX_BUF_LEN);

        if(this_time_rx_len == 0)//满了触发完成中断
        {
            dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
            dma_channel_enable(DMA_CH1);
            return;
        }

        dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
        if(usart1_rx_flag)
        {
            dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[0]);
            dma_channel_enable(DMA_CH1);
            usart1_rx_flag = 0;

        }
        else
        {
            dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[1]);
            dma_channel_enable(DMA_CH1);
            usart1_rx_flag = 1;
        }
    }
}
void DMA_Channel1_IRQHandler(void)
{
    if(RESET != dma_interrupt_flag_get(DMA_CH1, DMA_INT_FLAG_FTF))
    {
        /*disable and clear flag */
        dma_channel_disable(DMA_CH1);
        dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_FTF);
        dma_transfer_number_config(DMA_CH1, USART1_RX_BUF_LEN);

        if(usart1_rx_flag)
        {
            dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[0]);
            dma_channel_enable(DMA_CH1);
 
            usart1_rx_flag = 0;
        }
        else
        {
            dma_memory_address_config(DMA_CH1, (uint32_t)&usart1_rx_buf[1]);
            dma_channel_enable(DMA_CH1);
            usart1_rx_flag = 1;
            
        }
    }
}
  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值