feat(can): 增加EEPROM状态码和系统配置保存功能

- 在CAN通信中增加EEPROM状态码字段,并通过CAN FD发送
- 实现Flash EEPROM对系统配置参数的CRC校验与保存
- 改进目标角度、速度等关键参数的读写逻辑,支持掉电保存
- 调整EEPROM地址映射,优化错误处理和状态反馈机制
- 修复CRC计算相关问题,增强数据可靠性
This commit is contained in:
cbb
2025-12-18 18:23:34 +08:00
parent d6cf143e87
commit 7c2860f302
11 changed files with 546 additions and 225 deletions
+133
View File
@@ -0,0 +1,133 @@
#include "CRC.h"
#include <cstring>
#include <stdint.h>
CRC_Calculator CRC_Calculator;
// 静态成员初始化
bool CRC_Calculator::table_initialized = false;
u32 CRC_Calculator::crc_table[256];
/**
* @brief 初始化CRC表
*/
void CRC_Calculator::init_crc_table() {
if (table_initialized) {
return;
}
uint32_t polynomial = 0xEDB88320; // CRC-32 IEEE 802.3标准多项式
for (int i = 0; i < 256; i++) {
uint32_t crc = i;
for (int j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ polynomial;
} else {
crc >>= 1;
}
}
crc_table[i] = crc;
}
table_initialized = true;
}
/**
* @brief 更新CRC值
* @param crc 当前CRC值
* @param data 要处理的数据
* @return 更新后的CRC值
*/
uint32_t CRC_Calculator::update_crc(uint32_t crc, uint8_t data) {
// 确保表已初始化
if (!table_initialized) {
init_crc_table();
}
uint8_t table_index = (crc ^ data) & 0xFF;
return (crc >> 8) ^ crc_table[table_index];
}
/**
* @brief 计算单个float值的CRC32
* @param data float值
* @return CRC32校验值
*/
uint32_t CRC_Calculator::calculate(const float& data) {
// 强制初始化CRC表(如果尚未初始化)
if (!table_initialized) {
init_crc_table();
}
uint32_t crc = 0xFFFFFFFF;
// 将float值按字节处理
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&data);
for (size_t i = 0; i < sizeof(float); i++) {
crc = update_crc(crc, bytes[i]);
}
return crc ^ 0xFFFFFFFF;
}
/**
* @brief 计算float数组的CRC32
* @param data float数组指针
* @param length 数组长度
* @return CRC32校验值
*/
uint32_t CRC_Calculator::calculate(const float* data, size_t length) {
// 强制初始化CRC表(如果尚未初始化)
if (!table_initialized) {
init_crc_table();
}
uint32_t crc = 0xFFFFFFFF;
// 处理每个float值
for (size_t i = 0; i < length; i++) {
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&(data[i]));
for (size_t j = 0; j < sizeof(float); j++) {
crc = update_crc(crc, bytes[j]);
}
}
return crc ^ 0xFFFFFFFF;
}
/**
* @brief 验证单个float值的CRC32
* @param data float值
* @param expected_crc 期望的CRC值
* @return true表示校验成功,false表示校验失败
*/
bool CRC_Calculator::verify(const float& data, uint32_t expected_crc) {
return calculate(data) == expected_crc;
}
/**
* @brief 验证float数组的CRC32
* @param data float数组指针
* @param length 数组长度
* @param expected_crc 期望的CRC值
* @return true表示校验成功,false表示校验失败
*/
bool CRC_Calculator::verify(const float* data, size_t length, uint32_t expected_crc) {
return calculate(data, length) == expected_crc;
}
/**
* @brief 获取CRC表初始化状态
* @return true表示已初始化,false表示未初始化
*/
bool CRC_Calculator::isInitialized() {
return table_initialized;
}
/**
* @brief 强制重新初始化CRC表
*/
void CRC_Calculator::reinitialize() {
table_initialized = false;
init_crc_table();
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef __CRC_H
#define __CRC_H
#include <cstdint>
#ifdef __cplusplus
extern "C" {
#endif
#include "gd32c10x.h"
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#include <cstddef>
class CRC_Calculator {
private:
static bool table_initialized;
static uint32_t crc_table[256];
/**
* @brief 初始化CRC表
*/
static void init_crc_table();
/**
* @brief 更新CRC值
* @param crc 当前CRC值
* @param data 要处理的数据
* @return 更新后的CRC值
*/
static uint32_t update_crc(uint32_t crc, uint8_t data);
public:
/**
* @brief 计算单个float值的CRC32
* @param data float值
* @return CRC32校验值
*/
static uint32_t calculate(const float& data);
/**
* @brief 计算float数组的CRC32
* @param data float数组指针
* @param length 数组长度
* @return CRC32校验值
*/
static uint32_t calculate(const float* data, size_t length);
/**
* @brief 验证单个float值的CRC32
* @param data float值
* @param expected_crc 期望的CRC值
* @return true表示校验成功,false表示校验失败
*/
static bool verify(const float& data, uint32_t expected_crc);
/**
* @brief 验证float数组的CRC32
* @param data float数组指针
* @param length 数组长度
* @param expected_crc 期望的CRC值
* @return true表示校验成功,false表示校验失败
*/
static bool verify(const float* data, size_t length, uint32_t expected_crc);
/**
* @brief 获取CRC表初始化状态
* @return true表示已初始化,false表示未初始化
*/
static bool isInitialized();
/**
* @brief 强制重新初始化CRC表
*/
static void reinitialize();
};
#endif // __cplusplus
#endif // __CRC_H
+2
View File
@@ -35,6 +35,8 @@ project:
- file: Algorithm/DengFOC.h
- file: Algorithm/pid.cpp
- file: pid.h
- file: Algorithm/CRC.cpp
- file: Algorithm/CRC.h
components:
- component: ARM::CMSIS:CORE
- component: Device:Startup
+6 -4
View File
@@ -437,16 +437,17 @@ u8 CAN_transmiter::init() {
\brief CAN 数据更新
*/
void CAN_transmiter::update(void) {
target_angle_union.f = FOC.target_angle;
target_velocity_union.f = FOC.target_velocity;
limit_velocity_union.f = FOC.limit_velocity;
limit_voltage = FOC.limit_voltage * 1000;
mcu_temp = sampler.get_mcu_temp() * 100;
motor_temp = sampler.get_drv_temp() * 100;
Power_Voltage = sampler.get_vbus_voltage() * 1000;
rt_angle_union.f = FOC.rt_angle;
// rt_velocity_union.f = KTH7823.getVelocity();
rt_velocity_union.f = FOC.rt_velocity;
MotorStatus = gpio_input_bit_get(GPIOB, GPIO_PIN_2) == RESET;
EEPROMStatus = flashEEP.EEPROMStatus;
Target_Control_Mode = FOC.control_mode;
controller_Mode = FOC.control_mode;
@@ -634,8 +635,7 @@ u8 CAN_transmiter::CANFD_all_Send() {
transmit_data[10] =
(transmit_data[10] & ~0x07) |
((MotorStatus & 0x01) | ((MagStatus & 0x01) << 1) |
((ThermalStatus & 0x01) << 2) | ((EEPROMStatus & 0x01) << 3));
((ThermalStatus & 0x01) << 2) | ((EEPROMStatus & 0x07) << 3));
pack_u16_to_bytes(transmit_data, 11, Power_Voltage);
pack_float_to_bytes(transmit_data, 13, rt_angle_union);
pack_float_to_bytes(transmit_data, 17, rt_velocity_union);
@@ -697,6 +697,8 @@ void CAN_transmiter::communication_check() {
} else if (receive_message.rx_efid == 0x00010301) {
motor_reset();
flashEEP.save_angle(FOC.rt_angle, false);
flashEEP.save_system_config(false);
} else {
printf("Unknown CAN ID: %X\n", receive_message.rx_efid);
}
+1 -1
View File
@@ -82,6 +82,7 @@ class CAN_transmiter {
bool MotorStatus = 0; // 电机状态码
float_union_t target_angle_union = {0}; // 目标角度
u8 Target_Control_Mode = 0; // 目标控制模式
u8 EEPROMStatus = 0; // EEPROM状态码
float_union_t target_velocity_union = {0}; // 目标速度
float_union_t u_current_union = {0}; // U相电流
float_union_t w_current_union = {0}; // W相电流
@@ -110,7 +111,6 @@ class CAN_transmiter {
bool MagStatus = 0; // 磁状态码
bool ThermalStatus = 0; // 热能状态码
bool EEPROMStatus = 0; // EEPROM状态码
void communication_check(); // 通信检查
};
+3 -2
View File
@@ -45,8 +45,9 @@ int main(void) {
std::printf("初始化失败\r\n");
}
watchdog_init(500); // 看门狗初始化
angsens_MG_check(); // 角度传感器磁感应强度测试
watchdog_init(500); // 看门狗初始化
angsens_MG_check(); // 角度传感器磁感应强度测试
SystemCoreClockUpdate(); // 更新系统时钟变量
while (1) {
__disable_irq();
u32 currentTasks =
+190 -117
View File
@@ -1,17 +1,24 @@
#include "flash.h"
#include "DengFOC.h"
#include "ang_sensor.h"
#include "core_cmFunc.h"
#include "gd32c10x_fmc.h"
#include "math.h"
#include <CRC.h>
#include <Can.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdint.h>
FlashEEPROM flashEEP = FlashEEPROM();
extern angle_sensor KTH7823;
extern CAN_transmiter CAN0_transmiter;
extern FOC_Controlroller FOC; // FOC控制
extern CRC_Calculator CRC_Calculator;
constexpr u8 SIZE_U32 = sizeof(uint32_t);
constexpr u8 DEFAULT_VALUE = 0;
constexpr u8 NUM_SAVED = 5;
// FlashEEPROM类实现
FlashEEPROM::FlashEEPROM() {
@@ -25,15 +32,70 @@ FlashEEPROM::FlashEEPROM() {
*/
u8 FlashEEPROM::init() {
// 读取保存的参数
float angle;
// 尝试从Flash读取参数,如果不存在则使用默认值
if (readFloat(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) {
angle = 0; // 默认值
std::printf("角度初始化为: %f\r\n", angle);
} else {
std::printf("从Flash读取到角度数: %f\r\n", angle);
u32 CRC_NUM = 0x0000;
FlashEepromStatus status_read[NUM_SAVED + 1] = {FLASH_EEPROM_OK};
float angle = 0.0f;
float data[NUM_SAVED] = {FOC.target_angle, FOC.target_velocity,
FOC.limit_voltage, (float)FOC.control_mode};
FlashEepromStatus status = FLASH_EEPROM_OK;
if (readFloat(ADDR_ANGLE, &angle) != FLASH_EEPROM_OK) {
angle = DEFAULT_VALUE; // 默认值
}
// 尝试从Flash读取参数,如果不存在则使用默认值
status_read[1] = readFloat(ADDR_TARGET_ANGLE, &data[0]);
status_read[2] = readFloat(ADDR_TARGET_VEL, &data[1]);
status_read[3] = readFloat(ADDR_VOLTAGE_LIMIT, &data[2]);
status_read[4] = readFloat(ADDR_CONTROL_MODE, &data[3]);
// 读取失败则使用默认值
for (u8 i = 1; i < NUM_SAVED + 1; i++) {
if (status_read[i] ==
FLASH_EEPROM_DATA_NOT_FOUND) { // 首次读取,不保存报错
data[i - 1] = DEFAULT_VALUE;
} else if (status_read[i] != FLASH_EEPROM_OK) { // 其余错误,保存报错
data[i - 1] = DEFAULT_VALUE;
status_read[0] = status_read[i];
}
}
if (status_read[0] == FLASH_EEPROM_OK) {
u32 next_address = EEPROM_END_ADDRESS;
// 遍历Flash页面寻找下一个可写入位置
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address > EEPROM_START_ADDRESS; address -= SIZE_U32) {
// 安全读取Flash数据
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 data_word = *flash_ptr;
// 找到空位置
if (data_word == 0xFFFFFFFF) {
next_address = address + SIZE_U32;
break;
}
// 更新下一个可能的写入位置(如果需要格式化)
next_address = address - SIZE_U32;
}
CRC_NUM = CRC_Calculator::calculate(data, NUM_SAVED);
if (CRC_NUM != *((u32 *)next_address)) { // CRC错误
for (u8 i = 0; i < NUM_SAVED; i++) {
data[i] = DEFAULT_VALUE;
}
EEPROMStatus = FLASH_EEPROM_CRC_ERROR;
} else { // CRC正确
EEPROMStatus = FLASH_EEPROM_OK;
}
} else {
// 读取失败,报错
EEPROMStatus = status_read[0];
}
KTH7823.angle_set(angle);
FOC.target_angle = data[0];
FOC.target_velocity = data[1];
FOC.limit_voltage = data[2];
FOC.control_mode = (u8)data[3];
return 0;
}
@@ -45,7 +107,7 @@ u8 FlashEEPROM::init() {
*/
FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const {
// 参数检查
if (data == nullptr or virtualAddr > 0xFE) {
if (data == nullptr) {
return FLASH_EEPROM_INVALID_ADDR;
}
@@ -63,8 +125,7 @@ FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const {
}
}
}
// 未找到指定虚拟地址的数据
return FLASH_EEPROM_NOT_FOUND;
return FLASH_EEPROM_DATA_NOT_FOUND;
}
/**
@@ -74,10 +135,11 @@ FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const {
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
// 参数检查
if (data == nullptr or virtualAddr > 0xFE) {
// 检查参数有效性
if (data == nullptr) {
return FLASH_EEPROM_INVALID_ADDR;
}
// 从Flash末尾开始向前搜索,找到最新的数据
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address >= EEPROM_START_ADDRESS; address -= SIZE_U32) {
@@ -87,14 +149,16 @@ FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
u8 addr = (u8)(data_word & 0xFF);
// 找到匹配的虚拟地址
if (addr == virtualAddr) {
// 使用完整32位数据解释为float
memcpy(data, &data_word, sizeof(float));
// 清除最低的8位地址信息,保留高24位数据
u32 float_data = data_word & 0xFFFFFF00;
// 使用内存拷贝将处理后的数据解释为float
memcpy(data, &float_data, sizeof(float));
return FLASH_EEPROM_OK;
}
}
}
// 未找到指定虚拟地址的数据
return FLASH_EEPROM_NOT_FOUND;
return FLASH_EEPROM_DATA_NOT_FOUND;
}
/**
@@ -104,10 +168,6 @@ FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
// 参数检查
if (virtualAddr > 0xFE) {
return FLASH_EEPROM_INVALID_ADDR;
}
// 查找下一个可写入的位置
u32 next_address = EEPROM_START_ADDRESS;
@@ -157,12 +217,14 @@ FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
fmc_state_enum fmc_status =
fmc_word_program(EEPROM_START_ADDRESS, new_data_word);
if (fmc_status != FMC_READY) {
if (fmc_status == FMC_READY)
return FLASH_EEPROM_OK;
if (fmc_status == FMC_PGAERR)
return FLASH_EEPROM_ALIGNMENT_ERROR;
else if (fmc_status != FMC_READY)
return FLASH_EEPROM_WRITE_ERROR;
}
return FLASH_EEPROM_OK;
}
return FLASH_EEPROM_WRITE_ERROR;
}
/**
@@ -172,10 +234,6 @@ FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
* @retval FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
// 参数检查
if (virtualAddr > 0xFE) {
return FLASH_EEPROM_INVALID_ADDR;
}
// 查找下一个可写入的位置
u32 next_address = EEPROM_START_ADDRESS;
@@ -232,15 +290,18 @@ FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
memcpy(&data_word, &data, sizeof(float));
// 插入虚拟地址到低8位
data_word = (data_word & 0xFFFFFF00) | (u32)virtualAddr;
fmc_unlock();
fmc_state_enum fmc_status =
fmc_word_program(EEPROM_START_ADDRESS, data_word);
if (fmc_status != FMC_READY) {
fmc_lock();
if (fmc_status == FMC_READY)
return FLASH_EEPROM_OK;
if (fmc_status == FMC_PGAERR)
return FLASH_EEPROM_ALIGNMENT_ERROR;
else if (fmc_status != FMC_READY)
return FLASH_EEPROM_WRITE_ERROR;
}
return FLASH_EEPROM_OK;
}
return FLASH_EEPROM_WRITE_ERROR;
}
/**
@@ -276,7 +337,6 @@ FlashEepromStatus FlashEEPROM::format() {
break;
}
}
// 如果是新的虚拟地址/类型组合,添加到有效数据列表
if (!found && valid_count < (EEPROM_MAX_SIZE / SIZE_U32)) {
valid_entries[valid_count] =
@@ -291,7 +351,7 @@ FlashEepromStatus FlashEEPROM::format() {
if (fmc_status != FMC_READY) {
return FLASH_EEPROM_ERASE_ERROR;
}
fmc_unlock();
// 重新写入有效的数据项
for (u16 i = 0; i < valid_count; i++) {
fmc_status = fmc_word_program(EEPROM_START_ADDRESS + i * SIZE_U32,
@@ -300,17 +360,91 @@ FlashEepromStatus FlashEEPROM::format() {
return FLASH_EEPROM_WRITE_ERROR;
}
}
fmc_lock();
return FLASH_EEPROM_OK;
}
/**
* @brief 更新系统配置并保存到Flash
* @param config 新的系统配置值
*/
void FlashEEPROM::update_system_config(u16 config) {
write(ADDR_SYSTEM_CONFIG, config);
FlashEepromStatus FlashEEPROM::save_system_config(bool saved) {
u32 CRC_NUM = 0x0000;
u32 next_address;
FlashEepromStatus status_save[NUM_SAVED] = {FLASH_EEPROM_OK};
float data[NUM_SAVED] = {FOC.target_angle, FOC.target_velocity,
FOC.limit_voltage, (float)FOC.control_mode};
// 读取保存的参数
if (!system_config_saved) {
// 写入参数
status_save[0] = writeFloat(ADDR_TARGET_ANGLE, data[0]);
status_save[1] = writeFloat(ADDR_TARGET_VEL, data[1]);
status_save[2] = writeFloat(ADDR_VOLTAGE_LIMIT, data[2]);
status_save[3] = writeFloat(ADDR_CONTROL_MODE, data[3]);
for (FlashEepromStatus &p : status_save) {
if (p != FLASH_EEPROM_OK) {
EEPROMStatus = p;
return p;
}
}
CRC_NUM = CRC_Calculator.calculate(data, NUM_SAVED);
// 遍历Flash页面寻找下一个可写入位置
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
address > EEPROM_START_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_START_ADDRESS) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
fmc_state_enum fmc_status = fmc_word_program(next_address, CRC_NUM);
// printf("write address:0x%X,status:0x%x \r\n", next_address,
// fmc_status);
// printf("CRC cmp1,0x%X_0x%x \r\n", CRC_NUM, *((u32
// *)next_address));
fmc_lock();
} else {
// 空间不足,需要格式化页面
FlashEepromStatus status = format();
if (status != FLASH_EEPROM_OK) {
return status;
}
// 格式化后在页面底部写入数据
fmc_unlock();
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
fmc_state_enum fmc_status =
fmc_word_program(EEPROM_END_ADDRESS - SIZE_U32, CRC_NUM);
fmc_lock();
if (fmc_status == FMC_READY)
return FLASH_EEPROM_OK;
if (fmc_status == FMC_PGAERR)
return FLASH_EEPROM_ALIGNMENT_ERROR;
else if (fmc_status != FMC_READY)
return FLASH_EEPROM_WRITE_ERROR;
}
if (CRC_NUM == *((u32 *)next_address)) {
system_config_saved = saved; // 标记已保存过
EEPROMStatus = FLASH_EEPROM_OK; // 设置EEPROM状态
} else {
EEPROMStatus = FLASH_EEPROM_CRC_ERROR; // 设置EEPROM错误状态
return FLASH_EEPROM_CRC_ERROR;
}
}
EEPROMStatus = FLASH_EEPROM_OK;
return FLASH_EEPROM_OK;
}
/**
@@ -319,27 +453,30 @@ void FlashEEPROM::update_system_config(u16 config) {
* @return FlashEepromStatus: 操作状态
*/
FlashEepromStatus FlashEEPROM::save_angle(float angle, bool saved) {
float angle_read = 0;
FlashEepromStatus status = FLASH_EEPROM_ERROR;
float angle_read = DEFAULT_VALUE;
FlashEepromStatus status = FLASH_EEPROM_OK;
// 读取保存的参数
if (!angle_saved) {
// 写入参数
status = writeFloat(ADDR_ANGLE_DATA, angle);
status = writeFloat(ADDR_ANGLE, angle);
if (status != FLASH_EEPROM_OK) {
EEPROMStatus = status;
return status;
}
if (readFloat(ADDR_ANGLE_DATA, &angle_read) != FLASH_EEPROM_OK)
angle_read = 0; // 读不到角度值,存储失败
if (readFloat(ADDR_ANGLE, &angle_read) != FLASH_EEPROM_OK)
angle_read = DEFAULT_VALUE; // 读不到角度值,存储失败
if (fabsf(angle_read - angle) > 0.01 * angle) {
status = FLASH_EEPROM_WRITE_ERROR;
CAN0_transmiter.EEPROMStatus = 1; // 设置EEPROM错误状态
if (fabsf(angle_read - angle) > 0.01 * fabs(angle)) {
EEPROMStatus = FLASH_EEPROM_WRITE_ERROR; // 设置EEPROM错误状态
return FLASH_EEPROM_WRITE_ERROR;
} else {
angle_saved = saved; // 标记已保存过
CAN0_transmiter.EEPROMStatus = 0; // 设置EEPROM状态
angle_saved = saved; // 标记已保存过
EEPROMStatus = FLASH_EEPROM_OK; // 设置EEPROM状态
}
printf("read:%f\r\n", angle_read);
}
return status;
return FLASH_EEPROM_OK;
}
/**
@@ -347,73 +484,9 @@ FlashEepromStatus FlashEEPROM::save_angle(float angle, bool saved) {
* @return float: 角度数据
*/
float FlashEEPROM::read_angle() {
float angle = 0;
if (readFloat(ADDR_ANGLE_DATA, &angle) != FLASH_EEPROM_OK) {
angle = 0;
float angle = DEFAULT_VALUE;
if (readFloat(ADDR_ANGLE, &angle) != FLASH_EEPROM_OK) {
angle = DEFAULT_VALUE;
}
return angle; // 默认返回0度
return angle;
}
/**
* @brief 增加错误计数并保存到Flash
*/
void FlashEEPROM::increment_error_count(void) {
u16 error_count = 0;
// 读取当前错误计数
FlashEepromStatus read_status = read(ADDR_ERROR_COUNT, &error_count);
if (read_status == FLASH_EEPROM_OK ||
read_status == FLASH_EEPROM_NOT_FOUND) {
// 增加错误计数(如果是NOT_FOUND,则error_count已经是0)
error_count++;
// 保存更新后的错误计数
write(ADDR_ERROR_COUNT, error_count);
}
}
/**
* @brief 示例主函数 - 展示Flash EEPROM的使用方法
*/
void flash_eeprom_example_main(void) {
std::printf("\r\n=== Flash EEPROM 使用示例 ===\r\n");
// 初始化Flash EEPROM
flashEEP.init();
// 模拟系统配置更新
std::printf("\r\n--- 更新系统配置 ---\r\n");
flashEEP.update_system_config(0x03);
// 模拟错误发生
std::printf("\r\n--- 模拟错误计数增加 ---\r\n");
flashEEP.increment_error_count();
flashEEP.increment_error_count();
// 再次读取参数验证保存是否成功
std::printf("\r\n--- 验证保存的数据 ---\r\n");
u16 kp_value, ki_value, kd_value;
u16 system_config;
u16 error_count;
// if (flashEEP.read(ADDR_MOTOR_KP, &kp_value) == FLASH_EEPROM_OK) {
// std::printf("当前KP值: %d\r\n", kp_value);
// }
// if (flashEEP.read(ADDR_MOTOR_KI, &ki_value) == FLASH_EEPROM_OK) {
// std::printf("当前KI值: %d\r\n", ki_value);
// }
// if (flashEEP.read(ADDR_MOTOR_KD, &kd_value) == FLASH_EEPROM_OK) {
// std::printf("当前KD值: %d\r\n", kd_value);
// }
// if (flashEEP.read(ADDR_SYSTEM_CONFIG, &system_config) == FLASH_EEPROM_OK)
// { std::printf("当前系统配置: 0x%02X\r\n", system_config);
// }
// if (flashEEP.read(ADDR_ERROR_COUNT, &error_count) == FLASH_EEPROM_OK) {
// std::printf("当前错误计数: %d\r\n", error_count);
// }
std::printf("\r\n=== 示例结束 ===\r\n");
}
+14 -16
View File
@@ -10,11 +10,12 @@
// EEPROM操作状态
typedef enum {
FLASH_EEPROM_OK = 0, // 操作成功
FLASH_EEPROM_ERROR, // 操作失败
FLASH_EEPROM_NOT_FOUND, // 未找到指定数据
FLASH_EEPROM_INVALID_ADDR, // 无效地址
FLASH_EEPROM_WRITE_ERROR, // 写入错误
FLASH_EEPROM_READ_ERROR, // 读取错误
FLASH_EEPROM_ERASE_ERROR, // 擦除错误
FLASH_EEPROM_INVALID_ADDR, // 无效地址
FLASH_EEPROM_DATA_NOT_FOUND, // 找不到数据
FLASH_EEPROM_CRC_ERROR, // CRC错误
FLASH_EEPROM_ALIGNMENT_ERROR, // 对齐错误
} FlashEepromStatus;
@@ -23,21 +24,20 @@ class FlashEEPROM {
public:
// EEPROM emulation constants
static constexpr u32 EEPROM_START_ADDRESS =
0x0801F800; // Flash最后一页(2KB)
0x0801F800; // Flash最后一页(2KB)
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 u32 EEPROM_MAX_SIZE = 0x800; // EEPROM最大容量
// 定义用户自定义的虚拟地址
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 u8 ADDR_CONTROL_MODE = 0x0; // 控制模式
static constexpr u8 ADDR_ANGLE = 0x01; // 角度数据存储地址
static constexpr u8 ADDR_TARGET_ANGLE = 0x02; // 角度命令数据存储地址
static constexpr u8 ADDR_TARGET_VEL = 0x03; // 速度命令数据存储地址
static constexpr u8 ADDR_VOLTAGE_LIMIT = 0x4; // 电压限制
static constexpr u8 ADDR_ANGLE_DATA = 0x01; // 角度数据存储地址
bool angle_saved = false;
bool system_config_saved = false;
u8 EEPROMStatus;
// 构造函数
FlashEEPROM();
@@ -56,10 +56,8 @@ class FlashEEPROM {
// 格式化Flash EEPROM页面
FlashEepromStatus format();
void flash_eeprom_example_init(void);
void update_system_config(u16 config);
void increment_error_count(void);
FlashEepromStatus save_angle(float angle, bool saved);
FlashEepromStatus save_system_config(bool saved);
float read_angle();
private:
+2 -1
View File
@@ -96,7 +96,8 @@ void power_manage(void) {
float vbus = sampler.get_vbus_voltage();
if ((vbus < 22.0f) and (last_vbus > vbus) and vbus > 8.0f) {
FOC.shut_down();
// flashEEP.save_angle(FOC.rt_angle,false);
flashEEP.save_angle(FOC.rt_angle, true);
flashEEP.save_system_config(true);
} else {
FOC.resume();
}
+106 -84
View File
@@ -1,117 +1,139 @@
/*!
\file systick.c
\brief the systick configuration file
\version 2025-06-20, V1.5.1, firmware for GD32C10x
\file systick.c
\brief the systick configuration file
\version 2025-06-20, V1.5.1, firmware for GD32C10x
*/
/*
Copyright (c) 2024, GigaDevice Semiconductor Inc.
Copyright (c) 2024, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gd32c10x.h"
#include "systick.h"
#include "gd32c10x.h"
#include "gd32c10x_exti.h"
#include "gd32c10x_gpio.h"
volatile static uint32_t delay;
/*!
\brief configure systick
\param[in] none
\param[out] none
\retval none
\brief configure systick
\param[in] none
\param[out] none
\retval none
*/
void systick_config(void)
{
/* setup systick timer for 1000Hz interrupts */
if (SysTick_Config(SystemCoreClock / 1000U)){
/* capture error */
while (1){
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
void systick_config(void) {
/* setup systick timer for 1000Hz interrupts */
if (SysTick_Config(SystemCoreClock / 1000U)) {
/* capture error */
while (1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief delay a time in seconds
\param[in] count: count in seconds
\param[out] none
\retval none
\brief delay a time in seconds
\param[in] count: count in seconds
\param[out] none
\retval none
*/
void delay_1s(uint32_t count)
{
uint32_t i;
for(i = 0; i < count; i++){
delay_1ms(1000);
}
void delay_1s(uint32_t count) {
uint32_t i;
for (i = 0; i < count; i++) {
delay_1ms(1000);
}
}
/*!
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
*/
void delay_1ms(uint32_t count)
{
delay = count;
while(0U != delay){
void delay_1ms(uint32_t count) {
delay = count;
while (0U != delay) {
fwdgt_counter_reload();
fwdgt_counter_reload();
}
}
}
/*!
\brief delay decrement
\param[in] none
\param[out] none
\retval none
\brief delay decrement
\param[in] none
\param[out] none
\retval none
*/
void delay_decrement(void)
{
if (0U != delay){
delay--;
}
void delay_decrement(void) {
if (0U != delay) {
delay--;
}
}
/*!
\brief system soft reset
\param[in] none
\param[out] none
\retval none
\brief system soft reset
\param[in] none
\param[out] none
\retval none
*/
void system_soft_reset(void)
{
/* Set the software reset bit */
SCB->AIRCR = (0x05FA0000U | (SCB->AIRCR & (0x700U)) | (1U << 2));
/* Data Synchronization Barrier */
__DSB();
/* Wait for reset */
while (1){
__NOP();
}
void system_soft_reset(void) {
/* Set the software reset bit */
SCB->AIRCR = (0x05FA0000U | (SCB->AIRCR & (0x700U)) | (1U << 2));
/* Data Synchronization Barrier */
__DSB();
/* Wait for reset */
while (1) {
__NOP();
}
}
// 1. 进入深度睡眠前的准备
void prepare_deep_sleep(void) {
// 将SIT1044设置为低功耗待机模式
gpio_bit_set(GPIOB, GPIO_PIN_8); // STB = 高电平
// 配置EXTI中断(连接到SIT1044的RXD引脚)
exti_init(EXTI_1, EXTI_INTERRUPT, EXTI_TRIG_FALLING); // 下降沿触发
// 进入深度睡眠
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, WFI_CMD);
}
// 2. 唤醒中断处理
void EXTI1_IRQHandler(void) {
if (exti_interrupt_flag_get(EXTI_1) != RESET) {
// 清除中断标志
exti_interrupt_flag_clear(EXTI_1);
// 禁用EXTI线1的中断
exti_interrupt_disable(EXTI_1);
// 唤醒SIT1044到正常模式
gpio_bit_reset(GPIOB, GPIO_PIN_8); // STB = 低电平
}
}
+4
View File
@@ -54,6 +54,10 @@ void idle_task_count(void);
uint8_t get_cpu_usage(void);
/* 系统软复位 */
void system_soft_reset(void);
/* 准备进入低功耗模式 */
void prepare_deep_sleep(void);
/* 中断唤醒 */
void EXTI1_IRQHandler(void);
#ifdef __cplusplus
}