【发布时间】:2019-09-24 03:40:26
【问题描述】:
对于我的 STM32L053 微控制器应用程序,我需要一个稳定的 UART RX 缓冲区,并用于来自 github 的 DMA 实现,它基于 ST HAL:https://github.com/akospasztor/stm32-dma-uart。
如果 RX 输入数据根据相应的缓冲区大小对齐,则此实现非常稳定。例如,如果缓冲区大小为 24 字节,并且所有传入数据请求的大小是此缓冲区长度的倍数,例如每个请求 8 字节,则缓冲区溢出可以正常工作。
我的应用程序使用不同的消息长度,因此我发现此实现存在未对齐缓冲区溢出的弱点。例如,如果缓冲区长度设置为 23 字节,则前两个 8 字节消息都正确传递,但下一个 8 字节消息没有正确传输。
为此,我扩展了HAL_UART_RxCpltCallback 例程,通过使用CNDTR DMA 寄存器并记住变量dma_uart_rx.prevCNDTR 中的最后一个值来处理未对齐的缓冲区溢出:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
{
uint16_t i, pos, start, length;
uint32_t currCNDTR = huart.hdmarx->Instance->CNDTR;
/* Ignore IDLE Timeout when the received characters exactly filled up the DMA buffer and DMA Rx Complete IT is generated, but there is no new character during timeout */
if((dma_uart_rx.flag && currCNDTR == DMA_BUF_SIZE) || error_flag)
{
error_flag = RESET;
dma_uart_rx.flag = 0;
return;
}
/* Determine start position in DMA buffer based on previous CNDTR value */
start = (dma_uart_rx.prevCNDTR < DMA_BUF_SIZE) ? (DMA_BUF_SIZE - dma_uart_rx.prevCNDTR) : 0;
if (dma_uart_rx.flag) /* Timeout event */
{
/* Determine new data length based on previous DMA_CNDTR value:
* If previous CNDTR is less than DMA buffer size: there is old data in DMA buffer (from previous timeout) that has to be ignored.
* If CNDTR == DMA buffer size: entire buffer content is new and has to be processed.
*/
length = (dma_uart_rx.prevCNDTR < DMA_BUF_SIZE) ? (dma_uart_rx.prevCNDTR - currCNDTR) : (DMA_BUF_SIZE - currCNDTR);
dma_uart_rx.prevCNDTR = currCNDTR;
dma_uart_rx.flag = 0;
}
else /* DMA Rx Complete event */
{
// My buffer overrun handling
if (currCNDTR > dma_uart_rx.prevCNDTR)
{
length = dma_uart_rx.prevCNDTR + DMA_BUF_SIZE - currCNDTR;
// 1st rx data part
for (i=0, pos=DMA_BUF_SIZE - dma_uart_rx.prevCNDTR; pos < DMA_BUF_SIZE; ++i,++pos)
{
data[i] = dma_rx_buf[pos];
}
// 2nd rx data part
for (pos=0; pos < DMA_BUF_SIZE - currCNDTR; ++i,++pos)
{
data[i] = dma_rx_buf[pos];
}
receivedBytes = length;
dma_uart_rx.prevCNDTR = currCNDTR;
return;
}
length = DMA_BUF_SIZE - start;
dma_uart_rx.prevCNDTR = DMA_BUF_SIZE;
}
/* Copy and Process new data */
for (i=0,pos=start; i<length; ++i,++pos)
{
data[i] = dma_rx_buf[pos];
}
receivedBytes = length;
}
到目前为止,一切都可以无缝运行,但后来我发现了缓冲区溢出时 CNDTR 寄存器的奇怪行为:
如果我在将CNDTR 寄存器值分配给变量currCNDTR 后在断点处暂停,然后将CNDTR 寄存器的当前寄存器值与调试器中提到的变量进行比较,则该变量始终比CNDTR的寄存器值,虽然没有其他变量赋值?!
有人可以帮我弄清楚我在这里做错了什么吗?
【问题讨论】:
标签: stm32 uart dma cortex-m hal