RTThread使用DMA接收串口数据的问题
问题/现象
使用RTThread的DMA接收串口数据,数据不连续,即IDLE中断没有起到作为一个frame的判定.
经过对serial和drv_uarts源码的分析,得出原因:
graph LR RX_INT[USART1_IRQHandler] -->process1(...) process1 -->rx_isr1[dma_recv_isr] rx_isr1 -->flag1{isr_flag} flag1 -->|UART_RX_DMA_IT_IDLE_FLAG| serial_isr1[rt_hw_serial_isr] serial_isr1 -->event{event} DMA_INT[UART1_DMA_RX_IRQHandler] -->process2(...) process2 -->rx_isr2[dma_recv_isr] rx_isr2 -->flag2{isr_flag} flag2 -->|UART_RX_DMA_IT_HT_FLAG| serial_isr2[rt_hw_serial_isr] flag2 -->|UART_RX_DMA_IT_TC_FLAG| serial_isr2[rt_hw_serial_isr] serial_isr2 -->event{event} event -->|RT_SERIAL_EVENT_RX_DMADONE|do_something(...)从上图可知,发生IDLE中断时,USART1_IRQHandler
调用的是和UART1_DMA_RX_IRQHandler
相同的接口 —— rt_hw_serial_isr
.
这就造成无法区分是IDLE中断还是DMA中断.
不改变源码的情况下,仍使用DMA+IDLE中断,目前这两种方式是比较好的
解决方式①
- 接收数据
/* 接收数据回调函数 */
static rt_err_t uart2_input(rt_device_t dev, rt_size_t size)
{
rt_err_t result;
result = rt_sem_release(&serial2_sem);/*通知serial_thread_entry线程,有数据了*/
if ( result == RT_EOK)
{
rt_kprintf("sem release error!\n");
}
return result;
}
static void serial_thread_entry(void *parameter)
{
rt_err_t result;
rt_uint8_t c = 0;
rt_uint8_t i = 0, rx_state = SERIAL2_STATE_WAIT_FRAME;
rt_device_t serial2 = rt_device_find("uart2");
struct frame_msg msg;
while (1)
{
switch(rx_state)
{
case SERIAL2_STATE_WAIT_FRAME:
{
result = rt_sem_take(&serial2_sem, RT_WAITING_FOREVER); /* 等待新的一帧数据 */
if (result == RT_EOK)
{
rt_kprintf("%s: frame start\n", __func__);
rx_state = SERIAL2_STATE_RECV_DATA;
i = 0;
}
break;
}
case SERIAL2_STATE_RECV_DATA:
{
/* 读取一段数据 —— 数个字节(不足一帧) */
while(rt_device_read(serial2, 0, &c, 1) != 0)
{
framebuf[i] = c;
i++;
}
result = rt_sem_take(&serial2_sem, 10); /* 将信号量设置为带有超时的信号量,等待下一段数据 */
if(result == -RT_ETIMEOUT) /* 超过10个OSTicks没有读到数据,判定该帧结束 */
{
framebuf[i] = '\0';
msg.data = framebuf;
msg.size = i;
result = rt_mq_send(&rtc_rx_mq, (void*)&msg, sizeof(struct frame_msg)); /* 给其它线程通信 */
if(result != RT_EOK)
{
rt_kprintf("%s: msgqueue send error-[%d]\n", __func__, result);
}
rx_state = SERIAL2_STATE_WAIT_FRAME; /* 一帧结束 */
rt_kprintf("%s: frame end\n", __func__);
}
else
{
/*接收下一段数据*/
rt_kprintf("%s: frame recv ing...\n", __func__);
}
break;
}
default:
break;
}
}
}
解决方式②
把信号量换成消息队列.
其它问题
代码中的几个局部变量在线程中具有了和线程一样长的生成周期
life_circle(serial_thread_entry) = life_circle(variable(i))
= life_circle(variable(rx_state))
= life_circle(variable(serial2))
= ...
这样是不是意味着thread的stack一直被占用?
标签:rt,DMA,--,rx,result,串口,serial,接收数据 From: https://www.cnblogs.com/Rabbit-susu/p/17369923.html嗯,是的.