Files
Gimbal/modules/referee/rm_referee.c
T
SkyLiCoder 88702e2832 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.
2026-06-02 16:03:21 +08:00

149 lines
5.0 KiB
C

/**
* @file rm_referee.C
* @author kidneygood (you@domain.com)
* @brief
* @version 0.1
* @date 2022-11-18
*
* @copyright Copyright (c) 2022
*
*/
#include "rm_referee.h"
#include "string.h"
#include "crc_ref.h"
#include "bsp_usart.h"
#include "task.h"
#include "daemon.h"
#include "bsp_log.h"
#include "cmsis_os.h"
#define RE_RX_BUFFER_SIZE 255u // 裁判系统接收缓冲区大小
static USARTInstance *referee_usart_instance; // 裁判系统串口实例
static DaemonInstance *referee_daemon; // 裁判系统守护进程
static referee_info_t referee_info; // 裁判系统数据
/**
* @brief 读取裁判数据,中断中读取保证速度
* @param buff: 读取到的裁判系统原始数据
* @retval 是否对正误判断做处理
* @attention 在此判断帧头和CRC校验,无误再写入数据,不重复判断帧头
*/
static void JudgeReadData(uint8_t *buff)
{
uint16_t judge_length; // 统计一帧数据长度
if (buff == NULL) // 空数据包,则不作任何处理
return;
// 写入帧头数据(5-byte),用于判断是否开始存储裁判数据
memcpy(&referee_info.FrameHeader, buff, LEN_HEADER);
// 判断帧头数据(0)是否为0xA5
if (buff[SOF] == REFEREE_SOF)
{
// 帧头CRC8校验
if (Verify_CRC8_Check_Sum(buff, LEN_HEADER) == TRUE)
{
// 统计一帧数据长度(byte),用于CR16校验
judge_length = buff[DATA_LENGTH] + LEN_HEADER + LEN_CMDID + LEN_TAIL;
// 帧尾CRC16校验
if (Verify_CRC16_Check_Sum(buff, judge_length) == TRUE)
{
// 2个8位拼成16位int
referee_info.CmdID = (buff[6] << 8 | buff[5]);
// 解析数据命令码,将数据拷贝到相应结构体中(注意拷贝数据的长度)
// 第8个字节开始才是数据 data=7
switch (referee_info.CmdID)
{
case ID_game_state: // 0x0001
memcpy(&referee_info.GameState, (buff + DATA_Offset), LEN_game_state);
break;
case ID_game_result: // 0x0002
memcpy(&referee_info.GameResult, (buff + DATA_Offset), LEN_game_result);
break;
case ID_game_robot_survivors: // 0x0003
memcpy(&referee_info.GameRobotHP, (buff + DATA_Offset), LEN_game_robot_HP);
break;
case ID_event_data: // 0x0101
memcpy(&referee_info.EventData, (buff + DATA_Offset), LEN_event_data);
break;
case ID_supply_projectile_action: // 0x0102
memcpy(&referee_info.SupplyProjectileAction, (buff + DATA_Offset), LEN_supply_projectile_action);
break;
case ID_game_robot_state: // 0x0201
memcpy(&referee_info.GameRobotState, (buff + DATA_Offset), LEN_game_robot_state);
break;
case ID_power_heat_data: // 0x0202
memcpy(&referee_info.PowerHeatData, (buff + DATA_Offset), LEN_power_heat_data);
break;
case ID_game_robot_pos: // 0x0203
memcpy(&referee_info.GameRobotPos, (buff + DATA_Offset), LEN_game_robot_pos);
break;
case ID_buff_musk: // 0x0204
memcpy(&referee_info.BuffMusk, (buff + DATA_Offset), LEN_buff_musk);
break;
case ID_aerial_robot_energy: // 0x0205
memcpy(&referee_info.AerialRobotEnergy, (buff + DATA_Offset), LEN_aerial_robot_energy);
break;
case ID_robot_hurt: // 0x0206
memcpy(&referee_info.RobotHurt, (buff + DATA_Offset), LEN_robot_hurt);
break;
case ID_shoot_data: // 0x0207
memcpy(&referee_info.ShootData, (buff + DATA_Offset), LEN_shoot_data);
break;
case ID_student_interactive: // 0x0301 syhtodo接收代码未测试
memcpy(&referee_info.ReceiveData, (buff + DATA_Offset), LEN_receive_data);
break;
}
}
}
// 首地址加帧长度,指向CRC16下一字节,用来判断是否为0xA5,从而判断一个数据包是否有多帧数据
if (*(buff + sizeof(xFrameHeader) + LEN_CMDID + referee_info.FrameHeader.DataLength + LEN_TAIL) == 0xA5)
{ // 如果一个数据包出现了多帧数据,则再次调用解析函数,直到所有数据包解析完毕
JudgeReadData(buff + sizeof(xFrameHeader) + LEN_CMDID + referee_info.FrameHeader.DataLength + LEN_TAIL);
}
}
}
/*裁判系统串口接收回调函数,解析数据 */
static void RefereeRxCallback()
{
DaemonReload(referee_daemon);
JudgeReadData(referee_usart_instance->recv_buff);
}
// 裁判系统丢失回调函数,重新初始化裁判系统串口
static void RefereeLostCallback(void *arg)
{
USARTServiceInit(referee_usart_instance);
LOGWARNING("[rm_ref] lost referee data");
}
/* 裁判系统通信初始化 */
referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle)
{
USART_Init_Config_s conf;
conf.module_callback = RefereeRxCallback;
conf.usart_handle = referee_usart_handle;
referee_usart_instance = USARTRegister(&conf);
Daemon_Init_Config_s daemon_conf = {
.callback = RefereeLostCallback,
.owner_id = referee_usart_instance,
.reload_count = 30, // 0.3s没有收到数据,则认为丢失,重启串口接收
};
referee_daemon = DaemonRegister(&daemon_conf);
return &referee_info;
}
/**
* @brief 裁判系统数据发送函数
* @param
*/
void RefereeSend(uint8_t *send, uint16_t tx_len)
{
USARTSend(referee_usart_instance, send, tx_len, USART_TRANSFER_DMA);
osDelay(115);
}