add DMA remote control

This commit is contained in:
TuxMonkey
2026-07-14 21:56:46 +08:00
parent 591707d9fc
commit f4c0424c45
16 changed files with 371 additions and 191 deletions

View File

@@ -35,6 +35,7 @@
// #include "bsp_log.h" // #include "bsp_log.h"
#include "dev_cmd.h" #include "dev_cmd.h"
#include "daemon.h" #include "daemon.h"
#include "bsp_usart.h"
/* USER CODE END Includes */ /* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/
@@ -449,6 +450,8 @@ __attribute__((noreturn)) void StartDaemonTask(void *argument)
/* Infinite loop */ /* Infinite loop */
for (;;) for (;;)
{ {
USARTServiceTask();
// 1. 执行核心的数据刷新逻辑 // 1. 执行核心的数据刷新逻辑
Daemon_Update(); Daemon_Update();

View File

@@ -361,7 +361,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
hdma_uart5_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_uart5_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart5_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_uart5_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart5_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_uart5_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart5_rx.Init.Mode = DMA_CIRCULAR; hdma_uart5_rx.Init.Mode = DMA_NORMAL;
hdma_uart5_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_uart5_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_uart5_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; hdma_uart5_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_uart5_rx) != HAL_OK) if (HAL_DMA_Init(&hdma_uart5_rx) != HAL_OK)

View File

@@ -227,6 +227,17 @@ SECTIONS
PROVIDE( __bss_start = _sbss ); PROVIDE( __bss_start = _sbss );
PROVIDE( __bss_size = __bss_end - __bss_start ); PROVIDE( __bss_size = __bss_end - __bss_start );
/* DMA1/DMA2 cannot access DTCM. The MPU config makes RAM_D1 non-cacheable. */
.dma_buffer (NOLOAD) :
{
. = ALIGN(32);
__dma_buffer_start__ = .;
KEEP(*(.dma_buffer))
KEEP(*(.dma_buffer.*))
. = ALIGN(32);
__dma_buffer_end__ = .;
} >RAM_D1
/* 用户堆栈段用于检查剩余RAM是否足够 */ /* 用户堆栈段用于检查剩余RAM是否足够 */
._user_heap_stack (NOLOAD) : ._user_heap_stack (NOLOAD) :
{ {

View File

@@ -156,7 +156,7 @@ Dma.UART5_RX.13.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.UART5_RX.13.Instance=DMA1_Stream5 Dma.UART5_RX.13.Instance=DMA1_Stream5
Dma.UART5_RX.13.MemDataAlignment=DMA_MDATAALIGN_BYTE Dma.UART5_RX.13.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.UART5_RX.13.MemInc=DMA_MINC_ENABLE Dma.UART5_RX.13.MemInc=DMA_MINC_ENABLE
Dma.UART5_RX.13.Mode=DMA_CIRCULAR Dma.UART5_RX.13.Mode=DMA_NORMAL
Dma.UART5_RX.13.PeriphDataAlignment=DMA_PDATAALIGN_BYTE Dma.UART5_RX.13.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.UART5_RX.13.PeriphInc=DMA_PINC_DISABLE Dma.UART5_RX.13.PeriphInc=DMA_PINC_DISABLE
Dma.UART5_RX.13.Polarity=HAL_DMAMUX_REQ_GEN_RISING Dma.UART5_RX.13.Polarity=HAL_DMAMUX_REQ_GEN_RISING

View File

@@ -24,6 +24,7 @@
#include "delayticks.h" #include "delayticks.h"
#include "robot_def.h" #include "robot_def.h"
#include "rc.h"
/*---------------------VARIABLES---------------------*/ /*---------------------VARIABLES---------------------*/
uint8_t r = 0; uint8_t r = 0;
@@ -53,10 +54,13 @@ void robotSelfCheck(void)
void ws2812Task(void *argument) void ws2812Task(void *argument)
{ {
(void) argument; (void) argument;
RobotMode_t RobotMode = REMOTE_NOT_CONNECTED; // 初始状态为遥控器未连接
while (1) while (1)
{ {
switch (RobotMode) RobotMode_t display_mode = RobotMode;
if (display_mode != SYS_ERROR_OCCURRED && !RemoteControlIsOnline())
display_mode = REMOTE_NOT_CONNECTED;
switch (display_mode)
{ {
case NORMAL_MODE: case NORMAL_MODE:
BlinkGreen(); BlinkGreen();

View File

@@ -16,6 +16,8 @@
#include "bsp_init.h" #include "bsp_init.h"
#include "robot.h" #include "robot.h"
#include "rc.h"
#include "robot_def.h"
#include "cmsis_gcc.h" #include "cmsis_gcc.h"
// #include "robot_def.h" // #include "robot_def.h"
@@ -27,6 +29,8 @@
// #pragma message "check if you have configured the parameters in robot_def.h, IF NOT, please refer to the comments AND DO IT, otherwise the robot will have FATAL ERRORS!!!" // #pragma message "check if you have configured the parameters in robot_def.h, IF NOT, please refer to the comments AND DO IT, otherwise the robot will have FATAL ERRORS!!!"
// #endif // !ROBOT_DEF_PARAM_WARNING // #endif // !ROBOT_DEF_PARAM_WARNING
volatile RobotMode_t RobotMode = REMOTE_NOT_CONNECTED;
// #if defined(ONE_BOARD) || defined(CHASSIS_BOARD) // #if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
// #include "chassis.h" // #include "chassis.h"
// #endif // #endif
@@ -59,6 +63,9 @@ void RobotInit()
BSPInit(); BSPInit();
if (RemoteControlInit(&huart5) == NULL)
RobotMode = SYS_ERROR_OCCURRED;
#if defined(ONE_BOARD) || defined(GIMBAL_BOARD) #if defined(ONE_BOARD) || defined(GIMBAL_BOARD)
RobotCMDInit(); RobotCMDInit();
// GimbalInit(); // GimbalInit();

View File

@@ -11,43 +11,116 @@
#include "bsp_usart.h" #include "bsp_usart.h"
#include "bsp_log.h" #include "bsp_log.h"
#include "stdlib.h"
#include "memory.h" #include "memory.h"
/* usart service instance, modules' info would be recoreded here using USARTRegister() */ /* usart service instance, modules' info would be recoreded here using USARTRegister() */
/* usart服务实例,所有注册了usart的模块信息会被保存在这里 */ /* usart服务实例,所有注册了usart的模块信息会被保存在这里 */
static uint8_t idx; static uint8_t idx;
static USART_Instance *usart_instance[DEVICE_USART_CNT] = {NULL}; static USART_Instance *usart_instance[DEVICE_USART_CNT] = {NULL};
static USART_Instance usart_instance_pool[DEVICE_USART_CNT]
__attribute__((section(".dma_buffer"), aligned(32)));
static USART_Instance *USARTFindInstance(UART_HandleTypeDef *huart)
{
for (uint8_t i = 0; i < idx; ++i)
{
if (usart_instance[i]->usart_handle == huart)
return usart_instance[i];
}
return NULL;
}
/** /**
* @brief 启动串口服务,会在每个实例注册之后自动启用接收,当前实现为DMA接收,后续可能添加IT和BLOCKING接收 * @brief 启动串口DMA接收服务,模块完成实例和回调初始化后显式调用
* *
* @todo 串口服务会在每个实例注册之后自动启用接收,当前实现为DMA接收,后续可能添加IT和BLOCKING接收 * @note 配合DMA_NORMAL和ReceiveToIdle使用,每次接收事件后由BSP重新启动
* 可能还要将此函数修改为extern,使得module可以控制串口的启停
* *
* @param _instance instance owned by module,模块拥有的串口实例 * @param _instance instance owned by module,模块拥有的串口实例
*/ */
void USARTServiceInit(USART_Instance *_instance) HAL_StatusTypeDef USARTServiceInit(USART_Instance *_instance)
{ {
HAL_UARTEx_ReceiveToIdle_DMA(_instance->usart_handle, _instance->recv_buff, _instance->recv_buff_size); if (_instance == NULL || _instance->usart_handle == NULL || _instance->usart_handle->hdmarx == NULL)
return HAL_ERROR;
HAL_StatusTypeDef status = HAL_UARTEx_ReceiveToIdle_DMA(
_instance->usart_handle, _instance->recv_buff, _instance->recv_buff_size);
// 关闭dma half transfer中断防止两次进入HAL_UARTEx_RxEventCallback() // 关闭dma half transfer中断防止两次进入HAL_UARTEx_RxEventCallback()
// 这是HAL库的一个设计失误,发生DMA传输完成/半完成以及串口IDLE中断都会触发HAL_UARTEx_RxEventCallback() // 这是HAL库的一个设计失误,发生DMA传输完成/半完成以及串口IDLE中断都会触发HAL_UARTEx_RxEventCallback()
// 我们只希望处理第一种和第三种情况,因此直接关闭DMA半传输中断 // 我们只希望处理第一种和第三种情况,因此直接关闭DMA半传输中断
__HAL_DMA_DISABLE_IT(_instance->usart_handle->hdmarx, DMA_IT_HT); if (status == HAL_OK)
{
__HAL_DMA_DISABLE_IT(_instance->usart_handle->hdmarx, DMA_IT_HT);
_instance->rx_restart_pending = 0;
}
else
{
_instance->rx_restart_pending = 1;
}
return status;
}
static HAL_StatusTypeDef USARTRecoverRx(USART_Instance *instance)
{
UART_HandleTypeDef *huart = instance->usart_handle;
DMA_HandleTypeDef *hdma = huart->hdmarx;
HAL_StatusTypeDef abort_status = HAL_UART_AbortReceive(huart);
if (abort_status != HAL_OK || HAL_DMA_GetState(hdma) != HAL_DMA_STATE_READY)
{
if (HAL_DMA_DeInit(hdma) != HAL_OK || HAL_DMA_Init(hdma) != HAL_OK)
return HAL_ERROR;
/* An abort timeout returns before HAL restores the UART Rx state. */
if (HAL_UART_AbortReceive(huart) != HAL_OK)
return HAL_ERROR;
}
return USARTServiceInit(instance);
}
void USARTServiceTask(void)
{
for (uint8_t i = 0; i < idx; ++i)
{
USART_Instance *instance = usart_instance[i];
if (!instance->rx_restart_pending)
continue;
if (USARTRecoverRx(instance) != HAL_OK)
instance->rx_restart_error_count++;
}
} }
USART_Instance *USARTRegister(USART_Init_Config_s *init_config) USART_Instance *USARTRegister(USART_Init_Config_s *init_config)
{ {
if (init_config == NULL || init_config->usart_handle == NULL || init_config->usart_handle->hdmarx == NULL ||
init_config->recv_buff_size == 0 || init_config->recv_buff_size > USART_RXBUFF_LIMIT)
{
LOGERROR("[bsp_usart] invalid USART register config");
return NULL;
}
if (init_config->usart_handle->hdmarx->Init.Mode != DMA_NORMAL)
{
LOGERROR("[bsp_usart] ReceiveToIdle service requires DMA_NORMAL");
return NULL;
}
if (idx >= DEVICE_USART_CNT) // 超过最大实例数 if (idx >= DEVICE_USART_CNT) // 超过最大实例数
while (1) {
LOGERROR("[bsp_usart] USART exceed max instance count!"); LOGERROR("[bsp_usart] USART exceed max instance count!");
return NULL;
}
for (uint8_t i = 0; i < idx; i++) // 检查是否已经注册过 for (uint8_t i = 0; i < idx; i++) // 检查是否已经注册过
if (usart_instance[i]->usart_handle == init_config->usart_handle) if (usart_instance[i]->usart_handle == init_config->usart_handle)
while (1) {
LOGERROR("[bsp_usart] USART instance already registered!"); LOGERROR("[bsp_usart] USART instance already registered!");
return NULL;
}
USART_Instance *instance = (USART_Instance *) malloc(sizeof(USART_Instance)); USART_Instance *instance = &usart_instance_pool[idx];
memset(instance, 0, sizeof(USART_Instance)); memset(instance, 0, sizeof(USART_Instance));
instance->usart_handle = init_config->usart_handle; instance->usart_handle = init_config->usart_handle;
@@ -55,7 +128,6 @@ USART_Instance *USARTRegister(USART_Init_Config_s *init_config)
instance->module_callback = init_config->module_callback; instance->module_callback = init_config->module_callback;
usart_instance[idx++] = instance; usart_instance[idx++] = instance;
USARTServiceInit(instance);
return instance; return instance;
} }
@@ -82,10 +154,8 @@ void USARTSend(USART_Instance *_instance, uint8_t *send_buf, uint16_t send_size,
/* 串口发送时,gstate会被设为BUSY_TX */ /* 串口发送时,gstate会被设为BUSY_TX */
uint8_t USARTIsReady(USART_Instance *_instance) uint8_t USARTIsReady(USART_Instance *_instance)
{ {
if (_instance->usart_handle->gState | HAL_UART_STATE_BUSY_TX) return _instance != NULL && _instance->usart_handle != NULL &&
return 0; _instance->usart_handle->gState == HAL_UART_STATE_READY;
else
return 1;
} }
/** /**
@@ -97,27 +167,22 @@ uint8_t USARTIsReady(USART_Instance *_instance)
* 我们只希望处理因此直接关闭DMA半传输中断第一种和第三种情况 * 我们只希望处理因此直接关闭DMA半传输中断第一种和第三种情况
* *
* @param huart 发生中断的串口 * @param huart 发生中断的串口
* @param Size 此次接收到的总数居量,暂时没用 * @param Size 此次接收到的数据量
*/ */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{ {
for (uint8_t i = 0; i < idx; ++i) USART_Instance *instance = USARTFindInstance(huart);
{ if (instance == NULL)
// find the instance which is being handled return;
if (huart == usart_instance[i]->usart_handle)
{ instance->rx_event_count++;
// call the callback function if it is not NULL instance->last_rx_size = Size;
if (usart_instance[i]->module_callback != NULL)
{ if (Size > 0 && Size <= instance->recv_buff_size && instance->module_callback != NULL)
usart_instance[i]->module_callback(); instance->module_callback(instance, instance->recv_buff, Size);
memset(usart_instance[i]->recv_buff, 0, Size); // 接收结束后清空buffer,对于变长数据是必要的
} if (USARTServiceInit(instance) != HAL_OK)
HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, instance->rx_restart_error_count++;
usart_instance[i]->recv_buff_size);
__HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT);
return; // break the loop
}
}
} }
/** /**
@@ -129,17 +194,15 @@ void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
*/ */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{ {
for (uint8_t i = 0; i < idx; ++i) USART_Instance *instance = USARTFindInstance(huart);
{ if (instance == NULL)
if (huart == usart_instance[i]->usart_handle) return;
{
HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, instance->uart_error_count++;
usart_instance[i]->recv_buff_size); instance->last_uart_error = HAL_UART_GetError(huart);
__HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT);
LOGWARNING("[bsp_usart] USART error callback triggered, instance idx [%d]", i); if (USARTServiceInit(instance) != HAL_OK)
return; instance->rx_restart_error_count++;
}
}
} }

View File

@@ -7,8 +7,10 @@
#define DEVICE_USART_CNT 5 // 喵板至多分配5个串口 #define DEVICE_USART_CNT 5 // 喵板至多分配5个串口
#define USART_RXBUFF_LIMIT 256 // 如果协议需要更大的buff,请修改这里 #define USART_RXBUFF_LIMIT 256 // 如果协议需要更大的buff,请修改这里
typedef struct usart_instance USART_Instance;
// 模块回调函数,用于解析协议 // 模块回调函数,用于解析协议
typedef void (*usart_module_callback)(); typedef void (*usart_module_callback)(USART_Instance *instance, const uint8_t *recv_data, uint16_t recv_size);
/* 发送模式枚举 */ /* 发送模式枚举 */
typedef enum typedef enum
@@ -21,18 +23,24 @@ typedef enum
// 串口实例结构体,每个module都要包含一个实例. // 串口实例结构体,每个module都要包含一个实例.
// 由于串口是独占的点对点通信,所以不需要考虑多个module同时使用一个串口的情况,因此不用加入id;当然也可以选择加入,这样在bsp层可以访问到module的其他信息 // 由于串口是独占的点对点通信,所以不需要考虑多个module同时使用一个串口的情况,因此不用加入id;当然也可以选择加入,这样在bsp层可以访问到module的其他信息
typedef struct struct usart_instance
{ {
uint8_t recv_buff[USART_RXBUFF_LIMIT]; // 预先定义的最大buff大小,如果太小请修改USART_RXBUFF_LIMIT uint8_t recv_buff[USART_RXBUFF_LIMIT] __attribute__((aligned(32))); // DMA接收buffer
uint8_t recv_buff_size; // 模块接收一包数据的大小 uint16_t recv_buff_size; // 模块接收一包数据的大小
UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle
usart_module_callback module_callback; // 解析收到的数据的回调函数 usart_module_callback module_callback; // 解析收到的数据的回调函数
} USART_Instance; volatile uint32_t rx_event_count;
volatile uint32_t uart_error_count;
volatile uint32_t rx_restart_error_count;
volatile uint32_t last_uart_error;
volatile uint16_t last_rx_size;
volatile uint8_t rx_restart_pending;
};
/* usart 初始化配置结构体 */ /* usart 初始化配置结构体 */
typedef struct typedef struct
{ {
uint8_t recv_buff_size; // 模块接收一包数据的大小 uint16_t recv_buff_size; // 模块接收一包数据的大小
UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle UART_HandleTypeDef *usart_handle; // 实例对应的usart_handle
usart_module_callback module_callback; // 解析收到的数据的回调函数 usart_module_callback module_callback; // 解析收到的数据的回调函数
} USART_Init_Config_s; } USART_Init_Config_s;
@@ -45,11 +53,16 @@ typedef struct
USART_Instance *USARTRegister(USART_Init_Config_s *init_config); USART_Instance *USARTRegister(USART_Init_Config_s *init_config);
/** /**
* @brief 启动串口服务,需要传入一个usart实例.一般用于lost callback的情况(使用串口的模块daemon) * @brief 启动串口DMA接收服务,需要传入一个已注册的usart实例
* *
* @param _instance * @param _instance
*/ */
void USARTServiceInit(USART_Instance *_instance); HAL_StatusTypeDef USARTServiceInit(USART_Instance *_instance);
/**
* @brief 在任务上下文中恢复中断回调里启动失败的串口接收
*/
void USARTServiceTask(void);
/** /**

View File

@@ -13,7 +13,7 @@ typedef enum
// 添加其他模式 // 添加其他模式
} RobotMode_t; //机器人控制模式 } RobotMode_t; //机器人控制模式
extern RobotMode_t RobotMode; extern volatile RobotMode_t RobotMode;
// #pragma pack() // 开启字节对齐,结束前面的#pragma pack(1) // #pragma pack() // 开启字节对齐,结束前面的#pragma pack(1)

View File

@@ -313,9 +313,9 @@ void systemstart_song(void)
// buzzer_note(120, 0.5); //高音sol // buzzer_note(120, 0.5); //高音sol
// HAL_Delay(550); // HAL_Delay(550);
// SongSpring(); //为什么要演奏春日影!!! //SongSpring(); //为什么要演奏春日影!!!
// SongLaoda(); //SongLaoda();
buzzer_off(); buzzer_off();
} }

View File

@@ -77,23 +77,31 @@
#define REMOTE_CONTROL_FRAME_SIZE 25u // 遥控器接收的buffer大小 #define REMOTE_CONTROL_FRAME_SIZE 25u // 遥控器接收的buffer大小
//@todo测试define
#define REMOTE_FS_I6X
// 定义SBUS协议的起始标志 // 定义SBUS协议的起始标志
#define SBUS_HEAD 0X0F #define SBUS_HEAD 0X0F
// 定义SBUS协议的结束标志 // 定义SBUS协议的结束标志
#define SBUS_END 0X00 #define SBUS_END 0X00
#define SBUS_FLAG_FRAME_LOST (1u << 2)
#define SBUS_FLAG_FAILSAFE (1u << 3)
// 遥控器数据 // 遥控器数据
static RC_ctrl_t rc_ctrl[2]; //[0]:当前数据TEMP,[1]:上一次的数据LAST.用于按键持续按下和切换的判断 static RC_ctrl_t rc_ctrl[2]; //[0]:当前数据TEMP,[1]:上一次的数据LAST.用于按键持续按下和切换的判断
static uint8_t rc_init_flag = 0; // 遥控器初始化标志位 static uint8_t rc_init_flag = 0; // 遥控器初始化标志位
static volatile uint8_t rc_data_valid = 0;
static volatile uint32_t rc_valid_frame_count = 0;
static volatile uint32_t rc_invalid_frame_count = 0;
static volatile uint32_t rc_failsafe_count = 0;
// 遥控器拥有的串口实例,因为遥控器是单例,所以这里只有一个,就不封装了 // 遥控器拥有的串口实例,因为遥控器是单例,所以这里只有一个,就不封装了
static USART_Instance *rc_usart_instance; static USART_Instance *rc_usart_instance;
static Daemon_Instance *rc_daemon_instance; static Daemon_Instance *rc_daemon_instance;
static uint8_t SBusEndByteIsValid(uint8_t value)
{
return value == SBUS_END || value == 0x04u || value == 0x14u || value == 0x24u || value == 0x34u;
}
#ifdef REMOTE_DJI_DT7 #ifdef REMOTE_DJI_DT7
/** /**
@@ -112,8 +120,11 @@ static void RectifyRCjoystick()
* *
* @param sbus_buf 接收buffer * @param sbus_buf 接收buffer
*/ */
static void sbus_to_rc(const uint8_t *sbus_buf) static uint8_t sbus_to_rc(const uint8_t *sbus_buf, uint16_t size)
{ {
if (size != 18u)
return 0;
// 摇杆,直接解算时减去偏置 // 摇杆,直接解算时减去偏置
rc_ctrl[TEMP].rc.rocker_r_ = ((sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 0 rc_ctrl[TEMP].rc.rocker_r_ = ((sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 0
rc_ctrl[TEMP].rc.rocker_r1 = (((sbus_buf[1] >> 3) | (sbus_buf[2] << 5)) & 0x07ff) - RC_CH_VALUE_OFFSET; rc_ctrl[TEMP].rc.rocker_r1 = (((sbus_buf[1] >> 3) | (sbus_buf[2] << 5)) & 0x07ff) - RC_CH_VALUE_OFFSET;
@@ -169,6 +180,7 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
} }
memcpy(&rc_ctrl[LAST], &rc_ctrl[TEMP], sizeof(RC_ctrl_t)); // 保存上一次的数据,用于按键持续按下和切换的判断 memcpy(&rc_ctrl[LAST], &rc_ctrl[TEMP], sizeof(RC_ctrl_t)); // 保存上一次的数据,用于按键持续按下和切换的判断
return 1;
} }
#endif #endif
@@ -178,7 +190,7 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
* *
* @param sbus_buf 接收buffer * @param sbus_buf 接收buffer
*/ */
static void sbus_to_rc(const uint8_t *sbus_buf) static uint8_t sbus_to_rc(const uint8_t *sbus_buf, uint16_t size)
{ {
// // 摇杆,直接解算时减去偏置 // // 摇杆,直接解算时减去偏置
// rc_ctrl[TEMP].rc.rocker_r_ = ((sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 0 // rc_ctrl[TEMP].rc.rocker_r_ = ((sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 0
@@ -230,8 +242,11 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
// rc_ctrl[TEMP].key_count[KEY_PRESS_WITH_SHIFT][i]++; // rc_ctrl[TEMP].key_count[KEY_PRESS_WITH_SHIFT][i]++;
// } // }
if ((sbus_buf[0] != SBUS_HEAD) || (sbus_buf[24] != SBUS_END)) if (size != REMOTE_CONTROL_FRAME_SIZE || sbus_buf[0] != SBUS_HEAD || !SBusEndByteIsValid(sbus_buf[24]))
return; return 0;
if ((sbus_buf[23] & (SBUS_FLAG_FRAME_LOST | SBUS_FLAG_FAILSAFE)) != 0u)
return 0;
// if (sbus_buf[23] == 0x0C) // if (sbus_buf[23] == 0x0C)
// rc_ctrl->online = 0; // rc_ctrl->online = 0;
@@ -261,20 +276,18 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
// rc_ctrl[TEMP].rc.ch[9] = ((sbus_buf[12] >> 3 | sbus_buf[13] << 5) & 0x07FF); // 通道10 (VrB旋钮) // rc_ctrl[TEMP].rc.ch[9] = ((sbus_buf[12] >> 3 | sbus_buf[13] << 5) & 0x07FF); // 通道10 (VrB旋钮)
rc_ctrl[TEMP].sw_a = (rc_ctrl[TEMP].rc.ch[4] == 0x00F0) ? RC_SW_UP : RC_SW_DOWN; rc_ctrl[TEMP].sw_a = (rc_ctrl[TEMP].rc.ch[4] == 0x00F0) ? RC_SW_UP : RC_SW_DOWN;
rc_ctrl[TEMP].sw_b = rc_ctrl[TEMP].rc.ch[5]; //3档
rc_ctrl[TEMP].sw_c = rc_ctrl[TEMP].rc.ch[6]; //3档
rc_ctrl[TEMP].sw_d = (rc_ctrl[TEMP].rc.ch[7] == 0x00F0) ? RC_SW_UP : RC_SW_DOWN; rc_ctrl[TEMP].sw_d = (rc_ctrl[TEMP].rc.ch[7] == 0x00F0) ? RC_SW_UP : RC_SW_DOWN;
// 解析SWB状态 // 解析SWB状态
if (rc_ctrl[TEMP].rc.ch[6] == 0x00F0) if (rc_ctrl[TEMP].rc.ch[5] == 0x00F0)
{ {
rc_ctrl[TEMP].sw_b = RC_SW_UP; rc_ctrl[TEMP].sw_b = RC_SW_UP;
} }
else if (rc_ctrl[TEMP].rc.ch[6] == 0x0400) else if (rc_ctrl[TEMP].rc.ch[5] == 0x0400)
{ {
rc_ctrl[TEMP].sw_b = RC_SW_MID; rc_ctrl[TEMP].sw_b = RC_SW_MID;
} }
else if (rc_ctrl[TEMP].rc.ch[6] == 0x070F) else if (rc_ctrl[TEMP].rc.ch[5] == 0x070F)
{ {
rc_ctrl[TEMP].sw_b = RC_SW_DOWN; rc_ctrl[TEMP].sw_b = RC_SW_DOWN;
} }
@@ -283,27 +296,14 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
rc_ctrl[TEMP].sw_b = 0; rc_ctrl[TEMP].sw_b = 0;
} }
if (rc_ctrl[TEMP].sw_b != rc_ctrl[TEMP].sw_b_last) rc_ctrl[TEMP].sw_b_midtoup_flag =
{ rc_ctrl[TEMP].sw_b_last == RC_SW_MID && rc_ctrl[TEMP].sw_b == RC_SW_UP;
if (rc_ctrl[TEMP].sw_b == RC_SW_UP) rc_ctrl[TEMP].sw_b_uptomid_flag =
{ rc_ctrl[TEMP].sw_b_last == RC_SW_UP && rc_ctrl[TEMP].sw_b == RC_SW_MID;
rc_ctrl[TEMP].sw_b_midtoup_flag = 1; rc_ctrl[TEMP].sw_b_midtodown_flag =
rc_ctrl[TEMP].sw_b_uptomid_flag = 0; rc_ctrl[TEMP].sw_b_last == RC_SW_MID && rc_ctrl[TEMP].sw_b == RC_SW_DOWN;
rc_ctrl[TEMP].sw_b_midtodown_flag = 0; rc_ctrl[TEMP].sw_b_downtomid_flag =
} rc_ctrl[TEMP].sw_b_last == RC_SW_DOWN && rc_ctrl[TEMP].sw_b == RC_SW_MID;
else if (rc_ctrl[TEMP].sw_b == RC_SW_MID)
{
rc_ctrl[TEMP].sw_b_midtoup_flag = 0;
rc_ctrl[TEMP].sw_b_uptomid_flag = 1;
rc_ctrl[TEMP].sw_b_midtodown_flag = 0;
}
else if (rc_ctrl[TEMP].sw_b == RC_SW_DOWN)
{
rc_ctrl[TEMP].sw_b_midtoup_flag = 0;
rc_ctrl[TEMP].sw_b_uptomid_flag = 0;
rc_ctrl[TEMP].sw_b_midtodown_flag = 1;
}
}
rc_ctrl[TEMP].sw_b_last = rc_ctrl[TEMP].sw_b; rc_ctrl[TEMP].sw_b_last = rc_ctrl[TEMP].sw_b;
// 解析SWC状态 // 解析SWC状态
@@ -324,46 +324,22 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
rc_ctrl[TEMP].sw_c = 0; rc_ctrl[TEMP].sw_c = 0;
} }
if (rc_ctrl[TEMP].sw_c != rc_ctrl[TEMP].sw_c_last) rc_ctrl[TEMP].sw_c_midtoup_flag =
{ rc_ctrl[TEMP].sw_c_last == RC_SW_MID && rc_ctrl[TEMP].sw_c == RC_SW_UP;
if (rc_ctrl[TEMP].sw_c == RC_SW_UP) rc_ctrl[TEMP].sw_c_uptomid_flag =
{ rc_ctrl[TEMP].sw_c_last == RC_SW_UP && rc_ctrl[TEMP].sw_c == RC_SW_MID;
rc_ctrl[TEMP].sw_c_midtoup_flag = 1; rc_ctrl[TEMP].sw_c_midtodown_flag =
rc_ctrl[TEMP].sw_c_uptomid_flag = 0; rc_ctrl[TEMP].sw_c_last == RC_SW_MID && rc_ctrl[TEMP].sw_c == RC_SW_DOWN;
rc_ctrl[TEMP].sw_c_midtodown_flag = 0; rc_ctrl[TEMP].sw_c_downtomid_flag =
} rc_ctrl[TEMP].sw_c_last == RC_SW_DOWN && rc_ctrl[TEMP].sw_c == RC_SW_MID;
else if (rc_ctrl[TEMP].sw_c == RC_SW_MID)
{
rc_ctrl[TEMP].sw_c_midtoup_flag = 0;
rc_ctrl[TEMP].sw_c_uptomid_flag = 1;
rc_ctrl[TEMP].sw_c_midtodown_flag = 0;
}
else if (rc_ctrl[TEMP].sw_c == RC_SW_DOWN)
{
rc_ctrl[TEMP].sw_c_midtoup_flag = 0;
rc_ctrl[TEMP].sw_c_uptomid_flag = 0;
rc_ctrl[TEMP].sw_c_midtodown_flag = 1;
}
}
rc_ctrl[TEMP].sw_c_last = rc_ctrl[TEMP].sw_c; rc_ctrl[TEMP].sw_c_last = rc_ctrl[TEMP].sw_c;
// SWA和SWB的状态变化 // SWA和SWD的下降沿
if (rc_ctrl[TEMP].sw_a != rc_ctrl[TEMP].sw_a_last) rc_ctrl[TEMP].sw_a_up_to_down_flag =
{ rc_ctrl[TEMP].sw_a_last == RC_SW_UP && rc_ctrl[TEMP].sw_a == RC_SW_DOWN;
rc_ctrl[TEMP].sw_a_up_to_down_flag = (rc_ctrl[TEMP].sw_a == RC_SW_UP) ? 1 : 0;
}
rc_ctrl[TEMP].sw_a_last = rc_ctrl[TEMP].sw_a; rc_ctrl[TEMP].sw_a_last = rc_ctrl[TEMP].sw_a;
rc_ctrl[TEMP].sw_d_up_to_down_flag =
// if (rc_ctrl[TEMP].sw_b != rc_ctrl[TEMP].sw_b_last) { rc_ctrl[TEMP].sw_d_last == RC_SW_UP && rc_ctrl[TEMP].sw_d == RC_SW_DOWN;
// rc_ctrl[TEMP].sw_b_up_to_down_flag = (rc_ctrl[TEMP].sw_b == RC_SW_UP) ? 1 : 0;
// }
// rc_ctrl[TEMP].sw_b_last = rc_ctrl[TEMP].sw_b;
// SWD的状态变化
if (rc_ctrl[TEMP].sw_d != rc_ctrl[TEMP].sw_d_last)
{
rc_ctrl[TEMP].sw_d_up_to_down_flag = (rc_ctrl[TEMP].sw_d == RC_SW_UP) ? 1 : 0;
}
rc_ctrl[TEMP].sw_d_last = rc_ctrl[TEMP].sw_d; rc_ctrl[TEMP].sw_d_last = rc_ctrl[TEMP].sw_d;
// 修正 ch1~ch4 // 修正 ch1~ch4
@@ -374,17 +350,54 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
// ...existing code... // ...existing code...
memcpy(&rc_ctrl[LAST], &rc_ctrl[TEMP], sizeof(RC_ctrl_t)); // 保存上一次的数据,用于按键持续按下和切换的判断 memcpy(&rc_ctrl[LAST], &rc_ctrl[TEMP], sizeof(RC_ctrl_t)); // 保存上一次的数据,用于按键持续按下和切换的判断
return 1;
} }
#endif #endif
static void RemoteControlPublishOffline(uint8_t force)
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
uint8_t daemon_expired = rc_daemon_instance != NULL && rc_daemon_instance->temp_count == 0;
if (force || daemon_expired)
{
rc_data_valid = 0;
memset(rc_ctrl, 0, sizeof(rc_ctrl));
if (RobotMode != SYS_ERROR_OCCURRED)
RobotMode = REMOTE_NOT_CONNECTED;
}
__set_PRIMASK(primask);
}
/** /**
* @brief 对sbus_to_rc的简单封装,用于注册到bsp_usart的回调函数中 * @brief 对sbus_to_rc的简单封装,用于注册到bsp_usart的回调函数中
* *
*/ */
static void RemoteControlRxCallback() static void RemoteControlRxCallback(USART_Instance *instance, const uint8_t *recv_data, uint16_t recv_size)
{ {
sbus_to_rc(rc_usart_instance->recv_buff); // 进行协议解析 (void) instance;
DaemonReload(rc_daemon_instance); // 先喂狗
if (recv_size == REMOTE_CONTROL_FRAME_SIZE && recv_data[0] == SBUS_HEAD &&
SBusEndByteIsValid(recv_data[24]) && (recv_data[23] & SBUS_FLAG_FAILSAFE) != 0u)
{
rc_failsafe_count++;
RemoteControlPublishOffline(1);
return;
}
if (!sbus_to_rc(recv_data, recv_size))
{
rc_invalid_frame_count++;
return;
}
rc_valid_frame_count++;
rc_data_valid = 1;
DaemonReload(rc_daemon_instance);
if (RobotMode == REMOTE_NOT_CONNECTED)
RobotMode = REMOTE_CONNECTED;
} }
/** /**
@@ -393,38 +406,74 @@ static void RemoteControlRxCallback()
*/ */
static void RCLostCallback(void *id) static void RCLostCallback(void *id)
{ {
memset(rc_ctrl, 0, sizeof(rc_ctrl)); // 清空遥控器数据 (void) id;
USARTServiceInit(rc_usart_instance); // 尝试重新启动接收 RemoteControlPublishOffline(0);
RobotMode = REMOTE_NOT_CONNECTED;
// LEDErrLog(0, LED_COLOR_R); // 红灯常亮 表示遥控器离线 // LEDErrLog(0, LED_COLOR_R); // 红灯常亮 表示遥控器离线
} }
RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle) RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle)
{ {
USART_Init_Config_s conf; if (rc_init_flag)
conf.module_callback = RemoteControlRxCallback; return &rc_ctrl[TEMP];
conf.usart_handle = rc_usart_handle; if (rc_usart_handle == NULL || rc_usart_handle->hdmarx == NULL)
conf.recv_buff_size = REMOTE_CONTROL_FRAME_SIZE; return NULL;
rc_usart_instance = USARTRegister(&conf); memset(rc_ctrl, 0, sizeof(rc_ctrl));
rc_data_valid = 0;
// 进行守护进程的注册,用于定时检查遥控器是否正常工作 if (rc_usart_instance == NULL)
Daemon_Init_Config_s daemon_conf = { {
.reload_count = 10, // 100ms未收到数据视为离线,遥控器的接收频率实际上是1000/14Hz(大约70Hz) USART_Init_Config_s conf = {
.callback = RCLostCallback, .module_callback = RemoteControlRxCallback,
.owner_id = NULL, // 只有1个遥控器,不需要owner_id .usart_handle = rc_usart_handle,
}; .recv_buff_size = REMOTE_CONTROL_FRAME_SIZE,
rc_daemon_instance = DaemonRegister(&daemon_conf); };
rc_usart_instance = USARTRegister(&conf);
if (rc_usart_instance == NULL)
return NULL;
}
if (rc_daemon_instance == NULL)
{
// 100ms未收到有效数据视为离线,SBUS接收频率约70Hz.
Daemon_Init_Config_s daemon_conf = {
.reload_count = 10,
.callback = RCLostCallback,
.owner_id = NULL,
};
rc_daemon_instance = DaemonRegister(&daemon_conf);
}
rc_init_flag = 1; rc_init_flag = 1;
return rc_ctrl; if (USARTServiceInit(rc_usart_instance) != HAL_OK)
rc_usart_instance->rx_restart_error_count++;
return &rc_ctrl[TEMP];
} }
uint8_t RemoteControlIsOnline() uint8_t RemoteControlReadSnapshot(RC_ctrl_t *out)
{ {
if (rc_init_flag) if (out == NULL)
return DaemonIsOnline(rc_daemon_instance); return 0;
return 0;
uint32_t primask = __get_PRIMASK();
__disable_irq();
uint8_t valid = rc_init_flag && rc_data_valid && rc_daemon_instance != NULL &&
rc_daemon_instance->temp_count > 0;
if (valid)
memcpy(out, &rc_ctrl[TEMP], sizeof(*out));
__set_PRIMASK(primask);
return valid;
}
uint8_t RemoteControlIsOnline(void)
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
uint8_t online = rc_init_flag && rc_data_valid && rc_daemon_instance != NULL &&
rc_daemon_instance->temp_count > 0;
__set_PRIMASK(primask);
return online;
} }

View File

@@ -125,21 +125,30 @@ typedef struct
uint8_t key_count[3][16]; uint8_t key_count[3][16];
} RC_ctrl_t; } RC_ctrl_t;
#endif // FSI6X #endif // FSI6X
/* ------------------------- Internal Data ----------------------------------- */ /* ------------------------- Internal Data ----------------------------------- */
/** /**
* @brief 初始化遥控器,该函数会将遥控器注册到串口 * @brief 初始化遥控器,该函数会将遥控器注册到串口
* *
* @attention 注意分配正确的串口硬件,遥控器在C板上使用USART3 * @attention 当前板级配置使用UART5/PD2接收SBUS
* *
*/ */
RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle); RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle);
/**
* @brief 原子复制当前遥控器数据
*
* @param out 接收遥控器数据快照
* @return uint8_t 1:快照有效 0:未初始化、离线或参数无效
*/
uint8_t RemoteControlReadSnapshot(RC_ctrl_t *out);
/** /**
* @brief 检查遥控器是否在线,若尚未初始化也视为离线 * @brief 检查遥控器是否在线,若尚未初始化也视为离线
* *
* @return uint8_t 1:在线 0:离线 * @return uint8_t 1:在线 0:离线
*/ */
uint8_t RemoteControlIsOnline(); uint8_t RemoteControlIsOnline(void);
#endif // REMOTE_H #endif // REMOTE_H

View File

@@ -1,6 +1,7 @@
#include "daemon.h" #include "daemon.h"
#include "bsp_dwt.h" #include "bsp_dwt.h"
#include "cmsis_os2.h" #include "cmsis_os2.h"
#include "main.h"
#include "memory.h" #include "memory.h"
#include "stdlib.h" #include "stdlib.h"
@@ -16,8 +17,7 @@ Daemon_Instance *DaemonRegister(Daemon_Init_Config_s *config)
daemon_instance->id = config->owner_id; daemon_instance->id = config->owner_id;
daemon_instance->reload_count = config->reload_count == 0 ? 100 : config->reload_count; // 默认重载值为100 daemon_instance->reload_count = config->reload_count == 0 ? 100 : config->reload_count; // 默认重载值为100
daemon_instance->callback = config->callback; daemon_instance->callback = config->callback;
daemon_instance->temp_count = config->init_count == 0 ? 100 : config->init_count; // 默认上线等待时间为100 daemon_instance->temp_count = config->init_count == 0 ? daemon_instance->reload_count : config->init_count;
daemon_instance->temp_count = config->reload_count;
daemon_instances[idx++] = daemon_instance; daemon_instances[idx++] = daemon_instance;
@@ -31,7 +31,13 @@ Daemon_Instance *DaemonRegister(Daemon_Init_Config_s *config)
*/ */
void DaemonReload(Daemon_Instance *daemon) void DaemonReload(Daemon_Instance *daemon)
{ {
if (daemon == NULL)
return;
uint32_t primask = __get_PRIMASK();
__disable_irq();
daemon->temp_count = daemon->reload_count; daemon->temp_count = daemon->reload_count;
__set_PRIMASK(primask);
} }
/** /**
@@ -42,7 +48,14 @@ void DaemonReload(Daemon_Instance *daemon)
*/ */
uint8_t DaemonIsOnline(Daemon_Instance *daemon) uint8_t DaemonIsOnline(Daemon_Instance *daemon)
{ {
return daemon->temp_count > 0; if (daemon == NULL)
return 0;
uint32_t primask = __get_PRIMASK();
__disable_irq();
uint8_t online = daemon->temp_count > 0;
__set_PRIMASK(primask);
return online;
} }
/** /**
@@ -61,9 +74,17 @@ void Daemon_Update(void) // 名字改掉,不要叫 Task避免和 RTOS 线
for (uint8_t i = 0; i < idx; i++) for (uint8_t i = 0; i < idx; i++)
{ {
daemon = daemon_instances[i]; daemon = daemon_instances[i];
uint8_t expired = 0;
uint32_t primask = __get_PRIMASK();
__disable_irq();
if (daemon->temp_count > 0) if (daemon->temp_count > 0)
daemon->temp_count--; daemon->temp_count--;
else if (daemon->callback != NULL) else
expired = 1;
__set_PRIMASK(primask);
if (expired && daemon->callback != NULL)
daemon->callback(daemon->id); daemon->callback(daemon->id);
} }
} }

View File

@@ -25,7 +25,7 @@ typedef struct daemon_ins
uint16_t reload_count; // 重载值 uint16_t reload_count; // 重载值
offline_callback callback; // 离线处理函数,当模块离线时调用 offline_callback callback; // 离线处理函数,当模块离线时调用
uint16_t temp_count; // 当前值,减为零说明模块离线或异常 volatile uint16_t temp_count; // 当前值,减为零说明模块离线或异常
void *id; // 模块id,用于标识模块,初始化时传入 void *id; // 模块id,用于标识模块,初始化时传入
} Daemon_Instance; } Daemon_Instance;

View File

@@ -23,7 +23,7 @@ void OnProjectLoad (void) {
// Dialog-generated settings // Dialog-generated settings
// //
Project.SetDevice ("STM32H723VG"); Project.SetDevice ("STM32H723VG");
Project.SetHostIF ("USB", "602712948"); Project.SetHostIF ("USB", "63728936");
Project.SetTargetIF ("SWD"); Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("4 MHz"); Project.SetTIFSpeed ("4 MHz");
Project.AddPathSubstitute ("D:/RM/Elec Control/TronOneH7_Scaffold/ozonedeb", "$(ProjectDir)"); Project.AddPathSubstitute ("D:/RM/Elec Control/TronOneH7_Scaffold/ozonedeb", "$(ProjectDir)");

View File

@@ -4,15 +4,15 @@ Breakpoint=D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/power_m
GraphedExpression="(QEKF_INS).Roll", Color=#a00909 GraphedExpression="(QEKF_INS).Roll", Color=#a00909
GraphedExpression="(BMI088).Temperature", Color=#09a01b GraphedExpression="(BMI088).Temperature", Color=#09a01b
GraphedExpression="(QEKF_INS).Pitch", Color=#09a087 GraphedExpression="(QEKF_INS).Pitch", Color=#09a087
OpenDocument="bsp_dwt.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/bsp/dwt/bsp_dwt.c", Line=59 OpenDocument="main.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Core/Src/main.c", Line=72
OpenDocument="stm32h7xx_hal_spi.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c", Line=1553 OpenDocument="stm32h7xx_hal_spi.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_spi.c", Line=958
OpenDocument="tasks.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Middlewares/Third_Party/FreeRTOS/Source/tasks.c", Line=2295 OpenDocument="tasks.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Middlewares/Third_Party/FreeRTOS/Source/tasks.c", Line=2306
OpenDocument="delayticks.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/bsp/delayticks/delayticks.c", Line=4 OpenDocument="delayticks.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/bsp/delayticks/delayticks.c", Line=4
OpenDocument="dev_cmd.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/user_task/dev_tasks/dev_cmd.c", Line=23 OpenDocument="dev_cmd.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/user_task/dev_tasks/dev_cmd.c", Line=0
OpenDocument="main.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Core/Src/main.c", Line=71 OpenDocument="stm32h7xx_it.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Core/Src/stm32h7xx_it.c", Line=306
OpenDocument="xidipwmeter.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/power_meters/xiditech/xidipwmeter.c", Line=37 OpenDocument="xidipwmeter.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/power_meters/xiditech/xidipwmeter.c", Line=37
OpenDocument="stm32h7xx_hal.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c", Line=331 OpenDocument="stm32h7xx_hal.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c", Line=331
OpenDocument="stm32h7xx_it.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/Core/Src/stm32h7xx_it.c", Line=306 OpenDocument="bsp_dwt.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/bsp/dwt/bsp_dwt.c", Line=109
OpenDocument="QuaternionEKF.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/algorithm/ekf/QuaternionEKF.c", Line=436 OpenDocument="QuaternionEKF.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/algorithm/ekf/QuaternionEKF.c", Line=436
OpenDocument="buzzer.cpp", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/buzzer/buzzer.cpp", Line=319 OpenDocument="buzzer.cpp", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/buzzer/buzzer.cpp", Line=319
OpenDocument="rc.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/remote_control/rc.c", Line=0 OpenDocument="rc.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/remote_control/rc.c", Line=0
@@ -30,35 +30,35 @@ OpenDocument="ws2812.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Co
OpenDocument="ins_task.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/imu/ins_task.c", Line=0 OpenDocument="ins_task.c", FilePath="D:/RM/Elec Control/TronOneH7_Scaffold/User_Code/module/periph/imu/ins_task.c", Line=0
OpenToolbar="Debug", Floating=0, x=0, y=0 OpenToolbar="Debug", Floating=0, x=0, y=0
OpenToolbar="Breakpoints", Floating=0, x=1, y=0 OpenToolbar="Breakpoints", Floating=0, x=1, y=0
OpenWindow="Call Stack", DockArea=RIGHT, x=0, y=0, w=681, h=324, TabPos=0, TopOfStack=1, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Call Stack", DockArea=RIGHT, x=0, y=0, w=681, h=225, TabPos=0, TopOfStack=1, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Registers 1", DockArea=BOTTOM, x=1, y=0, w=361, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, FilteredItems=[], RefreshRate=1 OpenWindow="Registers 1", DockArea=BOTTOM, x=1, y=0, w=271, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, FilteredItems=[], RefreshRate=1
OpenWindow="Source Files", DockArea=LEFT, x=0, y=0, w=663, h=273, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Source Files", DockArea=LEFT, x=0, y=0, w=663, h=189, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Disassembly", DockArea=BOTTOM, x=2, y=0, w=629, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Disassembly", DockArea=BOTTOM, x=2, y=0, w=472, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Break & Tracepoints", DockArea=LEFT, x=0, y=1, w=663, h=240, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, VectorCatchIndexMask=254 OpenWindow="Break & Tracepoints", DockArea=LEFT, x=0, y=1, w=663, h=176, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, VectorCatchIndexMask=254
OpenWindow="Memory 1", DockArea=BOTTOM, x=3, y=0, w=465, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, EditorAddress=0x2000B98C OpenWindow="Memory 1", DockArea=BOTTOM, x=3, y=0, w=348, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, EditorAddress=0x2000B98C
OpenWindow="Global Data", DockArea=RIGHT, x=0, y=2, w=681, h=377, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Global Data", DockArea=RIGHT, x=0, y=2, w=681, h=260, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Watched Data 1", DockArea=LEFT, x=0, y=2, w=663, h=313, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Watched Data 1", DockArea=LEFT, x=0, y=2, w=663, h=206, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Functions", DockArea=LEFT, x=0, y=3, w=663, h=246, TabPos=1, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Functions", DockArea=LEFT, x=0, y=3, w=663, h=168, TabPos=1, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Call Graph", DockArea=LEFT, x=0, y=3, w=663, h=246, TabPos=2, TopOfStack=1, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Call Graph", DockArea=LEFT, x=0, y=3, w=663, h=168, TabPos=2, TopOfStack=1, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="Data Sampling", DockArea=BOTTOM, x=0, y=0, w=1102, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, VisibleTab=0, UniformSampleSpacing=0 OpenWindow="Data Sampling", DockArea=BOTTOM, x=0, y=0, w=826, h=181, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, VisibleTab=0, UniformSampleSpacing=0
OpenWindow="Timeline", DockArea=RIGHT, x=0, y=1, w=681, h=372, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=1, DataPaneShown=1, PowerPaneShown=0, CodePaneShown=0, PinCursor="Cursor Movable", TimePerDiv="1 s / Div", TimeStampFormat="Time", DataGraphDrawAsPoints=0, DataGraphLegendShown=1, DataGraphUniformSampleSpacing=0, DataGraphLegendPosition="0;0", PowerGraphDrawAsPoints=0, PowerGraphLegendShown=0, PowerGraphAvgFilterTime=Off, PowerGraphAvgFilterLen=Off, PowerGraphUniformSampleSpacing=0, PowerGraphLegendPosition="459;-65", CodeGraphLegendShown=0, CodeGraphLegendPosition="475;0" OpenWindow="Timeline", DockArea=RIGHT, x=0, y=1, w=681, h=255, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=1, DataPaneShown=1, PowerPaneShown=0, CodePaneShown=0, PinCursor="Cursor Movable", TimePerDiv="1 s / Div", TimeStampFormat="Time", DataGraphDrawAsPoints=0, DataGraphLegendShown=1, DataGraphUniformSampleSpacing=0, DataGraphLegendPosition="0;0", PowerGraphDrawAsPoints=0, PowerGraphLegendShown=0, PowerGraphAvgFilterTime=Off, PowerGraphAvgFilterLen=Off, PowerGraphUniformSampleSpacing=0, PowerGraphLegendPosition="484;-16", CodeGraphLegendShown=0, CodeGraphLegendPosition="498;0"
OpenWindow="Console", DockArea=LEFT, x=0, y=3, w=663, h=246, TabPos=0, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0 OpenWindow="Console", DockArea=LEFT, x=0, y=3, w=663, h=168, TabPos=0, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0
OpenWindow="FreeRTOS", DockArea=RIGHT, x=0, y=0, w=681, h=324, TabPos=1, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, Showing="Task List" OpenWindow="FreeRTOS", DockArea=RIGHT, x=0, y=0, w=681, h=225, TabPos=1, TopOfStack=0, FilterBarShown=0, TotalValueBarShown=0, ToolBarShown=0, Showing="Task List"
TableHeader="Call Graph", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Stack Total";"Stack Local";"Code Total";"Code Local";"Depth";"Called From"], ColWidths=[384;100;100;100;100;100;102]
TableHeader="Task List", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Run Count";"Priority";"Status";"Timeout";"Stack Info (Free / Size)";"ID";"Mutex Count";"Notified Value";"Notify State"], ColWidths=[110;110;110;110;110;110;110;110;110;110] TableHeader="Task List", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Run Count";"Priority";"Status";"Timeout";"Stack Info (Free / Size)";"ID";"Mutex Count";"Notified Value";"Notify State"], ColWidths=[110;110;110;110;110;110;110;110;110;110]
TableHeader="Functions", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Address";"Size";"#Insts";"Source"], ColWidths=[1164;100;100;100;100] TableHeader="Functions", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Address";"Size";"#Insts";"Source"], ColWidths=[1164;100;100;100;100]
TableHeader="Global Data", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Location";"Size";"Type";"Scope"], ColWidths=[222;130;100;54;95;486] TableHeader="Global Data", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Location";"Size";"Type";"Scope"], ColWidths=[222;130;100;54;95;100]
TableHeader="Vector Catches", SortCol="None", SortOrder="ASCENDING", VisibleCols=["";"Vector Catch";"Description"], ColWidths=[50;300;500] TableHeader="Vector Catches", SortCol="None", SortOrder="ASCENDING", VisibleCols=["";"Vector Catch";"Description"], ColWidths=[50;300;500]
TableHeader="Break & Tracepoints", SortCol="None", SortOrder="ASCENDING", VisibleCols=["";"Type";"Location";"Extras"], ColWidths=[100;100;142;321] TableHeader="Break & Tracepoints", SortCol="None", SortOrder="ASCENDING", VisibleCols=["";"Type";"Location";"Extras"], ColWidths=[100;100;142;321]
TableHeader="Source Files", SortCol="File", SortOrder="ASCENDING", VisibleCols=["File";"Status";"Size";"#Insts";"Path"], ColWidths=[229;100;100;100;1046] TableHeader="Source Files", SortCol="File", SortOrder="ASCENDING", VisibleCols=["File";"Status";"Size";"#Insts";"Path"], ColWidths=[229;100;100;100;917]
TableHeader="Data Sampling Table", SortCol="Index", SortOrder="ASCENDING", VisibleCols=["Index";"Time";" (QEKF_INS).Roll";" (BMI088).Temperature";" (QEKF_INS).Pitch"], ColWidths=[100;100;100;100;100] TableHeader="Data Sampling Table", SortCol="None", SortOrder="ASCENDING", VisibleCols=["Index";"Time";" (QEKF_INS).Roll";" (BMI088).Temperature";" (QEKF_INS).Pitch"], ColWidths=[100;100;100;100;100]
TableHeader="Data Sampling Setup", SortCol="Expression", SortOrder="ASCENDING", VisibleCols=["Expression";"Type";"Value";"Min";"Max";"Average";"# Changes";"Min. Change";"Max. Change"], ColWidths=[320;100;110;102;100;110;102;118;118] TableHeader="Data Sampling Setup", SortCol="Expression", SortOrder="ASCENDING", VisibleCols=["Expression";"Type";"Value";"Min";"Max";"Average";"# Changes";"Min. Change";"Max. Change"], ColWidths=[320;100;100;100;100;100;100;102;102]
TableHeader="Power Sampling", SortCol="Index", SortOrder="ASCENDING", VisibleCols=["Index";"Time";"Ch 0"], ColWidths=[100;100;100] TableHeader="Power Sampling", SortCol="Index", SortOrder="ASCENDING", VisibleCols=["Index";"Time";"Ch 0"], ColWidths=[100;100;100]
TableHeader="Registers 1", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Description"], ColWidths=[100;105;294] TableHeader="Registers 1", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Description"], ColWidths=[100;105;259]
TableHeader="Watched Data 1", SortCol="Expression", SortOrder="ASCENDING", VisibleCols=["Expression";"Value";"Type";"Location";"Refresh"], ColWidths=[171;101;162;112;117] TableHeader="Watched Data 1", SortCol="Expression", SortOrder="ASCENDING", VisibleCols=["Expression";"Value";"Type";"Location";"Refresh"], ColWidths=[171;101;162;112;100]
TableHeader="RegisterSelectionDialog", SortCol="None", SortOrder="ASCENDING", VisibleCols=[], ColWidths=[] TableHeader="RegisterSelectionDialog", SortCol="None", SortOrder="ASCENDING", VisibleCols=[], ColWidths=[]
TableHeader="Call Graph", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Stack Total";"Stack Local";"Code Total";"Code Local";"Depth";"Called From"], ColWidths=[384;100;100;100;100;100;118]
TableHeader="Call Stack", SortCol="Function", SortOrder="ASCENDING", VisibleCols=["Function";"Stack Frame";"Source";"PC";"Return Address";"Stack Used"], ColWidths=[110;126;190;100;190;100] TableHeader="Call Stack", SortCol="Function", SortOrder="ASCENDING", VisibleCols=["Function";"Stack Frame";"Source";"PC";"Return Address";"Stack Used"], ColWidths=[110;126;190;100;190;100]
TableHeader="TargetExceptionDialog", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Address";"Description"], ColWidths=[27;27;27;38] TableHeader="TargetExceptionDialog", SortCol="Name", SortOrder="ASCENDING", VisibleCols=["Name";"Value";"Address";"Description"], ColWidths=[27;27;27;32]
WatchedExpression="QEKF_INS", RefreshRate=2, Window=Watched Data 1 WatchedExpression="QEKF_INS", RefreshRate=2, Window=Watched Data 1
WatchedExpression="BMI088", RefreshRate=2, Window=Watched Data 1 WatchedExpression="BMI088", RefreshRate=2, Window=Watched Data 1
WatchedExpression="RobotMode_t", Window=Watched Data 1 WatchedExpression="RobotMode_t", Window=Watched Data 1