diff --git a/.DS_Store b/.DS_Store index 6386a06..7169f00 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/bsp/fdcan/can.h b/bsp/fdcan/can.h new file mode 100644 index 0000000..531f824 --- /dev/null +++ b/bsp/fdcan/can.h @@ -0,0 +1,79 @@ +/** + * @file can.h + * @brief CAN兼容层 - 将CAN接口映射到FDCAN + * @note 本文件用于FDCAN兼容CAN接口,设备层代码可以继续使用BSP_CAN_xxx接口 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include "bsp/fdcan.h" + +/* 类型映射 */ +typedef BSP_FDCAN_t BSP_CAN_t; +typedef BSP_FDCAN_Callback_t BSP_CAN_Callback_t; +typedef BSP_FDCAN_Format_t BSP_CAN_Format_t; +typedef BSP_FDCAN_FrameType_t BSP_CAN_FrameType_t; +typedef BSP_FDCAN_Message_t BSP_CAN_Message_t; +typedef BSP_FDCAN_StdDataFrame_t BSP_CAN_StdDataFrame_t; +typedef BSP_FDCAN_ExtDataFrame_t BSP_CAN_ExtDataFrame_t; +typedef BSP_FDCAN_RemoteFrame_t BSP_CAN_RemoteFrame_t; +typedef BSP_FDCAN_IdParser_t BSP_CAN_IdParser_t; + +/* 常量映射 */ +#define BSP_CAN_MAX_DLC BSP_FDCAN_MAX_DLC +#define BSP_CAN_DEFAULT_QUEUE_SIZE BSP_FDCAN_DEFAULT_QUEUE_SIZE +#define BSP_CAN_TIMEOUT_IMMEDIATE BSP_FDCAN_TIMEOUT_IMMEDIATE +#define BSP_CAN_TIMEOUT_FOREVER BSP_FDCAN_TIMEOUT_FOREVER +#define BSP_CAN_TX_QUEUE_SIZE BSP_FDCAN_TX_QUEUE_SIZE + +/* 枚举值映射 */ +#define BSP_CAN_1 BSP_FDCAN_1 +#define BSP_CAN_2 BSP_FDCAN_2 +#define BSP_CAN_3 BSP_FDCAN_3 +#define BSP_CAN_NUM BSP_FDCAN_NUM +#define BSP_CAN_ERR BSP_FDCAN_ERR + +#define BSP_CAN_FORMAT_STD_DATA BSP_FDCAN_FORMAT_STD_DATA +#define BSP_CAN_FORMAT_EXT_DATA BSP_FDCAN_FORMAT_EXT_DATA +#define BSP_CAN_FORMAT_STD_REMOTE BSP_FDCAN_FORMAT_STD_REMOTE +#define BSP_CAN_FORMAT_EXT_REMOTE BSP_FDCAN_FORMAT_EXT_REMOTE + +#define BSP_CAN_FRAME_STD_DATA BSP_FDCAN_FRAME_STD_DATA +#define BSP_CAN_FRAME_EXT_DATA BSP_FDCAN_FRAME_EXT_DATA +#define BSP_CAN_FRAME_STD_REMOTE BSP_FDCAN_FRAME_STD_REMOTE +#define BSP_CAN_FRAME_EXT_REMOTE BSP_FDCAN_FRAME_EXT_REMOTE + +/* 函数映射 */ +#define BSP_CAN_Init() BSP_FDCAN_Init() +#define BSP_CAN_GetHandle(can) BSP_FDCAN_GetHandle(can) +#define BSP_CAN_RegisterCallback(can, type, callback) \ + BSP_FDCAN_RegisterCallback(can, type, callback) +#define BSP_CAN_Transmit(can, format, id, data, dlc) \ + BSP_FDCAN_Transmit(can, format, id, data, dlc) +#define BSP_CAN_TransmitStdDataFrame(can, frame) \ + BSP_FDCAN_TransmitStdDataFrame(can, frame) +#define BSP_CAN_TransmitExtDataFrame(can, frame) \ + BSP_FDCAN_TransmitExtDataFrame(can, frame) +#define BSP_CAN_TransmitRemoteFrame(can, frame) \ + BSP_FDCAN_TransmitRemoteFrame(can, frame) +#define BSP_CAN_RegisterId(can, can_id, queue_size) \ + BSP_FDCAN_RegisterId(can, can_id, queue_size) +#define BSP_CAN_GetMessage(can, can_id, msg, timeout) \ + BSP_FDCAN_GetMessage(can, can_id, msg, timeout) +#define BSP_CAN_GetQueueCount(can, can_id) \ + BSP_FDCAN_GetQueueCount(can, can_id) +#define BSP_CAN_FlushQueue(can, can_id) \ + BSP_FDCAN_FlushQueue(can, can_id) +#define BSP_CAN_RegisterIdParser(parser) \ + BSP_FDCAN_RegisterIdParser(parser) +#define BSP_CAN_ParseId(original_id, frame_type) \ + BSP_FDCAN_ParseId(original_id, frame_type) + +#ifdef __cplusplus +} +#endif diff --git a/bsp/flash/flash.c b/bsp/flash/flash.c index 0df01ca..87af81a 100644 --- a/bsp/flash/flash.c +++ b/bsp/flash/flash.c @@ -26,10 +26,18 @@ void BSP_Flash_EraseSector(uint32_t sector) { flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS; flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; flash_erase.NbSectors = 1; +#if defined(STM32H7) + flash_erase.Banks = FLASH_BANK_1; // H7 requires Bank parameter +#endif HAL_FLASH_Unlock(); +#if defined(STM32H7) + while (FLASH_WaitForLastOperation(50, FLASH_BANK_1) != HAL_OK) + ; +#else while (FLASH_WaitForLastOperation(50) != HAL_OK) ; +#endif HAL_FLASHEx_Erase(&flash_erase, §or_error); HAL_FLASH_Lock(); } @@ -39,6 +47,24 @@ void BSP_Flash_EraseSector(uint32_t sector) { void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len) { HAL_FLASH_Unlock(); +#if defined(STM32H7) + // H7 uses FLASHWORD (32 bytes) programming + uint8_t flash_word[32] __attribute__((aligned(32))); + while (len > 0) { + size_t chunk = (len < 32) ? len : 32; + memset(flash_word, 0xFF, 32); + memcpy(flash_word, buf, chunk); + + while (FLASH_WaitForLastOperation(50, FLASH_BANK_1) != HAL_OK) + ; + HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, (uint32_t)flash_word); + + address += 32; + buf += chunk; + len -= chunk; + } +#else + // F4/F7 use byte programming while (len > 0) { while (FLASH_WaitForLastOperation(50) != HAL_OK) ; @@ -47,6 +73,7 @@ void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len) { buf++; len--; } +#endif HAL_FLASH_Lock(); } diff --git a/component/dependencies.csv b/component/dependencies.csv index c3f1e6d..b8e03ae 100644 --- a/component/dependencies.csv +++ b/component/dependencies.csv @@ -5,4 +5,5 @@ error_detect,bsp/mm pid,component/filter filter,component/ahrs mixer,component/user_math.h -ui,component/user_math.h \ No newline at end of file +ui,component/user_math.h +kalman_filter,arm_math.h \ No newline at end of file diff --git a/component/describe.csv b/component/describe.csv index 2752291..457125d 100644 --- a/component/describe.csv +++ b/component/describe.csv @@ -11,4 +11,5 @@ limiter,限幅器 mixer,混控器 ui,用户交互 user_math,用户自定义数学函数 -pid,PID控制器 \ No newline at end of file +pid,PID控制器 +kalman_filter,卡尔曼滤波器 \ No newline at end of file diff --git a/component/kalman_filter/kalman_filter.c b/component/kalman_filter/kalman_filter.c new file mode 100644 index 0000000..e5463a4 --- /dev/null +++ b/component/kalman_filter/kalman_filter.c @@ -0,0 +1,591 @@ +/* + 卡尔曼滤波器 modified from wang hongxi + 支持动态量测调整,使用ARM CMSIS DSP优化矩阵运算 + + 主要特性: + - 基于量测有效性的 H、R、K 矩阵动态调整 + - 支持不同传感器采样频率 + - 矩阵 P 防过度收敛机制 + - ARM CMSIS DSP 优化的矩阵运算 + - 可扩展架构,支持用户自定义函数(EKF/UKF/ESKF) + + 使用说明: + 1. 矩阵初始化:P、F、Q 使用标准初始化方式 + H、R 在使用自动调整时需要配置量测映射 + + 2. 自动调整模式 (use_auto_adjustment = 1): + - 提供 measurement_map:每个量测对应的状态索引 + - 提供 measurement_degree:H 矩阵元素值 + - 提供 mat_r_diagonal_elements:量测噪声方差 + + 3. 固定模式 (use_auto_adjustment = 0): + - 像初始化 P 矩阵那样正常初始化 z、H、R + + 4. 量测更新: + - 在传感器回调函数中更新 measured_vector + - 值为 0 表示量测无效 + - 向量在每次 KF 更新后会被重置为 0 + + 5. 防过度收敛: + - 设置 state_min_variance 防止 P 矩阵过度收敛 + - 帮助滤波器适应缓慢变化的状态 + + 使用示例:高度估计 + 状态向量 x = + | 高度 | + | 速度 | + | 加速度 | + + KF_t Height_KF; + + void INS_Task_Init(void) + { + // 初始协方差矩阵 P + static float P_Init[9] = + { + 10, 0, 0, + 0, 30, 0, + 0, 0, 10, + }; + + // 状态转移矩阵 F(根据运动学模型) + static float F_Init[9] = + { + 1, dt, 0.5*dt*dt, + 0, 1, dt, + 0, 0, 1, + }; + + // 过程噪声协方差矩阵 Q + static float Q_Init[9] = + { + 0.25*dt*dt*dt*dt, 0.5*dt*dt*dt, 0.5*dt*dt, + 0.5*dt*dt*dt, dt*dt, dt, + 0.5*dt*dt, dt, 1, + }; + + // 设置状态最小方差(防止过度收敛) + static float state_min_variance[3] = {0.03, 0.005, 0.1}; + + // 开启自动调整 + Height_KF.use_auto_adjustment = 1; + + // 量测映射:[气压高度对应状态1, GPS高度对应状态1, 加速度计对应状态3] + static uint8_t measurement_reference[3] = {1, 1, 3}; + + // 量测系数(H矩阵元素值) + static float measurement_degree[3] = {1, 1, 1}; + // 根据 measurement_reference 与 measurement_degree 生成 H 矩阵如下 + // (在当前周期全部量测数据有效的情况下) + // |1 0 0| + // |1 0 0| + // |0 0 1| + + // 量测噪声方差(R矩阵对角元素) + static float mat_r_diagonal_elements[3] = {30, 25, 35}; + // 根据 mat_r_diagonal_elements 生成 R 矩阵如下 + // (在当前周期全部量测数据有效的情况下) + // |30 0 0| + // | 0 25 0| + // | 0 0 35| + + // 初始化卡尔曼滤波器(状态维数3,控制维数0,量测维数3) + KF_Init(&Height_KF, 3, 0, 3); + + // 设置矩阵初值 + memcpy(Height_KF.P_data, P_Init, sizeof(P_Init)); + memcpy(Height_KF.F_data, F_Init, sizeof(F_Init)); + memcpy(Height_KF.Q_data, Q_Init, sizeof(Q_Init)); + memcpy(Height_KF.measurement_map, measurement_reference, + sizeof(measurement_reference)); + memcpy(Height_KF.measurement_degree, measurement_degree, + sizeof(measurement_degree)); + memcpy(Height_KF.mat_r_diagonal_elements, mat_r_diagonal_elements, + sizeof(mat_r_diagonal_elements)); + memcpy(Height_KF.state_min_variance, state_min_variance, + sizeof(state_min_variance)); + } + + void INS_Task(void const *pvParameters) + { + // 循环更新卡尔曼滤波器 + KF_Update(&Height_KF); + vTaskDelay(ts); + } + + // 传感器回调函数示例:在数据就绪时更新 measured_vector + void Barometer_Read_Over(void) + { + ...... + INS_KF.measured_vector[0] = baro_height; // 气压计高度 + } + + void GPS_Read_Over(void) + { + ...... + INS_KF.measured_vector[1] = GPS_height; // GPS高度 + } + + void Acc_Data_Process(void) + { + ...... + INS_KF.measured_vector[2] = acc.z; // Z轴加速度 + } +*/ + +#include "kalman_filter.h" + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ + +/* 私有函数声明 */ +static void KF_AdjustHKR(KF_t *kf); + +/** + * @brief 初始化卡尔曼滤波器并分配矩阵内存 + * + * @param kf 卡尔曼滤波器结构体指针 + * @param xhat_size 状态向量维度 + * @param u_size 控制向量维度(无控制输入时设为0) + * @param z_size 量测向量维度 + * @return int8_t 0对应没有错误 + */ +int8_t KF_Init(KF_t *kf, uint8_t xhat_size, uint8_t u_size, uint8_t z_size) { + if (kf == NULL) return -1; + + kf->xhat_size = xhat_size; + kf->u_size = u_size; + kf->z_size = z_size; + + kf->measurement_valid_num = 0; + + /* 量测标志分配 */ + kf->measurement_map = (uint8_t *)user_malloc(sizeof(uint8_t) * z_size); + memset(kf->measurement_map, 0, sizeof(uint8_t) * z_size); + + kf->measurement_degree = (float *)user_malloc(sizeof(float) * z_size); + memset(kf->measurement_degree, 0, sizeof(float) * z_size); + + kf->mat_r_diagonal_elements = (float *)user_malloc(sizeof(float) * z_size); + memset(kf->mat_r_diagonal_elements, 0, sizeof(float) * z_size); + + kf->state_min_variance = (float *)user_malloc(sizeof(float) * xhat_size); + memset(kf->state_min_variance, 0, sizeof(float) * xhat_size); + + kf->temp = (uint8_t *)user_malloc(sizeof(uint8_t) * z_size); + memset(kf->temp, 0, sizeof(uint8_t) * z_size); + + /* 滤波数据分配 */ + kf->filtered_value = (float *)user_malloc(sizeof(float) * xhat_size); + memset(kf->filtered_value, 0, sizeof(float) * xhat_size); + + kf->measured_vector = (float *)user_malloc(sizeof(float) * z_size); + memset(kf->measured_vector, 0, sizeof(float) * z_size); + + kf->control_vector = (float *)user_malloc(sizeof(float) * u_size); + memset(kf->control_vector, 0, sizeof(float) * u_size); + + /* 状态估计 xhat x(k|k) */ + kf->xhat_data = (float *)user_malloc(sizeof(float) * xhat_size); + memset(kf->xhat_data, 0, sizeof(float) * xhat_size); + KF_MatInit(&kf->xhat, kf->xhat_size, 1, kf->xhat_data); + + /* 先验状态估计 xhatminus x(k|k-1) */ + kf->xhatminus_data = (float *)user_malloc(sizeof(float) * xhat_size); + memset(kf->xhatminus_data, 0, sizeof(float) * xhat_size); + KF_MatInit(&kf->xhatminus, kf->xhat_size, 1, kf->xhatminus_data); + + /* 控制向量 u */ + if (u_size != 0) { + kf->u_data = (float *)user_malloc(sizeof(float) * u_size); + memset(kf->u_data, 0, sizeof(float) * u_size); + KF_MatInit(&kf->u, kf->u_size, 1, kf->u_data); + } + + /* 量测向量 z */ + kf->z_data = (float *)user_malloc(sizeof(float) * z_size); + memset(kf->z_data, 0, sizeof(float) * z_size); + KF_MatInit(&kf->z, kf->z_size, 1, kf->z_data); + + /* 协方差矩阵 P(k|k) */ + kf->P_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + memset(kf->P_data, 0, sizeof(float) * xhat_size * xhat_size); + KF_MatInit(&kf->P, kf->xhat_size, kf->xhat_size, kf->P_data); + + /* 先验协方差矩阵 P(k|k-1) */ + kf->Pminus_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + memset(kf->Pminus_data, 0, sizeof(float) * xhat_size * xhat_size); + KF_MatInit(&kf->Pminus, kf->xhat_size, kf->xhat_size, kf->Pminus_data); + + /* 状态转移矩阵 F 及其转置 FT */ + kf->F_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + kf->FT_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + memset(kf->F_data, 0, sizeof(float) * xhat_size * xhat_size); + memset(kf->FT_data, 0, sizeof(float) * xhat_size * xhat_size); + KF_MatInit(&kf->F, kf->xhat_size, kf->xhat_size, kf->F_data); + KF_MatInit(&kf->FT, kf->xhat_size, kf->xhat_size, kf->FT_data); + + /* 控制矩阵 B */ + if (u_size != 0) { + kf->B_data = (float *)user_malloc(sizeof(float) * xhat_size * u_size); + memset(kf->B_data, 0, sizeof(float) * xhat_size * u_size); + KF_MatInit(&kf->B, kf->xhat_size, kf->u_size, kf->B_data); + } + + /* 量测矩阵 H 及其转置 HT */ + kf->H_data = (float *)user_malloc(sizeof(float) * z_size * xhat_size); + kf->HT_data = (float *)user_malloc(sizeof(float) * xhat_size * z_size); + memset(kf->H_data, 0, sizeof(float) * z_size * xhat_size); + memset(kf->HT_data, 0, sizeof(float) * xhat_size * z_size); + KF_MatInit(&kf->H, kf->z_size, kf->xhat_size, kf->H_data); + KF_MatInit(&kf->HT, kf->xhat_size, kf->z_size, kf->HT_data); + + /* 过程噪声协方差矩阵 Q */ + kf->Q_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + memset(kf->Q_data, 0, sizeof(float) * xhat_size * xhat_size); + KF_MatInit(&kf->Q, kf->xhat_size, kf->xhat_size, kf->Q_data); + + /* 量测噪声协方差矩阵 R */ + kf->R_data = (float *)user_malloc(sizeof(float) * z_size * z_size); + memset(kf->R_data, 0, sizeof(float) * z_size * z_size); + KF_MatInit(&kf->R, kf->z_size, kf->z_size, kf->R_data); + + /* 卡尔曼增益 K */ + kf->K_data = (float *)user_malloc(sizeof(float) * xhat_size * z_size); + memset(kf->K_data, 0, sizeof(float) * xhat_size * z_size); + KF_MatInit(&kf->K, kf->xhat_size, kf->z_size, kf->K_data); + + /* 临时矩阵分配 */ + kf->S_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + kf->temp_matrix_data = + (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + kf->temp_matrix_data1 = + (float *)user_malloc(sizeof(float) * xhat_size * xhat_size); + kf->temp_vector_data = (float *)user_malloc(sizeof(float) * xhat_size); + kf->temp_vector_data1 = (float *)user_malloc(sizeof(float) * xhat_size); + + KF_MatInit(&kf->S, kf->xhat_size, kf->xhat_size, kf->S_data); + KF_MatInit(&kf->temp_matrix, kf->xhat_size, kf->xhat_size, + kf->temp_matrix_data); + KF_MatInit(&kf->temp_matrix1, kf->xhat_size, kf->xhat_size, + kf->temp_matrix_data1); + KF_MatInit(&kf->temp_vector, kf->xhat_size, 1, kf->temp_vector_data); + KF_MatInit(&kf->temp_vector1, kf->xhat_size, 1, kf->temp_vector_data1); + + /* 初始化跳过标志 */ + kf->skip_eq1 = 0; + kf->skip_eq2 = 0; + kf->skip_eq3 = 0; + kf->skip_eq4 = 0; + kf->skip_eq5 = 0; + + /* 初始化用户函数指针 */ + kf->User_Func0_f = NULL; + kf->User_Func1_f = NULL; + kf->User_Func2_f = NULL; + kf->User_Func3_f = NULL; + kf->User_Func4_f = NULL; + kf->User_Func5_f = NULL; + kf->User_Func6_f = NULL; + + return 0; +} + +/** + * @brief 获取量测并在启用自动调整时调整矩阵 + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_Measure(KF_t *kf) { + if (kf == NULL) return -1; + + /* 根据量测有效性自动调整 H, K, R 矩阵 */ + if (kf->use_auto_adjustment != 0) { + KF_AdjustHKR(kf); + } else { + memcpy(kf->z_data, kf->measured_vector, sizeof(float) * kf->z_size); + memset(kf->measured_vector, 0, sizeof(float) * kf->z_size); + } + + memcpy(kf->u_data, kf->control_vector, sizeof(float) * kf->u_size); + + return 0; +} + +/** + * @brief 步骤1:先验状态估计 - xhat'(k) = F·xhat(k-1) + B·u + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_PredictState(KF_t *kf) { + if (kf == NULL) return -1; + + if (!kf->skip_eq1) { + if (kf->u_size > 0) { + /* 有控制输入: xhat'(k) = F·xhat(k-1) + B·u */ + kf->temp_vector.numRows = kf->xhat_size; + kf->temp_vector.numCols = 1; + kf->mat_status = KF_MatMult(&kf->F, &kf->xhat, &kf->temp_vector); + + kf->temp_vector1.numRows = kf->xhat_size; + kf->temp_vector1.numCols = 1; + kf->mat_status = KF_MatMult(&kf->B, &kf->u, &kf->temp_vector1); + kf->mat_status = + KF_MatAdd(&kf->temp_vector, &kf->temp_vector1, &kf->xhatminus); + } else { + /* 无控制输入: xhat'(k) = F·xhat(k-1) */ + kf->mat_status = KF_MatMult(&kf->F, &kf->xhat, &kf->xhatminus); + } + } + + return 0; +} + +/** + * @brief 步骤2:先验协方差 - P'(k) = F·P(k-1)·F^T + Q + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_PredictCovariance(KF_t *kf) { + if (kf == NULL) return -1; + + if (!kf->skip_eq2) { + kf->mat_status = KF_MatTrans(&kf->F, &kf->FT); + kf->mat_status = KF_MatMult(&kf->F, &kf->P, &kf->Pminus); + kf->temp_matrix.numRows = kf->Pminus.numRows; + kf->temp_matrix.numCols = kf->FT.numCols; + /* F·P(k-1)·F^T */ + kf->mat_status = KF_MatMult(&kf->Pminus, &kf->FT, &kf->temp_matrix); + kf->mat_status = KF_MatAdd(&kf->temp_matrix, &kf->Q, &kf->Pminus); + } + + return 0; +} + +/** + * @brief 步骤3:卡尔曼增益 - K = P'(k)·H^T / (H·P'(k)·H^T + R) + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_CalcGain(KF_t *kf) { + if (kf == NULL) return -1; + + if (!kf->skip_eq3) { + kf->mat_status = KF_MatTrans(&kf->H, &kf->HT); + kf->temp_matrix.numRows = kf->H.numRows; + kf->temp_matrix.numCols = kf->Pminus.numCols; + /* H·P'(k) */ + kf->mat_status = KF_MatMult(&kf->H, &kf->Pminus, &kf->temp_matrix); + kf->temp_matrix1.numRows = kf->temp_matrix.numRows; + kf->temp_matrix1.numCols = kf->HT.numCols; + /* H·P'(k)·H^T */ + kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->HT, &kf->temp_matrix1); + kf->S.numRows = kf->R.numRows; + kf->S.numCols = kf->R.numCols; + /* S = H·P'(k)·H^T + R */ + kf->mat_status = KF_MatAdd(&kf->temp_matrix1, &kf->R, &kf->S); + /* S^-1 */ + kf->mat_status = KF_MatInv(&kf->S, &kf->temp_matrix1); + kf->temp_matrix.numRows = kf->Pminus.numRows; + kf->temp_matrix.numCols = kf->HT.numCols; + /* P'(k)·H^T */ + kf->mat_status = KF_MatMult(&kf->Pminus, &kf->HT, &kf->temp_matrix); + /* K = P'(k)·H^T·S^-1 */ + kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->temp_matrix1, &kf->K); + } + + return 0; +} + +/** + * @brief 步骤4:状态更新 - xhat(k) = xhat'(k) + K·(z - H·xhat'(k)) + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_UpdateState(KF_t *kf) { + if (kf == NULL) return -1; + + if (!kf->skip_eq4) { + kf->temp_vector.numRows = kf->H.numRows; + kf->temp_vector.numCols = 1; + /* H·xhat'(k) */ + kf->mat_status = KF_MatMult(&kf->H, &kf->xhatminus, &kf->temp_vector); + kf->temp_vector1.numRows = kf->z.numRows; + kf->temp_vector1.numCols = 1; + /* 新息: z - H·xhat'(k) */ + kf->mat_status = KF_MatSub(&kf->z, &kf->temp_vector, &kf->temp_vector1); + kf->temp_vector.numRows = kf->K.numRows; + kf->temp_vector.numCols = 1; + /* K·新息 */ + kf->mat_status = KF_MatMult(&kf->K, &kf->temp_vector1, &kf->temp_vector); + /* xhat = xhat' + K·新息 */ + kf->mat_status = KF_MatAdd(&kf->xhatminus, &kf->temp_vector, &kf->xhat); + } + + return 0; +} + +/** + * @brief 步骤5:协方差更新 - P(k) = P'(k) - K·H·P'(k) + * + * @param kf 卡尔曼滤波器结构体指针 + * @return int8_t 0对应没有错误 + */ +int8_t KF_UpdateCovariance(KF_t *kf) { + if (kf == NULL) return -1; + + if (!kf->skip_eq5) { + kf->temp_matrix.numRows = kf->K.numRows; + kf->temp_matrix.numCols = kf->H.numCols; + kf->temp_matrix1.numRows = kf->temp_matrix.numRows; + kf->temp_matrix1.numCols = kf->Pminus.numCols; + /* K·H */ + kf->mat_status = KF_MatMult(&kf->K, &kf->H, &kf->temp_matrix); + /* K·H·P'(k) */ + kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->Pminus, &kf->temp_matrix1); + /* P = P' - K·H·P' */ + kf->mat_status = KF_MatSub(&kf->Pminus, &kf->temp_matrix1, &kf->P); + } + + return 0; +} + +/** + * @brief 执行完整的卡尔曼滤波周期(五大方程) + * + * 实现标准KF,并支持用户自定义函数钩子用于扩展(EKF/UKF/ESKF/AUKF)。 + * 每个步骤都可以通过 User_Func 回调函数替换。 + * + * @param kf 卡尔曼滤波器结构体指针 + * @return float* 滤波后的状态估计值指针 + */ +float *KF_Update(KF_t *kf) { + if (kf == NULL) return NULL; + + /* 步骤0: 量测获取和矩阵调整 */ + KF_Measure(kf); + if (kf->User_Func0_f != NULL) kf->User_Func0_f(kf); + + /* 步骤1: 先验状态估计 - xhat'(k) = F·xhat(k-1) + B·u */ + KF_PredictState(kf); + if (kf->User_Func1_f != NULL) kf->User_Func1_f(kf); + + /* 步骤2: 先验协方差 - P'(k) = F·P(k-1)·F^T + Q */ + KF_PredictCovariance(kf); + if (kf->User_Func2_f != NULL) kf->User_Func2_f(kf); + + /* 量测更新(仅在存在有效量测时执行) */ + if (kf->measurement_valid_num != 0 || kf->use_auto_adjustment == 0) { + /* 步骤3: 卡尔曼增益 - K = P'(k)·H^T / (H·P'(k)·H^T + R) */ + KF_CalcGain(kf); + if (kf->User_Func3_f != NULL) kf->User_Func3_f(kf); + + /* 步骤4: 状态更新 - xhat(k) = xhat'(k) + K·(z - H·xhat'(k)) */ + KF_UpdateState(kf); + if (kf->User_Func4_f != NULL) kf->User_Func4_f(kf); + + /* 步骤5: 协方差更新 - P(k) = P'(k) - K·H·P'(k) */ + KF_UpdateCovariance(kf); + } else { + /* 无有效量测 - 仅预测 */ + memcpy(kf->xhat_data, kf->xhatminus_data, sizeof(float) * kf->xhat_size); + memcpy(kf->P_data, kf->Pminus_data, + sizeof(float) * kf->xhat_size * kf->xhat_size); + } + + /* 后处理钩子 */ + if (kf->User_Func5_f != NULL) kf->User_Func5_f(kf); + + /* 防过度收敛:强制最小方差 */ + for (uint8_t i = 0; i < kf->xhat_size; i++) { + if (kf->P_data[i * kf->xhat_size + i] < kf->state_min_variance[i]) + kf->P_data[i * kf->xhat_size + i] = kf->state_min_variance[i]; + } + + /* 复制结果到输出 */ + memcpy(kf->filtered_value, kf->xhat_data, sizeof(float) * kf->xhat_size); + + /* 附加后处理钩子 */ + if (kf->User_Func6_f != NULL) kf->User_Func6_f(kf); + + return kf->filtered_value; +} + +/** + * @brief 重置卡尔曼滤波器状态 + * + * @param kf 卡尔曼滤波器结构体指针 + */ +void KF_Reset(KF_t *kf) { + if (kf == NULL) return; + + memset(kf->xhat_data, 0, sizeof(float) * kf->xhat_size); + memset(kf->xhatminus_data, 0, sizeof(float) * kf->xhat_size); + memset(kf->filtered_value, 0, sizeof(float) * kf->xhat_size); + kf->measurement_valid_num = 0; +} + +/** + * @brief 根据量测有效性动态调整 H, R, K 矩阵 + * + * 该函数根据当前周期中哪些量测有效(非零)来重建量测相关矩阵。 + * 支持具有不同采样率的异步传感器。 + * + * @param kf 卡尔曼滤波器结构体指针 + */ +static void KF_AdjustHKR(KF_t *kf) { + kf->measurement_valid_num = 0; + + /* 复制并重置量测向量 */ + memcpy(kf->z_data, kf->measured_vector, sizeof(float) * kf->z_size); + memset(kf->measured_vector, 0, sizeof(float) * kf->z_size); + + /* 清空 H 和 R 矩阵 */ + memset(kf->R_data, 0, sizeof(float) * kf->z_size * kf->z_size); + memset(kf->H_data, 0, sizeof(float) * kf->xhat_size * kf->z_size); + + /* 识别有效量测并重建 z, H */ + for (uint8_t i = 0; i < kf->z_size; i++) { + if (kf->z_data[i] != 0) { /* 非零表示有效量测 */ + /* 将有效量测压缩到 z */ + kf->z_data[kf->measurement_valid_num] = kf->z_data[i]; + kf->temp[kf->measurement_valid_num] = i; + + /* 重建 H 矩阵行 */ + kf->H_data[kf->xhat_size * kf->measurement_valid_num + + kf->measurement_map[i] - 1] = kf->measurement_degree[i]; + kf->measurement_valid_num++; + } + } + + /* 用有效量测方差重建 R 矩阵 */ + for (uint8_t i = 0; i < kf->measurement_valid_num; i++) { + kf->R_data[i * kf->measurement_valid_num + i] = + kf->mat_r_diagonal_elements[kf->temp[i]]; + } + + /* 调整矩阵维度以匹配有效量测数量 */ + kf->H.numRows = kf->measurement_valid_num; + kf->H.numCols = kf->xhat_size; + kf->HT.numRows = kf->xhat_size; + kf->HT.numCols = kf->measurement_valid_num; + kf->R.numRows = kf->measurement_valid_num; + kf->R.numCols = kf->measurement_valid_num; + kf->K.numRows = kf->xhat_size; + kf->K.numCols = kf->measurement_valid_num; + kf->z.numRows = kf->measurement_valid_num; +} + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ diff --git a/component/kalman_filter/kalman_filter.h b/component/kalman_filter/kalman_filter.h new file mode 100644 index 0000000..7e6b7d1 --- /dev/null +++ b/component/kalman_filter/kalman_filter.h @@ -0,0 +1,199 @@ +/* + ˲ + ֶ֧̬ʹARM CMSIS DSPŻ +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "arm_math.h" + +#include +#include +#include +#include + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ + +/* ڴ */ +#ifndef user_malloc +#ifdef _CMSIS_OS_H +#define user_malloc pvPortMalloc /* FreeRTOSѷ */ +#else +#define user_malloc malloc /* ׼C */ +#endif +#endif + +/* ARM CMSIS DSP */ +#define KF_Mat arm_matrix_instance_f32 +#define KF_MatInit arm_mat_init_f32 +#define KF_MatAdd arm_mat_add_f32 +#define KF_MatSub arm_mat_sub_f32 +#define KF_MatMult arm_mat_mult_f32 +#define KF_MatTrans arm_mat_trans_f32 +#define KF_MatInv arm_mat_inverse_f32 + +/* ˲ṹ */ +typedef struct KF_s { + /* */ + float *filtered_value; /* ˲״̬ */ + float *measured_vector; /* */ + float *control_vector; /* */ + + /* ά */ + uint8_t xhat_size; /* ״̬ά */ + uint8_t u_size; /* ά */ + uint8_t z_size; /* ά */ + + /* Զ */ + uint8_t use_auto_adjustment; /* ö̬ H/R/K */ + uint8_t measurement_valid_num; /* Ч */ + + /* */ + uint8_t *measurement_map; /* ⵽״̬ӳ */ + float *measurement_degree; /* ÿHԪֵ */ + float *mat_r_diagonal_elements; /* RԽߣ */ + float *state_min_variance; /* С״̬ */ + uint8_t *temp; /* ʱ */ + + /* ־Զû */ + uint8_t skip_eq1, skip_eq2, skip_eq3, skip_eq4, skip_eq5; + + /* ˲ */ + KF_Mat xhat; /* ״̬ x(k|k) */ + KF_Mat xhatminus; /* ״̬ x(k|k-1) */ + KF_Mat u; /* */ + KF_Mat z; /* */ + KF_Mat P; /* Э P(k|k) */ + KF_Mat Pminus; /* Э P(k|k-1) */ + KF_Mat F, FT; /* ״̬תƾת */ + KF_Mat B; /* ƾ */ + KF_Mat H, HT; /* ת */ + KF_Mat Q; /* Э */ + KF_Mat R; /* Э */ + KF_Mat K; /* */ + KF_Mat S; /* ʱ S */ + KF_Mat temp_matrix, temp_matrix1; /* ʱ */ + KF_Mat temp_vector, temp_vector1; /* ʱ */ + + int8_t mat_status; /* ״̬ */ + + /* ûԶ庯ָ루EKF/UKF/ESKFչ */ + void (*User_Func0_f)(struct KF_s *kf); /* Զ⴦ */ + void (*User_Func1_f)(struct KF_s *kf); /* Զ״̬Ԥ */ + void (*User_Func2_f)(struct KF_s *kf); /* ԶЭԤ */ + void (*User_Func3_f)(struct KF_s *kf); /* Զ忨 */ + void (*User_Func4_f)(struct KF_s *kf); /* Զ״̬ */ + void (*User_Func5_f)(struct KF_s *kf); /* Զ */ + void (*User_Func6_f)(struct KF_s *kf); /* Զ庯 */ + + /* ݴ洢ָ */ + float *xhat_data, *xhatminus_data; + float *u_data; + float *z_data; + float *P_data, *Pminus_data; + float *F_data, *FT_data; + float *B_data; + float *H_data, *HT_data; + float *Q_data; + float *R_data; + float *K_data; + float *S_data; + float *temp_matrix_data, *temp_matrix_data1; + float *temp_vector_data, *temp_vector_data1; +} KF_t; + +/* USER STRUCT BEGIN */ + +/* USER STRUCT END */ + +/** + * @brief ʼ˲ڴ + * + * @param kf ˲ṹָ + * @param xhat_size ״̬ά + * @param u_size άȣ޿ʱΪ0 + * @param z_size ά + * @return int8_t 0Ӧûд + */ +int8_t KF_Init(KF_t *kf, uint8_t xhat_size, uint8_t u_size, uint8_t z_size); + +/** + * @brief ȡⲢԶʱ + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_Measure(KF_t *kf); + +/** + * @brief 1״̬ - xhat'(k) = Fxhat(k-1) + Bu + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_PredictState(KF_t *kf); + +/** + * @brief 2Э - P'(k) = FP(k-1)F^T + Q + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_PredictCovariance(KF_t *kf); + +/** + * @brief 3 - K = P'(k)H^T / (HP'(k)H^T + R) + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_CalcGain(KF_t *kf); + +/** + * @brief 4״̬ - xhat(k) = xhat'(k) + K(z - Hxhat'(k)) + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_UpdateState(KF_t *kf); + +/** + * @brief 5Э - P(k) = P'(k) - KHP'(k) + * + * @param kf ˲ṹָ + * @return int8_t 0Ӧûд + */ +int8_t KF_UpdateCovariance(KF_t *kf); + +/** + * @brief ִĿ˲ڣ󷽳̣ + * + * @param kf ˲ṹָ + * @return float* ˲״ֵָ̬ + */ +float *KF_Update(KF_t *kf); + +/** + * @brief ÿ˲״̬ + * + * @param kf ˲ṹָ + */ +void KF_Reset(KF_t *kf); + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ + +#ifdef __cplusplus +} +#endif diff --git a/config.csv b/config.csv index 1eb9b34..3f0ecc5 100644 --- a/config.csv +++ b/config.csv @@ -1,4 +1,4 @@ bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time,flash component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math -device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver +device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver,mrobot module, \ No newline at end of file diff --git a/device/config.yaml b/device/config.yaml index f02ad18..60e73f8 100644 --- a/device/config.yaml +++ b/device/config.yaml @@ -259,4 +259,19 @@ devices: thread_signals: [] files: header: "lcd.h" - source: "lcd.c" \ No newline at end of file + source: "lcd.c" + + mrobot: + name: "MRobot CLI" + description: "基于 FreeRTOS CLI 的嵌入式调试命令行系统,支持设备注册与监控、类 Unix 文件系统命令、htop 风格任务监控等" + dependencies: + bsp: ["uart", "mm"] + component: ["freertos_cli"] + bsp_requirements: + - type: "uart" + var_name: "BSP_UART_MROBOT" + description: "用于 MRobot CLI 命令行交互" + thread_signals: [] + files: + header: "mrobot.h" + source: "mrobot.c" \ No newline at end of file diff --git a/device/mrobot/mrobot.c b/device/mrobot/mrobot.c new file mode 100644 index 0000000..e96471a --- /dev/null +++ b/device/mrobot/mrobot.c @@ -0,0 +1,874 @@ +/** + * @file mrobot.c + * @brief MRobot CLI 实现 + */ + +/* Includes ----------------------------------------------------------------- */ +#include "device/mrobot.h" +#include "component/freertos_cli.h" +#include "bsp/uart.h" +#include "bsp/mm.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* Private constants -------------------------------------------------------- */ +static const char *const CLI_WELCOME_MESSAGE = + "\r\n" + " __ __ _____ _ _ \r\n" + " | \\/ | __ \\ | | | | \r\n" + " | \\ / | |__) |___ | |__ ___ | |_ \r\n" + " | |\\/| | _ // _ \\| '_ \\ / _ \\| __|\r\n" + " | | | | | \\ \\ (_) | |_) | (_) | |_ \r\n" + " |_| |_|_| \\_\\___/|_.__/ \\___/ \\__|\r\n" + " ------------------------------------\r\n" + " Welcome to use MRobot CLI. Type 'help' to view a list of registered commands.\r\n" + "\r\n"; + +/* ANSI 转义序列 */ +#define ANSI_CLEAR_SCREEN "\033[2J\033[H" +#define ANSI_CURSOR_HOME "\033[H" +#define ANSI_BACKSPACE "\b \b" + +/* Private types ------------------------------------------------------------ */ +/* CLI 上下文结构体 - 封装所有状态 */ +typedef struct { + /* 设备管理 */ + MRobot_Device_t devices[MROBOT_MAX_DEVICES]; + uint8_t device_count; + + /* 自定义命令 */ + CLI_Command_Definition_t *custom_cmds[MROBOT_MAX_CUSTOM_COMMANDS]; + uint8_t custom_cmd_count; + + /* CLI 状态 */ + MRobot_State_t state; + char current_path[MROBOT_PATH_MAX_LEN]; + + /* 命令缓冲区 */ + uint8_t cmd_buffer[MROBOT_CMD_BUFFER_SIZE]; + volatile uint8_t cmd_index; + volatile bool cmd_ready; + + /* UART 相关 */ + uint8_t uart_rx_char; + volatile bool tx_complete; + volatile bool htop_exit; + + /* 输出缓冲区 */ + char output_buffer[MROBOT_OUTPUT_BUFFER_SIZE]; + + /* 初始化标志 */ + bool initialized; + + /* 互斥锁 */ + SemaphoreHandle_t mutex; +} MRobot_Context_t; + +/* Private variables -------------------------------------------------------- */ +static MRobot_Context_t ctx = { + .device_count = 0, + .custom_cmd_count = 0, + .state = MROBOT_STATE_IDLE, + .current_path = "/", + .cmd_index = 0, + .cmd_ready = false, + .tx_complete = true, + .htop_exit = false, + .initialized = false, + .mutex = NULL +}; + +/* Private function prototypes ---------------------------------------------- */ +/* 命令处理函数 */ +static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); +static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); +static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); +static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); +static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); + +/* 内部辅助函数 */ +static void uart_tx_callback(void); +static void uart_rx_callback(void); +static void send_string(const char *str); +static void send_prompt(void); +static int format_float_va(char *buf, size_t size, const char *fmt, va_list args); + +/* CLI 命令定义表 */ +static const CLI_Command_Definition_t builtin_commands[] = { + { "help", " --help: 显示所有可用命令\r\n", cmd_help, 0 }, + { "htop", " --htop: 动态显示 FreeRTOS 任务状态 (按 'q' 退出)\r\n", cmd_htop, 0 }, + { "cd", " --cd : 切换目录\r\n", cmd_cd, 1 }, + { "ls", " --ls: 列出当前目录内容\r\n", cmd_ls, 0 }, + { "show", " --show [device] [count]: 显示设备信息\r\n", cmd_show, -1 }, +}; +#define BUILTIN_CMD_COUNT (sizeof(builtin_commands) / sizeof(builtin_commands[0])) + +/* ========================================================================== */ +/* 辅助函数实现 */ +/* ========================================================================== */ + +/** + * @brief 发送字符串到 UART(阻塞等待完成) + */ +static void send_string(const char *str) { + if (str == NULL || *str == '\0') return; + + ctx.tx_complete = false; + BSP_UART_Transmit(MROBOT_UART_PORT, (uint8_t *)str, strlen(str), true); + while (!ctx.tx_complete) { osDelay(1); } +} + +/** + * @brief 发送命令提示符 + */ +static void send_prompt(void) { + char prompt[MROBOT_PATH_MAX_LEN + 32]; + snprintf(prompt, sizeof(prompt), MROBOT_USER_NAME "@" MROBOT_HOST_NAME ":%s$ ", ctx.current_path); + send_string(prompt); +} + +/** + * @brief UART 发送完成回调 + */ +static void uart_tx_callback(void) { + ctx.tx_complete = true; +} + +/** + * @brief UART 接收回调 + */ +static void uart_rx_callback(void) { + uint8_t ch = ctx.uart_rx_char; + + /* htop 模式下检查退出键 */ + if (ctx.state == MROBOT_STATE_HTOP) { + if (ch == 'q' || ch == 'Q' || ch == 27) { + ctx.htop_exit = true; + } + BSP_UART_Receive(MROBOT_UART_PORT, &ctx.uart_rx_char, 1, false); + return; + } + + /* 正常命令输入处理 */ + if (ch == '\r' || ch == '\n') { + if (ctx.cmd_index > 0) { + ctx.cmd_buffer[ctx.cmd_index] = '\0'; + ctx.cmd_ready = true; + BSP_UART_Transmit(MROBOT_UART_PORT, (uint8_t *)"\r\n", 2, false); + } + } else if (ch == 127 || ch == 8) { /* 退格键 */ + if (ctx.cmd_index > 0) { + ctx.cmd_index--; + BSP_UART_Transmit(MROBOT_UART_PORT, (uint8_t *)ANSI_BACKSPACE, 3, false); + } + } else if (ch >= 32 && ch < 127 && ctx.cmd_index < sizeof(ctx.cmd_buffer) - 1) { + ctx.cmd_buffer[ctx.cmd_index++] = ch; + BSP_UART_Transmit(MROBOT_UART_PORT, &ch, 1, false); + } + + BSP_UART_Receive(MROBOT_UART_PORT, &ctx.uart_rx_char, 1, false); +} + +/* ========================================================================== */ +/* CLI 命令实现 */ +/* ========================================================================== */ + +/** + * @brief help 命令 - 显示帮助信息 + */ +static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { + (void)pcCommandString; + + int offset = snprintf(pcWriteBuffer, xWriteBufferLen, + "MRobot CLI v2.0\r\n" + "================\r\n" + "Built-in Commands:\r\n"); + + for (size_t i = 0; i < BUILTIN_CMD_COUNT && offset < (int)xWriteBufferLen - 50; i++) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " %s", builtin_commands[i].pcHelpString); + } + + if (ctx.custom_cmd_count > 0) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + "\r\nCustom Commands:\r\n"); + for (uint8_t i = 0; i < ctx.custom_cmd_count && offset < (int)xWriteBufferLen - 50; i++) { + if (ctx.custom_cmds[i] != NULL) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " %s", ctx.custom_cmds[i]->pcHelpString); + } + } + } + + return pdFALSE; +} + +/** + * @brief htop 命令 - 设置 htop 模式标志 + */ +static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { + (void)pcCommandString; + (void)pcWriteBuffer; + (void)xWriteBufferLen; + /* htop 模式在 MRobot_Run 中处理 */ + return pdFALSE; +} + +/** + * @brief cd 命令 - 切换目录 + */ +static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { + const char *param; + BaseType_t param_len; + + param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len); + + if (param == NULL) { + /* 无参数时切换到根目录 */ + strcpy(ctx.current_path, "/"); + snprintf(pcWriteBuffer, xWriteBufferLen, "Changed to: %s\r\n", ctx.current_path); + return pdFALSE; + } + + /* 安全复制路径参数 */ + char path[MROBOT_PATH_MAX_LEN]; + size_t copy_len = (size_t)param_len < sizeof(path) - 1 ? (size_t)param_len : sizeof(path) - 1; + strncpy(path, param, copy_len); + path[copy_len] = '\0'; + + /* 路径解析 */ + if (strcmp(path, "/") == 0 || strcmp(path, "..") == 0 || strcmp(path, "~") == 0) { + strcpy(ctx.current_path, "/"); + } else if (strcmp(path, "dev") == 0 || strcmp(path, "/dev") == 0) { + strcpy(ctx.current_path, "/dev"); + } else if (strcmp(path, "modules") == 0 || strcmp(path, "/modules") == 0) { + strcpy(ctx.current_path, "/modules"); + } else { + snprintf(pcWriteBuffer, xWriteBufferLen, "Error: Directory '%s' not found\r\n", path); + return pdFALSE; + } + + snprintf(pcWriteBuffer, xWriteBufferLen, "Changed to: %s\r\n", ctx.current_path); + return pdFALSE; +} + +/** + * @brief ls 命令 - 列出目录内容 + */ +static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { + (void)pcCommandString; + int offset = 0; + + if (strcmp(ctx.current_path, "/") == 0) { + snprintf(pcWriteBuffer, xWriteBufferLen, + "dev/\r\n" + "modules/\r\n"); + } else if (strcmp(ctx.current_path, "/dev") == 0) { + offset = snprintf(pcWriteBuffer, xWriteBufferLen, + "Device List (%d devices)\r\n\r\n", + ctx.device_count); + + if (ctx.device_count == 0) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " (No devices)\r\n"); + } else { + /* 直接列出所有设备 */ + for (uint8_t i = 0; i < ctx.device_count && offset < (int)xWriteBufferLen - 50; i++) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " - %s\r\n", ctx.devices[i].name); + } + } + } else if (strcmp(ctx.current_path, "/modules") == 0) { + snprintf(pcWriteBuffer, xWriteBufferLen, + "Module functions not yet implemented\r\n"); + } + + return pdFALSE; +} + +/** + * @brief show 命令 - 显示设备信息 + */ +static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { + const char *param; + const char *count_param; + BaseType_t param_len, count_param_len; + + /* 使用局部静态变量跟踪多次打印状态 */ + static uint32_t print_count = 0; + static uint32_t current_iter = 0; + static char target_device[MROBOT_DEVICE_NAME_LEN] = {0}; + + /* 首次调用时解析参数 */ + if (current_iter == 0) { + /* 检查是否在 /dev 目录 */ + if (strcmp(ctx.current_path, "/dev") != 0) { + snprintf(pcWriteBuffer, xWriteBufferLen, + "Error: 'show' command only works in /dev directory\r\n" + "Hint: Use 'cd /dev' to switch to device directory\r\n"); + return pdFALSE; + } + + param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len); + count_param = FreeRTOS_CLIGetParameter(pcCommandString, 2, &count_param_len); + + /* 解析打印次数 */ + print_count = 1; + if (count_param != NULL) { + char count_str[16]; + size_t copy_len = (size_t)count_param_len < sizeof(count_str) - 1 ? + (size_t)count_param_len : sizeof(count_str) - 1; + strncpy(count_str, count_param, copy_len); + count_str[copy_len] = '\0'; + int parsed = atoi(count_str); + if (parsed > 0 && parsed <= 1000) { + print_count = (uint32_t)parsed; + } + } + + /* 保存目标设备名称 */ + if (param != NULL) { + size_t copy_len = (size_t)param_len < sizeof(target_device) - 1 ? + (size_t)param_len : sizeof(target_device) - 1; + strncpy(target_device, param, copy_len); + target_device[copy_len] = '\0'; + } else { + target_device[0] = '\0'; + } + } + + int offset = 0; + + /* 连续打印模式:清屏 */ + if (print_count > 1) { + offset = snprintf(pcWriteBuffer, xWriteBufferLen, "%s[%lu/%lu]\r\n", + ANSI_CLEAR_SCREEN, + (unsigned long)(current_iter + 1), + (unsigned long)print_count); + } + + if (target_device[0] == '\0') { + /* 显示所有设备 */ + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + "=== All Devices ===\r\n\r\n"); + + for (uint8_t i = 0; i < ctx.device_count && offset < (int)xWriteBufferLen - 100; i++) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + "--- %s ---\r\n", ctx.devices[i].name); + + if (ctx.devices[i].print_cb != NULL) { + int written = ctx.devices[i].print_cb(ctx.devices[i].data, + pcWriteBuffer + offset, + xWriteBufferLen - offset); + offset += (written > 0) ? written : 0; + } else { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " (No print function)\r\n"); + } + } + + if (ctx.device_count == 0) { + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " (No devices registered)\r\n"); + } + } else { + /* 显示指定设备 */ + const MRobot_Device_t *dev = MRobot_FindDevice(target_device); + + if (dev == NULL) { + snprintf(pcWriteBuffer, xWriteBufferLen, + "Error: Device '%s' not found\r\n", + target_device); + current_iter = 0; + return pdFALSE; + } + + offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + "=== %s ===\r\n", dev->name); + + if (dev->print_cb != NULL) { + dev->print_cb(dev->data, pcWriteBuffer + offset, xWriteBufferLen - offset); + } else { + snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, + " (No print function)\r\n"); + } + } + + /* 判断是否继续打印 */ + current_iter++; + if (current_iter < print_count) { + osDelay(MROBOT_HTOP_REFRESH_MS); + return pdTRUE; + } else { + current_iter = 0; + return pdFALSE; + } +} + +/* ============================================================================ + * htop 模式处理 + * ========================================================================== */ +static void handle_htop_mode(void) { + send_string(ANSI_CLEAR_SCREEN); + send_string("=== MRobot Task Monitor (Press 'q' to exit) ===\r\n\r\n"); + + /* 获取任务列表 */ + char task_buffer[1024]; + char display_line[128]; + + vTaskList(task_buffer); + + /* 表头 */ + send_string("Task Name State Prio Stack Num\r\n"); + send_string("------------------------------------------------\r\n"); + + /* 解析并格式化任务列表 */ + char *line = strtok(task_buffer, "\r\n"); + while (line != NULL) { + char name[17] = {0}; + char state_char = '?'; + int prio = 0, stack = 0, num = 0; + + if (sscanf(line, "%16s %c %d %d %d", name, &state_char, &prio, &stack, &num) == 5) { + const char *state_str; + switch (state_char) { + case 'R': state_str = "Running"; break; + case 'B': state_str = "Blocked"; break; + case 'S': state_str = "Suspend"; break; + case 'D': state_str = "Deleted"; break; + case 'X': state_str = "Ready "; break; + default: state_str = "Unknown"; break; + } + + snprintf(display_line, sizeof(display_line), + "%-16s %-8s %-4d %-8d %-4d\r\n", + name, state_str, prio, stack, num); + send_string(display_line); + } + line = strtok(NULL, "\r\n"); + } + + /* 显示系统信息 */ + snprintf(display_line, sizeof(display_line), + "------------------------------------------------\r\n" + "System Tick: %lu | Free Heap: %lu bytes\r\n", + (unsigned long)xTaskGetTickCount(), + (unsigned long)xPortGetFreeHeapSize()); + send_string(display_line); + + /* 检查退出 */ + if (ctx.htop_exit) { + ctx.state = MROBOT_STATE_IDLE; + ctx.htop_exit = false; + send_string(ANSI_CLEAR_SCREEN); + send_prompt(); + } + + osDelay(MROBOT_HTOP_REFRESH_MS); +} + +/* ========================================================================== */ +/* 公共 API 实现 */ +/* ========================================================================== */ + +void MRobot_Init(void) { + if (ctx.initialized) return; + + /* 创建互斥锁 */ + ctx.mutex = xSemaphoreCreateMutex(); + + /* 初始化状态 */ + memset(ctx.devices, 0, sizeof(ctx.devices)); + ctx.device_count = 0; + ctx.custom_cmd_count = 0; + ctx.state = MROBOT_STATE_IDLE; + strcpy(ctx.current_path, "/"); + ctx.cmd_index = 0; + ctx.cmd_ready = false; + ctx.tx_complete = true; + ctx.htop_exit = false; + + /* 注册内置命令 */ + for (size_t i = 0; i < BUILTIN_CMD_COUNT; i++) { + FreeRTOS_CLIRegisterCommand(&builtin_commands[i]); + } + + /* 注册 UART 回调 */ + BSP_UART_RegisterCallback(MROBOT_UART_PORT, BSP_UART_RX_CPLT_CB, uart_rx_callback); + BSP_UART_RegisterCallback(MROBOT_UART_PORT, BSP_UART_TX_CPLT_CB, uart_tx_callback); + + /* 启动 UART 接收 */ + BSP_UART_Receive(MROBOT_UART_PORT, &ctx.uart_rx_char, 1, false); + + /* 等待用户按下回车 */ + while (ctx.uart_rx_char != '\r' && ctx.uart_rx_char != '\n') { + osDelay(10); + } + + /* 发送欢迎消息和提示符 */ + send_string(CLI_WELCOME_MESSAGE); + send_prompt(); + + ctx.initialized = true; +} + +void MRobot_DeInit(void) { + if (!ctx.initialized) return; + + /* 释放自定义命令内存 */ + for (uint8_t i = 0; i < ctx.custom_cmd_count; i++) { + if (ctx.custom_cmds[i] != NULL) { + BSP_Free(ctx.custom_cmds[i]); + ctx.custom_cmds[i] = NULL; + } + } + + /* 删除互斥锁 */ + if (ctx.mutex != NULL) { + vSemaphoreDelete(ctx.mutex); + ctx.mutex = NULL; + } + + ctx.initialized = false; +} + +MRobot_State_t MRobot_GetState(void) { + return ctx.state; +} + +MRobot_Error_t MRobot_RegisterDevice(const char *name, void *data, MRobot_PrintCallback_t print_cb) { + if (name == NULL || data == NULL) { + return MROBOT_ERR_NULL_PTR; + } + + if (ctx.device_count >= MROBOT_MAX_DEVICES) { + return MROBOT_ERR_FULL; + } + + /* 检查重名 */ + for (uint8_t i = 0; i < ctx.device_count; i++) { + if (strcmp(ctx.devices[i].name, name) == 0) { + return MROBOT_ERR_INVALID_ARG; /* 设备名已存在 */ + } + } + + /* 线程安全写入 */ + if (ctx.mutex != NULL) { + xSemaphoreTake(ctx.mutex, portMAX_DELAY); + } + + strncpy(ctx.devices[ctx.device_count].name, name, MROBOT_DEVICE_NAME_LEN - 1); + ctx.devices[ctx.device_count].name[MROBOT_DEVICE_NAME_LEN - 1] = '\0'; + ctx.devices[ctx.device_count].data = data; + ctx.devices[ctx.device_count].print_cb = print_cb; + ctx.device_count++; + + if (ctx.mutex != NULL) { + xSemaphoreGive(ctx.mutex); + } + + return MROBOT_OK; +} + +MRobot_Error_t MRobot_UnregisterDevice(const char *name) { + if (name == NULL) { + return MROBOT_ERR_NULL_PTR; + } + + if (ctx.mutex != NULL) { + xSemaphoreTake(ctx.mutex, portMAX_DELAY); + } + + for (uint8_t i = 0; i < ctx.device_count; i++) { + if (strcmp(ctx.devices[i].name, name) == 0) { + /* 移动后续设备 */ + for (uint8_t j = i; j < ctx.device_count - 1; j++) { + ctx.devices[j] = ctx.devices[j + 1]; + } + ctx.device_count--; + + if (ctx.mutex != NULL) { + xSemaphoreGive(ctx.mutex); + } + return MROBOT_OK; + } + } + + if (ctx.mutex != NULL) { + xSemaphoreGive(ctx.mutex); + } + return MROBOT_ERR_NOT_FOUND; +} + +MRobot_Error_t MRobot_RegisterCommand(const char *command, const char *help_text, + MRobot_CommandCallback_t callback, int8_t param_count) { + if (command == NULL || help_text == NULL || callback == NULL) { + return MROBOT_ERR_NULL_PTR; + } + + if (ctx.custom_cmd_count >= MROBOT_MAX_CUSTOM_COMMANDS) { + return MROBOT_ERR_FULL; + } + + /* 动态分配命令结构体 */ + CLI_Command_Definition_t *cmd_def = BSP_Malloc(sizeof(CLI_Command_Definition_t)); + if (cmd_def == NULL) { + return MROBOT_ERR_ALLOC; + } + + /* 初始化命令定义 */ + *(const char **)&cmd_def->pcCommand = command; + *(const char **)&cmd_def->pcHelpString = help_text; + *(pdCOMMAND_LINE_CALLBACK *)&cmd_def->pxCommandInterpreter = (pdCOMMAND_LINE_CALLBACK)callback; + cmd_def->cExpectedNumberOfParameters = param_count; + + /* 注册到 FreeRTOS CLI */ + FreeRTOS_CLIRegisterCommand(cmd_def); + + ctx.custom_cmds[ctx.custom_cmd_count] = cmd_def; + ctx.custom_cmd_count++; + + return MROBOT_OK; +} + +uint8_t MRobot_GetDeviceCount(void) { + return ctx.device_count; +} + +const MRobot_Device_t *MRobot_FindDevice(const char *name) { + if (name == NULL) return NULL; + + for (uint8_t i = 0; i < ctx.device_count; i++) { + if (strcmp(ctx.devices[i].name, name) == 0) { + return &ctx.devices[i]; + } + } + return NULL; +} + +int MRobot_Printf(const char *fmt, ...) { + if (fmt == NULL || !ctx.initialized) return -1; + + char buffer[MROBOT_OUTPUT_BUFFER_SIZE]; + va_list args; + va_start(args, fmt); + int len = format_float_va(buffer, sizeof(buffer), fmt, args); + va_end(args); + + if (len > 0) { + send_string(buffer); + } + return len; +} + +/** + * @brief 内部函数:格式化浮点数到缓冲区(va_list 版本) + */ +static int format_float_va(char *buf, size_t size, const char *fmt, va_list args) { + if (buf == NULL || size == 0 || fmt == NULL) return 0; + + char *buf_ptr = buf; + size_t buf_remain = size - 1; + + const char *p = fmt; + while (*p && buf_remain > 0) { + if (*p != '%') { + *buf_ptr++ = *p++; + buf_remain--; + continue; + } + + p++; /* 跳过 '%' */ + + /* 处理 %% */ + if (*p == '%') { + *buf_ptr++ = '%'; + buf_remain--; + p++; + continue; + } + + /* 解析精度 %.Nf */ + int precision = 2; /* 默认精度 */ + if (*p == '.') { + p++; + precision = 0; + while (*p >= '0' && *p <= '9') { + precision = precision * 10 + (*p - '0'); + p++; + } + if (precision > 6) precision = 6; + } + + int written = 0; + switch (*p) { + case 'f': { /* 浮点数 */ + double val = va_arg(args, double); + written = MRobot_FormatFloat(buf_ptr, buf_remain, (float)val, precision); + break; + } + case 'd': + case 'i': { + int val = va_arg(args, int); + written = snprintf(buf_ptr, buf_remain, "%d", val); + break; + } + case 'u': { + unsigned int val = va_arg(args, unsigned int); + written = snprintf(buf_ptr, buf_remain, "%u", val); + break; + } + case 'x': { + unsigned int val = va_arg(args, unsigned int); + written = snprintf(buf_ptr, buf_remain, "%x", val); + break; + } + case 'X': { + unsigned int val = va_arg(args, unsigned int); + written = snprintf(buf_ptr, buf_remain, "%X", val); + break; + } + case 's': { + const char *str = va_arg(args, const char *); + if (str == NULL) str = "(null)"; + written = snprintf(buf_ptr, buf_remain, "%s", str); + break; + } + case 'c': { + int ch = va_arg(args, int); + *buf_ptr = (char)ch; + written = 1; + break; + } + case 'l': { + p++; + if (*p == 'd' || *p == 'i') { + long val = va_arg(args, long); + written = snprintf(buf_ptr, buf_remain, "%ld", val); + } else if (*p == 'u') { + unsigned long val = va_arg(args, unsigned long); + written = snprintf(buf_ptr, buf_remain, "%lu", val); + } else if (*p == 'x' || *p == 'X') { + unsigned long val = va_arg(args, unsigned long); + written = snprintf(buf_ptr, buf_remain, *p == 'x' ? "%lx" : "%lX", val); + } else { + p--; + } + break; + } + default: { + *buf_ptr++ = '%'; + buf_remain--; + if (buf_remain > 0) { + *buf_ptr++ = *p; + buf_remain--; + } + written = 0; + break; + } + } + + if (written > 0) { + buf_ptr += written; + buf_remain -= (size_t)written; + } + p++; + } + + *buf_ptr = '\0'; + return (int)(buf_ptr - buf); +} + +int MRobot_Snprintf(char *buf, size_t size, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int len = format_float_va(buf, size, fmt, args); + va_end(args); + return len; +} + +int MRobot_FormatFloat(char *buf, size_t size, float val, int precision) { + if (buf == NULL || size == 0) return 0; + + int offset = 0; + + /* 处理负数 */ + if (val < 0) { + if (offset < (int)size - 1) buf[offset++] = '-'; + val = -val; + } + + /* 限制精度范围 */ + if (precision < 0) precision = 0; + if (precision > 6) precision = 6; + + /* 计算乘数 */ + int multiplier = 1; + for (int i = 0; i < precision; i++) multiplier *= 10; + + int int_part = (int)val; + int frac_part = (int)((val - int_part) * multiplier + 0.5f); + + /* 处理进位 */ + if (frac_part >= multiplier) { + int_part++; + frac_part -= multiplier; + } + + /* 格式化输出 */ + int written; + if (precision > 0) { + written = snprintf(buf + offset, size - offset, "%d.%0*d", int_part, precision, frac_part); + } else { + written = snprintf(buf + offset, size - offset, "%d", int_part); + } + return (written > 0) ? (offset + written) : offset; +} + +void MRobot_Run(void) { + if (!ctx.initialized) return; + + /* htop 模式 */ + if (ctx.state == MROBOT_STATE_HTOP) { + handle_htop_mode(); + return; + } + + /* 处理命令 */ + if (ctx.cmd_ready) { + ctx.state = MROBOT_STATE_PROCESSING; + + /* 检查是否是 htop 命令 */ + if (strcmp((char *)ctx.cmd_buffer, "htop") == 0) { + ctx.state = MROBOT_STATE_HTOP; + ctx.htop_exit = false; + } else { + /* 处理其他命令 */ + BaseType_t more; + do { + ctx.output_buffer[0] = '\0'; + more = FreeRTOS_CLIProcessCommand((char *)ctx.cmd_buffer, + ctx.output_buffer, + sizeof(ctx.output_buffer)); + + if (ctx.output_buffer[0] != '\0') { + send_string(ctx.output_buffer); + } + } while (more != pdFALSE); + + send_prompt(); + ctx.state = MROBOT_STATE_IDLE; + } + + ctx.cmd_index = 0; + ctx.cmd_ready = false; + } + + osDelay(10); +} diff --git a/device/mrobot/mrobot.h b/device/mrobot/mrobot.h new file mode 100644 index 0000000..74c0875 --- /dev/null +++ b/device/mrobot/mrobot.h @@ -0,0 +1,317 @@ +/** + * @file mrobot.h + * @brief MRobot CLI - 基于 FreeRTOS CLI 的嵌入式调试命令行系统 + * + * 功能特性: + * - 设备注册与监控(IMU、电机、传感器等) + * - 类 Unix 文件系统命令(cd, ls, pwd) + * - htop 风格的任务监控 + * - 自定义命令扩展 + * - 线程安全设计 + * + * @example IMU 设备注册示例 + * @code + * // 1. 定义 IMU 数据结构 + * typedef struct { + * bool online; + * float accl[3]; + * float gyro[3]; + * float euler[3]; // roll, pitch, yaw (deg) + * float temp; + * } MyIMU_t; + * + * MyIMU_t my_imu; + * + * // 2. 实现打印回调 + * static int print_imu(const void *data, char *buf, size_t size) { + * const MyIMU_t *imu = (const MyIMU_t *)data; + * return MRobot_Snprintf(buf, size, + * " Status: %s\r\n" + * " Accel : X=%.3f Y=%.3f Z=%.3f\r\n" + * " Euler : R=%.2f P=%.2f Y=%.2f\r\n" + * " Temp : %.1f C\r\n", + * imu->online ? "Online" : "Offline", + * imu->accl[0], imu->accl[1], imu->accl[2], + * imu->euler[0], imu->euler[1], imu->euler[2], + * imu->temp); + * } + * + * // 3. 注册设备 + * MRobot_RegisterDevice("imu", &my_imu, print_imu); + * @endcode + * + * @example 电机设备注册示例 + * @code + * typedef struct { + * bool online; + * float angle; // deg + * float speed; // RPM + * float current; // A + * } MyMotor_t; + * + * MyMotor_t motor[4]; + * + * static int print_motor(const void *data, char *buf, size_t size) { + * const MyMotor_t *m = (const MyMotor_t *)data; + * return MRobot_Snprintf(buf, size, + * " Status : %s\r\n" + * " Angle : %.2f deg\r\n" + * " Speed : %.1f RPM\r\n" + * " Current: %.3f A\r\n", + * m->online ? "Online" : "Offline", + * m->angle, m->speed, m->current); + * } + * + * // 注册 4 个电机 + * MRobot_RegisterDevice("motor0", &motor[0], print_motor); + * MRobot_RegisterDevice("motor1", &motor[1], print_motor); + * MRobot_RegisterDevice("motor2", &motor[2], print_motor); + * MRobot_RegisterDevice("motor3", &motor[3], print_motor); + * @endcode + * + * @example 自定义校准命令示例 + * @code + * // 校准数据 + * static float gyro_offset[3] = {0}; + * + * // 命令回调: cali gyro / cali accel / cali save + * static long cmd_cali(char *buf, size_t size, const char *cmd) { + * const char *param = FreeRTOS_CLIGetParameter(cmd, 1, NULL); + * + * if (param == NULL) { + * return MRobot_Snprintf(buf, size, "Usage: cali \r\n"); + * } + * if (strncmp(param, "gyro", 4) == 0) { + * // 采集 1000 次陀螺仪数据求平均 + * MRobot_Snprintf(buf, size, "Calibrating gyro... keep IMU still!\r\n"); + * // ... 校准逻辑 ... + * return 0; + * } + * if (strncmp(param, "save", 4) == 0) { + * // 保存到 Flash + * MRobot_Snprintf(buf, size, "Calibration saved to flash.\r\n"); + * return 0; + * } + * return MRobot_Snprintf(buf, size, "Unknown: %s\r\n", param); + * } + * + * // 注册命令 + * MRobot_RegisterCommand("cali", "cali : IMU calibration\r\n", cmd_cali, -1); + * @endcode + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include +#include +#include +#include "bsp/uart.h" + +/* Configuration ------------------------------------------------------------ */ +/* 可在编译时通过 -D 选项覆盖这些默认值 */ + +#ifndef MROBOT_MAX_DEVICES +#define MROBOT_MAX_DEVICES 64 /* 最大设备数 */ +#endif + +#ifndef MROBOT_MAX_CUSTOM_COMMANDS +#define MROBOT_MAX_CUSTOM_COMMANDS 16 /* 最大自定义命令数 */ +#endif + +#ifndef MROBOT_CMD_BUFFER_SIZE +#define MROBOT_CMD_BUFFER_SIZE 128 /* 命令缓冲区大小 */ +#endif + +#ifndef MROBOT_OUTPUT_BUFFER_SIZE +#define MROBOT_OUTPUT_BUFFER_SIZE 512 /* 输出缓冲区大小 */ +#endif + +#ifndef MROBOT_DEVICE_NAME_LEN +#define MROBOT_DEVICE_NAME_LEN 32 /* 设备名最大长度 */ +#endif + +#ifndef MROBOT_PATH_MAX_LEN +#define MROBOT_PATH_MAX_LEN 64 /* 路径最大长度 */ +#endif + +#ifndef MROBOT_HTOP_REFRESH_MS +#define MROBOT_HTOP_REFRESH_MS 200 /* htop 刷新间隔 (ms) */ +#endif + +#ifndef MROBOT_UART_PORT +#define MROBOT_UART_PORT BSP_UART_VOFA /* 默认 UART 端口 */ +#endif + +#ifndef MROBOT_USER_NAME +#define MROBOT_USER_NAME "root" /* CLI 用户名 */ +#endif + +#ifndef MROBOT_HOST_NAME +#define MROBOT_HOST_NAME "MRobot" /* CLI 主机名 */ +#endif + +/* Error codes -------------------------------------------------------------- */ +typedef enum { + MROBOT_OK = 0, /* 成功 */ + MROBOT_ERR_FULL = -1, /* 容量已满 */ + MROBOT_ERR_NULL_PTR = -2, /* 空指针 */ + MROBOT_ERR_INVALID_ARG = -3, /* 无效参数 */ + MROBOT_ERR_NOT_FOUND = -4, /* 未找到 */ + MROBOT_ERR_ALLOC = -5, /* 内存分配失败 */ + MROBOT_ERR_BUSY = -6, /* 设备忙 */ + MROBOT_ERR_NOT_INIT = -7, /* 未初始化 */ +} MRobot_Error_t; + +/* CLI 运行状态 */ +typedef enum { + MROBOT_STATE_IDLE, /* 空闲状态,等待输入 */ + MROBOT_STATE_HTOP, /* htop 模式 */ + MROBOT_STATE_PROCESSING, /* 正在处理命令 */ +} MRobot_State_t; + +/* Callback types ----------------------------------------------------------- */ + +/** + * @brief 设备打印回调函数类型 + * @param device_data 用户注册时传入的设备数据指针 + * @param buffer 输出缓冲区 + * @param buffer_size 缓冲区大小 + * @return 实际写入的字节数 + * @note 用户需要自行实现此函数来格式化设备数据 + */ +typedef int (*MRobot_PrintCallback_t)(const void *device_data, char *buffer, size_t buffer_size); + +/** + * @brief 命令处理回调函数类型(与 FreeRTOS CLI 兼容) + */ +typedef long (*MRobot_CommandCallback_t)(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); + +/* Device structure --------------------------------------------------------- */ +typedef struct { + char name[MROBOT_DEVICE_NAME_LEN]; /* 设备名称 */ + void *data; /* 用户设备数据指针 */ + MRobot_PrintCallback_t print_cb; /* 用户打印回调函数 */ +} MRobot_Device_t; + +/* Public API --------------------------------------------------------------- */ + +/** + * @brief 初始化 MRobot CLI 系统 + * @note 必须在 FreeRTOS 调度器启动后调用 + */ +void MRobot_Init(void); + +/** + * @brief 反初始化 MRobot CLI 系统,释放资源 + */ +void MRobot_DeInit(void); + +/** + * @brief 获取当前 CLI 状态 + * @return MRobot_State_t 当前状态 + */ +MRobot_State_t MRobot_GetState(void); + +/** + * @brief 注册设备到 MRobot 系统 + * @param name 设备名称(会被截断到 MROBOT_DEVICE_NAME_LEN-1) + * @param data 设备数据指针(不能为 NULL) + * @param print_cb 打印回调函数(可为 NULL,但无法用 show 命令查看) + * @return MRobot_Error_t 错误码 + */ +MRobot_Error_t MRobot_RegisterDevice(const char *name, void *data, MRobot_PrintCallback_t print_cb); + +/** + * @brief 注销设备 + * @param name 设备名称 + * @return MRobot_Error_t 错误码 + */ +MRobot_Error_t MRobot_UnregisterDevice(const char *name); + +/** + * @brief 注册自定义命令 + * @param command 命令名称 + * @param help_text 帮助文本 + * @param callback 命令回调函数 + * @param param_count 参数个数(-1 表示可变参数) + * @return MRobot_Error_t 错误码 + */ +MRobot_Error_t MRobot_RegisterCommand(const char *command, const char *help_text, + MRobot_CommandCallback_t callback, int8_t param_count); + +/** + * @brief 获取已注册设备数量 + * @return 设备数量 + */ +uint8_t MRobot_GetDeviceCount(void); + +/** + * @brief 根据名称查找设备 + * @param name 设备名称 + * @return 设备指针,未找到返回 NULL + */ +const MRobot_Device_t *MRobot_FindDevice(const char *name); + +/** + * @brief MRobot 主循环,在 CLI 任务中周期性调用 + * @note 建议调用周期 10ms + */ +void MRobot_Run(void); + +/** + * @brief 格式化输出到 CLI 终端(线程安全,支持浮点数) + * @param fmt 格式字符串 + * @param ... 可变参数 + * @return 实际输出的字符数,失败返回负数 + * + * @note 支持的格式说明符: + * - %d, %i, %u, %x, %X, %ld, %lu, %lx : 整数 + * - %s, %c : 字符串/字符 + * - %f : 浮点数 (默认2位小数) + * - %.Nf : 浮点数 (N位小数, N=0-6) + * - %% : 百分号 + * + * @example + * MRobot_Printf("Euler: R=%.2f P=%.2f Y=%.2f\\r\\n", roll, pitch, yaw); + */ +int MRobot_Printf(const char *fmt, ...); + +/** + * @brief 格式化到缓冲区(用于回调函数,支持浮点数) + * @note 格式说明符同 MRobot_Printf + * + * @example + * static int print_imu(const void *data, char *buf, size_t size) { + * const BMI088_t *imu = (const BMI088_t *)data; + * return MRobot_Snprintf(buf, size, + * " Accel: X=%.3f Y=%.3f Z=%.3f\\r\\n", + * imu->accl.x, imu->accl.y, imu->accl.z); + * } + */ +int MRobot_Snprintf(char *buf, size_t size, const char *fmt, ...); + +/* Utility functions -------------------------------------------------------- */ + +/** + * @brief 格式化浮点数为字符串(嵌入式环境不支持 %f) + * @param buf 输出缓冲区 + * @param size 缓冲区大小 + * @param val 要格式化的浮点数 + * @param precision 小数位数 (0-6) + * @return 写入的字符数 + * + * @example + * char buf[16]; + * MRobot_FormatFloat(buf, sizeof(buf), 3.14159f, 2); // "3.14" + * MRobot_FormatFloat(buf, sizeof(buf), -0.001f, 4); // "-0.0010" + */ +int MRobot_FormatFloat(char *buf, size_t size, float val, int precision); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/ioc/CtrBoard-H7_ALL.ioc b/ioc/CtrBoard-H7_ALL.ioc new file mode 100644 index 0000000..13166ec --- /dev/null +++ b/ioc/CtrBoard-H7_ALL.ioc @@ -0,0 +1,700 @@ +#MicroXplorer Configuration settings - do not modify +ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_4 +ADC1.Channel-1\#ChannelRegularConversion=ADC_CHANNEL_19 +ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV64 +ADC1.ContinuousConvMode=ENABLE +ADC1.ConversionDataManagement=ADC_CONVERSIONDATA_DMA_CIRCULAR +ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ClockPrescaler,ContinuousConvMode,ConversionDataManagement,Rank-1\#ChannelRegularConversion,Channel-1\#ChannelRegularConversion,SamplingTime-1\#ChannelRegularConversion,OffsetNumber-1\#ChannelRegularConversion,OffsetSignedSaturation-1\#ChannelRegularConversion,NbrOfConversion +ADC1.NbrOfConversion=2 +ADC1.NbrOfConversionFlag=1 +ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE +ADC1.OffsetNumber-1\#ChannelRegularConversion=ADC_OFFSET_NONE +ADC1.OffsetSignedSaturation-0\#ChannelRegularConversion=DISABLE +ADC1.OffsetSignedSaturation-1\#ChannelRegularConversion=DISABLE +ADC1.Rank-0\#ChannelRegularConversion=1 +ADC1.Rank-1\#ChannelRegularConversion=2 +ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_32CYCLES_5 +ADC1.SamplingTime-1\#ChannelRegularConversion=ADC_SAMPLETIME_32CYCLES_5 +ADC1.master=1 +CAD.formats= +CAD.pinconfig= +CAD.provider= +CORTEX_M7.BaseAddress-Cortex_Memory_Protection_Unit_Region0_Settings=0x24000000 +CORTEX_M7.CPU_DCache=Disabled +CORTEX_M7.CPU_ICache=Disabled +CORTEX_M7.Enable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_ENABLE +CORTEX_M7.IPParameters=CPU_DCache,CPU_ICache,MPU_Control,Enable-Cortex_Memory_Protection_Unit_Region0_Settings,BaseAddress-Cortex_Memory_Protection_Unit_Region0_Settings,Size-Cortex_Memory_Protection_Unit_Region0_Settings,TypeExtField-Cortex_Memory_Protection_Unit_Region0_Settings,IsCacheable-Cortex_Memory_Protection_Unit_Region0_Settings,IsBufferable-Cortex_Memory_Protection_Unit_Region0_Settings +CORTEX_M7.IsBufferable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_ACCESS_BUFFERABLE +CORTEX_M7.IsCacheable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_ACCESS_CACHEABLE +CORTEX_M7.MPU_Control=__NULL +CORTEX_M7.Size-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_SIZE_512B +CORTEX_M7.TypeExtField-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_TEX_LEVEL1 +Dma.ADC1.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.ADC1.0.EventEnable=DISABLE +Dma.ADC1.0.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.ADC1.0.Instance=DMA1_Stream0 +Dma.ADC1.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD +Dma.ADC1.0.MemInc=DMA_MINC_ENABLE +Dma.ADC1.0.Mode=DMA_CIRCULAR +Dma.ADC1.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD +Dma.ADC1.0.PeriphInc=DMA_PINC_DISABLE +Dma.ADC1.0.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.ADC1.0.Priority=DMA_PRIORITY_LOW +Dma.ADC1.0.RequestNumber=1 +Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.ADC1.0.SignalID=NONE +Dma.ADC1.0.SyncEnable=DISABLE +Dma.ADC1.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.ADC1.0.SyncRequestNumber=1 +Dma.ADC1.0.SyncSignalID=NONE +Dma.Request0=ADC1 +Dma.Request1=SPI2_RX +Dma.Request2=SPI2_TX +Dma.Request3=UART5_RX +Dma.RequestsNb=4 +Dma.SPI2_RX.1.Direction=DMA_PERIPH_TO_MEMORY +Dma.SPI2_RX.1.EventEnable=DISABLE +Dma.SPI2_RX.1.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI2_RX.1.Instance=DMA1_Stream1 +Dma.SPI2_RX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI2_RX.1.MemInc=DMA_MINC_ENABLE +Dma.SPI2_RX.1.Mode=DMA_NORMAL +Dma.SPI2_RX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI2_RX.1.PeriphInc=DMA_PINC_DISABLE +Dma.SPI2_RX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.SPI2_RX.1.Priority=DMA_PRIORITY_LOW +Dma.SPI2_RX.1.RequestNumber=1 +Dma.SPI2_RX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.SPI2_RX.1.SignalID=NONE +Dma.SPI2_RX.1.SyncEnable=DISABLE +Dma.SPI2_RX.1.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.SPI2_RX.1.SyncRequestNumber=1 +Dma.SPI2_RX.1.SyncSignalID=NONE +Dma.SPI2_TX.2.Direction=DMA_MEMORY_TO_PERIPH +Dma.SPI2_TX.2.EventEnable=DISABLE +Dma.SPI2_TX.2.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI2_TX.2.Instance=DMA1_Stream2 +Dma.SPI2_TX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI2_TX.2.MemInc=DMA_MINC_ENABLE +Dma.SPI2_TX.2.Mode=DMA_NORMAL +Dma.SPI2_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI2_TX.2.PeriphInc=DMA_PINC_DISABLE +Dma.SPI2_TX.2.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.SPI2_TX.2.Priority=DMA_PRIORITY_LOW +Dma.SPI2_TX.2.RequestNumber=1 +Dma.SPI2_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.SPI2_TX.2.SignalID=NONE +Dma.SPI2_TX.2.SyncEnable=DISABLE +Dma.SPI2_TX.2.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.SPI2_TX.2.SyncRequestNumber=1 +Dma.SPI2_TX.2.SyncSignalID=NONE +Dma.UART5_RX.3.Direction=DMA_PERIPH_TO_MEMORY +Dma.UART5_RX.3.EventEnable=DISABLE +Dma.UART5_RX.3.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.UART5_RX.3.Instance=DMA1_Stream3 +Dma.UART5_RX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.UART5_RX.3.MemInc=DMA_MINC_ENABLE +Dma.UART5_RX.3.Mode=DMA_NORMAL +Dma.UART5_RX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.UART5_RX.3.PeriphInc=DMA_PINC_DISABLE +Dma.UART5_RX.3.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.UART5_RX.3.Priority=DMA_PRIORITY_LOW +Dma.UART5_RX.3.RequestNumber=1 +Dma.UART5_RX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.UART5_RX.3.SignalID=NONE +Dma.UART5_RX.3.SyncEnable=DISABLE +Dma.UART5_RX.3.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.UART5_RX.3.SyncRequestNumber=1 +Dma.UART5_RX.3.SyncSignalID=NONE +FDCAN1.AutoRetransmission=ENABLE +FDCAN1.CalculateBaudRateNominal=1000000 +FDCAN1.CalculateTimeBitNominal=1000 +FDCAN1.CalculateTimeQuantumNominal=200.0 +FDCAN1.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission +FDCAN1.NominalPrescaler=24 +FDCAN1.NominalTimeSeg1=3 +FDCAN1.RxFifo0ElmtsNbr=32 +FDCAN1.StdFiltersNbr=1 +FDCAN1.TxFifoQueueElmtsNbr=32 +FDCAN2.AutoRetransmission=ENABLE +FDCAN2.CalculateBaudRateNominal=1000000 +FDCAN2.CalculateTimeBitNominal=1000 +FDCAN2.CalculateTimeQuantumNominal=200.0 +FDCAN2.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,MessageRAMOffset,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission,RxFifo1ElmtsNbr +FDCAN2.MessageRAMOffset=0x406 +FDCAN2.NominalPrescaler=24 +FDCAN2.NominalTimeSeg1=3 +FDCAN2.RxFifo0ElmtsNbr=32 +FDCAN2.RxFifo1ElmtsNbr=32 +FDCAN2.StdFiltersNbr=1 +FDCAN2.TxFifoQueueElmtsNbr=32 +FDCAN3.AutoRetransmission=ENABLE +FDCAN3.CalculateBaudRateNominal=1000000 +FDCAN3.CalculateTimeBitNominal=1000 +FDCAN3.CalculateTimeQuantumNominal=200.0 +FDCAN3.ExtFiltersNbr=1 +FDCAN3.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,MessageRAMOffset,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission,RxFifo1ElmtsNbr,ExtFiltersNbr +FDCAN3.MessageRAMOffset=0x812 +FDCAN3.NominalPrescaler=24 +FDCAN3.NominalTimeSeg1=3 +FDCAN3.RxFifo0ElmtsNbr=32 +FDCAN3.RxFifo1ElmtsNbr=32 +FDCAN3.StdFiltersNbr=1 +FDCAN3.TxFifoQueueElmtsNbr=32 +FREERTOS.IPParameters=Tasks01,configTOTAL_HEAP_SIZE +FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL +FREERTOS.configTOTAL_HEAP_SIZE=0x10000 +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=false +MMTAppRegionsCount=0 +MMTConfigApplied=false +Mcu.CPN=STM32H723VGT6 +Mcu.Family=STM32H7 +Mcu.IP0=ADC1 +Mcu.IP1=CORTEX_M7 +Mcu.IP10=OCTOSPI1 +Mcu.IP11=RCC +Mcu.IP12=SPI1 +Mcu.IP13=SPI2 +Mcu.IP14=SYS +Mcu.IP15=TIM1 +Mcu.IP16=TIM2 +Mcu.IP17=TIM3 +Mcu.IP18=TIM12 +Mcu.IP19=UART5 +Mcu.IP2=DEBUG +Mcu.IP20=UART7 +Mcu.IP21=USART1 +Mcu.IP22=USART2 +Mcu.IP23=USART3 +Mcu.IP24=USART10 +Mcu.IP25=USB_OTG_HS +Mcu.IP3=DMA +Mcu.IP4=FDCAN1 +Mcu.IP5=FDCAN2 +Mcu.IP6=FDCAN3 +Mcu.IP7=FREERTOS +Mcu.IP8=MEMORYMAP +Mcu.IP9=NVIC +Mcu.IPNb=26 +Mcu.Name=STM32H723VGTx +Mcu.Package=LQFP100 +Mcu.Pin0=PE2 +Mcu.Pin1=PE3 +Mcu.Pin10=PC3_C +Mcu.Pin11=PA0 +Mcu.Pin12=PA1 +Mcu.Pin13=PA2 +Mcu.Pin14=PA3 +Mcu.Pin15=PA5 +Mcu.Pin16=PA7 +Mcu.Pin17=PC4 +Mcu.Pin18=PC5 +Mcu.Pin19=PB0 +Mcu.Pin2=PC13 +Mcu.Pin20=PB1 +Mcu.Pin21=PB2 +Mcu.Pin22=PE7 +Mcu.Pin23=PE8 +Mcu.Pin24=PE9 +Mcu.Pin25=PE10 +Mcu.Pin26=PE11 +Mcu.Pin27=PE12 +Mcu.Pin28=PE13 +Mcu.Pin29=PE15 +Mcu.Pin3=PC14-OSC32_IN +Mcu.Pin30=PB10 +Mcu.Pin31=PB11 +Mcu.Pin32=PB12 +Mcu.Pin33=PB13 +Mcu.Pin34=PB14 +Mcu.Pin35=PB15 +Mcu.Pin36=PD8 +Mcu.Pin37=PD9 +Mcu.Pin38=PD10 +Mcu.Pin39=PD11 +Mcu.Pin4=PC15-OSC32_OUT +Mcu.Pin40=PD12 +Mcu.Pin41=PD13 +Mcu.Pin42=PA8 +Mcu.Pin43=PA9 +Mcu.Pin44=PA10 +Mcu.Pin45=PA11 +Mcu.Pin46=PA12 +Mcu.Pin47=PA13(JTMS/SWDIO) +Mcu.Pin48=PA14(JTCK/SWCLK) +Mcu.Pin49=PA15(JTDI) +Mcu.Pin5=PH0-OSC_IN +Mcu.Pin50=PC12 +Mcu.Pin51=PD0 +Mcu.Pin52=PD1 +Mcu.Pin53=PD2 +Mcu.Pin54=PD4 +Mcu.Pin55=PD5 +Mcu.Pin56=PD6 +Mcu.Pin57=PD7 +Mcu.Pin58=PB3(JTDO/TRACESWO) +Mcu.Pin59=PB5 +Mcu.Pin6=PH1-OSC_OUT +Mcu.Pin60=PB6 +Mcu.Pin61=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin62=VP_OCTOSPI1_VS_octo +Mcu.Pin63=VP_SYS_VS_tim23 +Mcu.Pin64=VP_MEMORYMAP_VS_MEMORYMAP +Mcu.Pin7=PC0 +Mcu.Pin8=PC1 +Mcu.Pin9=PC2_C +Mcu.PinsNb=65 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32H723VGTx +MxCube.Version=6.15.0 +MxDb.Version=DB.6.0.150 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.DMA1_Stream0_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Stream1_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Stream3_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.EXTI15_10_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN1_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN1_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN2_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN2_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN3_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.FDCAN3_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SPI2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false +NVIC.SavedPendsvIrqHandlerGenerated=true +NVIC.SavedSvcallIrqHandlerGenerated=true +NVIC.SavedSystickIrqHandlerGenerated=true +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:true\:false +NVIC.TIM23_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true +NVIC.TimeBase=TIM23_IRQn +NVIC.TimeBaseIP=TIM23 +NVIC.UART5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.UART7_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.USART10_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.USART1_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.USART2_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.USART3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +PA0.Locked=true +PA0.Signal=S_TIM2_CH1_ETR +PA1.Locked=true +PA1.Mode=OCTOSPI1_IOL_Port1L +PA1.Signal=OCTOSPIM_P1_IO3 +PA10.Locked=true +PA10.Mode=Asynchronous +PA10.Signal=USART1_RX +PA11.Mode=Device_Only_FS +PA11.Signal=USB_OTG_HS_DM +PA12.Mode=Device_Only_FS +PA12.Signal=USB_OTG_HS_DP +PA13(JTMS/SWDIO).Locked=true +PA13(JTMS/SWDIO).Mode=Serial_Wire +PA13(JTMS/SWDIO).Signal=DEBUG_JTMS-SWDIO +PA14(JTCK/SWCLK).Locked=true +PA14(JTCK/SWCLK).Mode=Serial_Wire +PA14(JTCK/SWCLK).Signal=DEBUG_JTCK-SWCLK +PA15(JTDI).Locked=true +PA15(JTDI).Signal=GPIO_Input +PA2.Locked=true +PA2.Signal=S_TIM2_CH3 +PA3.Locked=true +PA3.Mode=OCTOSPI1_IOL_Port1L +PA3.Signal=OCTOSPIM_P1_IO2 +PA5.Locked=true +PA5.Signal=ADCx_INP19 +PA7.GPIOParameters=GPIO_Label +PA7.GPIO_Label=WS2812 +PA7.Locked=true +PA7.Signal=S_TIM3_CH2 +PA8.Locked=true +PA8.Mode=Clock-out-1 +PA8.Signal=RCC_MCO_1 +PA9.Locked=true +PA9.Mode=Asynchronous +PA9.Signal=USART1_TX +PB0.Locked=true +PB0.Mode=OCTOSPI1_IOL_Port1L +PB0.Signal=OCTOSPIM_P1_IO1 +PB1.GPIOParameters=GPIO_Label +PB1.GPIO_Label=IMU_HEAT +PB1.Locked=true +PB1.Signal=S_TIM3_CH4 +PB10.GPIOParameters=GPIO_Label +PB10.GPIO_Label=LCD_BLK +PB10.Locked=true +PB10.Signal=GPIO_Output +PB11.GPIOParameters=GPIO_Label +PB11.GPIO_Label=LCD_RES +PB11.Locked=true +PB11.Signal=GPIO_Output +PB12.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PB12.GPIO_Label=DCMI_REST +PB12.GPIO_PuPd=GPIO_PULLUP +PB12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PB12.Locked=true +PB12.PinState=GPIO_PIN_SET +PB12.Signal=GPIO_Output +PB13.GPIOParameters=GPIO_Speed +PB13.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PB13.Locked=true +PB13.Mode=Full_Duplex_Master +PB13.Signal=SPI2_SCK +PB14.Mode=Hardware Flow Control (RS485) +PB14.Signal=USART3_DE +PB15.GPIOParameters=GPIO_Label +PB15.GPIO_Label=BUZZER +PB15.Locked=true +PB15.Signal=S_TIM12_CH2 +PB2.Locked=true +PB2.Mode=O1_P1_CLK +PB2.Signal=OCTOSPIM_P1_CLK +PB3(JTDO/TRACESWO).GPIOParameters=GPIO_Speed +PB3(JTDO/TRACESWO).GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PB3(JTDO/TRACESWO).Mode=TX_Only_Simplex_Unidirect_Master +PB3(JTDO/TRACESWO).Signal=SPI1_SCK +PB5.Locked=true +PB5.Mode=FDCAN_Activate +PB5.Signal=FDCAN2_RX +PB6.Locked=true +PB6.Mode=FDCAN_Activate +PB6.Signal=FDCAN2_TX +PC0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PC0.GPIO_Label=ACCL_CS +PC0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC0.Locked=true +PC0.PinState=GPIO_PIN_SET +PC0.Signal=GPIO_Output +PC1.GPIOParameters=GPIO_Speed +PC1.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC1.Mode=Full_Duplex_Master +PC1.Signal=SPI2_MOSI +PC12.Mode=Asynchronous +PC12.Signal=UART5_TX +PC13.GPIOParameters=PinState,GPIO_Label +PC13.GPIO_Label=POWER_24V_2 +PC13.Locked=true +PC13.PinState=GPIO_PIN_SET +PC13.Signal=GPIO_Output +PC14-OSC32_IN.GPIOParameters=PinState,GPIO_Label +PC14-OSC32_IN.GPIO_Label=POWER_24V_1 +PC14-OSC32_IN.Locked=true +PC14-OSC32_IN.PinState=GPIO_PIN_SET +PC14-OSC32_IN.Signal=GPIO_Output +PC15-OSC32_OUT.GPIOParameters=PinState,GPIO_Label +PC15-OSC32_OUT.GPIO_Label=POWER_5V +PC15-OSC32_OUT.Locked=true +PC15-OSC32_OUT.PinState=GPIO_PIN_SET +PC15-OSC32_OUT.Signal=GPIO_Output +PC2_C.GPIOParameters=GPIO_Speed +PC2_C.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC2_C.Mode=Full_Duplex_Master +PC2_C.Signal=SPI2_MISO +PC3_C.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PC3_C.GPIO_Label=GYRO_CS +PC3_C.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC3_C.Locked=true +PC3_C.PinState=GPIO_PIN_SET +PC3_C.Signal=GPIO_Output +PC4.Locked=true +PC4.Signal=ADCx_INP4 +PC5.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PC5.GPIO_Label=DCMI_PWDN +PC5.GPIO_PuPd=GPIO_NOPULL +PC5.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC5.Locked=true +PC5.PinState=GPIO_PIN_SET +PC5.Signal=GPIO_Output +PD0.Mode=FDCAN_Activate +PD0.Signal=FDCAN1_RX +PD1.Locked=true +PD1.Mode=FDCAN_Activate +PD1.Signal=FDCAN1_TX +PD10.GPIOParameters=GPIO_Label +PD10.GPIO_Label=LCD_DC +PD10.Locked=true +PD10.Signal=GPIO_Output +PD11.Locked=true +PD11.Mode=OCTOSPI1_IOL_Port1L +PD11.Signal=OCTOSPIM_P1_IO0 +PD12.Mode=FDCAN_Activate +PD12.Signal=FDCAN3_RX +PD13.Locked=true +PD13.Mode=FDCAN_Activate +PD13.Signal=FDCAN3_TX +PD2.Mode=Asynchronous +PD2.Signal=UART5_RX +PD4.Locked=true +PD4.Mode=Hardware Flow Control (RS485) +PD4.Signal=USART2_DE +PD5.Locked=true +PD5.Mode=Asynchronous +PD5.Signal=USART2_TX +PD6.Locked=true +PD6.Mode=Asynchronous +PD6.Signal=USART2_RX +PD7.GPIOParameters=GPIO_Speed +PD7.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PD7.Locked=true +PD7.Mode=TX_Only_Simplex_Unidirect_Master +PD7.Signal=SPI1_MOSI +PD8.Mode=Asynchronous +PD8.Signal=USART3_TX +PD9.Mode=Asynchronous +PD9.Signal=USART3_RX +PE10.GPIOParameters=GPIO_Label +PE10.GPIO_Label=ACCL_INT +PE10.Locked=true +PE10.Signal=GPXTI10 +PE11.Locked=true +PE11.Mode=OCTOSPI1_Port1_NCS +PE11.Signal=OCTOSPIM_P1_NCS +PE12.GPIOParameters=GPIO_Label +PE12.GPIO_Label=GYRO_INT +PE12.Locked=true +PE12.Signal=GPXTI12 +PE13.Signal=S_TIM1_CH3 +PE15.GPIOParameters=GPIO_Label +PE15.GPIO_Label=LCD_CS +PE15.Locked=true +PE15.Signal=GPIO_Output +PE2.Mode=Asynchronous +PE2.Signal=USART10_RX +PE3.Mode=Asynchronous +PE3.Signal=USART10_TX +PE7.Mode=Asynchronous +PE7.Signal=UART7_RX +PE8.Mode=Asynchronous +PE8.Signal=UART7_TX +PE9.Locked=true +PE9.Signal=S_TIM1_CH1 +PH0-OSC_IN.Mode=HSE-External-Oscillator +PH0-OSC_IN.Signal=RCC_OSC_IN +PH1-OSC_OUT.Mode=HSE-External-Oscillator +PH1-OSC_OUT.Signal=RCC_OSC_OUT +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32H723VGTx +ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.12.1 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x1000 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=0 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=CtrBoard-H7_ALL.ioc +ProjectManager.ProjectName=CtrBoard-H7_ALL +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x2000 +ProjectManager.TargetToolchain=MDK-ARM V5.32 +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_TIM12_Init-TIM12-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_SPI2_Init-SPI2-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_USART1_UART_Init-USART1-false-HAL-true,10-MX_USART2_UART_Init-USART2-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_UART7_Init-UART7-false-HAL-true,13-MX_USART10_UART_Init-USART10-false-HAL-true,14-MX_FDCAN1_Init-FDCAN1-false-HAL-true,15-MX_FDCAN2_Init-FDCAN2-false-HAL-true,16-MX_FDCAN3_Init-FDCAN3-false-HAL-true,17-MX_TIM1_Init-TIM1-false-HAL-true,18-MX_TIM2_Init-TIM2-false-HAL-true,19-MX_OCTOSPI1_Init-OCTOSPI1-false-HAL-true,20-MX_USB_OTG_HS_PCD_Init-USB_OTG_HS-false-HAL-true,21-MX_UART5_Init-UART5-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true +RCC.ADCFreq_Value=96000000 +RCC.AHB12Freq_Value=240000000 +RCC.AHB4Freq_Value=240000000 +RCC.APB1Freq_Value=120000000 +RCC.APB2Freq_Value=120000000 +RCC.APB3Freq_Value=120000000 +RCC.APB4Freq_Value=120000000 +RCC.AXIClockFreq_Value=240000000 +RCC.CECFreq_Value=32000 +RCC.CKPERFreq_Value=64000000 +RCC.CortexFreq_Value=480000000 +RCC.CpuClockFreq_Value=480000000 +RCC.D1CPREFreq_Value=480000000 +RCC.D1PPRE=RCC_APB3_DIV2 +RCC.D2PPRE1=RCC_APB1_DIV2 +RCC.D2PPRE2=RCC_APB2_DIV2 +RCC.D3PPRE=RCC_APB4_DIV2 +RCC.DFSDMACLkFreq_Value=120000000 +RCC.DFSDMFreq_Value=120000000 +RCC.DIVM1=2 +RCC.DIVM2=2 +RCC.DIVN1=40 +RCC.DIVN2=16 +RCC.DIVP1=1 +RCC.DIVP1Freq_Value=480000000 +RCC.DIVP2Freq_Value=96000000 +RCC.DIVP3Freq_Value=48375000 +RCC.DIVQ1=4 +RCC.DIVQ1Freq_Value=120000000 +RCC.DIVQ2Freq_Value=96000000 +RCC.DIVQ3Freq_Value=48375000 +RCC.DIVR1Freq_Value=240000000 +RCC.DIVR2Freq_Value=96000000 +RCC.DIVR3Freq_Value=48375000 +RCC.EnbaleCSS=false +RCC.FDCANFreq_Value=120000000 +RCC.FMCFreq_Value=240000000 +RCC.FamilyName=M +RCC.HCLK3ClockFreq_Value=240000000 +RCC.HCLKFreq_Value=240000000 +RCC.HPRE=RCC_HCLK_DIV2 +RCC.HSE_VALUE=24000000 +RCC.I2C123Freq_Value=120000000 +RCC.I2C4Freq_Value=120000000 +RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,EnbaleCSS,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HSE_VALUE,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLL2_VCI_Range-AdvancedSettings,PLL2_VCO_SEL-AdvancedSettings,PLL3FRACN,PLL3_VCO_SEL-AdvancedSettings,PLLFRACN,PLLSourceVirtual,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6CLockSelection,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBCLockSelection,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value +RCC.LPTIM1Freq_Value=120000000 +RCC.LPTIM2Freq_Value=120000000 +RCC.LPTIM345Freq_Value=120000000 +RCC.LPUART1Freq_Value=120000000 +RCC.LTDCFreq_Value=48375000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MCO2PinFreq_Value=480000000 +RCC.PLL2FRACN=0 +RCC.PLL2_VCI_Range-AdvancedSettings=RCC_PLL2VCIRANGE_0 +RCC.PLL2_VCO_SEL-AdvancedSettings=RCC_PLL2VCOWIDE +RCC.PLL3FRACN=0 +RCC.PLL3_VCO_SEL-AdvancedSettings=RCC_PLL3VCOMEDIUM +RCC.PLLFRACN=0 +RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE +RCC.QSPIFreq_Value=240000000 +RCC.RNGFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.SAI1Freq_Value=120000000 +RCC.SAI4AFreq_Value=120000000 +RCC.SAI4BFreq_Value=120000000 +RCC.SDMMCFreq_Value=120000000 +RCC.SPDIFRXFreq_Value=120000000 +RCC.SPI123Freq_Value=120000000 +RCC.SPI45Freq_Value=120000000 +RCC.SPI6CLockSelection=RCC_SPI6CLKSOURCE_HSE +RCC.SPI6Freq_Value=24000000 +RCC.SWPMI1Freq_Value=120000000 +RCC.SYSCLKFreq_VALUE=480000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.Tim1OutputFreq_Value=240000000 +RCC.Tim2OutputFreq_Value=240000000 +RCC.TraceFreq_Value=240000000 +RCC.USART16Freq_Value=120000000 +RCC.USART234578Freq_Value=120000000 +RCC.USBCLockSelection=RCC_USBCLKSOURCE_HSI48 +RCC.USBFreq_Value=48000000 +RCC.VCO1OutputFreq_Value=480000000 +RCC.VCO2OutputFreq_Value=192000000 +RCC.VCO3OutputFreq_Value=96750000 +RCC.VCOInput1Freq_Value=12000000 +RCC.VCOInput2Freq_Value=12000000 +RCC.VCOInput3Freq_Value=750000 +SH.ADCx_INP19.0=ADC1_INP19,IN19-Single-Ended +SH.ADCx_INP19.ConfNb=1 +SH.ADCx_INP4.0=ADC1_INP4,IN4-Single-Ended +SH.ADCx_INP4.ConfNb=1 +SH.GPXTI10.0=GPIO_EXTI10 +SH.GPXTI10.ConfNb=1 +SH.GPXTI12.0=GPIO_EXTI12 +SH.GPXTI12.ConfNb=1 +SH.S_TIM12_CH2.0=TIM12_CH2,PWM Generation2 CH2 +SH.S_TIM12_CH2.ConfNb=1 +SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 +SH.S_TIM1_CH1.ConfNb=1 +SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3 +SH.S_TIM1_CH3.ConfNb=1 +SH.S_TIM2_CH1_ETR.0=TIM2_CH1,PWM Generation1 CH1 +SH.S_TIM2_CH1_ETR.ConfNb=1 +SH.S_TIM2_CH3.0=TIM2_CH3,PWM Generation3 CH3 +SH.S_TIM2_CH3.ConfNb=1 +SH.S_TIM3_CH2.0=TIM3_CH2,PWM Generation2 CH2 +SH.S_TIM3_CH2.ConfNb=1 +SH.S_TIM3_CH4.0=TIM3_CH4,PWM Generation4 CH4 +SH.S_TIM3_CH4.ConfNb=1 +SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4 +SPI1.CLKPolarity=SPI_POLARITY_HIGH +SPI1.CalculateBaudRate=30.0 MBits/s +SPI1.DataSize=SPI_DATASIZE_8BIT +SPI1.Direction=SPI_DIRECTION_2LINES_TXONLY +SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPolarity +SPI1.Mode=SPI_MODE_MASTER +SPI1.VirtualType=VM_MASTER +SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_32 +SPI2.CLKPhase=SPI_PHASE_2EDGE +SPI2.CLKPolarity=SPI_POLARITY_HIGH +SPI2.CalculateBaudRate=3.75 MBits/s +SPI2.DataSize=SPI_DATASIZE_8BIT +SPI2.Direction=SPI_DIRECTION_2LINES +SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPolarity,CLKPhase +SPI2.Mode=SPI_MODE_MASTER +SPI2.VirtualType=VM_MASTER +TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM1.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation1 CH1,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation3 CH3,Prescaler +TIM1.Period=10000 +TIM1.Prescaler=24 +TIM1.Pulse-PWM\ Generation1\ CH1=5000 +TIM1.Pulse-PWM\ Generation3\ CH3=5000 +TIM12.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM12.IPParameters=Channel-PWM Generation2 CH2,Prescaler,Period +TIM12.Period=2000-1 +TIM12.Prescaler=24-1 +TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM2.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM2.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation3 CH3,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation3 CH3,Prescaler +TIM2.Period=10000 +TIM2.Prescaler=24 +TIM2.Pulse-PWM\ Generation1\ CH1=5000 +TIM2.Pulse-PWM\ Generation3\ CH3=5000 +TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE +TIM3.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 +TIM3.IPParameters=Channel-PWM Generation4 CH4,Prescaler,Period,AutoReloadPreload,Channel-PWM Generation2 CH2 +TIM3.Period=10000-1 +TIM3.Prescaler=24-1 +UART5.BaudRate=100000 +UART5.IPParameters=Mode,WordLength,Parity,BaudRate +UART5.Mode=MODE_RX +UART5.Parity=PARITY_EVEN +UART5.WordLength=WORDLENGTH_9B +UART7.BaudRate=921600 +UART7.IPParameters=BaudRate +USART1.BaudRate=921600 +USART1.IPParameters=VirtualMode-Asynchronous,BaudRate +USART1.VirtualMode-Asynchronous=VM_ASYNC +USART10.BaudRate=921600 +USART10.IPParameters=VirtualMode,BaudRate +USART10.VirtualMode=VM_ASYNC +USART2.BaudRate=921600 +USART2.IPParameters=VirtualMode-Asynchronous,VirtualMode-Hardware Flow Control (RS485),BaudRate +USART2.VirtualMode-Asynchronous=VM_ASYNC +USART2.VirtualMode-Hardware\ Flow\ Control\ (RS485)=VM_ASYNC +USART3.BaudRate=921600 +USART3.IPParameters=VirtualMode-Asynchronous,VirtualMode-Hardware Flow Control (RS485),BaudRate +USART3.VirtualMode-Asynchronous=VM_ASYNC +USART3.VirtualMode-Hardware\ Flow\ Control\ (RS485)=VM_ASYNC +USB_OTG_HS.IPParameters=VirtualMode-Device_Only_FS +USB_OTG_HS.VirtualMode-Device_Only_FS=Device_Only_FS +VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 +VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 +VP_MEMORYMAP_VS_MEMORYMAP.Mode=CurAppReg +VP_MEMORYMAP_VS_MEMORYMAP.Signal=MEMORYMAP_VS_MEMORYMAP +VP_OCTOSPI1_VS_octo.Mode=octo_mode +VP_OCTOSPI1_VS_octo.Signal=OCTOSPI1_VS_octo +VP_SYS_VS_tim23.Mode=TIM23 +VP_SYS_VS_tim23.Signal=SYS_VS_tim23 +board=custom +rtos.0.ip=FREERTOS diff --git a/ioc/DevC.ioc b/ioc/DevC.ioc new file mode 100644 index 0000000..46909f1 --- /dev/null +++ b/ioc/DevC.ioc @@ -0,0 +1,743 @@ +#MicroXplorer Configuration settings - do not modify +ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_TEMPSENSOR +ADC1.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV6 +ADC1.IPParameters=Rank-0\#ChannelRegularConversion,master,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler +ADC1.NbrOfConversionFlag=1 +ADC1.Rank-0\#ChannelRegularConversion=1 +ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES +ADC1.master=1 +ADC3.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_8 +ADC3.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV6 +ADC3.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler +ADC3.NbrOfConversionFlag=1 +ADC3.Rank-0\#ChannelRegularConversion=1 +ADC3.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES +CAD.formats= +CAD.pinconfig= +CAD.provider= +CAN1.ABOM=DISABLE +CAN1.BS1=CAN_BS1_6TQ +CAN1.BS2=CAN_BS2_7TQ +CAN1.CalculateBaudRate=1000000 +CAN1.CalculateTimeBit=1000 +CAN1.CalculateTimeQuantum=71.42857142857143 +CAN1.IPParameters=CalculateTimeQuantum,BS1,BS2,Prescaler,TXFP,ABOM,CalculateTimeBit,CalculateBaudRate,NART +CAN1.NART=ENABLE +CAN1.Prescaler=3 +CAN1.TXFP=ENABLE +CAN2.BS1=CAN_BS1_6TQ +CAN2.BS2=CAN_BS2_7TQ +CAN2.CalculateBaudRate=1000000 +CAN2.CalculateTimeBit=1000 +CAN2.CalculateTimeQuantum=71.42857142857143 +CAN2.IPParameters=CalculateTimeQuantum,BS1,BS2,Prescaler,TXFP,CalculateTimeBit,CalculateBaudRate,NART +CAN2.NART=ENABLE +CAN2.Prescaler=3 +CAN2.TXFP=ENABLE +Dma.I2C2_TX.2.Direction=DMA_MEMORY_TO_PERIPH +Dma.I2C2_TX.2.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.I2C2_TX.2.Instance=DMA1_Stream7 +Dma.I2C2_TX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.I2C2_TX.2.MemInc=DMA_MINC_ENABLE +Dma.I2C2_TX.2.Mode=DMA_NORMAL +Dma.I2C2_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.I2C2_TX.2.PeriphInc=DMA_PINC_DISABLE +Dma.I2C2_TX.2.Priority=DMA_PRIORITY_HIGH +Dma.I2C2_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.I2C3_RX.7.Direction=DMA_PERIPH_TO_MEMORY +Dma.I2C3_RX.7.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.I2C3_RX.7.Instance=DMA1_Stream2 +Dma.I2C3_RX.7.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.I2C3_RX.7.MemInc=DMA_MINC_ENABLE +Dma.I2C3_RX.7.Mode=DMA_NORMAL +Dma.I2C3_RX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.I2C3_RX.7.PeriphInc=DMA_PINC_DISABLE +Dma.I2C3_RX.7.Priority=DMA_PRIORITY_LOW +Dma.I2C3_RX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.Request0=SPI1_RX +Dma.Request1=SPI1_TX +Dma.Request2=I2C2_TX +Dma.Request3=USART3_RX +Dma.Request4=USART6_RX +Dma.Request5=USART6_TX +Dma.Request6=USART1_TX +Dma.Request7=I2C3_RX +Dma.Request8=USART1_RX +Dma.RequestsNb=9 +Dma.SPI1_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.SPI1_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI1_RX.0.Instance=DMA2_Stream2 +Dma.SPI1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI1_RX.0.MemInc=DMA_MINC_ENABLE +Dma.SPI1_RX.0.Mode=DMA_NORMAL +Dma.SPI1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI1_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.SPI1_RX.0.Priority=DMA_PRIORITY_VERY_HIGH +Dma.SPI1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.SPI1_TX.1.Direction=DMA_MEMORY_TO_PERIPH +Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI1_TX.1.Instance=DMA2_Stream3 +Dma.SPI1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI1_TX.1.MemInc=DMA_MINC_ENABLE +Dma.SPI1_TX.1.Mode=DMA_NORMAL +Dma.SPI1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI1_TX.1.PeriphInc=DMA_PINC_DISABLE +Dma.SPI1_TX.1.Priority=DMA_PRIORITY_HIGH +Dma.SPI1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART1_RX.8.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART1_RX.8.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_RX.8.Instance=DMA2_Stream5 +Dma.USART1_RX.8.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_RX.8.MemInc=DMA_MINC_ENABLE +Dma.USART1_RX.8.Mode=DMA_NORMAL +Dma.USART1_RX.8.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_RX.8.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_RX.8.Priority=DMA_PRIORITY_MEDIUM +Dma.USART1_RX.8.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART1_TX.6.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART1_TX.6.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_TX.6.Instance=DMA2_Stream7 +Dma.USART1_TX.6.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_TX.6.MemInc=DMA_MINC_ENABLE +Dma.USART1_TX.6.Mode=DMA_NORMAL +Dma.USART1_TX.6.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_TX.6.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_TX.6.Priority=DMA_PRIORITY_MEDIUM +Dma.USART1_TX.6.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART3_RX.3.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART3_RX.3.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART3_RX.3.Instance=DMA1_Stream1 +Dma.USART3_RX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART3_RX.3.MemInc=DMA_MINC_ENABLE +Dma.USART3_RX.3.Mode=DMA_NORMAL +Dma.USART3_RX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART3_RX.3.PeriphInc=DMA_PINC_DISABLE +Dma.USART3_RX.3.Priority=DMA_PRIORITY_HIGH +Dma.USART3_RX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART6_RX.4.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART6_RX.4.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART6_RX.4.Instance=DMA2_Stream1 +Dma.USART6_RX.4.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART6_RX.4.MemInc=DMA_MINC_ENABLE +Dma.USART6_RX.4.Mode=DMA_NORMAL +Dma.USART6_RX.4.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART6_RX.4.PeriphInc=DMA_PINC_DISABLE +Dma.USART6_RX.4.Priority=DMA_PRIORITY_MEDIUM +Dma.USART6_RX.4.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART6_TX.5.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART6_TX.5.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART6_TX.5.Instance=DMA2_Stream6 +Dma.USART6_TX.5.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART6_TX.5.MemInc=DMA_MINC_ENABLE +Dma.USART6_TX.5.Mode=DMA_NORMAL +Dma.USART6_TX.5.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART6_TX.5.PeriphInc=DMA_PINC_DISABLE +Dma.USART6_TX.5.Priority=DMA_PRIORITY_MEDIUM +Dma.USART6_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +FREERTOS.FootprintOK=true +FREERTOS.INCLUDE_pcTaskGetTaskName=1 +FREERTOS.INCLUDE_uxTaskGetStackHighWaterMark2=1 +FREERTOS.INCLUDE_vTaskCleanUpResources=1 +FREERTOS.INCLUDE_xEventGroupSetBitFromISR=1 +FREERTOS.INCLUDE_xSemaphoreGetMutexHolder=1 +FREERTOS.INCLUDE_xTaskAbortDelay=1 +FREERTOS.INCLUDE_xTaskGetCurrentTaskHandle=1 +FREERTOS.INCLUDE_xTaskGetHandle=1 +FREERTOS.IPParameters=Tasks01,FootprintOK,configENABLE_FPU,configENABLE_BACKWARD_COMPATIBILITY,configRECORD_STACK_HIGH_ADDRESS,configCHECK_FOR_STACK_OVERFLOW,configGENERATE_RUN_TIME_STATS,configUSE_STATS_FORMATTING_FUNCTIONS,configTOTAL_HEAP_SIZE,INCLUDE_xTaskGetCurrentTaskHandle,INCLUDE_xTaskGetHandle,INCLUDE_uxTaskGetStackHighWaterMark2,INCLUDE_xEventGroupSetBitFromISR,INCLUDE_xTaskAbortDelay,INCLUDE_pcTaskGetTaskName,INCLUDE_xSemaphoreGetMutexHolder,INCLUDE_vTaskCleanUpResources,configUSE_APPLICATION_TASK_TAG +FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL +FREERTOS.configCHECK_FOR_STACK_OVERFLOW=2 +FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=0 +FREERTOS.configENABLE_FPU=1 +FREERTOS.configGENERATE_RUN_TIME_STATS=1 +FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1 +FREERTOS.configTOTAL_HEAP_SIZE=0x10000 +FREERTOS.configUSE_APPLICATION_TASK_TAG=0 +FREERTOS.configUSE_STATS_FORMATTING_FUNCTIONS=1 +File.Version=6 +GPIO.groupedBy=Group By Peripherals +I2C1.I2C_Mode=I2C_Fast +I2C1.IPParameters=I2C_Mode +I2C2.I2C_Mode=I2C_Fast +I2C2.IPParameters=I2C_Mode +I2C3.I2C_Mode=I2C_Fast +I2C3.IPParameters=I2C_Mode +KeepUserPlacement=false +Mcu.CPN=STM32F407IGH6 +Mcu.Family=STM32F4 +Mcu.IP0=ADC1 +Mcu.IP1=ADC3 +Mcu.IP10=NVIC +Mcu.IP11=RCC +Mcu.IP12=RNG +Mcu.IP13=SPI1 +Mcu.IP14=SPI2 +Mcu.IP15=SYS +Mcu.IP16=TIM1 +Mcu.IP17=TIM3 +Mcu.IP18=TIM4 +Mcu.IP19=TIM5 +Mcu.IP2=CAN1 +Mcu.IP20=TIM7 +Mcu.IP21=TIM8 +Mcu.IP22=TIM10 +Mcu.IP23=USART1 +Mcu.IP24=USART3 +Mcu.IP25=USART6 +Mcu.IP26=USB_DEVICE +Mcu.IP27=USB_OTG_FS +Mcu.IP3=CAN2 +Mcu.IP4=CRC +Mcu.IP5=DMA +Mcu.IP6=FREERTOS +Mcu.IP7=I2C1 +Mcu.IP8=I2C2 +Mcu.IP9=I2C3 +Mcu.IPNb=28 +Mcu.Name=STM32F407I(E-G)Hx +Mcu.Package=UFBGA176 +Mcu.Pin0=PB8 +Mcu.Pin1=PB5 +Mcu.Pin10=PD0 +Mcu.Pin11=PC11 +Mcu.Pin12=PC10 +Mcu.Pin13=PA12 +Mcu.Pin14=PI6 +Mcu.Pin15=PG9 +Mcu.Pin16=PD1 +Mcu.Pin17=PA11 +Mcu.Pin18=PF0 +Mcu.Pin19=PA9 +Mcu.Pin2=PG14 +Mcu.Pin20=PC9 +Mcu.Pin21=PA8 +Mcu.Pin22=PH0-OSC_IN +Mcu.Pin23=PC8 +Mcu.Pin24=PH1-OSC_OUT +Mcu.Pin25=PF1 +Mcu.Pin26=PC6 +Mcu.Pin27=PG6 +Mcu.Pin28=PF6 +Mcu.Pin29=PH12 +Mcu.Pin3=PB4 +Mcu.Pin30=PG3 +Mcu.Pin31=PF10 +Mcu.Pin32=PH11 +Mcu.Pin33=PH10 +Mcu.Pin34=PC0 +Mcu.Pin35=PC1 +Mcu.Pin36=PC2 +Mcu.Pin37=PD14 +Mcu.Pin38=PA0-WKUP +Mcu.Pin39=PA4 +Mcu.Pin4=PB3 +Mcu.Pin40=PC4 +Mcu.Pin41=PE13 +Mcu.Pin42=PC5 +Mcu.Pin43=PE9 +Mcu.Pin44=PE11 +Mcu.Pin45=PE14 +Mcu.Pin46=PB12 +Mcu.Pin47=PB13 +Mcu.Pin48=PA7 +Mcu.Pin49=PB0 +Mcu.Pin5=PA14 +Mcu.Pin50=PB14 +Mcu.Pin51=PB15 +Mcu.Pin52=VP_ADC1_TempSens_Input +Mcu.Pin53=VP_ADC1_Vref_Input +Mcu.Pin54=VP_CRC_VS_CRC +Mcu.Pin55=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin56=VP_RNG_VS_RNG +Mcu.Pin57=VP_SYS_VS_Systick +Mcu.Pin58=VP_TIM1_VS_ClockSourceINT +Mcu.Pin59=VP_TIM3_VS_ClockSourceINT +Mcu.Pin6=PA13 +Mcu.Pin60=VP_TIM4_VS_ClockSourceINT +Mcu.Pin61=VP_TIM5_VS_ClockSourceINT +Mcu.Pin62=VP_TIM7_VS_ClockSourceINT +Mcu.Pin63=VP_TIM8_VS_ClockSourceINT +Mcu.Pin64=VP_TIM10_VS_ClockSourceINT +Mcu.Pin65=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS +Mcu.Pin7=PB9 +Mcu.Pin8=PB7 +Mcu.Pin9=PB6 +Mcu.PinsNb=66 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32F407IGHx +MxCube.Version=6.15.0 +MxDb.Version=DB.6.0.150 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.CAN1_RX0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.CAN1_RX1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.CAN1_TX_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.CAN2_RX0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.CAN2_RX1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.CAN2_TX_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.DMA1_Stream1_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Stream7_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream1_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream2_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream3_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream5_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream6_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DMA2_Stream7_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.EXTI0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.EXTI3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.EXTI4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +NVIC.OTG_FS_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false +NVIC.SavedPendsvIrqHandlerGenerated=true +NVIC.SavedSvcallIrqHandlerGenerated=true +NVIC.SavedSystickIrqHandlerGenerated=true +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:false\:true\:false +NVIC.TIM1_BRK_TIM9_IRQn=true\:5\:0\:false\:false\:true\:false\:false\:true\:true +NVIC.TIM7_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.USART1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.USART6_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.UsageFault_IRQn=true\:0\:0\:true\:false\:true\:false\:false\:false\:false +PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PA0-WKUP.GPIO_Label=USER_KEY +PA0-WKUP.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PA0-WKUP.GPIO_PuPd=GPIO_PULLUP +PA0-WKUP.Locked=true +PA0-WKUP.Signal=GPXTI0 +PA11.Mode=Device_Only +PA11.Signal=USB_OTG_FS_DM +PA12.Mode=Device_Only +PA12.Signal=USB_OTG_FS_DP +PA13.Mode=Serial_Wire +PA13.Signal=SYS_JTMS-SWDIO +PA14.Mode=Serial_Wire +PA14.Signal=SYS_JTCK-SWCLK +PA4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PA4.GPIO_Label=ACCL_CS +PA4.GPIO_PuPd=GPIO_PULLUP +PA4.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM +PA4.Locked=true +PA4.PinState=GPIO_PIN_SET +PA4.Signal=GPIO_Output +PA7.GPIOParameters=GPIO_PuPd +PA7.GPIO_PuPd=GPIO_PULLUP +PA7.Locked=true +PA7.Mode=Full_Duplex_Master +PA7.Signal=SPI1_MOSI +PA8.GPIOParameters=GPIO_Pu +PA8.GPIO_Pu=GPIO_PULLUP +PA8.Locked=true +PA8.Mode=I2C +PA8.Signal=I2C3_SCL +PA9.Locked=true +PA9.Mode=Asynchronous +PA9.Signal=USART1_TX +PB0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PB0.GPIO_Label=GYRO_CS +PB0.GPIO_PuPd=GPIO_PULLUP +PB0.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM +PB0.Locked=true +PB0.PinState=GPIO_PIN_SET +PB0.Signal=GPIO_Output +PB12.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PB12.GPIO_Label=SPI2_CS +PB12.GPIO_PuPd=GPIO_PULLUP +PB12.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM +PB12.Locked=true +PB12.PinState=GPIO_PIN_SET +PB12.Signal=GPIO_Output +PB13.GPIOParameters=GPIO_PuPd +PB13.GPIO_PuPd=GPIO_PULLUP +PB13.Locked=true +PB13.Mode=Full_Duplex_Master +PB13.Signal=SPI2_SCK +PB14.GPIOParameters=GPIO_PuPd +PB14.GPIO_PuPd=GPIO_PULLUP +PB14.Locked=true +PB14.Mode=Full_Duplex_Master +PB14.Signal=SPI2_MISO +PB15.GPIOParameters=GPIO_PuPd +PB15.GPIO_PuPd=GPIO_PULLUP +PB15.Locked=true +PB15.Mode=Full_Duplex_Master +PB15.Signal=SPI2_MOSI +PB3.GPIOParameters=GPIO_PuPd +PB3.GPIO_PuPd=GPIO_PULLUP +PB3.Locked=true +PB3.Mode=Full_Duplex_Master +PB3.Signal=SPI1_SCK +PB4.GPIOParameters=GPIO_PuPd +PB4.GPIO_PuPd=GPIO_PULLUP +PB4.Locked=true +PB4.Mode=Full_Duplex_Master +PB4.Signal=SPI1_MISO +PB5.Locked=true +PB5.Mode=CAN_Activate +PB5.Signal=CAN2_RX +PB6.Locked=true +PB6.Mode=CAN_Activate +PB6.Signal=CAN2_TX +PB7.Locked=true +PB7.Mode=Asynchronous +PB7.Signal=USART1_RX +PB8.GPIOParameters=GPIO_Pu +PB8.GPIO_Pu=GPIO_PULLUP +PB8.Locked=true +PB8.Mode=I2C +PB8.Signal=I2C1_SCL +PB9.GPIOParameters=GPIO_Pu +PB9.GPIO_Pu=GPIO_PULLUP +PB9.Locked=true +PB9.Mode=I2C +PB9.Signal=I2C1_SDA +PC0.GPIOParameters=GPIO_Label +PC0.GPIO_Label=HW0 +PC0.Locked=true +PC0.Signal=GPIO_Input +PC1.GPIOParameters=GPIO_Label +PC1.GPIO_Label=HW1 +PC1.Locked=true +PC1.Signal=GPIO_Input +PC10.Locked=true +PC10.Mode=Asynchronous +PC10.Signal=USART3_TX +PC11.Locked=true +PC11.Mode=Asynchronous +PC11.Signal=USART3_RX +PC2.GPIOParameters=GPIO_Label +PC2.GPIO_Label=HW2 +PC2.Locked=true +PC2.Signal=GPIO_Input +PC4.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PC4.GPIO_Label=ACCL_INT +PC4.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PC4.GPIO_PuPd=GPIO_PULLUP +PC4.Locked=true +PC4.Signal=GPXTI4 +PC5.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PC5.GPIO_Label=GYRO_INT +PC5.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PC5.GPIO_PuPd=GPIO_PULLUP +PC5.Locked=true +PC5.Signal=GPXTI5 +PC6.GPIOParameters=GPIO_Speed,GPIO_PuPd +PC6.GPIO_PuPd=GPIO_PULLUP +PC6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PC6.Locked=true +PC6.Signal=S_TIM8_CH1 +PC8.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PC8.GPIO_Label=LASER +PC8.GPIO_PuPd=GPIO_PULLUP +PC8.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PC8.Locked=true +PC8.Signal=S_TIM3_CH3 +PC9.GPIOParameters=GPIO_Pu +PC9.GPIO_Pu=GPIO_PULLUP +PC9.Locked=true +PC9.Mode=I2C +PC9.Signal=I2C3_SDA +PD0.Locked=true +PD0.Mode=CAN_Activate +PD0.Signal=CAN1_RX +PD1.Locked=true +PD1.Mode=CAN_Activate +PD1.Signal=CAN1_TX +PD14.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PD14.GPIO_Label=BUZZER +PD14.GPIO_PuPd=GPIO_PULLUP +PD14.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PD14.Locked=true +PD14.Signal=S_TIM4_CH3 +PE11.GPIOParameters=GPIO_Speed,GPIO_PuPd +PE11.GPIO_PuPd=GPIO_PULLUP +PE11.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PE11.Locked=true +PE11.Signal=S_TIM1_CH2 +PE13.GPIOParameters=GPIO_Speed,GPIO_PuPd +PE13.GPIO_PuPd=GPIO_PULLUP +PE13.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PE13.Locked=true +PE13.Signal=S_TIM1_CH3 +PE14.GPIOParameters=GPIO_Speed,GPIO_PuPd +PE14.GPIO_PuPd=GPIO_PULLUP +PE14.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PE14.Locked=true +PE14.Signal=S_TIM1_CH4 +PE9.GPIOParameters=GPIO_Speed,GPIO_PuPd +PE9.GPIO_PuPd=GPIO_PULLUP +PE9.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PE9.Locked=true +PE9.Signal=S_TIM1_CH1 +PF0.GPIOParameters=GPIO_Pu +PF0.GPIO_Pu=GPIO_PULLUP +PF0.Locked=true +PF0.Mode=I2C +PF0.Signal=I2C2_SDA +PF1.GPIOParameters=GPIO_Pu +PF1.GPIO_Pu=GPIO_PULLUP +PF1.Locked=true +PF1.Mode=I2C +PF1.Signal=I2C2_SCL +PF10.GPIOParameters=GPIO_Label +PF10.GPIO_Label=ADC_BAT +PF10.Locked=true +PF10.Mode=IN8 +PF10.Signal=ADC3_IN8 +PF6.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PF6.GPIO_Label=IMU_HEAT_PWM +PF6.GPIO_PuPd=GPIO_PULLDOWN +PF6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PF6.Locked=true +PF6.Signal=S_TIM10_CH1 +PG14.Locked=true +PG14.Mode=Asynchronous +PG14.Signal=USART6_TX +PG3.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PG3.GPIO_Label=CMPS_INT +PG3.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PG3.GPIO_PuPd=GPIO_PULLUP +PG3.Locked=true +PG3.Signal=GPXTI3 +PG6.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PG6.GPIO_Label=CMPS_RST +PG6.GPIO_PuPd=GPIO_PULLUP +PG6.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM +PG6.Locked=true +PG6.PinState=GPIO_PIN_RESET +PG6.Signal=GPIO_Output +PG9.Locked=true +PG9.Mode=Asynchronous +PG9.Signal=USART6_RX +PH0-OSC_IN.Mode=HSE-External-Oscillator +PH0-OSC_IN.Signal=RCC_OSC_IN +PH1-OSC_OUT.Mode=HSE-External-Oscillator +PH1-OSC_OUT.Signal=RCC_OSC_OUT +PH10.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PH10.GPIO_Label=LED_B +PH10.GPIO_PuPd=GPIO_PULLUP +PH10.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PH10.Locked=true +PH10.Signal=S_TIM5_CH1 +PH11.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PH11.GPIO_Label=LED_G +PH11.GPIO_PuPd=GPIO_PULLUP +PH11.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PH11.Locked=true +PH11.Signal=S_TIM5_CH2 +PH12.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label +PH12.GPIO_Label=LED_R +PH12.GPIO_PuPd=GPIO_PULLUP +PH12.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PH12.Locked=true +PH12.Signal=S_TIM5_CH3 +PI6.GPIOParameters=GPIO_Speed,GPIO_PuPd +PI6.GPIO_PuPd=GPIO_PULLUP +PI6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PI6.Signal=S_TIM8_CH2 +PinOutPanel.CurrentBGAView=Top +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32F407IGHx +ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=true +ProjectManager.HeapSize=0x1000 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=0 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=DevC.ioc +ProjectManager.ProjectName=DevC +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x1000 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-SystemClock_Config-RCC-false-HAL-false,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_ADC3_Init-ADC3-false-HAL-true,6-MX_CAN1_Init-CAN1-false-HAL-true,7-MX_CAN2_Init-CAN2-false-HAL-true,8-MX_I2C1_Init-I2C1-false-HAL-true,9-MX_SPI1_Init-SPI1-false-HAL-true,10-MX_TIM4_Init-TIM4-false-HAL-true,11-MX_TIM5_Init-TIM5-false-HAL-true,12-MX_USART3_UART_Init-USART3-false-HAL-true,13-MX_TIM8_Init-TIM8-false-HAL-true,14-MX_CRC_Init-CRC-false-HAL-true,15-MX_RNG_Init-RNG-false-HAL-true,16-MX_I2C2_Init-I2C2-false-HAL-true,17-MX_I2C3_Init-I2C3-false-HAL-true,18-MX_SPI2_Init-SPI2-false-HAL-true,19-MX_TIM1_Init-TIM1-false-HAL-true,20-MX_TIM3_Init-TIM3-false-HAL-true,21-MX_TIM10_Init-TIM10-false-HAL-true,22-MX_USART1_UART_Init-USART1-false-HAL-true,23-MX_USART6_UART_Init-USART6-false-HAL-true,24-MX_TIM7_Init-TIM7-false-HAL-true,25-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false +RCC.48MHZClocksFreq_Value=48000000 +RCC.AHBFreq_Value=168000000 +RCC.APB1CLKDivider=RCC_HCLK_DIV4 +RCC.APB1Freq_Value=42000000 +RCC.APB1TimFreq_Value=84000000 +RCC.APB2CLKDivider=RCC_HCLK_DIV2 +RCC.APB2Freq_Value=84000000 +RCC.APB2TimFreq_Value=168000000 +RCC.CortexFreq_Value=168000000 +RCC.EthernetFreq_Value=168000000 +RCC.FCLKCortexFreq_Value=168000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=168000000 +RCC.HSE_VALUE=12000000 +RCC.HSI_VALUE=16000000 +RCC.I2SClocksFreq_Value=192000000 +RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,RCC_RTC_Clock_Source,RCC_RTC_Clock_SourceVirtual,RCC_RTC_Clock_Source_FROM_HSE,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO2PinFreq_Value=168000000 +RCC.PLLCLKFreq_Value=168000000 +RCC.PLLM=6 +RCC.PLLN=168 +RCC.PLLQ=7 +RCC.PLLQCLKFreq_Value=48000000 +RCC.RCC_RTC_Clock_Source=RCC_RTCCLKSOURCE_LSI +RCC.RCC_RTC_Clock_SourceVirtual=RCC_RTCCLKSOURCE_HSE_DIV30 +RCC.RCC_RTC_Clock_Source_FROM_HSE=RCC_RTCCLKSOURCE_HSE_DIV30 +RCC.RTCFreq_Value=32000 +RCC.RTCHSEDivFreq_Value=400000 +RCC.SYSCLKFreq_VALUE=168000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.VCOI2SOutputFreq_Value=384000000 +RCC.VCOInputFreq_Value=2000000 +RCC.VCOOutputFreq_Value=336000000 +RCC.VcooutputI2S=192000000 +SH.GPXTI0.0=GPIO_EXTI0 +SH.GPXTI0.ConfNb=1 +SH.GPXTI3.0=GPIO_EXTI3 +SH.GPXTI3.ConfNb=1 +SH.GPXTI4.0=GPIO_EXTI4 +SH.GPXTI4.ConfNb=1 +SH.GPXTI5.0=GPIO_EXTI5 +SH.GPXTI5.ConfNb=1 +SH.S_TIM10_CH1.0=TIM10_CH1,PWM Generation1 CH1 +SH.S_TIM10_CH1.ConfNb=1 +SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 +SH.S_TIM1_CH1.ConfNb=1 +SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 +SH.S_TIM1_CH2.ConfNb=1 +SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3 +SH.S_TIM1_CH3.ConfNb=1 +SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4 +SH.S_TIM1_CH4.ConfNb=1 +SH.S_TIM3_CH3.0=TIM3_CH3,PWM Generation3 CH3 +SH.S_TIM3_CH3.ConfNb=1 +SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3 +SH.S_TIM4_CH3.ConfNb=1 +SH.S_TIM5_CH1.0=TIM5_CH1,PWM Generation1 CH1 +SH.S_TIM5_CH1.ConfNb=1 +SH.S_TIM5_CH2.0=TIM5_CH2,PWM Generation2 CH2 +SH.S_TIM5_CH2.ConfNb=1 +SH.S_TIM5_CH3.0=TIM5_CH3,PWM Generation3 CH3 +SH.S_TIM5_CH3.ConfNb=1 +SH.S_TIM8_CH1.0=TIM8_CH1,PWM Generation1 CH1 +SH.S_TIM8_CH1.ConfNb=1 +SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2 +SH.S_TIM8_CH2.ConfNb=1 +SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 +SPI1.CLKPhase=SPI_PHASE_2EDGE +SPI1.CLKPolarity=SPI_POLARITY_HIGH +SPI1.CalculateBaudRate=5.25 MBits/s +SPI1.Direction=SPI_DIRECTION_2LINES +SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPolarity,CLKPhase +SPI1.Mode=SPI_MODE_MASTER +SPI1.VirtualType=VM_MASTER +SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_64 +SPI2.CLKPhase=SPI_PHASE_1EDGE +SPI2.CLKPolarity=SPI_POLARITY_LOW +SPI2.CalculateBaudRate=656.25 KBits/s +SPI2.Direction=SPI_DIRECTION_2LINES +SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPolarity,CLKPhase +SPI2.Mode=SPI_MODE_MASTER +SPI2.VirtualType=VM_MASTER +TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 +TIM1.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Period,Prescaler,Pulse-PWM Generation1 CH1,Pulse-PWM Generation2 CH2,Pulse-PWM Generation3 CH3,Pulse-PWM Generation4 CH4 +TIM1.Period=19999 +TIM1.Prescaler=167 +TIM1.Pulse-PWM\ Generation1\ CH1=0 +TIM1.Pulse-PWM\ Generation2\ CH2=0 +TIM1.Pulse-PWM\ Generation3\ CH3=0 +TIM1.Pulse-PWM\ Generation4\ CH4=1000 +TIM10.Channel=TIM_CHANNEL_1 +TIM10.IPParameters=Channel,Period +TIM10.Period=4999 +TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM3.IPParameters=Channel-PWM Generation3 CH3,Period +TIM3.Period=65535 +TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM4.IPParameters=Channel-PWM Generation3 CH3,Prescaler,Period +TIM4.Period=65535 +TIM4.Prescaler=167 +TIM5.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM5.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM5.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM5.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Prescaler,Period +TIM5.Period=65535 +TIM5.Prescaler=0 +TIM7.IPParameters=Period,Prescaler +TIM7.Period=9 +TIM7.Prescaler=83 +TIM8.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM8.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM8.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Prescaler,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation2 CH2 +TIM8.Period=19999 +TIM8.Prescaler=167 +TIM8.Pulse-PWM\ Generation1\ CH1=1000 +TIM8.Pulse-PWM\ Generation2\ CH2=1000 +USART1.IPParameters=VirtualMode +USART1.VirtualMode=VM_ASYNC +USART3.BaudRate=100000 +USART3.IPParameters=VirtualMode,BaudRate,Parity,Mode +USART3.Mode=MODE_RX +USART3.Parity=PARITY_EVEN +USART3.VirtualMode=VM_ASYNC +USART6.IPParameters=VirtualMode +USART6.VirtualMode=VM_ASYNC +USB_DEVICE.CLASS_NAME_FS=CDC +USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS +USB_DEVICE.VirtualMode-CDC_FS=Cdc +USB_DEVICE.VirtualModeFS=Cdc_FS +USB_OTG_FS.IPParameters=VirtualMode +USB_OTG_FS.VirtualMode=Device_Only +VP_ADC1_TempSens_Input.Mode=IN-TempSens +VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input +VP_ADC1_Vref_Input.Mode=IN-Vrefint +VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input +VP_CRC_VS_CRC.Mode=CRC_Activate +VP_CRC_VS_CRC.Signal=CRC_VS_CRC +VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 +VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM10_VS_ClockSourceINT.Mode=Enable_Timer +VP_TIM10_VS_ClockSourceINT.Signal=TIM10_VS_ClockSourceINT +VP_TIM1_VS_ClockSourceINT.Mode=Internal +VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT +VP_TIM3_VS_ClockSourceINT.Mode=Internal +VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT +VP_TIM4_VS_ClockSourceINT.Mode=Internal +VP_TIM4_VS_ClockSourceINT.Signal=TIM4_VS_ClockSourceINT +VP_TIM5_VS_ClockSourceINT.Mode=Internal +VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT +VP_TIM7_VS_ClockSourceINT.Mode=Enable_Timer +VP_TIM7_VS_ClockSourceINT.Signal=TIM7_VS_ClockSourceINT +VP_TIM8_VS_ClockSourceINT.Mode=Internal +VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT +VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS +VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS +board=custom +rtos.0.ip=FREERTOS diff --git a/task/template_task/atti_esti.c b/task/template_task/atti_esti.c new file mode 100644 index 0000000..31736eb --- /dev/null +++ b/task/template_task/atti_esti.c @@ -0,0 +1,96 @@ +/* + atti_esti Task + 带有pwm温控的纯陀螺仪(BMI088)姿态解算任务(无磁力计,赛场环境一般不适用)。 + 控制IMU加热到指定温度防止温漂,收集IMU数据给AHRS算法。 + 收集BMI088的数据,解算后得到四元数,转换为欧拉角之后放到消息队列中, + 等待其他任务取用。 + 陀螺仪使用前需要校准,校准结果保存在bmi088_cali结构体中,需要自行实现。 +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "task/user_task.h" +/* USER INCLUDE BEGIN */ + +#include "bsp/mm.h" +#include "bsp/pwm.h" +#include "component/ahrs.h" +#include "component/pid.h" +#include "device/bmi088.h" +/* USER INCLUDE END */ + +/* Private typedef ---------------------------------------------------------- */ +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private variables -------------------------------------------------------- */ +/* USER STRUCT BEGIN */ +BMI088_t bmi088; +AHRS_t gimbal_ahrs; +AHRS_Magn_t magn; +AHRS_Eulr_t eulr_to_send; +KPID_t imu_temp_ctrl_pid; + +/*默认校准参数*/ +BMI088_Cali_t cali_bmi088 = { + .gyro_offset = {0.0f, 0.0f, 0.0f}, +}; + +static const KPID_Params_t imu_temp_ctrl_pid_param = { + .k = 0.15f, + .p = 1.0f, + .i = 0.0f, + .d = 0.0f, + .i_limit = 1.0f, + .out_limit = 1.0f, +}; + +/* USER STRUCT END */ + +/* Private function --------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ +void Task_atti_esti(void *argument) { + (void)argument; /* 未使用argument,消除警告 */ + + + osDelay(ATTI_ESTI_INIT_DELAY); /* 延时一段时间再开启任务 */ + + /* USER CODE INIT BEGIN */ + BMI088_Init(&bmi088, &cali_bmi088); + AHRS_Init(&gimbal_ahrs, &magn, BMI088_GetUpdateFreq(&bmi088)); + PID_Init(&imu_temp_ctrl_pid, KPID_MODE_NO_D, + 1.0f / BMI088_GetUpdateFreq(&bmi088), &imu_temp_ctrl_pid_param); + BSP_PWM_Start(BSP_PWM_IMU_HEAT); + + /* USER CODE INIT END */ + + while (1) { + /* USER CODE BEGIN */ + BMI088_WaitNew(); + BMI088_AcclStartDmaRecv(); + BMI088_AcclWaitDmaCplt(); + + BMI088_GyroStartDmaRecv(); + BMI088_GyroWaitDmaCplt(); + + /* 锁住RTOS内核防止数据解析过程中断,造成错误 */ + osKernelLock(); + /* 接收完所有数据后,把数据从原始字节加工成方便计算的数据 */ + BMI088_ParseAccl(&bmi088); + BMI088_ParseGyro(&bmi088); + + /* 根据设备接收到的数据进行姿态解析 */ + AHRS_Update(&gimbal_ahrs, &bmi088.accl, &bmi088.gyro, &magn); + + /* 根据解析出来的四元数计算欧拉角 */ + AHRS_GetEulr(&eulr_to_send, &gimbal_ahrs); + osKernelUnlock(); + + /* 在此处用消息队列传递imu数据 */ + /* osMessageQueuePut( ... ); */ + + /* 控制IMU加热器 */ + BSP_PWM_SetComp(BSP_PWM_IMU_HEAT, PID_Calc(&imu_temp_ctrl_pid, 40.5f, + bmi088.temp, 0.0f, 0.0f)); + /* USER CODE END */ + } + +} \ No newline at end of file diff --git a/task/template_task/task.yaml b/task/template_task/task.yaml new file mode 100644 index 0000000..5a6d279 --- /dev/null +++ b/task/template_task/task.yaml @@ -0,0 +1,18 @@ +atti_esti: + name: "atti_esti" + frequency: 1000 + delay: 100 + stack: 512 + freq_control: false + description: | + 带有PWM温控的纯陀螺仪(BMI088)姿态解算任务 + 功能特点: + - 控制IMU加热到指定温度防止温漂 + - 收集BMI088数据给AHRS算法进行姿态解算 + - 解算后得到四元数,转换为欧拉角放到消息队列 + - 使用PID控制IMU温度到40.5°C + - 运行频率1000Hz,提供高精度姿态信息 + 注意事项: + - 陀螺仪使用前需要校准,校准结果保存在bmi088_cali结构体中 + - 无磁力计版本,适用于干净的电磁环境 + - 需要配置PWM通道用于IMU加热控制