From d6cf143e87f4ea7524a7b1f994aa6f858b8e6448 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Wed, 17 Dec 2025 02:34:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(flash):=20=E4=BF=AE=E6=94=B9=E8=A7=92?= =?UTF-8?q?=E5=BA=A6=E5=AD=98=E5=82=A8=E7=B1=BB=E5=9E=8B=E4=B8=BAfloat?= =?UTF-8?q?=E5=B9=B6=E6=9B=B4=E6=96=B0=E8=AF=BB=E5=86=99=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将FlashEEPROM中角度数据的存储类型从u16改为float,并相应地更新了读写函数。 新增readFloat和writeFloat函数以支持浮点数存储,同时调整了虚拟地址类型为u8。 修改了save_angle和read_angle函数实现,确保角度值能正确保存与读取。 优化了格式化函数中的数据解析方式,提高数据存储可靠性。 --- Robot_V2/device/Can.cpp | 2 +- Robot_V2/sys/flash.cpp | 182 ++++++++++++++++++++++++++++++---------- Robot_V2/sys/flash.h | 54 ++++++------ 3 files changed, 169 insertions(+), 69 deletions(-) diff --git a/Robot_V2/device/Can.cpp b/Robot_V2/device/Can.cpp index 82859ea..7fcf9a7 100644 --- a/Robot_V2/device/Can.cpp +++ b/Robot_V2/device/Can.cpp @@ -696,7 +696,7 @@ void CAN_transmiter::communication_check() { FOC.target_velocity = target_velocity_union.f; } else if (receive_message.rx_efid == 0x00010301) { motor_reset(); - flashEEP.save_angle((u16)FOC.rt_angle, false); + flashEEP.save_angle(FOC.rt_angle, false); } else { printf("Unknown CAN ID: %X\n", receive_message.rx_efid); } diff --git a/Robot_V2/sys/flash.cpp b/Robot_V2/sys/flash.cpp index ea93778..f5ab6c2 100644 --- a/Robot_V2/sys/flash.cpp +++ b/Robot_V2/sys/flash.cpp @@ -2,8 +2,10 @@ #include "ang_sensor.h" #include "core_cmFunc.h" #include "gd32c10x_fmc.h" +#include "math.h" #include #include +#include #include FlashEEPROM flashEEP = FlashEEPROM(); @@ -23,15 +25,15 @@ FlashEEPROM::FlashEEPROM() { */ u8 FlashEEPROM::init() { // 读取保存的参数 - u16 angle; + float angle; // 尝试从Flash读取参数,如果不存在则使用默认值 - if (read(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) { + if (readFloat(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) { angle = 0; // 默认值 - std::printf("角度初始化为: %d\r\n", angle); + std::printf("角度初始化为: %f\r\n", angle); } else { - std::printf("从Flash读取到角度数: %d\r\n", angle); + std::printf("从Flash读取到角度数: %f\r\n", angle); } - KTH7823.angle_set((float)angle); + KTH7823.angle_set(angle); return 0; } @@ -41,9 +43,9 @@ u8 FlashEEPROM::init() { * @param data: 指向存储读取数据的指针 * @retval FlashEepromStatus: 操作状态 */ -FlashEepromStatus FlashEEPROM::read(u16 virtualAddr, u16 *data) const { - // 检查参数有效性 - if (data == nullptr || virtualAddr > 0xFFFE) { +FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const { + // 参数检查 + if (data == nullptr or virtualAddr > 0xFE) { return FLASH_EEPROM_INVALID_ADDR; } @@ -53,7 +55,7 @@ FlashEepromStatus FlashEEPROM::read(u16 virtualAddr, u16 *data) const { u32 data_word = *((u32 *)address); // 检查是否是有效数据(非擦除状态) if (data_word != 0xFFFFFFFF) { - u16 addr = (u16)(data_word & 0xFFFF); + u8 addr = (u8)(data_word & 0xFF); // 找到匹配的虚拟地址 if (addr == virtualAddr) { *data = (u16)((data_word >> 16) & 0xFFFF); @@ -65,15 +67,45 @@ FlashEepromStatus FlashEEPROM::read(u16 virtualAddr, u16 *data) const { return FLASH_EEPROM_NOT_FOUND; } +/** + * @brief 从Flash EEPROM读取float数据 + * @param virtualAddr: 虚拟地址 + * @param data: 指向存储读取数据的指针 + * @retval FlashEepromStatus: 操作状态 + */ +FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const { + // 参数检查 + if (data == nullptr or virtualAddr > 0xFE) { + return FLASH_EEPROM_INVALID_ADDR; + } + // 从Flash末尾开始向前搜索,找到最新的数据 + for (u32 address = EEPROM_END_ADDRESS - SIZE_U32; + address >= EEPROM_START_ADDRESS; address -= SIZE_U32) { + u32 data_word = *((u32 *)address); + // 检查是否是有效数据(非擦除状态) + if (data_word != 0xFFFFFFFF) { + u8 addr = (u8)(data_word & 0xFF); + // 找到匹配的虚拟地址 + if (addr == virtualAddr) { + // 使用完整32位数据解释为float + memcpy(data, &data_word, sizeof(float)); + return FLASH_EEPROM_OK; + } + } + } + // 未找到指定虚拟地址的数据 + return FLASH_EEPROM_NOT_FOUND; +} + /** * @brief 向Flash EEPROM写入数据 * @param virtualAddr: 虚拟地址 * @param data: 要写入的数据 * @retval FlashEepromStatus: 操作状态 */ -FlashEepromStatus FlashEEPROM::write(u16 virtualAddr, u16 data) { +FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) { // 参数检查 - if (virtualAddr > 0xFFFE) { + if (virtualAddr > 0xFE) { return FLASH_EEPROM_INVALID_ADDR; } // 查找下一个可写入的位置 @@ -97,6 +129,7 @@ FlashEepromStatus FlashEEPROM::write(u16 virtualAddr, u16 data) { // 如果有足够空间,直接写入 if (next_address < EEPROM_END_ADDRESS) { + // 新格式: [addr:8bit][reserved:8bit][data:16bit] u32 data_word = ((u32)data << 16) | (u32)virtualAddr; // 使用GD32库函数进行安全编程 @@ -119,7 +152,8 @@ FlashEepromStatus FlashEEPROM::write(u16 virtualAddr, u16 data) { } // 格式化后在页面开头写入数据 - u32 new_data_word = ((u32)data << 16) | (virtualAddr & 0xFFFF); + // 新格式: [addr:8bit][reserved:8bit][data:16bit] + u32 new_data_word = ((u32)data << 16) | (u32)virtualAddr; fmc_state_enum fmc_status = fmc_word_program(EEPROM_START_ADDRESS, new_data_word); @@ -131,6 +165,84 @@ FlashEepromStatus FlashEEPROM::write(u16 virtualAddr, u16 data) { } } +/** + * @brief 向Flash EEPROM写入float数据 + * @param virtualAddr: 虚拟地址 + * @param data: 要写入的数据 + * @retval FlashEepromStatus: 操作状态 + */ +FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) { + // 参数检查 + if (virtualAddr > 0xFE) { + return FLASH_EEPROM_INVALID_ADDR; + } + // 查找下一个可写入的位置 + u32 next_address = EEPROM_START_ADDRESS; + + // 遍历Flash页面寻找下一个可写入位置 + for (u32 address = EEPROM_START_ADDRESS; address < EEPROM_END_ADDRESS; + address += SIZE_U32) { + + // 安全读取Flash数据 + volatile u32 *flash_ptr = (volatile u32 *)address; + u32 data_word = *flash_ptr; + // 找到空位置 + if (data_word == 0xFFFFFFFF) { + next_address = address; + break; + } + // 更新下一个可能的写入位置(如果需要格式化) + next_address = address + SIZE_U32; + } + + // 如果有足够空间,直接写入 + if (next_address < EEPROM_END_ADDRESS) { + u32 float_bits; + + u32 data_word; + // 将完整的float数据复制到32位变量中 + memcpy(&data_word, &data, sizeof(float)); + // 插入虚拟地址到低8位 + data_word = (data_word & 0xFFFFFF00) | (u32)virtualAddr; + + // 使用GD32库函数进行安全编程 + fmc_unlock(); + fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR); + + // 确保使用对齐地址 + fmc_state_enum fmc_status = fmc_word_program(next_address, data_word); + + fmc_lock(); + if (fmc_status != FMC_READY) { + return FLASH_EEPROM_WRITE_ERROR; + } + return FLASH_EEPROM_OK; + } else { + // 空间不足,需要格式化页面 + FlashEepromStatus status = format(); + if (status != FLASH_EEPROM_OK) { + return status; + } + + // 格式化后在页面开头写入数据 + u32 float_bits; + + u32 data_word; + // 将完整的float数据复制到32位变量中 + memcpy(&data_word, &data, sizeof(float)); + // 插入虚拟地址到低8位 + data_word = (data_word & 0xFFFFFF00) | (u32)virtualAddr; + + fmc_state_enum fmc_status = + fmc_word_program(EEPROM_START_ADDRESS, data_word); + + if (fmc_status != FMC_READY) { + return FLASH_EEPROM_WRITE_ERROR; + } + return FLASH_EEPROM_OK; + } +} + /** * @brief 格式化Flash EEPROM页面 * @param None @@ -150,24 +262,25 @@ FlashEepromStatus FlashEEPROM::format() { // 检查是否是有效数据项 if (data_word != 0xFFFFFFFF) { - u16 addr = (u16)(data_word & 0xFFFF); - u16 value = (u16)((data_word >> 16) & 0xFFFF); + u8 addr = (u8)(data_word & 0xFF); + u32 value = (data_word & 0xFFFFFF00); // 保留高24位 // 查找是否已经有相同虚拟地址的数据项 uint8_t found = 0; for (u16 i = 0; i < valid_count; i++) { - u16 existing_addr = (u16)(valid_entries[i] & 0xFFFF); + u8 existing_addr = (u8)(valid_entries[i] & 0xFF); if (existing_addr == addr) { // 更新为最新的数据 - valid_entries[i] = ((u32)value << 16) | addr; + valid_entries[i] = value | addr; found = 1; break; } } - // 如果是新的虚拟地址,添加到有效数据列表 + // 如果是新的虚拟地址/类型组合,添加到有效数据列表 if (!found && valid_count < (EEPROM_MAX_SIZE / SIZE_U32)) { - valid_entries[valid_count] = ((u32)value << 16) | addr; + valid_entries[valid_count] = + ((u32)value << 16) | ((u32)value << 8) | addr; valid_count++; } } @@ -191,17 +304,6 @@ FlashEepromStatus FlashEEPROM::format() { return FLASH_EEPROM_OK; } -/** - * @brief 更新参数并保存到Flash - * @param kp 新的KP值 - * @param ki 新的KI值 - * @param kd 新的KD值 - */ -void FlashEEPROM::update_pid_parameters(u16 kp, u16 ki, u16 kd) { - write(ADDR_MOTOR_KP, kp); - write(ADDR_MOTOR_KI, ki); - write(ADDR_MOTOR_KD, kd); -} /** * @brief 更新系统配置并保存到Flash @@ -216,25 +318,26 @@ void FlashEEPROM::update_system_config(u16 config) { * @param angle 角度数据 * @return FlashEepromStatus: 操作状态 */ -FlashEepromStatus FlashEEPROM::save_angle(u16 angle, bool saved) { - u16 angle_read = 0; +FlashEepromStatus FlashEEPROM::save_angle(float angle, bool saved) { + float angle_read = 0; FlashEepromStatus status = FLASH_EEPROM_ERROR; // 读取保存的参数 if (!angle_saved) { // 写入参数 - status = write(ADDR_ANGLE_DATA, angle); + status = writeFloat(ADDR_ANGLE_DATA, angle); - if (read(ADDR_ANGLE_DATA, &angle_read) != FLASH_EEPROM_OK) + if (readFloat(ADDR_ANGLE_DATA, &angle_read) != FLASH_EEPROM_OK) angle_read = 0; // 读不到角度值,存储失败 - if (angle_read != angle) { + if (fabsf(angle_read - angle) > 0.01 * angle) { status = FLASH_EEPROM_WRITE_ERROR; CAN0_transmiter.EEPROMStatus = 1; // 设置EEPROM错误状态 } else { angle_saved = saved; // 标记已保存过 CAN0_transmiter.EEPROMStatus = 0; // 设置EEPROM状态 } + printf("read:%f\r\n", angle_read); } return status; } @@ -244,11 +347,11 @@ FlashEepromStatus FlashEEPROM::save_angle(u16 angle, bool saved) { * @return float: 角度数据 */ float FlashEEPROM::read_angle() { - u16 angle = 0; - if (read(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) { + float angle = 0; + if (readFloat(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) { angle = 0; } - return (float)angle; // 默认返回0度 + return angle; // 默认返回0度 } /** @@ -277,11 +380,6 @@ void flash_eeprom_example_main(void) { // 初始化Flash EEPROM flashEEP.init(); - - // 模拟参数更新 - std::printf("\r\n--- 更新PID参数 ---\r\n"); - flashEEP.update_pid_parameters(120, 80, 30); - // 模拟系统配置更新 std::printf("\r\n--- 更新系统配置 ---\r\n"); flashEEP.update_system_config(0x03); diff --git a/Robot_V2/sys/flash.h b/Robot_V2/sys/flash.h index 7e6025c..4029b15 100644 --- a/Robot_V2/sys/flash.h +++ b/Robot_V2/sys/flash.h @@ -5,59 +5,61 @@ #include #include // 修改后 - 强制4字节对齐 -#define ALIGN_4BYTE(addr) ((addr) & 0xFFFFFFFC) // 4字节对齐 +#define ALIGN_4BYTE(addr) ((addr) & 0xFFFFFFFC) // 4字节对齐 // EEPROM操作状态 typedef enum { - FLASH_EEPROM_OK = 0, // 操作成功 - FLASH_EEPROM_ERROR, // 操作失败 - FLASH_EEPROM_NOT_FOUND, // 未找到指定数据 - FLASH_EEPROM_INVALID_ADDR, // 无效地址 - FLASH_EEPROM_WRITE_ERROR, // 写入错误 - FLASH_EEPROM_ERASE_ERROR, // 擦除错误 - FLASH_EEPROM_ALIGNMENT_ERROR,// 对齐错误 + FLASH_EEPROM_OK = 0, // 操作成功 + FLASH_EEPROM_ERROR, // 操作失败 + FLASH_EEPROM_NOT_FOUND, // 未找到指定数据 + FLASH_EEPROM_INVALID_ADDR, // 无效地址 + FLASH_EEPROM_WRITE_ERROR, // 写入错误 + FLASH_EEPROM_ERASE_ERROR, // 擦除错误 + FLASH_EEPROM_ALIGNMENT_ERROR, // 对齐错误 } FlashEepromStatus; // Flash EEPROM类 class FlashEEPROM { public: // EEPROM emulation constants - static constexpr uint32_t EEPROM_START_ADDRESS = + static constexpr u32 EEPROM_START_ADDRESS = 0x0801F800; // Flash最后一页(2KB) - static constexpr uint32_t EEPROM_END_ADDRESS = 0x08020000; // Flash结束地址 - static constexpr uint32_t EEPROM_PAGE_SIZE = 0x800; // 页大小2KB - static constexpr uint32_t EEPROM_MAX_SIZE = 0x800; // EEPROM最大容量 + static constexpr u32 EEPROM_END_ADDRESS = 0x08020000; // Flash结束地址 + static constexpr u32 EEPROM_PAGE_SIZE = 0x800; // 页大小2KB + static constexpr u32 EEPROM_MAX_SIZE = 0x800; // EEPROM最大容量 // 定义用户自定义的虚拟地址 - static constexpr uint16_t ADDR_MOTOR_KP = 0x0010; // 电机KP参数地址 - static constexpr uint16_t ADDR_MOTOR_KI = 0x0011; // 电机KI参数地址 - static constexpr uint16_t ADDR_MOTOR_KD = 0x0012; // 电机KD参数地址 - static constexpr uint16_t ADDR_SYSTEM_CONFIG = 0x0020; // 系统配置参数地址 - static constexpr uint16_t ADDR_ERROR_COUNT = 0x0030; // 错误计数地址 + static constexpr u8 ADDR_MOTOR_KP = 0x10; // 电机KP参数地址 + static constexpr u8 ADDR_MOTOR_KI = 0x11; // 电机KI参数地址 + static constexpr u8 ADDR_MOTOR_KD = 0x12; // 电机KD参数地址 + static constexpr u8 ADDR_SYSTEM_CONFIG = 0x20; // 系统配置参数地址 + static constexpr u8 ADDR_ERROR_COUNT = 0x30; // 错误计数地址 - // 角度数据存储地址 - static constexpr u16 ADDR_ANGLE_DATA = 0x0013; + static constexpr u8 ADDR_ANGLE_DATA = 0x01; // 角度数据存储地址 bool angle_saved = false; + // 构造函数 FlashEEPROM(); // 初始化Flash EEPROM模拟 u8 init(); - // 从Flash EEPROM读取数据 - FlashEepromStatus read(uint16_t virtualAddr, uint16_t *data) const; - + // 从Flash EEPROM中读取数据 + FlashEepromStatus read(u8 virtualAddr, u16 *data) const; // 向Flash EEPROM写入数据 - FlashEepromStatus write(uint16_t virtualAddr, uint16_t data); + FlashEepromStatus write(u8 virtualAddr, u16 data); + // Float数据读相关函数 + FlashEepromStatus readFloat(u8 virtualAddr, float *data) const; + // Float数据存储相关函数 + FlashEepromStatus writeFloat(u8 virtualAddr, float data); // 格式化Flash EEPROM页面 FlashEepromStatus format(); void flash_eeprom_example_init(void); - void update_pid_parameters(uint16_t kp, uint16_t ki, uint16_t kd); - void update_system_config(uint16_t config); + void update_system_config(u16 config); void increment_error_count(void); - FlashEepromStatus save_angle(u16 angle, bool saved); + FlashEepromStatus save_angle(float angle, bool saved); float read_angle(); private: