基础响应功能的实现
This commit is contained in:
+82
-46
@@ -1,31 +1,47 @@
|
||||
#include "OTA.h"
|
||||
#include "gd32c10x_fmc.h"
|
||||
#include "systick.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <flash.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern CAN_transmiter CAN0_transmiter; // CAN初始化
|
||||
extern FlashEEPROM flashEEP;
|
||||
OTAHandler ota;
|
||||
extern "C" {
|
||||
void canfd_rx_irq_handler(void);
|
||||
}
|
||||
#define DEBUG_OTA 1
|
||||
|
||||
OTAHandler::OTAHandler() : ota_active(false), received_size(0) {}
|
||||
|
||||
void OTAHandler::init() {
|
||||
// 初始化CANFD接收中断
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 1, 1);
|
||||
}
|
||||
void OTAHandler::init() {}
|
||||
|
||||
void OTAHandler::process() {
|
||||
if (!ota_active)
|
||||
if (!ota_active) {
|
||||
ota_time = 0; // 重置计时器
|
||||
static u8 zero[1] = {ota_active};
|
||||
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 0, zero);
|
||||
#ifdef DEBUG_OTA
|
||||
printf("wait OTA%d\r\n", ota_active);
|
||||
#endif
|
||||
delay_1ms(10);
|
||||
return;
|
||||
} else {
|
||||
delay_1ms(1);
|
||||
ota_time++;
|
||||
}
|
||||
|
||||
// 这里可以添加超时处理逻辑
|
||||
// 例如:10秒无数据则退出OTA模式
|
||||
// 检查是否超时(例如:10秒无数据则退出OTA模式)
|
||||
if (ota_time > 10000) { // 10秒超时(10000 x 1ms)
|
||||
ota_time = 0;
|
||||
ota_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool OTAHandler::validateApplication() {
|
||||
uint32_t *app_vector = (uint32_t *)APP_START_ADDR;
|
||||
uint32_t stack_ptr = app_vector[0];
|
||||
uint32_t reset_handler = app_vector[1];
|
||||
u32 *app_vector = (u32 *)APP_START_ADDR;
|
||||
u32 stack_ptr = app_vector[0];
|
||||
u32 reset_handler = app_vector[1];
|
||||
|
||||
// 简单验证:检查栈指针是否在SRAM范围内
|
||||
return (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000) &&
|
||||
@@ -34,45 +50,58 @@ bool OTAHandler::validateApplication() {
|
||||
}
|
||||
|
||||
void OTAHandler::jumpToApplication() {
|
||||
if (!validateApplication()) {
|
||||
// 无效APP,停留在bootloader
|
||||
return;
|
||||
}
|
||||
|
||||
// 关闭所有中断
|
||||
__disable_irq();
|
||||
|
||||
// 设置主栈指针
|
||||
uint32_t msp_value = *(__IO uint32_t *)APP_START_ADDR;
|
||||
__set_MSP(msp_value);
|
||||
|
||||
// 获取复位地址
|
||||
uint32_t reset_handler = *(__IO uint32_t *)(APP_START_ADDR + 4);
|
||||
typedef void (*AppEntryFunc)(void);
|
||||
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
|
||||
|
||||
// 跳转
|
||||
app_entry();
|
||||
if (!validateApplication()) return;
|
||||
|
||||
// 1. 关闭所有中断
|
||||
__disable_irq();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
NVIC->ICER[i] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// 2. 重置外设(特别是CAN,防止冲突)
|
||||
can_deinit(CAN0);
|
||||
|
||||
// 3. 重置系统时钟到默认状态
|
||||
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
|
||||
|
||||
// 4. 关闭一些关键外设时钟
|
||||
rcu_periph_clock_disable(RCU_GPIOA);
|
||||
rcu_periph_clock_disable(RCU_GPIOB);
|
||||
rcu_periph_clock_disable(RCU_GPIOC);
|
||||
rcu_periph_clock_disable(RCU_USART0);
|
||||
rcu_periph_clock_disable(RCU_CAN0);
|
||||
rcu_periph_clock_disable(RCU_TIMER0);
|
||||
rcu_periph_clock_disable(RCU_DMA0);
|
||||
|
||||
// 5. 设置MSP并跳转
|
||||
uint32_t msp_value = *(__IO uint32_t*)APP_START_ADDR;
|
||||
__set_MSP(msp_value);
|
||||
|
||||
uint32_t reset_handler = *(__IO uint32_t*)(APP_START_ADDR + 4);
|
||||
typedef void (*AppEntryFunc)(void);
|
||||
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
|
||||
|
||||
// 6. 跳转
|
||||
app_entry();
|
||||
}
|
||||
|
||||
void OTAHandler::eraseApplicationArea() {
|
||||
// 擦除APP区域
|
||||
fmc_unlock();
|
||||
for (uint32_t addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
|
||||
for (u32 addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
|
||||
addr += FMC_PAGE_SIZE) {
|
||||
fmc_page_erase(addr);
|
||||
}
|
||||
fmc_lock();
|
||||
}
|
||||
|
||||
void OTAHandler::writeApplicationData(uint32_t offset, uint8_t *data,
|
||||
uint32_t size) {
|
||||
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
|
||||
fmc_unlock();
|
||||
uint32_t write_addr = APP_START_ADDR + offset;
|
||||
u32 write_addr = APP_START_ADDR + offset;
|
||||
|
||||
// 32位对齐写入
|
||||
for (uint32_t i = 0; i < size; i += 4) {
|
||||
uint32_t word = 0;
|
||||
for (u32 i = 0; i < size; i += 4) {
|
||||
u32 word = 0;
|
||||
memcpy(&word, &data[i], 4);
|
||||
fmc_word_program(write_addr + i, word);
|
||||
}
|
||||
@@ -80,27 +109,34 @@ void OTAHandler::writeApplicationData(uint32_t offset, uint8_t *data,
|
||||
fmc_lock();
|
||||
}
|
||||
|
||||
void OTAHandler::handleOTAMessage(uint32_t id, uint8_t *data, uint8_t len) {
|
||||
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
|
||||
if (id == CANFD_OTA_REQ_ID) {
|
||||
#ifdef DEBUG_OTA
|
||||
printf("req OTA\r\n");
|
||||
#endif
|
||||
// OTA请求包
|
||||
uint32_t new_size = *(uint32_t *)data;
|
||||
u32 new_size = *(u32 *)data;
|
||||
if (new_size <= APP_MAX_SIZE) {
|
||||
expected_size = new_size;
|
||||
received_size = 0;
|
||||
eraseApplicationArea();
|
||||
// eraseApplicationArea();
|
||||
ota_active = true;
|
||||
sendACK(0xFFFFFFFF); // 确认开始
|
||||
sendACK(new_size); // 确认开始
|
||||
#ifdef DEBUG_OTA
|
||||
printf("start OTA%d\r\n", ota_active);
|
||||
#endif
|
||||
}
|
||||
} else if (id == CANFD_OTA_DATA_ID && ota_active) {
|
||||
// 数据包格式:[4字节包序号][实际数据]
|
||||
if (len >= 4) {
|
||||
uint32_t packet_num = *(uint32_t *)data;
|
||||
uint32_t offset = packet_num * (len - 4);
|
||||
u32 packet_num = *(u32 *)data;
|
||||
u32 offset = packet_num * (len - 4);
|
||||
|
||||
if (offset < expected_size) {
|
||||
writeApplicationData(offset, &data[4], len - 4);
|
||||
writeApplicationData(offset, &data[4], len - 4); // 写入数据
|
||||
received_size += (len - 4);
|
||||
sendACK(packet_num);
|
||||
sendACK(packet_num); // 确认ACK
|
||||
ota_time = 0; // 重置计时器
|
||||
|
||||
// 检查是否完成
|
||||
if (received_size >= expected_size) {
|
||||
@@ -115,6 +151,6 @@ void OTAHandler::handleOTAMessage(uint32_t id, uint8_t *data, uint8_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
void OTAHandler::sendACK(uint32_t packet_num) {
|
||||
void OTAHandler::sendACK(u32 packet_num) {
|
||||
CAN0_transmiter.sendACK(CANFD_OTA_ACK_ID, packet_num);
|
||||
}
|
||||
+1
-1
@@ -8,10 +8,10 @@
|
||||
class OTAHandler {
|
||||
public:
|
||||
bool ota_active;
|
||||
u32 ota_time;
|
||||
uint32_t received_size;
|
||||
uint32_t expected_size;
|
||||
|
||||
OTAHandler();
|
||||
void init();
|
||||
void process();
|
||||
bool isActive() const { return ota_active; }
|
||||
|
||||
+19
-14
@@ -1,21 +1,26 @@
|
||||
#pragma once
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
#include "stdint.h"
|
||||
|
||||
// Flash分区配置
|
||||
constexpr uint32_t BOOTLOADER_SIZE = 0x4000; // 16KB
|
||||
constexpr uint32_t APP_START_ADDR = 0x08004000; // APP起始地址
|
||||
constexpr uint32_t APP_MAX_SIZE = 0x0001C000; // 112KB
|
||||
constexpr uint32_t FMC_PAGE_SIZE = 0x400;
|
||||
constexpr u32 BOOTLOADER_SIZE = 0x4000; // 16KB
|
||||
constexpr u32 APP_START_ADDR = 0x08004000; // APP起始地址
|
||||
constexpr u32 APP2_START_ADDR = 0x08010000; // APP2起始地址
|
||||
constexpr u32 APP_MAX_SIZE = 0xC000; // 48KB
|
||||
constexpr u32 FMC_PAGE_SIZE = 0x400; // 1KB
|
||||
|
||||
// CANFD配置
|
||||
constexpr uint32_t CANFD_OTA_REQ_ID = 0x00000100;
|
||||
constexpr uint32_t CANFD_OTA_DATA_ID = 0x00000101;
|
||||
constexpr uint32_t CANFD_OTA_ACK_ID = 0x00000102;
|
||||
constexpr u32 CANFD_OTA_REQ_ID = 0x00000100;
|
||||
constexpr u32 CANFD_OTA_DATA_ID = 0x00000101;
|
||||
constexpr u32 CANFD_OTA_ACK_ID = 0x00000102;
|
||||
constexpr u32 CANFD_OTA_WAIT_ID = 0x00000103;
|
||||
|
||||
// CANFD数据段最大64字节,我们用32字节数据 + 4字节头部
|
||||
constexpr uint32_t OTA_PACKET_SIZE = 32;
|
||||
// CANFD数据段最大64字节,我们用1字节序号 + 48字节数据 + 1字节CRC校验
|
||||
constexpr u32 OTA_PACKET_SIZE = 48;
|
||||
typedef struct {
|
||||
uint32_t packet_num; // 包序号
|
||||
uint8_t data[OTA_PACKET_SIZE]; // 32字节有效数据
|
||||
uint32_t crc32; // 简单校验
|
||||
} canfd_ota_packet_t;
|
||||
u32 packet_num; // 包序号
|
||||
u8 data[OTA_PACKET_SIZE]; // 48字节有效数据
|
||||
u32 crc32; // 简单校验
|
||||
} canfd_ota_packet_t;
|
||||
|
||||
#endif
|
||||
+2
-346
@@ -10,11 +10,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
FlashEEPROM flashEEP = FlashEEPROM();
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
constexpr u8 SIZE_U32 = sizeof(uint32_t);
|
||||
constexpr u8 SIZE_FLOAT = sizeof(float);
|
||||
constexpr u8 DEFAULT_VALUE = 0;
|
||||
constexpr u8 NUM_SAVED = 6;
|
||||
#define EEPDEBUG 0
|
||||
|
||||
// FlashEEPROM类实现
|
||||
@@ -31,322 +28,7 @@ u8 FlashEEPROM::init() {
|
||||
rcu_periph_clock_enable(RCU_CRC);
|
||||
crc_deinit(); // 初始化CRC模块
|
||||
|
||||
FlashEepromStatus status = FLASH_EEPROM_OK;
|
||||
// 读取系统配置
|
||||
read_saved_system_config();
|
||||
|
||||
if (EEPROMStatus == FLASH_EEPROM_OK) {
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
return FLASH_EEPROM_READ_ERROR;
|
||||
}
|
||||
return 1; // 正常不会返回这个,未预料的异常情况返回
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取EEPROM数据
|
||||
* @param virtualAddr: 虚拟地址
|
||||
* @param data: 存储读取数据的指针
|
||||
* @retval EEPROMStatus: 是否成功
|
||||
*/
|
||||
u8 FlashEEPROM::read_saved_system_config(void) {
|
||||
// 读取保存的参数
|
||||
u32 CRC_NUM = 0x0000;
|
||||
FlashEepromStatus status_read[NUM_SAVED + 1] = {FLASH_EEPROM_OK};
|
||||
float data[NUM_SAVED] = {0.0f};
|
||||
// 尝试从Flash读取参数,如果不存在则使用默认值
|
||||
status_read[1] = readFloat(ADDR_CONTROL_MODE, &data[0]);
|
||||
status_read[2] = readFloat(ADDR_VOLTAGE_LIMIT, &data[1]);
|
||||
status_read[3] = readFloat(ADDR_VEL_LIMIT, &data[2]);
|
||||
status_read[4] = readFloat(ADDR_ANGLE, &data[3]);
|
||||
status_read[5] = readFloat(ADDR_TARGET_ANGLE, &data[4]);
|
||||
status_read[6] = readFloat(ADDR_TARGET_VEL, &data[5]);
|
||||
|
||||
// 读取失败则使用默认值
|
||||
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_DATA_START_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;
|
||||
}
|
||||
if (next_address == EEPROM_DATA_START_ADDRESS) {
|
||||
// 从来没有存储过,直接返回
|
||||
return FLASH_EEPROM_OK;
|
||||
}
|
||||
|
||||
crc_data_register_reset(); // 确保CRC计算从初始状态开始
|
||||
CRC_NUM = crc_block_data_calculate((uint32_t *)data, NUM_SAVED);
|
||||
|
||||
#if EEPDEBUG
|
||||
printf("CRC cmp1,0x%X_0x%x \r\n", CRC_NUM, *((u32 *)next_address));
|
||||
#endif
|
||||
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];
|
||||
}
|
||||
|
||||
return EEPROMStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从Flash EEPROM读取数据
|
||||
* @param virtualAddr: 虚拟地址
|
||||
* @param data: 指向存储读取数据的指针
|
||||
* @retval FlashEepromStatus: 操作状态
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::read(u8 virtualAddr, u16 *data) const {
|
||||
// 参数检查
|
||||
if (data == nullptr) {
|
||||
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 & DATA_ADDR_MASK);
|
||||
// 找到匹配的虚拟地址
|
||||
if (addr == virtualAddr) {
|
||||
*data = (u16)(data_word & DATA_U16_MASK);
|
||||
return FLASH_EEPROM_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FLASH_EEPROM_DATA_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从Flash EEPROM读取float数据
|
||||
* @param virtualAddr: 虚拟地址
|
||||
* @param data: 指向存储读取数据的指针
|
||||
* @retval FlashEepromStatus: 操作状态
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
|
||||
// 检查参数有效性
|
||||
if (data == nullptr) {
|
||||
return FLASH_EEPROM_INVALID_ADDR;
|
||||
}
|
||||
|
||||
// 从Flash末尾开始向前搜索,找到最新的数据
|
||||
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
|
||||
address >= EEPROM_START_ADDRESS; address -= SIZE_U32) {
|
||||
// 使用volatile确保每次都从内存读取,防止编译器优化
|
||||
volatile u32 *flash_ptr = (volatile u32 *)address;
|
||||
u32 data_word = *flash_ptr;
|
||||
|
||||
// 检查是否是有效数据(非擦除状态)
|
||||
if (data_word != 0xFFFFFFFF) {
|
||||
u8 addr = (u8)(data_word & DATA_ADDR_MASK);
|
||||
// 找到匹配的虚拟地址
|
||||
if (addr == virtualAddr) {
|
||||
// 清除最低的8位地址信息,保留高24位数据
|
||||
u32 float_data = data_word & DATA_FLOAT_MASK;
|
||||
// 使用内存拷贝将处理后的数据解释为float
|
||||
memcpy(data, &float_data, SIZE_FLOAT);
|
||||
#if EEPDEBUG
|
||||
printf("read:0x%x=%f\r\n", address, *data);
|
||||
#endif
|
||||
return FLASH_EEPROM_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 未找到指定虚拟地址的数据
|
||||
return FLASH_EEPROM_DATA_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向Flash EEPROM写入数据
|
||||
* @param virtualAddr: 虚拟地址
|
||||
* @param data: 要写入的数据
|
||||
* @retval FlashEepromStatus: 操作状态
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
|
||||
// 查找下一个可写入的位置
|
||||
u32 next_address = EEPROM_START_ADDRESS;
|
||||
u32 data_read;
|
||||
// 插入虚拟地址到低8位 格式: [data:16bit][reserved:8bit][addr:8bit]
|
||||
data = (data & DATA_U16_MASK) | (u32)virtualAddr;
|
||||
|
||||
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
|
||||
address >= EEPROM_DATA_START_ADDRESS; address -= SIZE_U32) {
|
||||
// 安全读取Flash数据
|
||||
volatile u32 *flash_ptr = (volatile u32 *)address;
|
||||
data_read = *flash_ptr;
|
||||
|
||||
if ((data_read & DATA_ADDR_MASK) == (u32)virtualAddr) { // 虚拟地址相同
|
||||
if ((data_read & DATA_U16_MASK) ==
|
||||
(data & DATA_U16_MASK)) { // 数据相同
|
||||
#if EEPDEBUG
|
||||
data_read = data_read & DATA_U16_MASK;
|
||||
u16 float_data_read = *((u16 *)&data_read);
|
||||
printf("Found data in:0x%x=%u\r\n", address, data_read);
|
||||
#endif
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历Flash页面寻找下一个可写入位置
|
||||
for (u32 address = EEPROM_DATA_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 data_word = ((u32)data << 16) | (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 { // 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
if (status == FLASH_EEPROM_OK) {
|
||||
return status;
|
||||
} else {
|
||||
return FLASH_EEPROM_ERASE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向Flash EEPROM写入float数据
|
||||
* @param virtualAddr: 虚拟地址
|
||||
* @param data: 要写入的数据
|
||||
* @retval FlashEepromStatus: 操作状态
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
|
||||
// 查找下一个可写入的位置
|
||||
u32 next_address = EEPROM_START_ADDRESS;
|
||||
u32 data_word;
|
||||
|
||||
// 将完整的float数据复制到32位变量中
|
||||
memcpy(&data_word, &data, SIZE_FLOAT);
|
||||
// 插入虚拟地址到低8位 格式: [data:24bit][addr:8bit]
|
||||
data_word = (data_word & DATA_FLOAT_MASK) | (u32)virtualAddr;
|
||||
|
||||
// 从Flash末尾开始向前搜索,找到最新的数据
|
||||
for (u32 address = EEPROM_END_ADDRESS - SIZE_U32;
|
||||
address >= EEPROM_DATA_START_ADDRESS; address -= SIZE_U32) {
|
||||
// 安全读取Flash数据
|
||||
volatile u32 *flash_ptr = (volatile u32 *)address;
|
||||
u32 data_word_read = *flash_ptr;
|
||||
|
||||
if ((data_word_read & DATA_ADDR_MASK) ==
|
||||
(u32)virtualAddr) { // 虚拟地址相同
|
||||
if ((data_word_read & DATA_FLOAT_MASK) ==
|
||||
(data_word & DATA_FLOAT_MASK)) { // 数据相同
|
||||
#if EEPDEBUG
|
||||
data_word_read = data_word_read & DATA_FLOAT_MASK;
|
||||
float float_data_read = *((float *)&data_word_read);
|
||||
printf("Found data in:0x%x=%f\r\n", address, float_data_read);
|
||||
#endif
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
break; // 找到相同地址但数据不同,需要更新
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历Flash页面寻找下一个可写入位置
|
||||
for (u32 address = EEPROM_DATA_START_ADDRESS; address < EEPROM_END_ADDRESS;
|
||||
address += SIZE_U32) {
|
||||
// 安全读取Flash数据
|
||||
volatile u32 *flash_ptr = (volatile u32 *)address;
|
||||
u32 data_word_read = *flash_ptr;
|
||||
// 找到空位置
|
||||
if (data_word_read == 0xFFFFFFFF) {
|
||||
next_address = address;
|
||||
break;
|
||||
}
|
||||
// 更新下一个可能的写入位置(如果需要格式化)
|
||||
next_address = address + SIZE_U32;
|
||||
}
|
||||
|
||||
// 如果有足够空间,直接写入
|
||||
if (next_address < EEPROM_END_ADDRESS) {
|
||||
// 使用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 EEPDEBUG
|
||||
u32 data_word_c = *((u32 *)next_address);
|
||||
data_word_c = data_word_c & DATA_FLOAT_MASK;
|
||||
float float_data = *((float *)&data_word_c);
|
||||
printf("save:0x%x=%f\r\n", next_address, float_data);
|
||||
#endif
|
||||
if (fmc_status != FMC_READY) {
|
||||
return FLASH_EEPROM_WRITE_ERROR;
|
||||
}
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
// 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
if (status == FLASH_EEPROM_OK) {
|
||||
return status;
|
||||
} else {
|
||||
return FLASH_EEPROM_ERASE_ERROR;
|
||||
}
|
||||
}
|
||||
return 0; // 正常不会返回这个,未预料的异常情况返回
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,24 +57,11 @@ FlashEepromStatus FlashEEPROM::format() {
|
||||
return FLASH_EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取角度数据从Flash
|
||||
* @return float: 角度数据
|
||||
*/
|
||||
float FlashEEPROM::read_angle() {
|
||||
float angle = DEFAULT_VALUE;
|
||||
if (readFloat(ADDR_ANGLE, &angle) != FLASH_EEPROM_OK) {
|
||||
angle = DEFAULT_VALUE;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 保存CRC数据到Flash
|
||||
* @param saved: 是否一次性保存
|
||||
* @return FlashEepromStatus: 状态
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
|
||||
FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM) {
|
||||
static u32 next_address;
|
||||
// 遍历Flash页面寻找下一个可写入crc的位置
|
||||
for (u32 address = EEPROM_DATA_START_ADDRESS - SIZE_U32;
|
||||
@@ -426,24 +95,11 @@ FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
|
||||
EEPROMStatus = fmc_status;
|
||||
return FLASH_EEPROM_WRITE_ERROR;
|
||||
}
|
||||
} else {
|
||||
// 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
if (status == FLASH_EEPROM_OK) {
|
||||
return status;
|
||||
} else {
|
||||
EEPROMStatus = FLASH_EEPROM_ERASE_ERROR;
|
||||
return FLASH_EEPROM_ERASE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重新读取CRC校验
|
||||
if (CRC_NUM == *((u32 *)next_address)) {
|
||||
system_config_saved = saved; // 标记已保存过
|
||||
EEPROMStatus = FLASH_EEPROM_OK; // 设置EEPROM状态
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
|
||||
+2
-30
@@ -2,8 +2,6 @@
|
||||
#define __FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
// 修改后 - 强制4字节对齐
|
||||
#define ALIGN_4BYTE(addr) ((addr) & 0xFFFFFFFC) // 4字节对齐
|
||||
|
||||
// EEPROM操作状态
|
||||
typedef enum {
|
||||
@@ -26,21 +24,8 @@ class FlashEEPROM {
|
||||
static constexpr u32 EEPROM_END_ADDRESS = 0x08020000; // Flash结束地址
|
||||
static constexpr u32 EEPROM_MAX_SIZE = 0x800; // EEPROM最大容量
|
||||
static constexpr u32 EEPROM_DATA_START_ADDRESS =
|
||||
0x0801F900; // DATA段开始地址
|
||||
static constexpr u32 DATA_FLOAT_MASK = 0xFFFFFF00; // float存储地址掩码
|
||||
static constexpr u32 DATA_U16_MASK = 0xFFFF0000; // u16存储地址掩码
|
||||
static constexpr u32 DATA_ADDR_MASK = 0x000000FF; // 虚拟地址掩码
|
||||
0x0801F900; // DATA段开始地址
|
||||
|
||||
// 定义用户自定义的虚拟地址
|
||||
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_VEL_LIMIT = 0x05; // 角度数据存储地址
|
||||
|
||||
bool angle_saved = false;
|
||||
bool system_config_saved = false;
|
||||
u8 EEPROMStatus;
|
||||
// 构造函数
|
||||
FlashEEPROM();
|
||||
@@ -48,24 +33,11 @@ class FlashEEPROM {
|
||||
// 初始化Flash EEPROM模拟
|
||||
u8 init();
|
||||
|
||||
// 从Flash EEPROM中读取数据
|
||||
FlashEepromStatus read(u8 virtualAddr, u16 *data) const;
|
||||
// 向Flash EEPROM写入数据
|
||||
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();
|
||||
|
||||
u8 read_saved_system_config(void);
|
||||
float read_angle();
|
||||
FlashEepromStatus writeCRC(u32 CRC_NUM);
|
||||
|
||||
private:
|
||||
FlashEepromStatus writeCRC(u32 CRC_NUM, bool saved);
|
||||
};
|
||||
|
||||
void flash_eeprom_example_main(void);
|
||||
#endif /* __FLASH_H */
|
||||
@@ -1,103 +0,0 @@
|
||||
#include "health.h"
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern sampler sampler;
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
extern FOC_Controlroller FOC;
|
||||
extern FlashEEPROM flashEEP;
|
||||
ThermalController thermalController; // 热量控制器初始化
|
||||
|
||||
#define max(a, b, c) \
|
||||
((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))
|
||||
constexpr u16 PROTECT_TIME = 6000; // 过热保护时间,单位*10ms
|
||||
/**
|
||||
** @brief 热能计算
|
||||
** @param None
|
||||
** @retval 热量值
|
||||
*/
|
||||
u32 ThermalController::update() {
|
||||
thermal_value = Q16_16_MUL(thermal_value, thermalRate);
|
||||
// 添加温度积累
|
||||
int drv_temp = (int)sampler.get_drv_temp();
|
||||
int mcu_temp = (int)sampler.get_mcu_temp();
|
||||
if (drv_temp == 255)
|
||||
drv_temp = 0;
|
||||
if (mcu_temp == 255)
|
||||
mcu_temp = 0;
|
||||
thermal_value += drv_temp * drv_temp + mcu_temp * mcu_temp;
|
||||
|
||||
if (remainingTime10Ms) {
|
||||
// 过热停机状态
|
||||
// 检查是否可以恢复
|
||||
q16_16_t recovery_threshold =
|
||||
Q16_16_MUL(thermal_capacity, recoveryRate);
|
||||
if (thermal_value < recovery_threshold) {
|
||||
remainingTime10Ms = 1; // 可以恢复工作
|
||||
}
|
||||
if (remainingTime10Ms == 1) { // 过热恢复
|
||||
FOC.resume();
|
||||
CAN0_transmiter.ThermalStatus = 0;
|
||||
return --remainingTime10Ms;
|
||||
}
|
||||
return --remainingTime10Ms;
|
||||
} else {
|
||||
// 当前没有过热停机
|
||||
// 添加电流热积累
|
||||
u32 currents[3] = {(u32)(sampler.get_current('U') * 1000),
|
||||
(u32)(sampler.get_current('V') * 1000),
|
||||
(u32)(sampler.get_current('W') * 1000)};
|
||||
|
||||
// 找最大电流(原始ADC值)
|
||||
current_max = max(currents[0], currents[1], currents[2]);
|
||||
if (current_max < 2000) {
|
||||
thermal_value += current_max * current_max * gapTimeMs *
|
||||
0.00007f; // 计算当前电流热积累值
|
||||
} else if (current_max > 3800) {
|
||||
thermal_value += current_max * current_max * gapTimeMs *
|
||||
0.01f; // 添加当前电流热积累值
|
||||
} else if (current_max > 3400) {
|
||||
thermal_value += current_max * current_max * gapTimeMs *
|
||||
0.005f; // 计算当前电流热积累值
|
||||
} else if (current_max > 3000) {
|
||||
thermal_value += current_max * current_max * gapTimeMs *
|
||||
0.0002f; // 计算当前电流热积累值
|
||||
} else if (current_max > 2000) {
|
||||
thermal_value += current_max * current_max * gapTimeMs *
|
||||
0.0001f; // 计算当前电流热积累值
|
||||
}
|
||||
}
|
||||
|
||||
if (thermal_value > thermal_capacity) {
|
||||
FOC.shut_down();
|
||||
remainingTime10Ms = PROTECT_TIME; // 过热停机
|
||||
CAN0_transmiter.ThermalStatus = 1;
|
||||
return remainingTime10Ms;
|
||||
}
|
||||
return thermal_value;
|
||||
}
|
||||
/**
|
||||
** @brief 温度检测
|
||||
** @param None
|
||||
*/
|
||||
void angsens_MG_check(void) {
|
||||
bool MGH = gpio_input_bit_get(GPIOB, GPIO_PIN_10);
|
||||
bool MGL = gpio_input_bit_get(GPIOB, GPIO_PIN_11);
|
||||
CAN0_transmiter.MagStatus = MGH or MGL;
|
||||
}
|
||||
|
||||
void power_manage(void) {
|
||||
float last_vbus = sampler.get_vbus_voltage();
|
||||
sampler.update_vbus_voltage();
|
||||
FOC.update_power();
|
||||
float vbus = sampler.get_vbus_voltage();
|
||||
if ((vbus < 22.0f) and (last_vbus > vbus) and vbus > 8.0f) {
|
||||
FOC.shut_down();
|
||||
flashEEP.save_system_config(true);
|
||||
} else {
|
||||
FOC.resume();
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef _HEALTH_H
|
||||
#define _HEALTH_H
|
||||
|
||||
#include "stdint.h"
|
||||
typedef int32_t q16_16_t; // Q16.16格式
|
||||
// 定点数运算宏
|
||||
#define Q16_16_ONE 65536 // 1.0 in Q16.16
|
||||
#define FLOAT_TO_Q16_16(x) ((q16_16_t)((x) * Q16_16_ONE))
|
||||
#define Q16_16_TO_FLOAT(x) ((float)(x) / Q16_16_ONE)
|
||||
#define Q16_16_MUL(a, b) ((q16_16_t)(((int64_t)(a) * (b)) >> 16))
|
||||
#define Q16_16_SQUARE(x) Q16_16_MUL((x), (x))
|
||||
|
||||
class ThermalController {
|
||||
private:
|
||||
u8 temperature;
|
||||
u16 current_max;
|
||||
|
||||
q16_16_t thermalRate; // 热耗散系数(每单位时间散热比例)
|
||||
q16_16_t recoveryRate; // 自然恢复率(散热到多少以下开始工作)
|
||||
|
||||
u32 thermal_value = 0;
|
||||
u32 thermal_capacity = 3600000; // 热容量
|
||||
|
||||
u16 gapTimeMs = 10; // 单次计算间隔ms
|
||||
u16 remainingTime10Ms = 0; // 过热冷却剩余ms
|
||||
public:
|
||||
ThermalController()
|
||||
: thermalRate(FLOAT_TO_Q16_16(0.995f)),
|
||||
recoveryRate(FLOAT_TO_Q16_16(0.33f)) {}
|
||||
u32 update();
|
||||
void reset() {
|
||||
thermal_value = 0;
|
||||
remainingTime10Ms = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void angsens_MG_check(void);
|
||||
void power_manage(void);
|
||||
|
||||
#endif
|
||||
@@ -12,21 +12,6 @@ u8 USART0_init() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the watchdog peripheral
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
u8 watchdog_init(u32 time) {
|
||||
u8 status = 0;
|
||||
/* configure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz */
|
||||
/* time = reload_value / clock_frequency */
|
||||
status = fwdgt_config(time * 0.625, FWDGT_PSC_DIV64);
|
||||
fwdgt_enable();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int fputc(int ch, FILE *f) throw() {
|
||||
usart_data_transmit(EVAL_COM0, (uint8_t)ch);
|
||||
@@ -48,46 +33,4 @@ void unused_pin_init() {
|
||||
gpio_bit_reset(GPIOA, GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
|
||||
gpio_bit_reset(GPIOB, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15);
|
||||
gpio_bit_reset(GPIOC, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 检测并打印复位源信息
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
u16 get_reset_cause(void) {
|
||||
u16 cause = 0;
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_FWDGTRST)) {
|
||||
// printf("Free Watchdog Timer Reset\r\n");
|
||||
cause = RCU_FLAG_FWDGTRST;
|
||||
}
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_EPRST)) {
|
||||
// printf("External Pin Reset\r\n");
|
||||
cause = RCU_FLAG_EPRST;
|
||||
}
|
||||
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_PORRST)) {
|
||||
// printf("Power Reset\r\n");
|
||||
cause = RCU_FLAG_PORRST;
|
||||
}
|
||||
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_WWDGTRST)) {
|
||||
// printf("Window Watchdog Timer Reset\r\n");
|
||||
cause = RCU_FLAG_WWDGTRST;
|
||||
}
|
||||
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_LPRST)) {
|
||||
// printf("Low Power Reset\r\n");
|
||||
cause = RCU_FLAG_LPRST;
|
||||
}
|
||||
|
||||
if (RESET != rcu_flag_get(RCU_FLAG_SWRST)) {
|
||||
// printf("Software Reset\r\n");
|
||||
cause = RCU_FLAG_SWRST;
|
||||
}
|
||||
// 清除所有复位标志
|
||||
rcu_all_reset_flag_clear();
|
||||
// printf("cause:%d\r\n", cause);
|
||||
return cause;
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,9 @@ extern "C" {
|
||||
#include "stdint.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
constexpr u16 REDUCTION_RATIO = 25;
|
||||
constexpr float DEG2RAD = 1.0f / 360.0f * 6.28318530718f;
|
||||
constexpr float RAD2DEG = 360.0f / 6.28318530718f;
|
||||
|
||||
void rcu_config(void);
|
||||
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
|
||||
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
|
||||
int fputc(int ch, FILE *f); // 声明fputc函数以重载标准库实现
|
||||
|
||||
u8 USART0_init(void);
|
||||
u8 watchdog_init(u32 time);
|
||||
u16 get_reset_cause(void);
|
||||
void unused_pin_init();
|
||||
|
||||
|
||||
@@ -48,10 +48,6 @@ void delay_1ms(uint32_t count);
|
||||
void delay_1s(uint32_t count);
|
||||
/* delay decrement */
|
||||
void delay_decrement(void);
|
||||
/* 空闲任务计数 */
|
||||
void idle_task_count(void);
|
||||
/* 获取CPU使用率 */
|
||||
uint8_t get_cpu_usage(void);
|
||||
/* 系统软复位 */
|
||||
void system_soft_reset(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user