RT-Thread论坛
直播中

贾埃罗

8年用户 1799经验值
私信 关注
[问答]

STM32H743 UART DMA接收不到数据是为什么?

主分支的bsp下STM32 拷贝的
配置如下:

  • /* Device Drivers */

  • #define RT_USING_DEVICE_IPC
  • #define RT_UNAMED_PIPE_NUMBER 64
  • #define RT_USING_SERIAL
  • #define RT_USING_SERIAL_V2
  • #define RT_SERIAL_USING_DMA
  • #define RT_USING_PIN


  • /* On-chip Peripheral Drivers */

  • #define BSP_USING_GPIO
  • #define BSP_USING_ON_CHIP_FLASH
  • #define BSP_USING_UART
  • #define BSP_USING_UART3
  • #define BSP_UART3_RX_USING_DMA
  • #define BSP_UART3_RX_BUFSIZE 256
  • #define BSP_UART3_TX_BUFSIZE 128
  • #define BSP_USING_UART8
  • #define BSP_UART8_TX_BUFSIZE 128
  • #define BSP_UART8_RX_BUFSIZE 128


  • 其中BSP_USING_UART8作为msh串口,对uart8除了msp.c的初始化,没有使用其他配置,msh使用正常.

  • 对uart3 增加一下内容宏定义
  • /* DMA1 stream1 */
  • #if defined(BSP_UART3_RX_USING_DMA) && !defined(UART3_RX_DMA_INSTANCE)
  • #define UART3_DMA_RX_IRQHandler          DMA1_Stream1_IRQHandler
  • #define UART3_RX_DMA_RCC                 RCC_AHB1ENR_DMA1EN
  • #define UART3_RX_DMA_INSTANCE            DMA1_Stream1
  • #define UART3_RX_DMA_REQUEST             DMA_REQUEST_USART3_RX
  • #define UART3_RX_DMA_IRQ                 DMA1_Stream1_IRQn
  • #endif


main.c代码如下

  • #include
  • #include
  • #include

  • #define LED1_PIN    GET_PIN(C, 12)
  • /* 串口设备句柄 */
  • static rt_device_t serial;
  • int main(void)
  • {
  •         int rx_length;
  •         uint8_t buff[32];
  •     /* set LED2 pin mode to output */
  •     rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
  •         /* 查找串口设备 */
  •     serial = rt_device_find("uart3");
  •     if (!serial)
  •     {
  •         rt_kprintf("find %s failed!n", "uart3");
  •         return RT_ERROR;
  •     }
  •         /* 以 DMA 接收及轮询发送方式打开串口设备 */
  •     rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);

  •         rt_device_write(serial, 0, "hello", (strlen("hello")));
  •     while (1)
  •     {
  •             rx_length = rt_device_read(serial, 0, buff, 32);
  •             if(rx_length>0)
  •             {
  •                 rt_kprintf("%*sn",rx_length,buff);
  •             }
  •         rt_pin_write(LED1_PIN, PIN_HIGH);
  •         rt_thread_mdelay(1000);
  •         rt_pin_write(LED1_PIN, PIN_LOW);
  •         rt_thread_mdelay(1000);
  •     }
  • }


使用串口助手,PC端能收到“hello”,但是PC端下发的数据,没有收到。
如果配置上不使用DMA,串口收发没问题。


回帖(1)

马占云

2025-9-15 17:48:41

为了解决STM32H743 UART DMA接收不到数据的问题,请按照以下步骤排查:




1. 检查DMA配置(Cache一致性问题)


问题原因:STM32H7的缓存(Cache)可能导致DMA写入的数据未被CPU正确读取。

解决方法:在DMA接收缓冲区声明时添加非缓存属性:


// 在board.h或uart初始化文件中定义缓冲区
ALIGN(RT_ALIGN_SIZE)
ATTR_NOCACHE_SECTION  // 关键:添加非缓存属性
static rt_uint8_t uart3_rx_buf[BSP_UART3_RX_BUFSIZE];


  • 在串口初始化配置中指定此缓冲区:
    // stm32_uart.c中uart3的配置
    struct stm32_uart uart3 = {
    .uart_device = {
        .config = {
            .bufsz = BSP_UART3_RX_BUFSIZE, // 确保大小为256
            .rx_buf = uart3_rx_buf,        // 指向定义的缓冲区
        }
    },
    .dma_rx = &uart3_dma_rx,
    };




2. 验证DMA中断配置


问题原因:DMA中断未正确触发导致数据未被处理。

解决方法



  • 在STM32CubeMX或代码中确认DMA配置:

    • 接收方向:外设到内存(Peripheral to Memory)

    • 循环模式:使能(Circular Mode)

    • 内存地址自增:使能

    • 外设地址自增:禁用


  • stm32h7xx_hal_msp.c中检查DMA中断使能:
    void HAL_UART_MspInit(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART3) {
        // 使能DMA流中断
        HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0); // 根据实际DMA流调整
        HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
    }
    }




3. 启用串口空闲中断(IDLE Interrupt)


问题原因:DMA不会自动通知数据包结束,需要空闲中断检测帧结束。

解决方法



  • 在串口初始化后添加:
    __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); // 使能空闲中断

  • USART3_IRQHandler中处理空闲中断:
    void USART3_IRQHandler(void) {
    if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE)) {
        __HAL_UART_CLEAR_FLAG(&huart3, UART_CLEAR_IDLEF); // 清除标志
        rt_hw_serial_isr(&serial3, RT_SERIAL_EVENT_RX_DMADONE); // 通知RT-Thread
    }
    }




4. 确保驱动层配置正确


问题原因:RT-Thread的串口驱动可能未正确关联DMA。

解决方法



  • 检查stm32_uart.c中是否包含以下逻辑:

    • DMA接收回调函数调用rt_hw_serial_isr()

    • 为UART3正确分配DMA流(如uart3_dma_rx结构体)。


  • 示例DMA配置结构体:
    static struct dma_config uart3_dma_rx = {
    .dma_instance = DMA1_Stream0, // 根据实际调整
    .dma_channel  = DMA_CHANNEL_4,
    .direction    = DMA_PERIPH_TO_MEMORY,
    };




5. 硬件连接与信号验证



  • 物理线路:确认USART3的RX引脚(如PD9)连接正确,无短路/断路。

  • 信号质量:用示波器检查:

    • 发送端是否有数据输出?

    • 波特率(如115200)是否匹配?

    • 信号电压是否在3.3V左右?





6. 调试建议



  1. 简化测试:使用轮询模式接收数据(禁用DMA),确认串口基础功能正常。

  2. 打印调试信息:在DMA中断和空闲中断中添加日志,观察是否触发。

  3. 检查DMA寄存器:通过调试器查看:

    • DMA通道是否使能(DMA_SxCR.EN=1)?

    • 外设/内存地址是否正确?

    • 传输计数器(DMA_SxNDTR)是否变化?





完整修复流程


// 步骤1: 定义非缓存缓冲区
ATTR_NOCACHE_SECTION rt_uint8_t uart3_rx_buf[256];

// 步骤2: 初始化时关联缓冲区
struct stm32_uart uart3 = {
    .uart_device.config.rx_buf = uart3_rx_buf,
    ...
};

// 步骤3: 使能空闲中断(在HAL_UART_Init之后)
HAL_UART_Init(&huart3);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);

// 步骤4: 实现空闲中断处理
void USART3_IRQHandler(void) {
    if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE)) {
        __HAL_UART_CLEAR_FLAG(&huart3, UART_CLEAR_IDLEF);
        rt_hw_serial_isr(&serial3, RT_SERIAL_EVENT_RX_DMADONE);
    }
    HAL_UART_IRQHandler(&huart3);
}

通过以上步骤,90%以上的类似问题可被解决。重点检查Cache一致性空闲中断配置。如果问题依旧,请提供更多代码细节(如DMA初始化、中断函数等)进一步分析。

举报

更多回帖

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