嵌入式技术william hill官网
直播中

安德森大

9年用户 1317经验值
擅长:接口/总线/驱动
私信 关注
[问答]

串口open参数对消息队列rt_mq_recv执行的影响线程假死如何解决?

我的环境是潘多拉开发板
DMA接收及轮询发送章节:
/*
* 程序清单:这是一个串口设备 DMA 接收使用例程
* 例程导出了 uart_dma_sample 命令到控制终端
* 命令调用格式:uart_dma_sample uart3
* 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
* 程序功能:通过串口输出字符串"hello RT-Thread!",并通过串口输出接收到的数据,然后打印接收到的数据。
*/
#include
#define SAMPLE_UART_NAME       "uart3"      /* 串口设备名称 */
/* 串口接收消息结构*/
struct rx_msg
{
    rt_device_t dev;
    rt_size_t size;
};
/* 串口设备句柄 */
static rt_device_t serial;
/* 消息队列控制块 */
static struct rt_messagequeue rx_mq;
/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    struct rx_msg msg;
    rt_err_t result;
    msg.dev = dev;
    msg.size = size;
    result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
    if ( result == -RT_EFULL)
    {
        /* 消息队列满 */
        rt_kprintf("message queue full!n");
    }
    return result;
}
static void serial_thread_entry(void *parameter)
{
    struct rx_msg msg;
    rt_err_t result;
    rt_uint32_t rx_length;
    static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];
    while (1)
    {
        rt_memset(&msg, 0, sizeof(msg));
        /* 从消息队列中读取消息*/
        result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
        if (result == RT_EOK)
        {
            /* 从串口读取数据*/
            rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
            rx_buffer[rx_length] = '';
            /* 通过串口设备 serial 输出读取到的消息 */
            rt_device_write(serial, 0, rx_buffer, rx_length);
            /* 打印数据 */
            rt_kprintf("%sn",rx_buffer);
        }
    }
}
static int uart_dma_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    static char msg_pool[256];
    char str[] = "hello RT-Thread!rn";
    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }
    /* 查找串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!n", uart_name);
        return RT_ERROR;
    }
    /* 初始化消息队列 */
    rt_mq_init(&rx_mq, "rx_mq",
               msg_pool,                 /* 存放消息的缓冲区 */
               sizeof(struct rx_msg),    /* 一条消息的最大长度 */
               sizeof(msg_pool),         /* 存放消息的缓冲区大小 */
               RT_IPC_FLAG_FIFO);        /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
    /* 以 DMA 接收及轮询发送方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    /* 发送字符串 */
    rt_device_write(serial, 0, str, (sizeof(str) - 1));
    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_dma_sample, uart device dma sample);
上面的代码,我只修改了串口的定义为”uart2”,然后基于芯片创建工程,在/drivers/board.h中增加:
#define BSP_USING_UART2
#define BSP_UART2_TX_PIN       "PA2"
#define BSP_UART2_RX_PIN       "PA3"
#define BSP_UART2_RX_USING_DMA
rtconfig.h中增加:
#define RT_SERIAL_USING_DMA
编译,运行msh >uart_dma_sample。串口调试助手发送大量的数据,没有问题如下(哪怕报队列满message queue full):
2.jpg

接着,我将代码修改如下:
/* 以 DMA 接收及轮询发送方式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX|RT_DEVICE_FLAG_INT_TX);
增加了RT_DEVICE_FLAG_INT_TX,同样发送大量的数据,就会导致停止在这里:
result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
我将RT_WAITING_FOREVER,改为5,同样有这个问题,效果如下:
2.jpg
上图,表明serial_thread_entry已经不会打印数据了,只有串口中断里面一直报队列已经满了,然后我进入断点:
2.jpg
这个线程确实出了问题,超时已经不起作用了。
为什么rt_device_open里面增加RT_DEVICE_FLAG_INT_TX,竟然会导致消息队列接收的问题,是我使用不当还是系统存在隐藏的bug呢。我用的是4.0.3版本。



回帖(1)

h1654155275.5614

2023-2-8 10:51:48
换4.1.1版本吧。还可以试试 od_cmd 那套工具集,深入查看一下相关线程消息队列状态细节
举报

更多回帖

发帖
×
20
完善资料,
赚取积分