菜单

uwidjw
uwidjw
发布于 2025-11-22 / 5 阅读
0
0

LPDMA与SRAM4联调-测试部分

完成 LPDMA 与 SRAM4 配置后,修改原先的代码并进行测试,发现接收不到任何数据,于是进行调试:

串口发送调试

我先进行了串口发送的调试,APP 代码中将生成的遥测数据通过 memcpy 将生成的 tx_buf 数据从 SRAM1 内存中,通过调试器可以看到 SRAM4 中的数据。

在向 tx_buf 搬运完数据后打断点,通过调试器查看 SRAM4 数据:


可以看到数据被正确拷贝到 SRAM4 中等待 LPDMA 来搬运给 LPUART 了,但是此时通过逻辑分析仪查看 LPUART 的输出,发现所有的数据都是“00”。此时明白是 DMA 没有正确的搬运数据导致的,但是数据的来源和目的地都是正确的,此时需要去排查 DMA 的配置。最终发现是上一篇文章中留下的 bug:SRAM4 被配置为仅限特权级访问了。对于存放数据的 SRAM4 来说最好配置为非特权级,最开始我也确实是这样配置的,可能打开了 CubeMX 的一些开关后这个配置被覆盖了,不过无论如何开启了 LPDMA 的特权级后发送 00 的问题就解决了。

串口上电就报错

我的业务代码中上电会对 LoRa 模块进行初始化,包括对 LoRa 模块中所有配置寄存器的覆写。查看 LoRa 模块的数据手册我们可以看到该模块配置寄存器的方式是通过串口发送对应数据:

但是:写入配置后模块会马上响应,返回对应的相应命令。就是这个返回响应的操作导致串口上电发送 Init 命令后就会进入 Error 中断,报错为UART Error 8(Overrun)。定位问题后通过初始化时串口只发送不接收来解决问题。

UART Error 16

完成发送测试后进行串口接收测试,发现串口接收出现严重 bug:不仅丢包,收到的包也只搬运了一个字符,还会不停进入 Error 中断。于是尝试在串口的错误中断中添加 DEBUG 信息输出:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == hlpuart1.Instance) {
#ifdef DEBUG
        debug_error_count++;
        debug_last_error_code = huart->ErrorCode;
#endif
    ...
    }
}

在 SWO 输出可以看到串口的错误中断报错码是 16,HAL 库宏定义为#define HAL_UART_ERROR_DMA 0x00000010U,即 DMA 错误。这时我已经排除了 DMA 特权级和 DMA 地址的问题,没有办法,只能从 LPDMA 的寄存器入手:

(这里是正确的配置,当时的图没有保留)

发现了一个奇怪的现象:LPDMA_C1LLR 的值居然不为 0!LLR 就是之前提到过的链表模式。为什么我没有开启链表模式这个寄存器还被写入数据了呢?我们再回头检查 LPDMA CH1 的配置:

此时我启用了 Circular 模式

于是可以看到启用 Circular 模式后 DMA 一定是工作在链表模式的,但是我没有进行配置,导致了 LLR 寄存器去内存中一个随机地址抓取任务配置,读取了非法的内存区域,触发了总线错误。关闭 Circular 模式后串口接收数据不会报 16 错误。

STOP2唤醒后数据丢失

为了实现低功耗,系统大部分时间都是在 STOP2 模式下休眠的,想要接收服务器命令并响应,必须要实现 LoRa 模块接收数据包时唤醒 MCU,接收数据并处理。LoRa 模块有一个 AUX 引脚,模块空闲时为高电平,模块忙碌时为低电平。通过这个引脚,可以实现即将接收数据包时通过 EXIT 中断唤醒 CPU 进行处理。清楚工作原理后进行唤醒功能测试,使用 LiveWatch 串口查看接收的数组:

测试时发现搬运到 SRAM4 中的数据只有第一个字节 "{",并且报错ORE (Overrun Error)。判断这是由于 STM32 唤醒后恢复时钟需要时间导致的。尝试开启 LPUART 的 FIFO 并设置 Threshold 为 1/8,解决了问题。

丢包问题

虽然数据链路通畅了,但是在进行高频数据接收测试时出现了严重的丢包问题,不是接收不到,就是串口报 Overrun 错误。具体的现象如下:

  1. 命令发送成功:SWO 打印Telemetry send success,说明 tx_dma 工作正常;

  2. 超时丢包:接着日志就会打印[MISSING PACKET DEBUG]

  3. 中断未触发:调试计数器显示ISR Count: 0

  4. 偶尔 SRAM4 中有一个“{”,但是随后就报错结束了。

我尝试过用逻辑分析仪抓取 LoRa 模块的 tx,发现接收到的数据是正常的。那么将问题定位到软件上,是 MCU 将串口数据放过去了。那么需要排查与串口接收逻辑相关的代码。最终发现问题出在两个地方,第一个是将所有的中断优先级都配置成 5,这样导致了串口接收中断被其他任务中的中断(i2c 等)打断,产生无法经过验证的数据包,自然无法完成搬运:

当时这里的优先级都配置成 5

第二个是发现Lora_UARTTransmit函数中的接收逻辑与 LoRa 模块的时序有严重冲突,LoRa 模块接收数据时 AUX 引脚为低(设备忙碌),但是在Lora_UARTTransmit函数中完成发送后先等待 AUX 为高,再开启串口接收,导致了丢包。

通道 0 是 AUX,通道 1 是 LoRa 模块的 TX

HAL_StatusTypeDef Lora_UART_Transmit(Lora_Handle_Struct_t *dev, uint8_t *data, uint16_t len) {

    ...

    HAL_UART_AbortReceive_IT(dev->uart_buffer.huart);

    if (Wait_For_AUX_High(dev, 1000) != HAL_OK) {
        Lora_StartReceive(dev);
        osMutexRelease(lora_usart_mutexHandle);
        return HAL_TIMEOUT;
    }

    ...

    Lora_StartReceive(dev);
    osMutexRelease(lora_usart_mutexHandle);

    return status;
}

可以看到代码中的时序产生了严重的 bug

定位问题后将代码修改为完成发送后立刻开启串口接收,解决了丢包问题。

调试中进入RTOS的prvTaskExitError函数

原因在于我将 printf 重定向到 SWO 输出,又没有修改 printf 的库大小,导致了任务的栈溢出问题。

//重定向printf函数
int fputc(int ch, FILE *f)
{
  ITM_SendChar(ch);
  return ch;
}

IAR 中的 printf 库大小设置

在HAL_UART_ErrorCallback中使用printf导致了进入prvTaskExitError函数。

至此完成 LoRa 模块的调试。


评论