From 88702e28325a17bf9a193c848a6f00ecae638cc6 Mon Sep 17 00:00:00 2001 From: SkyLi Date: Tue, 2 Jun 2026 16:03:21 +0800 Subject: [PATCH] fix: move DMA buffers from DTCM to RAM_D1, improve bsp_usart error recovery - Add .dma_buf section in RAM_D1 for DMA-accessible USART instance pool. DTCM (0x20000000) is not reachable by DMA on STM32H7, causing bus errors (TE) when DMA writes to malloc'd buffers placed in DTCM by the XG linker script. - Replace malloc with static pool (usart_pool[]) placed in .dma_buf section. - In RxEventCallback, set recv_buff_size from Size so module callbacks know how many bytes were actually received. - Use USART_RXBUFF_LIMIT (256) as the DMA transfer size instead of per-module recv_buff_size. The actual buffer is always 256 bytes. - Remove recv_buff_size from USART_Init_Config_s; it is now set at runtime. - Flush RDR, clear error flags, and clear stale DMAR in error callback to prevent residual conditions from re-triggering errors on DMA restart. - Switch Vision module from UART10 to UART1. --- STM32H723XG_FLASH.ld | 9 ++++++- application/cmd/robot_cmd.c | 2 +- bsp/usart/bsp_usart.c | 35 +++++++++++++++++-------- bsp/usart/bsp_usart.h | 3 +-- modules/bluetooth/HC05.c | 1 - modules/master_machine/master_machine.c | 1 - modules/referee/rm_referee.c | 1 - modules/remote/remote_control.c | 1 - modules/timachine/board_comm.c | 1 - 9 files changed, 34 insertions(+), 20 deletions(-) diff --git a/STM32H723XG_FLASH.ld b/STM32H723XG_FLASH.ld index 05a611a..4ac8d60 100644 --- a/STM32H723XG_FLASH.ld +++ b/STM32H723XG_FLASH.ld @@ -241,7 +241,14 @@ SECTIONS . = ALIGN(8); } >DTCMRAM - + /* DMA-accessible buffers in RAM_D1 (SRAM). DTCM is not reachable by DMA */ + .dma_buf (NOLOAD) : + { + . = ALIGN(4); + *(.dma_buf) + *(.dma_buf*) + . = ALIGN(4); + } >RAM_D1 /* Remove information from the standard libraries */ /DISCARD/ : diff --git a/application/cmd/robot_cmd.c b/application/cmd/robot_cmd.c index 3a38266..cf8d182 100644 --- a/application/cmd/robot_cmd.c +++ b/application/cmd/robot_cmd.c @@ -228,7 +228,7 @@ void RobotCMDInit() PIDInit(&vision_pitch_pid, &pitch_vpid_config); VisionKalmanFilterInit(); - Vision_Uart_Init(&huart10); + Vision_Uart_Init(&huart1); laser_off(); } diff --git a/bsp/usart/bsp_usart.c b/bsp/usart/bsp_usart.c index ccefeb3..e27a942 100644 --- a/bsp/usart/bsp_usart.c +++ b/bsp/usart/bsp_usart.c @@ -10,9 +10,12 @@ */ #include "bsp_usart.h" #include "bsp_log.h" -#include "stdlib.h" #include "memory.h" +/* Static pool in RAM_D1 (.dma_buf section) for DMA-accessible USART instances. + DTCM is not reachable by DMA, so malloc'd instances would cause bus errors. */ +static USARTInstance usart_pool[DEVICE_USART_CNT] __attribute__((section(".dma_buf"))); + /* usart service instance, modules' info would be recoreded here using USARTRegister() */ /* usart服务实例,所有注册了usart的模块信息会被保存在这里 */ static uint8_t idx; @@ -28,7 +31,7 @@ static USARTInstance *usart_instance[DEVICE_USART_CNT] = {NULL}; */ void USARTServiceInit(USARTInstance *_instance) { - HAL_UARTEx_ReceiveToIdle_DMA(_instance->usart_handle, _instance->recv_buff, _instance->recv_buff_size); + HAL_UARTEx_ReceiveToIdle_DMA(_instance->usart_handle, _instance->recv_buff, USART_RXBUFF_LIMIT); // 关闭dma half transfer中断防止两次进入HAL_UARTEx_RxEventCallback() // 这是HAL库的一个设计失误,发生DMA传输完成/半完成以及串口IDLE中断都会触发HAL_UARTEx_RxEventCallback() // 我们只希望处理第一种和第三种情况,因此直接关闭DMA半传输中断 @@ -46,11 +49,10 @@ USARTInstance *USARTRegister(USART_Init_Config_s *init_config) while (1) LOGERROR("[bsp_usart] USART instance already registered!"); - USARTInstance *instance = (USARTInstance *)malloc(sizeof(USARTInstance)); + USARTInstance *instance = &usart_pool[idx]; memset(instance, 0, sizeof(USARTInstance)); instance->usart_handle = init_config->usart_handle; - instance->recv_buff_size = init_config->recv_buff_size; instance->module_callback = init_config->module_callback; usart_instance[idx++] = instance; @@ -102,17 +104,18 @@ uint8_t USARTIsReady(USARTInstance *_instance) void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { for (uint8_t i = 0; i < idx; ++i) - { // find the instance which is being handled + { if (huart == usart_instance[i]->usart_handle) - { // call the callback function if it is not NULL + { + usart_instance[i]->recv_buff_size = Size; // 实际接收到的数据量 if (usart_instance[i]->module_callback != NULL) { usart_instance[i]->module_callback(); - memset(usart_instance[i]->recv_buff, 0, Size); // 接收结束后清空buffer,对于变长数据是必要的 + memset(usart_instance[i]->recv_buff, 0, Size); } - HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, usart_instance[i]->recv_buff_size); + HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, USART_RXBUFF_LIMIT); __HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT); - return; // break the loop + return; } } } @@ -130,9 +133,19 @@ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if (huart == usart_instance[i]->usart_handle) { - HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, usart_instance[i]->recv_buff_size); + LOGWARNING("[bsp_usart] USART error callback, idx [%d], ErrorCode: 0x%02X", i, huart->ErrorCode); + + /* Flush RDR and clear error flags before restarting DMA */ + (void)READ_REG(huart->Instance->RDR); + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF | UART_CLEAR_FEF | UART_CLEAR_NEF | UART_CLEAR_PEF); + huart->ErrorCode = HAL_UART_ERROR_NONE; + + /* Clear stale DMAR to avoid a residual DMA request triggering a + bus error when UART_Start_Receive_DMA re-enables the stream */ + ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, USART_RXBUFF_LIMIT); __HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT); - LOGWARNING("[bsp_usart] USART error callback triggered, instance idx [%d]", i); return; } } diff --git a/bsp/usart/bsp_usart.h b/bsp/usart/bsp_usart.h index f8c5a43..ffeefe6 100644 --- a/bsp/usart/bsp_usart.h +++ b/bsp/usart/bsp_usart.h @@ -24,7 +24,7 @@ typedef enum typedef struct { uint8_t recv_buff[USART_RXBUFF_LIMIT]; // 预先定义的最大buff大小,如果太小请修改USART_RXBUFF_LIMIT - uint8_t recv_buff_size; // 模块接收一包数据的大小 + uint16_t recv_buff_size; // 实际接收到的数据量(由RxEventCallback赋值) UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle usart_module_callback module_callback; // 解析收到的数据的回调函数 } USARTInstance; @@ -32,7 +32,6 @@ typedef struct /* usart 初始化配置结构体 */ typedef struct { - uint8_t recv_buff_size; // 模块接收一包数据的大小 UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle usart_module_callback module_callback; // 解析收到的数据的回调函数 } USART_Init_Config_s; diff --git a/modules/bluetooth/HC05.c b/modules/bluetooth/HC05.c index 2d170d6..eadc530 100644 --- a/modules/bluetooth/HC05.c +++ b/modules/bluetooth/HC05.c @@ -33,7 +33,6 @@ HC05 *HC05Init(UART_HandleTypeDef *hc05_usart_handle) USART_Init_Config_s conf; conf.module_callback = HC05RxCallback; conf.usart_handle = hc05_usart_handle; - conf.recv_buff_size = HC05_BUFFERSIZE; hc05_usart_instance = USARTRegister(&conf); hc05_init_flag = 1; diff --git a/modules/master_machine/master_machine.c b/modules/master_machine/master_machine.c index 9a548b0..1a5ab46 100644 --- a/modules/master_machine/master_machine.c +++ b/modules/master_machine/master_machine.c @@ -80,7 +80,6 @@ void Vision_Uart_Init(UART_HandleTypeDef *_handle) { USART_Init_Config_s conf = { .module_callback = DecodeVision, - .recv_buff_size = 64, .usart_handle = _handle, }; cv_usart_instance = USARTRegister(&conf); diff --git a/modules/referee/rm_referee.c b/modules/referee/rm_referee.c index 2743d7d..4a9cc0e 100644 --- a/modules/referee/rm_referee.c +++ b/modules/referee/rm_referee.c @@ -125,7 +125,6 @@ referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle) USART_Init_Config_s conf; conf.module_callback = RefereeRxCallback; conf.usart_handle = referee_usart_handle; - conf.recv_buff_size = RE_RX_BUFFER_SIZE; // mx 255(u8) referee_usart_instance = USARTRegister(&conf); Daemon_Init_Config_s daemon_conf = { diff --git a/modules/remote/remote_control.c b/modules/remote/remote_control.c index e45f03d..b2197c9 100644 --- a/modules/remote/remote_control.c +++ b/modules/remote/remote_control.c @@ -229,7 +229,6 @@ RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle) USART_Init_Config_s conf; conf.module_callback = RemoteControlRxCallback; conf.usart_handle = rc_usart_handle; - conf.recv_buff_size = REMOTE_CONTROL_FRAME_SIZE; rc_usart_instance = USARTRegister(&conf); // 进行守护进程的注册,用于定时检查遥控器是否正常工作 diff --git a/modules/timachine/board_comm.c b/modules/timachine/board_comm.c index 549de5b..eafccde 100644 --- a/modules/timachine/board_comm.c +++ b/modules/timachine/board_comm.c @@ -59,7 +59,6 @@ board_comm_data_t* BoardCommInit(UART_HandleTypeDef *uart_handle) USART_Init_Config_s conf; conf.module_callback = BoardCommRxCallback; conf.usart_handle = uart_handle; - conf.recv_buff_size = BOARD_COMM_FRAME_SIZE; board_comm_usart_instance = USARTRegister(&conf); // 暂时注释掉 daemon 注册,专注于数据传输