RT-Thread串口接收的BUG(DMA缓存区太小)
RT-Thread串口接收的问题(ringbuffer溢出)
问题描述
串口+DMA接收数据,发送数据一般会用到缓存区.这几天使用UART+DMA+ringbuff+缓存区的方式处理json数据时,发现程序会跑飞,也就是ringbuffer溢出.
按理说,官方的代码应该不会有什么问题,但问题就是在这,不清楚是中断的问题,还是缓存区的问题.
问题是怎么发生的 :
- 首先,如下代码:
#define RT_SERIAL_RB_BUFSZ 128
RT_SERIAL_RB_BUFSZ
这个宏决定了DMA的buffer大小和serial的ringbuffer大小.
- 配置 DMA buffer 大小的代码如下:
/* enable interrupt */
if (flag == RT_DEVICE_FLAG_DMA_RX)
{
rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
/* Start DMA transfer */
if (HAL_UART_Receive_DMA(&(uart->handle), rx_fifo->buffer, serial->config.bufsz) != HAL_OK)
{
/* Transfer error in reception process */
RT_ASSERT(0);
}
CLEAR_BIT(uart->handle.Instance->CR3, USART_CR3_EIE);
__HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_IDLE);
}
- 分配 serial 的 ringbuffer 大小的代码如下:
struct rt_serial_rx_fifo* rx_fifo;
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + serial->config.bufsz);
RT_ASSERT(rx_fifo != RT_NULL);
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
rx_fifo->put_index = 0;
rx_fifo->get_index = 0;
rx_fifo->is_full = RT_FALSE;
serial->serial_rx = rx_fifo;
/* configure fifo address and length to low level device */
serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX);
通过RT-Thread的源码可知 DMA buffer 和 serial 的 ringbuffer 公用一个 buffer.
我发送的数据长度为129,发送间隔>250ms(就是象征性表示这个速度不快),连续发几帧(没摸到规律,一般是4帧有时候也不一定),就会出现这个问题.
当然之前发送的是192+bytes的数据,现象一样的.
hard fault on handler
bus fault:
SCB_CFSR_BFSR:0x04 IMPRECISERR
- 串口的回调函数为
rt_err_t uart2_input(rt_device_t device, size_t size)
{
rt_mb_send(&serial2_rx_mb, size);
return RT_EOK;
}
- 这是线程中读取的代码,使用的邮箱来阻塞线程.
rt_uint8_t buffer[512] = {0};
/* 省略一部分无关代码 */
result = rt_mb_recv(&serial2_rx_mb, &length, RT_WAITING_FOREVER);
/* 省略一部分无关代码 */
result = rt_device_read(device,0,buffer,length);
LOG_D("r_len:%d", result);
i = i+result;
通过LOG_D
输出result,length这俩变量的值.
上面这个图没有加入这段代码:
cjson_ptr = cJSON_Parse((char *)json_buffer);
LOG_I("%s", cJSON_GetErrorPtr());
if(cjson_ptr == NULL)
{
LOG_I("cJSON_Parse failed");
continue;
}
加入这段cJSON的防错代码之后.
目前的解决方式 :
增加DMA buffer的大小RT_SERIAL_RB_BUFSZ
#define RT_SERIAL_RB_BUFSZ 256
目的是确保一帧数据(这里就是一帧JSON报文),小于这个RT_SERIAL_RB_BUFSZ
.
这样,就可以在1帧/100ms的速度下,可以稳定的运行,不出现错误.
本文来自博客园,作者:当最后一片树叶落下,转载请注明原文链接:https://www.cnblogs.com/Rabbit-susu/p/17400727.html