stm32f091rc 使用 rt-thread时UART串口的阻塞问题

1. 问题描述

在项目中用到了两个串口uart4和uart6,在使用uart6发送数据的时候会阻塞,猜想应该是驱动的问题,所以接下来进行分析

2. 分析过程

先分析串口驱动,关于串口驱动这部分的架构不再赘述,我们看下源文件,在发送的地方看到了一处while循环读取串口发送完成寄存器的代码

while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET);

在这里插入图片描述
在整个发送数据的过程中也只有这处可能阻塞,这块阻塞的话肯定是在别处有清这个中断的动作,还是继续在这个驱动文件继续找线索

我们知道 F091 这个芯片的 UART3~UART8 用的是同一个中断入口函数,我使用的UART4主要是用来接收数据的,在测试的时候也发现关闭UART4就不会引起UART6发送的阻塞,所以从中断这块看起

在这里插入图片描述
USART3_8_IRQHandler 这个是我后期加入的rt-thread并没有实现这块的代码,我们接着分析uart_isr这个中断处理函数,在里面发现了有清除UART_FLAG_TC 这个状态寄存器的动作,按道理来说这个中断应该在发送前清除就可以了,而且这个芯片多个串口共用一个中断入口函数,很有可能是别的串口触发中断的时候误清除了这个寄存器,导致UART6在发送的时候阻塞

以下是这个中断处理函数的代码,我们可以简单的分析下
第一个if是判断是否有数据接收
在这里插入图片描述
下面的else if 是判断空闲中断的,这块一般是配合DMA来用的
在这里插入图片描述
再往下的一个 else if 是判断发送完成状态寄存器的,并在里面做了清除中断的处理,由于UART6和别的串口共用一个串口入口函数,也就是说,在别的串口产生中断的话,也会进来这个函数,那么这时候上面两个if条件UART6肯定不成立,但是正好到第三个条件的时候如果UART6这时候在发送数据的话就有可能会成立,并且在这里把UART_FLAG_TC这个中断清除了,等中断退出后,UART6 读这个已经被清除过的寄存器条件就始终成立,导致了发送阻塞,我的 UART4 接受数据的频率比较多这个问题容易复现出来,如果是数据少的话,这个问题还很难被发现

static void uart_isr(struct rt_serial_device *serial)
{
    
    
    struct stm32_uart *uart;
#ifdef RT_SERIAL_USING_DMA
    rt_size_t recv_total_index, recv_len;
    rt_base_t level;
#endif

    RT_ASSERT(serial != RT_NULL);
    uart = rt_container_of(serial, struct stm32_uart, serial);

    /* UART in mode Receiver -------------------------------------------------*/
    if ((__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET) &&
            (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_RXNE) != RESET))
    {
    
    
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
    }
#ifdef RT_SERIAL_USING_DMA
    else if ((uart->uart_dma_flag) && (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_IDLE) != RESET)
             && (__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_IDLE) != RESET))
    {
    
    
        level = rt_hw_interrupt_disable();
        recv_total_index = serial->config.bufsz - __HAL_DMA_GET_COUNTER(&(uart->dma_rx.handle));
        recv_len = recv_total_index - uart->dma_rx.last_index;
        uart->dma_rx.last_index = recv_total_index;
        rt_hw_interrupt_enable(level);

        if (recv_len)
        {
    
    
            rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
        }
        __HAL_UART_CLEAR_IDLEFLAG(&uart->handle);
    }
    else if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) != RESET)
    {
    
    
        if ((serial->parent.open_flag & RT_DEVICE_FLAG_DMA_TX) != 0)
        {
    
    
            HAL_UART_IRQHandler(&(uart->handle));
        }
        else
        {
    
    
           //UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
        }
    }
#endif
    else
    {
    
    
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_ORE) != RESET)
        {
    
    
            __HAL_UART_CLEAR_OREFLAG(&uart->handle);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_NE) != RESET)
        {
    
    
            __HAL_UART_CLEAR_NEFLAG(&uart->handle);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_FE) != RESET)
        {
    
    
            __HAL_UART_CLEAR_FEFLAG(&uart->handle);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_PE) != RESET)
        {
    
    
            __HAL_UART_CLEAR_PEFLAG(&uart->handle);
        }
#if !defined(SOC_SERIES_STM32L4) && !defined(SOC_SERIES_STM32F7) && !defined(SOC_SERIES_STM32F0) \
    && !defined(SOC_SERIES_STM32L0) && !defined(SOC_SERIES_STM32G0) && !defined(SOC_SERIES_STM32H7) \
    && !defined(SOC_SERIES_STM32G4)
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_LBD) != RESET)
        {
    
    
            UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_LBD);
        }
#endif
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_CTS) != RESET)
        {
    
    
            UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_CTS);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TXE) != RESET)
        {
    
    
            UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TXE);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) != RESET)
        {
    
    
            //UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
        }
        if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET)
        {
    
    
            UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_RXNE);
        }
    }
}

3. 问题解决

我们把这块代码注释掉UART6阻塞的问题就不存在了,而且在发送之前都是会清中断的,这块代码也确实没用,所以在使用别人的代码的时候还是要多做测试时,要分析源代码,要不然挖出来的坑只能自己来填

猜你喜欢

转载自blog.csdn.net/gmq_syy/article/details/108381854