更新OTA功能,config独立成文件统一定义
refactor(build): 更新项目配置和链接器设置 - 修改GD32C103CB的ROM基地址和大小配置 - 更新系统时钟向量表偏移量设置 - 在cproject.yml中添加BIN输出格式支持 - 增加-O3优化级别和代码移除选项 - 更新csolution版本依赖 feat(device): 优化ADC采样和配置管理 - 将DengFOC依赖替换为FOC模块 - 从config.h引入配置常量 - 重命名FILTER_SIZE为ADC_FILTER_SIZE以提高清晰度 - 优化温度和电流采样滤波实现 refactor(algorithm): 简化FOC控制函数接口 - 为angle_control、velocity_control等函数移除不必要的参数 - 统一函数指针类型定义 - 优化电流计算函数的代码格式 - 调整PID控制器初始化参数
This commit is contained in:
@@ -1,26 +1,15 @@
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "Can.h"
|
||||
#include "Timer.h"
|
||||
#include "adc.h"
|
||||
#include "ang_sensor.h"
|
||||
#include "initial.h"
|
||||
#include "config.h"
|
||||
#include "motor.h"
|
||||
#include "pid.h"
|
||||
#include <cmath>
|
||||
#include <gd32c10x.h>
|
||||
#include <stdint.h>
|
||||
#include "motor.h"
|
||||
|
||||
constexpr double PI = 3.1415926535897932384626433832795f;
|
||||
constexpr float ANGLE_FACTOR = 25.0f / 360.0f * 2.0f * 3.14159265358979323846f;
|
||||
constexpr float _1_SQRT3 = 0.57735026919f;
|
||||
constexpr float _2_SQRT3 = 1.15470053838f;
|
||||
constexpr float _3PI_2 = 4.71238898038f;
|
||||
constexpr u8 PP = 11;
|
||||
constexpr float DIR = 1.0;
|
||||
constexpr float sqrt3 = 1.73205080757f; // sqrt(3)的预计算值
|
||||
constexpr float sqrt3dv2 = 0.86602540378f; // sqrt(3)/2的预计算值
|
||||
constexpr float zero_electric_angle = 0.0f;
|
||||
constexpr u16 LUT_SCALE = (LUT_SIZE / (2.0f * PI));
|
||||
|
||||
FOC_Controlroller FOC; // FOC控制初始化
|
||||
extern sampler sampler;
|
||||
@@ -62,7 +51,7 @@ inline float FOC_Controlroller::cal_Iq_Id(float current_a, float current_b,
|
||||
sin_el = sin_lut[(u16)(angle_el * LUT_SCALE) & LUT_MASK];
|
||||
float I_q = I_beta * cos_el - I_alpha * sin_el;
|
||||
|
||||
return I_q*1000.0f; // 返回Iq值,乘以1000以转换为mA
|
||||
return I_q * 1000.0f; // 返回Iq值,乘以1000以转换为mA
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,13 +112,15 @@ void FOC_Controlroller::drv_stop() { Set_3Pwm(0.0f, 0.0f, 0.0f); }
|
||||
/**
|
||||
* @brief 电机锁止
|
||||
*/
|
||||
void FOC_Controlroller::drv_hold(float duty) {
|
||||
if (duty > 0.95f) {
|
||||
duty = 0.95f;
|
||||
} else if (duty < 0.0f) {
|
||||
duty = 0.0f;
|
||||
float FOC_Controlroller::drv_hold() {
|
||||
float hold_pwm_duty = HOLD_PWM_DUTY;
|
||||
if (HOLD_PWM_DUTY > 0.95f) {
|
||||
hold_pwm_duty = 0.95f;
|
||||
} else if (HOLD_PWM_DUTY < 0.0f) {
|
||||
hold_pwm_duty = 0.0f;
|
||||
}
|
||||
Set_3Pwm(duty, duty, duty);
|
||||
Set_3Pwm(hold_pwm_duty, hold_pwm_duty, hold_pwm_duty);
|
||||
return hold_pwm_duty;
|
||||
}
|
||||
/**
|
||||
* @brief 电机恢复
|
||||
@@ -173,7 +164,8 @@ float FOC_Controlroller::velocity_open_loop() {
|
||||
|
||||
setPhaseVoltage(Uq, 0.0f);
|
||||
// CAN0_transmiter.testfloat_union.f =
|
||||
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'), sampler.get_current('W'));
|
||||
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
|
||||
return limit_voltage;
|
||||
}
|
||||
@@ -198,7 +190,7 @@ float FOC_Controlroller::velocity_open_loop() {
|
||||
* @param target_angle: 目标角度
|
||||
* @return float: 当前角度
|
||||
*/
|
||||
float FOC_Controlroller::angle_control(float target_angle) {
|
||||
float FOC_Controlroller::angle_control() {
|
||||
// PID 控制计算
|
||||
float Uq = angle_loop(target_angle - rt_angle);
|
||||
|
||||
@@ -216,45 +208,27 @@ float FOC_Controlroller::angle_control(float target_angle) {
|
||||
* @param max_velocity: 最大速度限制 (单位: rad/s)
|
||||
* @return float: 当前角度
|
||||
*/
|
||||
float FOC_Controlroller::angle_control_with_velocity_limit(float target_angle) {
|
||||
float FOC_Controlroller::angle_control_with_velocity_limit() {
|
||||
// 计算角度误差
|
||||
float angle_error = target_angle - rt_angle;
|
||||
|
||||
|
||||
// 使用角度PID控制器计算目标速度
|
||||
float target_velocity = ang_inVelAngloop(angle_error);
|
||||
|
||||
|
||||
// 对目标速度进行限幅
|
||||
target_velocity = _constrain(target_velocity, -limit_velocity, limit_velocity);
|
||||
|
||||
target_velocity =
|
||||
_constrain(target_velocity, -limit_velocity, limit_velocity);
|
||||
|
||||
// 使用速度PID控制器计算最终输出电压
|
||||
float Uq = vel_inVelAngloop(target_velocity - rt_velocity);
|
||||
// CAN0_transmiter.testfloat_union.f = target_velocity - rt_velocity;
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
|
||||
|
||||
// 设置相电压
|
||||
setPhaseVoltage(Uq, 0.0f);
|
||||
|
||||
return shaft_angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 角度闭环控制
|
||||
*
|
||||
* @param target_angle: 目标角度
|
||||
* @return float: 当前角度
|
||||
*/
|
||||
float FOC_Controlroller::angle_control_NPID(float target_angle) {
|
||||
static float Kp = 20.0f;
|
||||
// 控制力矩计算
|
||||
float Uq = _constrain(Kp * (target_angle - rt_angle), -voltage_power_supply,
|
||||
voltage_power_supply);
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
|
||||
|
||||
// 设置相电压
|
||||
setPhaseVoltage(Uq, 0.0f);
|
||||
|
||||
return shaft_angle;
|
||||
}
|
||||
|
||||
@@ -264,22 +238,24 @@ float FOC_Controlroller::angle_control_NPID(float target_angle) {
|
||||
* @param target_velocity: 目标速度
|
||||
* @return float: 当前速度
|
||||
*/
|
||||
float FOC_Controlroller::velocity_control(float target_velocity) {
|
||||
float FOC_Controlroller::velocity_control() {
|
||||
// PID 控制计算
|
||||
float Uq = vel_loop((target_velocity - rt_velocity)*25);
|
||||
float Uq = vel_loop((target_velocity - rt_velocity) * 25);
|
||||
|
||||
// 获取电机轴角度
|
||||
shaft_angle = KTH7823.getcurrent_sensorangle() * DEG2RAD;
|
||||
// 设置相电压
|
||||
setPhaseVoltage(Uq, 0.0f);
|
||||
// CAN0_transmiter.testfloat_union.f =
|
||||
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'), sampler.get_current('W'));
|
||||
cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
return rt_velocity;
|
||||
}
|
||||
|
||||
float FOC_Controlroller::current_control(float target_current) {
|
||||
float FOC_Controlroller::current_control() {
|
||||
// PID 控制计算
|
||||
float Iq = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'), sampler.get_current('W'));
|
||||
float Iq = cal_Iq_Id(sampler.get_current('U'), sampler.get_current('V'),
|
||||
sampler.get_current('W'));
|
||||
float Uq = current_loop(target_current - Iq);
|
||||
CAN0_transmiter.testfloat_union.f = Iq;
|
||||
// 获取电机轴角度
|
||||
@@ -1,6 +1,7 @@
|
||||
// 函数声明
|
||||
#ifndef _DENGFOC_H
|
||||
#define _DENGFOC_H
|
||||
#ifndef _FOC_H
|
||||
#define _FOC_H
|
||||
#include "config.h"
|
||||
#include "pid.h"
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -14,6 +15,7 @@ class FOC_Controlroller {
|
||||
float limit_velocity = 0.0f;
|
||||
float target_angle = 0.0f;
|
||||
float target_velocity = 0.0f;
|
||||
float target_current = 0.0f;
|
||||
float rt_angle = 0.0f;
|
||||
float rt_velocity = 0.0f;
|
||||
bool over_current = false;
|
||||
@@ -23,19 +25,18 @@ class FOC_Controlroller {
|
||||
float v_safe = voltage_power_supply * 1.05f;
|
||||
float duty_a = 0, duty_b = 0, duty_c = 0;
|
||||
float Ua = 0, Ub = 0, Uc = 0;
|
||||
float velocity_open_loop();
|
||||
float angle_control(float target_angle);
|
||||
float angle_control_with_velocity_limit(float target_angle);
|
||||
float velocity_control(float target_velocity);
|
||||
float current_control(float target_current);
|
||||
float angle_control_NPID(float target_angle);
|
||||
float velocity_open_loop(void);
|
||||
float angle_control(void);
|
||||
float angle_control_with_velocity_limit(void);
|
||||
float velocity_control(void);
|
||||
float current_control(void);
|
||||
|
||||
void update_power(void);
|
||||
void DFOC_alignSensor(int _PP);
|
||||
void shut_down(void);
|
||||
void resume(void);
|
||||
void drv_stop(void);
|
||||
void drv_hold(float duty = 0.5f);
|
||||
float drv_hold(void);
|
||||
|
||||
protected:
|
||||
float shaft_angle = 0;
|
||||
@@ -50,7 +51,7 @@ class FOC_Controlroller {
|
||||
PIDController current_loop =
|
||||
PIDController{0.006f, 0.02f, 0, 100000, voltage_power_supply}; // 12V
|
||||
PIDController vel_inVelAngloop =
|
||||
PIDController{0.35f, 5.0f,1e-3, 1000000, voltage_power_supply};
|
||||
PIDController{0.35f, 5.0f, 1e-3, 1000000, voltage_power_supply};
|
||||
PIDController ang_inVelAngloop =
|
||||
PIDController{30.0f, 0.0f, 1e-3, 1000000, 999};
|
||||
|
||||
@@ -58,12 +59,12 @@ class FOC_Controlroller {
|
||||
float cal_Iq_Id(float current_a, float current_b, float current_c);
|
||||
};
|
||||
|
||||
// 定义函数指针类型
|
||||
typedef float (FOC_Controlroller::*FOCFunctionPtr)(void);
|
||||
|
||||
float _normalizeAngle(float angle);
|
||||
inline float _electricalAngle();
|
||||
|
||||
constexpr u16 LUT_SIZE = 1024;
|
||||
constexpr u16 LUT_MASK = (LUT_SIZE - 1);
|
||||
|
||||
__attribute__((aligned(4))) const float sin_lut[LUT_SIZE] = {
|
||||
0.000000f, 0.006136f, 0.012272f, 0.018407f, 0.024541f, 0.030675f,
|
||||
0.036807f, 0.042938f, 0.049068f, 0.055195f, 0.061321f, 0.067444f,
|
||||
@@ -4,14 +4,13 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
extern angle_sensor KTH7823;
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
extern u32 system_runtime_us;
|
||||
EncoderAngleKalman Angle_kalman(0, 1.0f, 1e-4f, 0.25f);
|
||||
EncoderVelocityKalman Vel_kalman(0, 1e-5f, 1e-6f, 0.02f);
|
||||
|
||||
constexpr u8 SIZE_FLOAT = sizeof(float);
|
||||
|
||||
/*!
|
||||
\brief 中值滤波器函数
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
LR_ROM0 __ROM0_BASE __ROM0_SIZE {
|
||||
|
||||
ER_ROM0 __ROM0_BASE __ROM0_SIZE {
|
||||
*.o (RESET, +First)
|
||||
*.o (RESET, +First) /* 向量表和复位处理程序 */
|
||||
*(.text.init) /* 确保系统初始化代码在最前面 */
|
||||
*(InRoot$$Sections)
|
||||
*(+RO +XO)
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
// <o> Base address <0x0-0xFFFFFFFF:8>
|
||||
// <i> Defines base address of memory region. Default: 0x08000000
|
||||
// <i> Contains Startup and Vector Table
|
||||
#define __ROM0_BASE 0x08000000
|
||||
#define __ROM0_BASE 0x08011000
|
||||
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
|
||||
// <i> Defines size of memory region. Default: 0x00020000
|
||||
#define __ROM0_SIZE 0x00020000
|
||||
#define __ROM0_SIZE 0x0000C000
|
||||
// </h>
|
||||
|
||||
// <h> __ROM1 (unused)
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
|
||||
|
||||
/* Vector Table base offset */
|
||||
#define VECT_TAB_OFFSET 0x00 /* This value must be a multiple of 0x200. */
|
||||
#define APP_BASE ((uint32_t)0x08011000U) /*!< main FLASH base address */
|
||||
#define VECT_TAB_OFFSET (uint32_t)APP_BASE-FLASH_BASE /* This value must be a multiple of 0x200. */
|
||||
|
||||
/* select a system clock by uncommenting the following line */
|
||||
/* use IRC8M */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CSOLUTION generated file: DO NOT EDIT!
|
||||
* Generated by: csolution version 2.11.0
|
||||
* Generated by: csolution version 2.12.0+p41-gfeadfc5e
|
||||
*
|
||||
* Project: 'Robot_V2.Debug+GD32C103CB'
|
||||
* Target: 'Debug+GD32C103CB'
|
||||
@@ -17,8 +17,12 @@
|
||||
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:ADC@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_ADC
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:BKP@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_BKP
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:CAN@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_CAN
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:CRC@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_CRC
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:DBG@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_DBG
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:DMA@1.0.0 */
|
||||
@@ -37,6 +41,8 @@
|
||||
#define RTE_DEVICE_STDPERIPHERALS_PMU
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:RCU@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_RCU
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:RTC@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_RTC
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:SPI_I2S@1.0.0 */
|
||||
#define RTE_DEVICE_STDPERIPHERALS_SPI
|
||||
/* GigaDevice::Device:GD32C10x_StdPeripherals:TIMER@1.0.0 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CSOLUTION generated file: DO NOT EDIT!
|
||||
* Generated by: csolution version 2.12.0
|
||||
* Generated by: csolution version 2.12.0+p41-gfeadfc5e
|
||||
*
|
||||
* Project: 'Robot_V2.Release+GD32C103CB'
|
||||
* Target: 'Release+GD32C103CB'
|
||||
|
||||
@@ -14,6 +14,7 @@ project:
|
||||
- file: sys/health.cpp
|
||||
- file: sys/flash.h
|
||||
- file: sys/flash.cpp
|
||||
- file: sys/config.h
|
||||
- group: device
|
||||
files:
|
||||
- file: device/Can.cpp
|
||||
@@ -31,18 +32,20 @@ project:
|
||||
files:
|
||||
- file: Algorithm/Filter.cpp
|
||||
- file: Algorithm/Filter.h
|
||||
- file: Algorithm/DengFOC.cpp
|
||||
- file: Algorithm/DengFOC.h
|
||||
- file: Algorithm/FOC.cpp
|
||||
- file: Algorithm/FOC.h
|
||||
- file: Algorithm/pid.cpp
|
||||
- file: Algorithm/pid.h
|
||||
components:
|
||||
- component: ARM::CMSIS:CORE
|
||||
- component: Device:Startup
|
||||
- component: Device:EVAL:GD32C10x
|
||||
- component: Device:GD32C10x_libopt
|
||||
- component: Device:GD32C10x_StdPeripherals:FMC
|
||||
- component: Device:GD32C10x_StdPeripherals:ADC
|
||||
- component: Device:GD32C10x_StdPeripherals:CAN
|
||||
- component: Device:GD32C10x_StdPeripherals:DMA
|
||||
- component: Device:GD32C10x_StdPeripherals:EXTI
|
||||
- component: Device:GD32C10x_StdPeripherals:FMC
|
||||
- component: Device:GD32C10x_StdPeripherals:GPIO
|
||||
- component: Device:GD32C10x_StdPeripherals:MISC
|
||||
- component: Device:GD32C10x_StdPeripherals:PMU
|
||||
@@ -50,9 +53,7 @@ project:
|
||||
- component: Device:GD32C10x_StdPeripherals:SPI_I2S
|
||||
- component: Device:GD32C10x_StdPeripherals:TIMER
|
||||
- component: Device:GD32C10x_StdPeripherals:USART
|
||||
- component: Device:GD32C10x_libopt
|
||||
- component: Device:GD32C10x_StdPeripherals:DBG
|
||||
- component: Device:EVAL:GD32C10x
|
||||
- component: Device:GD32C10x_StdPeripherals:FWDGT
|
||||
- component: Device:GD32C10x_StdPeripherals:WWDGT
|
||||
- component: Device:GD32C10x_StdPeripherals:BKP
|
||||
@@ -62,6 +63,7 @@ project:
|
||||
type:
|
||||
- elf
|
||||
- hex
|
||||
- bin
|
||||
- map
|
||||
packs:
|
||||
- pack: ARM::CMSIS
|
||||
@@ -73,11 +75,14 @@ project:
|
||||
- -fshort-wchar
|
||||
- -D__MICROLIB
|
||||
- -Wno-register
|
||||
- -O3 # 添加优化级别
|
||||
C:
|
||||
- -D__packed=packed
|
||||
- -D__packed=__attribute__((packed))
|
||||
ASM:
|
||||
- -D__packed=packed
|
||||
- -D__packed=__attribute__((packed))
|
||||
- -D__MICROLIB
|
||||
Link:
|
||||
- --library_type=microlib
|
||||
- --entry=Reset_Handler
|
||||
- --remove # 移除未使用的代码段
|
||||
- --diag_suppress=L6207,L6210,L6218,L6220,L6222,L6224,L6226,L6228,L6230,L6232,L6234,L6236,L6238,L6240,L6242,L6244,L6246,L6248,L6308,L6329,L6310,L6312,L6314,L6316,L6318,L6320,L6322,L6324,L6326,L6328,L6330,L6332,L6334,L6336,L6338,L6340,L6342,L6344,L6346,L6348,L6350,L6352,L6354,L6311,L6313,L6315,L6317,L6319,L6321,L6323,L6325,L6327,L6329,L6331,L6333,L6335,L6337,L6339,L6341,L6343,L6345,L6347,L6349,L6351,L6353
|
||||
|
||||
+20
-27
@@ -1,29 +1,22 @@
|
||||
#include "adc.h"
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "Filter.h"
|
||||
#include "config.h"
|
||||
#include "math.h"
|
||||
#include "systick.h"
|
||||
#include <cstring>
|
||||
#include <gd32c10x_dma.h>
|
||||
#include <stdint.h>
|
||||
#include "systick.h"
|
||||
|
||||
constexpr float ERROR_ADC_VAL = 255.0f;
|
||||
constexpr float ADC_SCALE = 3.3f / 4096.0f;
|
||||
constexpr float TEMP_FACTOR = 1000.0f / 4.3f;
|
||||
constexpr float VCC_FACTOR = 11.0f;
|
||||
constexpr float CURRENT_OFFSET = -1.60f;
|
||||
constexpr float CURRENT_FACTOR =
|
||||
1.0f / 50.0f * 100.0f; // 50倍放大,100倍电流采样电阻, 单位mA
|
||||
constexpr float MAX_TEMP = 150.0f;
|
||||
constexpr float MIN_TEMP = -40.0f;
|
||||
constexpr float MAX_CURRENT = 40.0f;
|
||||
constexpr float MIN_CURRENT = -40.0f;
|
||||
constexpr float MAX_VCC = 65.0f;
|
||||
constexpr float MIN_VCC = -0.1f;
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
extern FOC_Controlroller FOC;
|
||||
sampler sampler; // 采样器初始化
|
||||
sampler sampler; // 采样器初始化
|
||||
u16 adc_value[6] = {0}; // 显式初始化数组元素为0
|
||||
/*!
|
||||
\brief configure the DMA peripheral
|
||||
@@ -116,7 +109,7 @@ u8 sampler::init() {
|
||||
adc_config(); // ADC初始化
|
||||
delay_1ms(1);
|
||||
// 初始采样
|
||||
for (int i = 0; i < FILTER_SIZE + 1; i++) {
|
||||
for (int i = 0; i < ADC_FILTER_SIZE + 1; i++) {
|
||||
mcu_temp_samples[i] =
|
||||
(1.43f - adc_value[0] * ADC_SCALE) * TEMP_FACTOR + 35.0f;
|
||||
|
||||
@@ -142,7 +135,7 @@ u8 sampler::init() {
|
||||
* 温度值,单位为摄氏度,范围应在-40到145之间,如果读取失败则返回0.0f
|
||||
*/
|
||||
float sampler::get_mcu_temp() {
|
||||
tempora_sample = medium_filter(mcu_temp_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(mcu_temp_samples, ADC_FILTER_SIZE + 1);
|
||||
// 检查温度读数是否在有效范围内
|
||||
if (tempora_sample < MIN_TEMP or tempora_sample > MAX_TEMP) {
|
||||
return ERROR_ADC_VAL;
|
||||
@@ -158,7 +151,7 @@ float sampler::get_mcu_temp() {
|
||||
* 如果计算结果超出有效范围(-40到255摄氏度),则重新采样计算。
|
||||
*/
|
||||
float sampler::get_drv_temp() {
|
||||
tempora_sample = medium_filter(drv_temp_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(drv_temp_samples, ADC_FILTER_SIZE + 1);
|
||||
// 检查温度读数是否在有效范围内
|
||||
if (tempora_sample < MIN_TEMP || tempora_sample > MAX_TEMP) {
|
||||
return ERROR_ADC_VAL;
|
||||
@@ -177,17 +170,17 @@ float sampler::get_current(char type) {
|
||||
switch (type) {
|
||||
case 'U': {
|
||||
// return currU_samples[current_sample_index];
|
||||
tempora_sample = medium_filter(currU_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(currU_samples, ADC_FILTER_SIZE + 1);
|
||||
break;
|
||||
}
|
||||
case 'V': {
|
||||
// return currV_samples[current_sample_index];
|
||||
tempora_sample = medium_filter(currV_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(currV_samples, ADC_FILTER_SIZE + 1);
|
||||
break;
|
||||
}
|
||||
case 'W': {
|
||||
// return currW_samples[current_sample_index];
|
||||
tempora_sample = medium_filter(currW_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(currW_samples, ADC_FILTER_SIZE + 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -209,10 +202,10 @@ float sampler::get_current(char type) {
|
||||
* 如果计算结果超出有效范围(-40到255伏特),则重新采样计算。
|
||||
*/
|
||||
float sampler::get_vbus_voltage() {
|
||||
tempora_sample = medium_filter(vbus_samples, FILTER_SIZE + 1);
|
||||
tempora_sample = medium_filter(vbus_samples, ADC_FILTER_SIZE + 1);
|
||||
// 检查电压读数是否在有效范围内
|
||||
if (vbus_samples[FILTER_SIZE / 2] > MAX_VCC or
|
||||
vbus_samples[FILTER_SIZE / 2] < MIN_VCC) {
|
||||
if (vbus_samples[ADC_FILTER_SIZE / 2] > MAX_VCC or
|
||||
vbus_samples[ADC_FILTER_SIZE / 2] < MIN_VCC) {
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
return tempora_sample;
|
||||
@@ -226,8 +219,8 @@ float sampler::get_vbus_voltage() {
|
||||
*/
|
||||
void sampler::update_mcu_temp() {
|
||||
memmove(mcu_temp_samples, mcu_temp_samples + 1,
|
||||
FILTER_SIZE * sizeof(float));
|
||||
mcu_temp_samples[FILTER_SIZE] =
|
||||
ADC_FILTER_SIZE * sizeof(float));
|
||||
mcu_temp_samples[ADC_FILTER_SIZE] =
|
||||
(1.43f - adc_value[0] * ADC_SCALE) * TEMP_FACTOR + 35.0f;
|
||||
}
|
||||
|
||||
@@ -236,9 +229,9 @@ void sampler::update_mcu_temp() {
|
||||
*/
|
||||
void sampler::update_drv_temp() {
|
||||
memmove(drv_temp_samples, drv_temp_samples + 1,
|
||||
FILTER_SIZE * sizeof(float));
|
||||
ADC_FILTER_SIZE * sizeof(float));
|
||||
float R_now = (float)adc_value[1] / (4096 - (float)adc_value[1]) * 4700;
|
||||
drv_temp_samples[FILTER_SIZE] =
|
||||
drv_temp_samples[ADC_FILTER_SIZE] =
|
||||
1.0f / (0.00335f + 0.00025f * log(R_now / 10000.0f)) - 273.15f;
|
||||
}
|
||||
|
||||
@@ -258,7 +251,7 @@ void sampler::update_current() {
|
||||
|
||||
// 更新索引
|
||||
current_sample_index++;
|
||||
if (current_sample_index >= FILTER_SIZE - 1) {
|
||||
if (current_sample_index >= ADC_FILTER_SIZE - 1) {
|
||||
current_sample_index = 0;
|
||||
}
|
||||
// 卡尔曼滤波更新
|
||||
@@ -269,6 +262,6 @@ void sampler::update_current() {
|
||||
* @brief 更新供电电压
|
||||
*/
|
||||
void sampler::update_vbus_voltage() {
|
||||
memmove(vbus_samples, vbus_samples + 1, FILTER_SIZE * sizeof(float));
|
||||
vbus_samples[FILTER_SIZE] = adc_value[5] * ADC_SCALE * VCC_FACTOR;
|
||||
memmove(vbus_samples, vbus_samples + 1, ADC_FILTER_SIZE * sizeof(float));
|
||||
vbus_samples[ADC_FILTER_SIZE] = adc_value[5] * ADC_SCALE * VCC_FACTOR;
|
||||
}
|
||||
+182
-150
@@ -1,8 +1,9 @@
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "Filter.h"
|
||||
#include "adc.h"
|
||||
#include "ang_sensor.h"
|
||||
#include "config.h"
|
||||
#include "flash.h"
|
||||
#include "gd32c10x.h"
|
||||
#include "gd32c10x_can.h"
|
||||
@@ -19,10 +20,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
constexpr u16 CANX = CAN0;
|
||||
constexpr u16 DEV_CAN0_ID = 0x0000;
|
||||
constexpr u16 DEV_CAN0_MASK = 0x0000;
|
||||
constexpr u16 DEV_CAN_LOOPBACK_ID = 0x0000;
|
||||
constexpr float ANGLE_FACTOR = 25.0f / 360.0f * 2.0f * 3.14159265358979323846f;
|
||||
|
||||
CAN_transmiter CAN0_transmiter; // CAN初始化
|
||||
extern FOC_Controlroller FOC;
|
||||
@@ -157,8 +154,11 @@ void can_config(void) {
|
||||
|
||||
/* configure CAN0 NVIC */
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
|
||||
nvic_irq_enable(CAN0_TX_IRQn, 1, 1); // 添加发送中断
|
||||
/* enable can receive FIFO0 not empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
/* enable can transmit mailbox empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
|
||||
|
||||
// 使能DMA中断
|
||||
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 1);
|
||||
@@ -173,6 +173,7 @@ void can_config(void) {
|
||||
*/
|
||||
void canfd_config(void) {
|
||||
can_gpio_init();
|
||||
can_dma_init(); // 初始化DMA
|
||||
can_parameter_struct can_parameter;
|
||||
can_fdframe_struct can_fd_parameter;
|
||||
can_fd_tdc_struct can_fd_tdc_parameter;
|
||||
@@ -235,6 +236,9 @@ void canfd_config(void) {
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
|
||||
/* enable can receive FIFO0 not empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
// 使能DMA中断
|
||||
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 1);
|
||||
dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -458,128 +462,6 @@ void CAN_transmiter::update(void) {
|
||||
v_current_union.f = sampler.get_current('V') * 1000;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN 数据发送
|
||||
\param id CAN ID
|
||||
\param length 数据长度
|
||||
\param data 数据
|
||||
*/
|
||||
u8 CAN_transmiter::CAN_Send(u32 id, u8 length, u8 *data) {
|
||||
// 检查数据长度是否符合CAN规范
|
||||
if (length > 8) {
|
||||
printf("CAN data length exceeds maximum of 8 bytes\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_STANDARD; // 标准帧格式
|
||||
transmit_message.tx_sfid = id; // 设置帧ID
|
||||
transmit_message.tx_dlen = length; // 设置数据长度
|
||||
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < length && i < 8; i++) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
}
|
||||
|
||||
// 将数据复制到DMA缓冲区
|
||||
memcpy(can_tx_buffer, data, length);
|
||||
|
||||
// 配置DMA发送参数
|
||||
dma_tx_parameter.number = length;
|
||||
dma_init(DMA0, DMA_CH5, &dma_tx_parameter);
|
||||
|
||||
// 启动DMA传输
|
||||
dma_channel_enable(DMA0, DMA_CH5);
|
||||
|
||||
// 自动选择空闲mailbox发送消息,不需要人为指定
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (CAN_NOMAILBOX == transmit_mailbox) {
|
||||
// 没有可用的mailbox,可能所有mailbox都在使用中
|
||||
printf("No available mailbox for CAN transmission\r\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CANFD 数据发送
|
||||
\param id CAN消息ID
|
||||
\param length CAN消息长度
|
||||
\param data CAN消息数据
|
||||
*/
|
||||
u8 CAN_transmiter::CANFD_Send(u32 id, u8 length, u8 *data) {
|
||||
// 检查CANFD模式是否启用
|
||||
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
|
||||
printf("CANFD mode not enabled\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据长度是否符合CANFD规范
|
||||
if (length > 64) {
|
||||
printf("CANFD data length exceeds maximum of 64 bytes\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
|
||||
// transmit_message.tx_sfid = id; // 设置帧ID
|
||||
transmit_message.tx_efid = id; // 扩展帧ID
|
||||
transmit_message.tx_dlen = length; // 设置数据长度
|
||||
|
||||
// 设置CANFD特定参数
|
||||
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD帧格式
|
||||
transmit_message.fd_brs = ENABLE; // 使能比特率切换
|
||||
transmit_message.fd_esi = DISABLE; // 错误状态指示
|
||||
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < length && i < 64; i++) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
}
|
||||
|
||||
// 将数据复制到DMA缓冲区
|
||||
memcpy(can_tx_buffer, data, length);
|
||||
|
||||
// 配置DMA发送参数
|
||||
dma_tx_parameter.number = length;
|
||||
dma_init(DMA0, DMA_CH5, &dma_tx_parameter);
|
||||
|
||||
// 启动DMA传输
|
||||
dma_channel_enable(DMA0, DMA_CH5);
|
||||
|
||||
// 自动选择空闲mailbox发送消息,不需要人为指定
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (CAN_NOMAILBOX == transmit_mailbox) {
|
||||
static u32 count = 0;
|
||||
// 没有可用的mailbox,可能所有mailbox都在使用中
|
||||
count++;
|
||||
printf("No available mailbox for CANFD transmission\r\n");
|
||||
if (count > 0xff and !is_sleep) {
|
||||
init();
|
||||
count = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAN发送函数
|
||||
* @retval 0: 发送失败
|
||||
@@ -594,31 +476,39 @@ u8 CAN_transmiter::CAN_all_Send() {
|
||||
constexpr u32 Status_FEED = 0x118;
|
||||
constexpr u32 Limit_Vel_Vol_FEED = 0x119;
|
||||
|
||||
// 打包RT_Vel_Ang_FEED
|
||||
// 打包RT_Vel_Ang_FEED - 只清零实际使用的8字节
|
||||
memset(transmit_data, 0, 8);
|
||||
pack_float_to_bytes(transmit_data, 0, rt_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 4, rt_velocity_union);
|
||||
success_flag += CAN_Send(RT_Vel_Ang_FEED, 8, transmit_data);
|
||||
// 打包SET_Vel_Ang_FEED
|
||||
success_flag += CAN_AsyncSend(RT_Vel_Ang_FEED, 8, transmit_data);
|
||||
|
||||
// 打包SET_Vel_Ang_FEED - 只清零实际使用的8字节
|
||||
memset(transmit_data, 0, 8);
|
||||
pack_float_to_bytes(transmit_data, 0, target_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 4, target_velocity_union);
|
||||
success_flag += CAN_Send(SET_Vel_Ang_FEED, 8, transmit_data);
|
||||
// 打包Current_FEED
|
||||
success_flag += CAN_AsyncSend(SET_Vel_Ang_FEED, 8, transmit_data);
|
||||
|
||||
// 打包Current_FEED - 只清零实际使用的6字节
|
||||
memset(transmit_data, 0, 6);
|
||||
pack_u16_to_bytes(transmit_data, 0, u16(u_current_union.f));
|
||||
pack_u16_to_bytes(transmit_data, 2, u16(w_current_union.f));
|
||||
pack_u16_to_bytes(transmit_data, 4, u16(v_current_union.f));
|
||||
success_flag += CAN_Send(Current_FEED, 6, transmit_data);
|
||||
success_flag += CAN_AsyncSend(Current_FEED, 6, transmit_data);
|
||||
|
||||
// 打包Status_FEED
|
||||
// 打包Status_FEED - 只清零实际使用的8字节
|
||||
memset(transmit_data, 0, 8);
|
||||
transmit_data[0] = MotorStatus;
|
||||
transmit_data[1] = controller_Mode;
|
||||
pack_u16_to_bytes(transmit_data, 2, motor_temp);
|
||||
pack_u16_to_bytes(transmit_data, 4, mcu_temp);
|
||||
pack_u16_to_bytes(transmit_data, 6, Power_Voltage);
|
||||
success_flag += CAN_Send(Status_FEED, 8, transmit_data);
|
||||
// 打包Limit_Vel_Vol_FEED
|
||||
success_flag += CAN_AsyncSend(Status_FEED, 8, transmit_data);
|
||||
|
||||
// 打包Limit_Vel_Vol_FEED - 只清零实际使用的6字节
|
||||
memset(transmit_data, 0, 6);
|
||||
pack_float_to_bytes(transmit_data, 0, limit_velocity_union);
|
||||
pack_u16_to_bytes(transmit_data, 4, limit_voltage);
|
||||
success_flag += CAN_Send(Limit_Vel_Vol_FEED, 6, transmit_data);
|
||||
success_flag += CAN_AsyncSend(Limit_Vel_Vol_FEED, 6, transmit_data);
|
||||
|
||||
return success_flag;
|
||||
}
|
||||
@@ -631,9 +521,8 @@ u8 CAN_transmiter::CAN_all_Send() {
|
||||
u8 CAN_transmiter::CANFD_all_Send() {
|
||||
u32 success_flag = 0;
|
||||
|
||||
constexpr u32 STATUS_ID = 0x00010100;
|
||||
constexpr u32 CONFIG_ID = 0x00010101;
|
||||
// 打包status数据
|
||||
// 打包status数据 - 只清零实际使用的32字节
|
||||
memset(transmit_data, 0, 32);
|
||||
pack_u16_to_bytes(transmit_data, 0, mcu_temp);
|
||||
pack_u16_to_bytes(transmit_data, 2, motor_temp);
|
||||
pack_u16_to_bytes(transmit_data, 4, u16(u_current_union.f));
|
||||
@@ -647,15 +536,16 @@ u8 CAN_transmiter::CANFD_all_Send() {
|
||||
pack_float_to_bytes(transmit_data, 13, rt_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 17, rt_velocity_union);
|
||||
pack_float_to_bytes(transmit_data, 21, testfloat_union);
|
||||
success_flag += CANFD_Send(STATUS_ID, 32, transmit_data);
|
||||
success_flag += CANFD_AsyncSend(CANFD_STATUS_ID, 32, transmit_data);
|
||||
|
||||
// 打包config数据
|
||||
// 打包config数据 - 只清零实际使用的16字节
|
||||
memset(transmit_data, 0, 16);
|
||||
transmit_data[0] = controller_Mode;
|
||||
pack_u16_to_bytes(transmit_data, 1, limit_voltage);
|
||||
pack_float_to_bytes(transmit_data, 3, limit_velocity_union);
|
||||
pack_float_to_bytes(transmit_data, 7, target_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 11, target_velocity_union);
|
||||
success_flag += CANFD_Send(CONFIG_ID, 16, transmit_data);
|
||||
success_flag += CANFD_AsyncSend(CANFD_CONFIG_ID, 16, transmit_data);
|
||||
|
||||
return success_flag;
|
||||
}
|
||||
@@ -669,9 +559,9 @@ void CAN_transmiter::communication_check() {
|
||||
// CAN0 发送数据标志
|
||||
if (SET == can0_send_flag) {
|
||||
// printf("\r\n can0 %X receive data:", receive_message.rx_efid);
|
||||
CAN0_transmiter.update();
|
||||
update();
|
||||
// CAN0_transmiter.CAN_all_Send();
|
||||
CAN0_transmiter.CANFD_all_Send();
|
||||
CANFD_all_Send();
|
||||
can0_send_flag = RESET;
|
||||
}
|
||||
|
||||
@@ -681,7 +571,7 @@ void CAN_transmiter::communication_check() {
|
||||
// for (i = 0; i < receive_message.rx_dlen; i++) {
|
||||
// printf(" %02x", receive_message.rx_data[i]);
|
||||
// }
|
||||
if (receive_message.rx_efid == 0x00010200) {
|
||||
if (receive_message.rx_efid == CANFD_CMD_ID) {
|
||||
FOC.control_mode = receive_message.rx_data[0];
|
||||
if (float(unpack_bytes_to_u16(receive_message.rx_data, 1)) / 1000 !=
|
||||
FOC.limit_voltage) {
|
||||
@@ -701,7 +591,7 @@ void CAN_transmiter::communication_check() {
|
||||
target_velocity_union.f =
|
||||
unpack_bytes_to_float(receive_message.rx_data, 11).f;
|
||||
FOC.target_velocity = target_velocity_union.f;
|
||||
} else if (receive_message.rx_efid == 0x00010301) {
|
||||
} else if (receive_message.rx_efid == CANFD_RESET_ID) {
|
||||
u8 first_byte = receive_message.rx_data[0];
|
||||
u8 eigth_byte = receive_message.rx_data[7];
|
||||
if (first_byte & 0x01) {
|
||||
@@ -722,7 +612,8 @@ void CAN_transmiter::communication_check() {
|
||||
prepare_deep_sleep(true);
|
||||
// CAN_Sleep();
|
||||
}
|
||||
|
||||
} else if (receive_message.rx_efid == CANFD_BOOT_ID) {
|
||||
jumpToBOOT();
|
||||
} else {
|
||||
printf("Unknown CAN ID: %X\n", receive_message.rx_efid);
|
||||
}
|
||||
@@ -800,7 +691,6 @@ void DMA0_Channel4_IRQHandler(void) {
|
||||
if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_FTF)) {
|
||||
// 清除DMA传输完成中断标志
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
|
||||
|
||||
// 将DMA缓冲区的数据复制到接收消息结构体
|
||||
for (int i = 0; i < CAN0_transmiter.receive_message.rx_dlen && i < 8;
|
||||
i++) {
|
||||
@@ -815,7 +705,149 @@ void DMA0_Channel4_IRQHandler(void) {
|
||||
*/
|
||||
void DMA0_Channel5_IRQHandler(void) {
|
||||
if (dma_interrupt_flag_get(DMA0, DMA_CH5, DMA_INT_FLAG_FTF)) {
|
||||
// DMA传输完成,可以在此处执行后续处理
|
||||
// 清除DMA传输完成中断标志
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_G);
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_FTF);
|
||||
// 可以在此添加后续处理逻辑,如发送下一个数据包等
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异步CAN数据发送(使用DMA和中断机制)
|
||||
* @param id CAN消息ID
|
||||
* @param length CAN消息长度
|
||||
* @param data CAN消息数据
|
||||
*/
|
||||
u8 CAN_transmiter::CAN_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
// 检查数据长度是否符合CAN规范
|
||||
if (length > 8) {
|
||||
printf("CAN data length exceeds maximum of 8 bytes\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_STANDARD; // 标准帧格式
|
||||
transmit_message.tx_sfid = id; // 设置帧ID
|
||||
transmit_message.tx_dlen = length; // 设置数据长度
|
||||
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < length && i < 8; i++) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
}
|
||||
|
||||
// 自动选择空闲mailbox发送消息
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (transmit_mailbox == CAN_NOMAILBOX) {
|
||||
// 没有可用的mailbox,启用发送中断以便在邮箱可用时重试
|
||||
printf("No available mailbox for CAN transmission, enabling TX "
|
||||
"interrupt\r\n");
|
||||
// 可以设置一个标志位,当邮箱可用时发送
|
||||
// 在实际应用中,可以维护一个待发送队列
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 启用CAN发送中断以检测传输完成
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异步CANFD数据发送(使用DMA和中断机制)
|
||||
* @param id CAN消息ID
|
||||
* @param length CAN消息长度
|
||||
* @param data CAN消息数据
|
||||
*/
|
||||
u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
u8 valid_length = length;
|
||||
// 检查CANFD模式是否启用
|
||||
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
|
||||
printf("CANFD mode not enabled\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据长度是否符合CANFD规范
|
||||
if (length > 8) {
|
||||
if (length > 8 and length < 13) {
|
||||
valid_length = 12;
|
||||
} else if (length > 12 and length < 17) {
|
||||
valid_length = 16;
|
||||
} else if (length > 16 and length < 21) {
|
||||
valid_length = 20;
|
||||
} else if (length > 20 and length < 24) {
|
||||
valid_length = 24;
|
||||
} else if (length > 28 and length < 33) {
|
||||
valid_length = 32;
|
||||
} else if (length > 32 and length < 49) {
|
||||
valid_length = 48;
|
||||
} else if (length > 48 and length < 65) {
|
||||
valid_length = 64;
|
||||
} else {
|
||||
printf("CANFD data length error\r\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
|
||||
transmit_message.tx_efid = id; // 扩展帧ID
|
||||
transmit_message.tx_dlen = valid_length; // 设置数据长度
|
||||
|
||||
// 设置CANFD特定参数
|
||||
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD帧格式
|
||||
transmit_message.fd_brs = ENABLE; // 使能比特率切换
|
||||
transmit_message.fd_esi = DISABLE; // 错误状态指示
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < valid_length; i++) {
|
||||
if (i < length) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
} else {
|
||||
transmit_message.tx_data[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 自动选择空闲mailbox发送消息
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (transmit_mailbox == CAN_NOMAILBOX) {
|
||||
// 没有可用的mailbox,启用发送中断以便在邮箱可用时重试
|
||||
printf("No available mailbox for CANFD transmission, enabling TX "
|
||||
"interrupt\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 启用CAN发送中断以检测传输完成
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 添加CAN传输中断处理函数
|
||||
void CAN0_TX_IRQHandler(void) {
|
||||
// 检查是否有发送邮箱空闲
|
||||
if (can_flag_get(CAN0, CAN_FLAG_TME0) != RESET ||
|
||||
can_flag_get(CAN0, CAN_FLAG_TME1) != RESET ||
|
||||
can_flag_get(CAN0, CAN_FLAG_TME2) != RESET) {
|
||||
// 邮箱已空闲,可以发送新消息
|
||||
// 可以在这里处理待发送队列中的消息
|
||||
// 清除发送中断标志
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME0);
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME1);
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ void can_dma_init(void); // CAN DMA初始化
|
||||
void CAN0_RX0_IRQHandler(void); // CAN接收中断处理函数
|
||||
void DMA0_Channel4_IRQHandler(void); // DMA通道4中断处理函数(CAN接收)
|
||||
void DMA0_Channel5_IRQHandler(void); // DMA通道5中断处理函数(CAN发送)
|
||||
void jumpToBOOT();
|
||||
|
||||
void can_loopback_init(void);
|
||||
void can_loopback_test(void);
|
||||
@@ -97,8 +98,8 @@ class CAN_transmiter {
|
||||
void update(); // 更新数据
|
||||
u8 CAN_Receive(); // CAN接收
|
||||
u8 CANFD_Receive(); // CANFD接收
|
||||
u8 CAN_Send(u32 ID, u8 length, u8 *data); // CAN发送
|
||||
u8 CANFD_Send(u32 ID, u8 length, u8 *data); // CANFD发送
|
||||
u8 CAN_AsyncSend(u32 ID, u8 length, u8 *data); // CAN异步发送(使用DMA)
|
||||
u8 CANFD_AsyncSend(u32 ID, u8 length, u8 *data); // CANFD异步发送(使用DMA)
|
||||
u8 CAN_all_Send(); // CAN发送
|
||||
u8 CANFD_all_Send(); // CANFD发送
|
||||
|
||||
|
||||
+10
-20
@@ -1,6 +1,6 @@
|
||||
#include "Timer.h"
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "Timer.h"
|
||||
#include "gd32c10x.h"
|
||||
#include "gd32c10x_gpio.h"
|
||||
@@ -12,16 +12,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
constexpr int TIMER2_PRESCALER = 119; // 120MHz / 120 = 1MHz
|
||||
constexpr int TIMER2_PERIOD = 99; // 1MHz / 100 = 100us
|
||||
|
||||
constexpr int TIMER1_PRESCALER = 0; // 不分频,计数器时钟为120MHz
|
||||
constexpr int TIMER1_PERIOD = 5999; // 120MHz / (0+1) / (5999+1) = 20kHz
|
||||
constexpr int TIMER1_CH0_PULSE = 0;
|
||||
constexpr int TIMER1_CH1_PULSE = 0;
|
||||
constexpr int TIMER1_CH2_PULSE = 0;
|
||||
constexpr int TIMER1_CH3_COMPARE_VALUE =
|
||||
(TIMER1_PERIOD + 1) * 0.5 - 1; // PWM周期50%位置触发中断
|
||||
|
||||
volatile u32 total_us100_counter = 0; // 总计数器,每100微秒增加1
|
||||
extern u16 adc_value[7];
|
||||
@@ -46,7 +36,7 @@ void nvic_config(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置定时器2
|
||||
* @brief 配置定时器2-任务管理
|
||||
* @return void
|
||||
*
|
||||
*配置定时器2,用于定时执行FOC控制、采样、CAN发送等任务
|
||||
@@ -87,7 +77,7 @@ void TIMER2_config(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置TIMER2中断
|
||||
* @brief 配置TIMER2-任务管理中断
|
||||
* @return void
|
||||
*/
|
||||
void User_timer_init(void) {
|
||||
@@ -98,7 +88,7 @@ void User_timer_init(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER2中断处理函数
|
||||
* @brief TIMER2-任务管理中断处理函数
|
||||
* @return void
|
||||
*/
|
||||
void TIMER2_IRQHandler(void) {
|
||||
@@ -174,7 +164,7 @@ void TIMER2_IRQHandler(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER1 GPIO配置函数
|
||||
* @brief TIMER1-PWM GPIO配置函数
|
||||
*/
|
||||
void timer1_gpio_config(void) {
|
||||
// 时钟使能
|
||||
@@ -198,7 +188,7 @@ void timer1_gpio_config(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER1 配置函数
|
||||
* @brief TIMER1-PWM 配置函数
|
||||
*/
|
||||
void timer1_pwm_config(void) {
|
||||
timer_parameter_struct timer_initpara;
|
||||
@@ -242,11 +232,11 @@ void timer1_pwm_config(void) {
|
||||
TIMER_OC_MODE_PWM0); // CH3也设为PWM模式
|
||||
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0,
|
||||
TIMER1_CH0_PULSE);
|
||||
TIMER1_DEFAULT_PULSE);
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1,
|
||||
TIMER1_CH1_PULSE);
|
||||
TIMER1_DEFAULT_PULSE);
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_2,
|
||||
TIMER1_CH2_PULSE);
|
||||
TIMER1_DEFAULT_PULSE);
|
||||
// 设置CH3比较值为PWM周期x%位置
|
||||
timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3,
|
||||
TIMER1_CH3_COMPARE_VALUE);
|
||||
@@ -262,7 +252,7 @@ void timer1_pwm_config(void) {
|
||||
timer_enable(TIMER1);
|
||||
}
|
||||
|
||||
// 添加TIMER1中断处理函数
|
||||
// 添加TIMER1-PWM中断处理函数
|
||||
/**
|
||||
* @brief TIMER1中断处理函数
|
||||
* @return void
|
||||
|
||||
@@ -16,10 +16,6 @@ void timer1_pwm_config(void);
|
||||
void timer1_gpio_config(void);
|
||||
void TIMER1_IRQHandler(void); // 添加TIMER1中断处理函数声明
|
||||
|
||||
/* 获取系统运行时间 */
|
||||
uint64_t get_system_runtime_us(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,16 +6,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
constexpr u8 FILTER_SIZE = 6;
|
||||
constexpr u8 BLOCK_SIZE = FILTER_SIZE * sizeof(float);
|
||||
#include "config.h"
|
||||
|
||||
class sampler {
|
||||
private:
|
||||
float vbus_samples[FILTER_SIZE + 1];
|
||||
float currU_samples[FILTER_SIZE + 1];
|
||||
float currV_samples[FILTER_SIZE + 1];
|
||||
float currW_samples[FILTER_SIZE + 1];
|
||||
float mcu_temp_samples[FILTER_SIZE + 1];
|
||||
float drv_temp_samples[FILTER_SIZE + 1];
|
||||
float vbus_samples[ADC_FILTER_SIZE + 1];
|
||||
float currU_samples[ADC_FILTER_SIZE + 1];
|
||||
float currV_samples[ADC_FILTER_SIZE + 1];
|
||||
float currW_samples[ADC_FILTER_SIZE + 1];
|
||||
float mcu_temp_samples[ADC_FILTER_SIZE + 1];
|
||||
float drv_temp_samples[ADC_FILTER_SIZE + 1];
|
||||
u8 current_sample_index;
|
||||
|
||||
float tempora_sample;
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
#include "ang_sensor.h"
|
||||
#include "Can.h"
|
||||
#include "Filter.h"
|
||||
#include "core_cmFunc.h"
|
||||
#include "gd32c10x_can.h"
|
||||
#include "flash.h"
|
||||
#include "gd32c10x_dma.h"
|
||||
#include "gd32c10x_gpio.h"
|
||||
#include "gd32c10x_spi.h"
|
||||
#include "initial.h"
|
||||
#include "flash.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "Can.h"
|
||||
#include <stdint.h>
|
||||
#define ANG_SENS_DEBUG 1
|
||||
|
||||
#define ANG_SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
|
||||
#define ANG_SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
|
||||
#define DRV_SPI_CS_ENABLE() gpio_bit_reset(GPIOB, GPIO_PIN_14)
|
||||
#define DRV_SPI_CS_DISABLE() gpio_bit_set(GPIOB, GPIO_PIN_14)
|
||||
|
||||
constexpr float ANGLE_FACTOR = 1.0f / 65536.0f * 360.0f;
|
||||
constexpr float RAD_FACTOR = 1.0f / 65536.0f * 2.0f * 3.14159265358979323846f;
|
||||
constexpr u16 DEFAULT_COMMAND = 0x0000;
|
||||
constexpr u16 FAULT_RECEIVE = 0xFFFF;
|
||||
constexpr float VELOCITY_SCALE = 1e4f;
|
||||
constexpr float ANGLE_WRAP_THRESHOLD = 300.0f;
|
||||
constexpr float ANGLE_WRAP_VALUE = 360.0f;
|
||||
constexpr u8 SIZE_FLOAT = sizeof(float);
|
||||
|
||||
// DMA传输完成标志
|
||||
volatile bool spi_dma_tx_complete = false;
|
||||
volatile bool spi_dma_rx_complete = false;
|
||||
@@ -34,7 +23,7 @@ angle_sensor KTH7823; // 角度传感器初始化
|
||||
extern FlashEEPROM flashEEP;
|
||||
extern EncoderAngleKalman Angle_kalman;
|
||||
extern EncoderVelocityKalman Vel_kalman;
|
||||
extern CAN_transmiter CAN0_transmiter; // CAN初始化
|
||||
extern CAN_transmiter CAN0_transmiter; // CAN初始化
|
||||
|
||||
/**
|
||||
* @brief SPI DMA initialization
|
||||
@@ -199,10 +188,9 @@ void KTH7823_spi_init(void) {
|
||||
spi_enable(SPI0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ 角度传感器类 初始化
|
||||
* @return 0:初始化成功 1:初始化失败
|
||||
* @ 角度传感器类 初始化
|
||||
* @return 0:初始化成功 1:初始化失败
|
||||
*/
|
||||
u8 angle_sensor::init(void) {
|
||||
KTH7823_gpio_init(); // GPIO初始化
|
||||
@@ -211,17 +199,16 @@ u8 angle_sensor::init(void) {
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @ 角度传感器类 设置当前角度
|
||||
* @param angle 输出级角度值
|
||||
* @return 0成功/1失败
|
||||
* @ 角度传感器类 设置当前角度
|
||||
* @param angle 输出级角度值
|
||||
* @return 0成功/1失败
|
||||
*/
|
||||
u8 angle_sensor::angle_set(float angle){
|
||||
m_cumulativeAngle = angle*REDUCTION_RATIO; // 从Flash读取上次保存的角度
|
||||
u8 angle_sensor::angle_set(float angle) {
|
||||
m_cumulativeAngle = angle * REDUCTION_RATIO; // 从Flash读取上次保存的角度
|
||||
m_firstUpdate = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 读取传感器数据
|
||||
* @return 传感器数据
|
||||
@@ -235,19 +222,17 @@ inline float angle_sensor::read_sensorAngle(void) {
|
||||
|
||||
if (result == 0) {
|
||||
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
|
||||
float angle_deg = (float)raw_data * ANGLE_FACTOR;
|
||||
float angle_deg = (float)raw_data * ANGLESENS_FACTOR;
|
||||
current_angle_deg = angle_deg;
|
||||
current_angle_rad = angle_deg * DEG2RAD; // M_PI/180.0f
|
||||
return angle_deg;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// 仅在调试模式下输出错误,避免发布版本中的I/O开销
|
||||
if (result != 0) {
|
||||
// 使用更高效的串口输出替代printf(如果可用)
|
||||
printf("Error reading angle from sensor.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return (float)FAULT_RECEIVE;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ extern "C" {
|
||||
#endif
|
||||
#include "gd32c10x_eval.h"
|
||||
#include "stdio.h"
|
||||
#include "config.h"
|
||||
|
||||
u16 spi_rw_half_word(u32 spi_periph, const u16 i_HalfWord);
|
||||
int spi_rw_half_word_dma(uint32_t spi_periph, uint16_t tx_data,
|
||||
uint16_t *rx_data);
|
||||
|
||||
constexpr u16 VEL_FILTER_SIZE = 4;
|
||||
|
||||
class angle_sensor {
|
||||
public:
|
||||
|
||||
+48
-50
@@ -1,16 +1,16 @@
|
||||
#include "main.h"
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "Filter.h"
|
||||
#include "Timer.h"
|
||||
#include "adc.h"
|
||||
#include "ang_sensor.h"
|
||||
#include "core_cm4.h"
|
||||
#include "core_cmFunc.h"
|
||||
#include "flash.h"
|
||||
#include "health.h"
|
||||
#include "initial.h"
|
||||
#include "motor.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/flash.h"
|
||||
#include "sys/initial.h"
|
||||
#include "systick.h"
|
||||
#include <cstdio>
|
||||
@@ -28,35 +28,14 @@ TaskScheduler scheduler = {0};
|
||||
volatile u32 system_runtime_us = 0; // 电机驱动计算轮次
|
||||
volatile u32 cnt_test = 0; // 负载检测
|
||||
int main(void) {
|
||||
systick_config(); // 系统时钟初始化
|
||||
SystemCoreClockUpdate(); // 更新系统时钟变量
|
||||
watchdog_init(50); // 看门狗初始化
|
||||
unused_pin_init(); // 未使用引脚初始化
|
||||
USART0_init(); // 调试串口初始化
|
||||
motor_init(); // 电机驱动初始化
|
||||
if (get_reset_cause() ==
|
||||
RCU_FLAG_FWDGTRST) { // 如果是看门狗复位,本次看门狗时间延长并休眠
|
||||
printf("continue sleep\r\n");
|
||||
watchdog_init(5000); // 看门狗初始化
|
||||
delay_1ms(1);
|
||||
prepare_deep_sleep(false);
|
||||
}
|
||||
User_timer_init(); // 任务Timer初始化
|
||||
u8 init_status = 0;
|
||||
init_status += KTH7823.init(); // 角度传感器初始化
|
||||
init_status += sampler.init(); // 采样器初始化
|
||||
init_status +=
|
||||
flashEEP.init(); // EEPROM初始化,必须放在角度卡尔曼之前,角度传感器之后
|
||||
|
||||
init_status += Angle_kalman.init(KTH7823.getAngle()); // 角度滤波初始化
|
||||
init_status += Vel_kalman.init(0.0f); // 速度滤波初始化
|
||||
init_status += CAN0_transmiter.init(); // CAN初始化
|
||||
u8 init_status = hardware_init();
|
||||
|
||||
while (init_status) { // 初始化检测
|
||||
std::printf("初始化失败\r\n");
|
||||
}
|
||||
|
||||
OTA_initial(); // OTA初始化,A/B分区处理
|
||||
angsens_MG_check(); // 角度传感器磁感应强度测试
|
||||
|
||||
while (1) {
|
||||
__disable_irq();
|
||||
u32 currentTasks =
|
||||
@@ -69,6 +48,32 @@ int main(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 hardware_init(void) {
|
||||
__enable_irq();
|
||||
systick_config(); // 系统时钟初始化
|
||||
watchdog_init(50); // 看门狗初始化
|
||||
unused_pin_init(); // 未使用引脚初始化
|
||||
USART0_init(); // 调试串口初始化
|
||||
motor_init(); // 电机驱动初始化
|
||||
if (get_reset_cause() ==
|
||||
RCU_FLAG_FWDGTRST) { // 如果是看门狗复位,本次看门狗时间延长并休眠
|
||||
printf("continue sleep\r\n");
|
||||
watchdog_init(5000); // 看门狗初始化
|
||||
delay_1ms(3000);
|
||||
prepare_deep_sleep(false);
|
||||
}
|
||||
User_timer_init(); // 任务Timer初始化
|
||||
u8 init_status = 0;
|
||||
init_status += KTH7823.init(); // 角度传感器初始化
|
||||
init_status += sampler.init(); // 采样器初始化
|
||||
flashEEP.init(); // EEPROM初始化,必须放在角度卡尔曼之前,角度传感器之后
|
||||
|
||||
init_status += Angle_kalman.init(KTH7823.getAngle()); // 角度滤波初始化
|
||||
init_status += Vel_kalman.init(0.0f); // 速度滤波初始化
|
||||
init_status += CAN0_transmiter.init(); // CAN初始化
|
||||
return init_status;
|
||||
}
|
||||
|
||||
void do_task(u32 currentTasks) {
|
||||
// 按照优先级和重要性处理任务
|
||||
if (currentTasks & (1 << TASK_CURRENT_UPDATE)) { // 更新电流采样值
|
||||
@@ -83,29 +88,22 @@ void do_task(u32 currentTasks) {
|
||||
}
|
||||
if (currentTasks & (1 << TASK_MOTOR_CONTROL)) { // 电机控制任务(最高优先级)
|
||||
system_runtime_us++;
|
||||
switch (FOC.control_mode) {
|
||||
case 0: {
|
||||
FOC.drv_hold(0.95); // 占空比置0
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// FOC.angle_control(FOC.target_angle); // 角度闭环控制
|
||||
FOC.angle_control_with_velocity_limit(FOC.target_angle); // 角度闭环控制,带速度限制
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
FOC.velocity_control(FOC.target_velocity); // 速度闭环控制
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// FOC.angle_control_NPID(FOC.target_angle); // 角度闭环控制
|
||||
FOC.current_control(FOC.limit_velocity); // 电流闭环控制
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
FOC.velocity_open_loop(); // 速度开环控制
|
||||
break;
|
||||
}
|
||||
|
||||
// 函数指针数组,包含各种控制模式对应的函数
|
||||
static FOCFunctionPtr control_functions[] = {
|
||||
&FOC_Controlroller::drv_hold, // 0: 占空比置
|
||||
&FOC_Controlroller::
|
||||
angle_control_with_velocity_limit, // 1:
|
||||
// 角度闭环控制,带速度限制
|
||||
&FOC_Controlroller::velocity_control, // 2: 速度闭环控制
|
||||
&FOC_Controlroller::current_control, // 3: 电流闭环控制
|
||||
&FOC_Controlroller::velocity_open_loop // 4: 速度开环控制
|
||||
};
|
||||
|
||||
// 边界检查,防止数组越界
|
||||
if (FOC.control_mode >= 0 && FOC.control_mode < 5) {
|
||||
// 调用对应的控制函数
|
||||
(FOC.*control_functions[FOC.control_mode])();
|
||||
}
|
||||
}
|
||||
if (currentTasks & (1 << TASK_MCU_TEMP_UPDATE)) { // 更新mcu温度传感器值
|
||||
|
||||
@@ -37,5 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "stdint.h"
|
||||
|
||||
void do_task(u32 currentTasks);
|
||||
u8 hardware_init(void);
|
||||
|
||||
#endif /* MAIN_H */
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
#include <stdint.h>
|
||||
|
||||
// 如果使用CMSIS DSP库,需要定义ARM_MATH_CM4
|
||||
// #define ARM_MATH_CM4
|
||||
|
||||
#define EEP_DEBUG 1
|
||||
// BOOT 相关
|
||||
constexpr u32 BOOTLOADER_START_ADDR = 0x08000000; // BOOT起始地址
|
||||
constexpr u32 OTA_CONFIG_NUM = 6;
|
||||
constexpr u32 n_APP_LATEST_AVAL_ADDR = 0x0801D000;
|
||||
constexpr u32 n_APP_BACKUP_AVAL_ADDR = 0x0801D004;
|
||||
constexpr u32 n_APP_LATEST_EN_ADDR = 0x0801D008;
|
||||
constexpr u32 n_APP_BACKUP_EN_ADDR = 0x0801D00C;
|
||||
constexpr u32 n_APP_LATEST_CHECK_ADDR = 0x0801D010;
|
||||
constexpr u32 n_APP_BACKUP_CHECK_ADDR = 0x0801D014;
|
||||
constexpr u32 OTA_NOT_AVAL = 0xFFFFFFFF;
|
||||
constexpr u32 OTA_AVAL = 0x00000000; // 全零表示可用
|
||||
|
||||
// 参数配置
|
||||
constexpr u8 PP = 11;
|
||||
constexpr float DIR = 1.0;
|
||||
constexpr u16 REDUCTION_RATIO = 25;
|
||||
constexpr float CURRENT_OFFSET = -1.615f; // 当前电流传感器的零点偏移
|
||||
constexpr float HOLD_PWM_DUTY = 0.95f;
|
||||
|
||||
constexpr u32 CANFD_BOOT_ID = 0x00000000;
|
||||
constexpr u32 CANFD_STATUS_ID = 0x00010100;
|
||||
constexpr u32 CANFD_CONFIG_ID = 0x00010101;
|
||||
constexpr u32 CANFD_CMD_ID = 0x00010200;
|
||||
constexpr u32 CANFD_RESET_ID = 0x00010301;
|
||||
|
||||
// 常量定义
|
||||
constexpr u8 SIZE_FLOAT = sizeof(float);
|
||||
constexpr u8 SIZE_U32 = sizeof(uint32_t);
|
||||
constexpr float ADC_MAX = 65536.0f;
|
||||
constexpr float PI = 3.14159265358979323846f;
|
||||
constexpr float ANGLE_FACTOR = 25.0f / 360.0f * 2.0f * PI;
|
||||
constexpr float DEG2RAD = 1.0f / 360.0f * 2 * PI;
|
||||
constexpr float RAD2DEG = 360.0f / 2 * PI;
|
||||
constexpr float _1_SQRT3 = 0.57735026919f; // 1/sqrt(3)
|
||||
constexpr float sqrt3dv2 = 0.86602540378f; // sqrt(3)/2的预计算值
|
||||
constexpr u8 DEFAULT_VALUE = 0;
|
||||
constexpr u8 CONFIG_SAVED_NUM = 6;
|
||||
|
||||
// 三角函数快速计算LUT
|
||||
constexpr u16 LUT_SIZE = 1024;
|
||||
constexpr u16 LUT_MASK = (LUT_SIZE - 1);
|
||||
constexpr u16 LUT_SCALE = (LUT_SIZE / (2.0f * PI));
|
||||
|
||||
// CAN相关
|
||||
constexpr u16 DEV_CAN0_ID = 0x0000;
|
||||
constexpr u16 DEV_CAN0_MASK = 0x0000;
|
||||
constexpr u16 DEV_CAN_LOOPBACK_ID = 0x0000;
|
||||
|
||||
// ADC
|
||||
constexpr u8 ADC_FILTER_SIZE = 6;
|
||||
constexpr u8 BLOCK_SIZE = ADC_FILTER_SIZE * SIZE_FLOAT;
|
||||
constexpr float ERROR_ADC_VAL = 255.0f;
|
||||
constexpr float MAX_TEMP = 150.0f;
|
||||
constexpr float MIN_TEMP = -40.0f;
|
||||
constexpr float MAX_CURRENT = 40.0f;
|
||||
constexpr float MIN_CURRENT = -40.0f;
|
||||
constexpr float MAX_VCC = 65.0f;
|
||||
constexpr float MIN_VCC = -0.1f;
|
||||
|
||||
// ang_sensor
|
||||
constexpr u16 VEL_FILTER_SIZE = 4;
|
||||
constexpr u16 DEFAULT_COMMAND = 0x0000;
|
||||
constexpr u16 FAULT_RECEIVE = 0xFFFF;
|
||||
constexpr float ANGLE_WRAP_THRESHOLD = 300.0f;
|
||||
constexpr float ANGLE_WRAP_VALUE = 360.0f;
|
||||
constexpr float RAD_FACTOR = 1.0f / ADC_MAX * 2.0f * PI;
|
||||
constexpr float ANGLESENS_FACTOR = 1.0f / ADC_MAX * 360.0f;
|
||||
|
||||
// TIMER2-任务调度
|
||||
constexpr int TIMER2_PRESCALER = 119; // 120MHz / 120 = 1MHz
|
||||
constexpr int TIMER2_PERIOD = 99; // 1MHz / 100 = 100us
|
||||
|
||||
// TIMER1-PWM
|
||||
constexpr int TIMER1_PRESCALER = 0; // 不分频,计数器时钟为120MHz
|
||||
constexpr int TIMER1_PERIOD = 5999; // 120MHz / (0+1) / (5999+1) = 20kHz
|
||||
constexpr int TIMER1_DEFAULT_PULSE = 0;
|
||||
constexpr int TIMER1_CH3_COMPARE_VALUE =
|
||||
(TIMER1_PERIOD + 1) * 0.5 - 1; // PWM周期50%位置触发中断
|
||||
|
||||
#endif
|
||||
+226
-51
@@ -1,26 +1,28 @@
|
||||
#include "flash.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "ang_sensor.h"
|
||||
#include "config.h"
|
||||
#include "gd32c10x.h"
|
||||
#include "gd32c10x_crc.h"
|
||||
#include "gd32c10x_fmc.h"
|
||||
#include "math.h"
|
||||
#include <Can.h>
|
||||
#include <Filter.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控制
|
||||
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
|
||||
|
||||
inline fmc_state_enum write_ADDRESS(u32 address, u32 data) {
|
||||
fmc_unlock();
|
||||
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
|
||||
|
||||
// 确保使用对齐地址
|
||||
fmc_state_enum fmc_status = fmc_word_program(address, data);
|
||||
|
||||
fmc_lock();
|
||||
return fmc_status;
|
||||
}
|
||||
// FlashEEPROM类实现
|
||||
FlashEEPROM::FlashEEPROM() {
|
||||
// 构造函数可以为空,或者做一些初始化工作
|
||||
@@ -56,8 +58,8 @@ u8 FlashEEPROM::init() {
|
||||
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};
|
||||
FlashEepromStatus status_read[CONFIG_SAVED_NUM + 1] = {FLASH_EEPROM_OK};
|
||||
float data[CONFIG_SAVED_NUM] = {0.0f};
|
||||
// 尝试从Flash读取参数,如果不存在则使用默认值
|
||||
status_read[1] = readFloat(ADDR_CONTROL_MODE, &data[0]);
|
||||
status_read[2] = readFloat(ADDR_VOLTAGE_LIMIT, &data[1]);
|
||||
@@ -67,7 +69,7 @@ u8 FlashEEPROM::read_saved_system_config(void) {
|
||||
status_read[6] = readFloat(ADDR_TARGET_VEL, &data[5]);
|
||||
|
||||
// 读取失败则使用默认值
|
||||
for (u8 i = 1; i < NUM_SAVED + 1; i++) {
|
||||
for (u8 i = 1; i < CONFIG_SAVED_NUM + 1; i++) {
|
||||
if (status_read[i] ==
|
||||
FLASH_EEPROM_DATA_NOT_FOUND) { // 首次读取,不保存报错
|
||||
data[i - 1] = DEFAULT_VALUE;
|
||||
@@ -99,13 +101,13 @@ u8 FlashEEPROM::read_saved_system_config(void) {
|
||||
}
|
||||
|
||||
crc_data_register_reset(); // 确保CRC计算从初始状态开始
|
||||
CRC_NUM = crc_block_data_calculate((uint32_t *)data, NUM_SAVED);
|
||||
CRC_NUM = crc_block_data_calculate((uint32_t *)data, CONFIG_SAVED_NUM);
|
||||
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
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++) {
|
||||
for (u8 i = 0; i < CONFIG_SAVED_NUM; i++) {
|
||||
data[i] = DEFAULT_VALUE;
|
||||
}
|
||||
EEPROMStatus = FLASH_EEPROM_CRC_ERROR;
|
||||
@@ -185,7 +187,7 @@ FlashEepromStatus FlashEEPROM::readFloat(u8 virtualAddr, float *data) const {
|
||||
u32 float_data = data_word & DATA_FLOAT_MASK;
|
||||
// 使用内存拷贝将处理后的数据解释为float
|
||||
memcpy(data, &float_data, SIZE_FLOAT);
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
printf("read:0x%x=%f\r\n", address, *data);
|
||||
#endif
|
||||
return FLASH_EEPROM_OK;
|
||||
@@ -218,7 +220,7 @@ FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
|
||||
if ((data_read & DATA_ADDR_MASK) == (u32)virtualAddr) { // 虚拟地址相同
|
||||
if ((data_read & DATA_U16_MASK) ==
|
||||
(data & DATA_U16_MASK)) { // 数据相同
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
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);
|
||||
@@ -249,19 +251,14 @@ FlashEepromStatus FlashEEPROM::write(u8 virtualAddr, u16 data) {
|
||||
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();
|
||||
fmc_state_enum fmc_status = write_ADDRESS(next_address, data_word);
|
||||
|
||||
if (fmc_status != FMC_READY) {
|
||||
return FLASH_EEPROM_WRITE_ERROR;
|
||||
}
|
||||
return FLASH_EEPROM_OK;
|
||||
} else { // 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
@@ -301,7 +298,7 @@ FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
|
||||
(u32)virtualAddr) { // 虚拟地址相同
|
||||
if ((data_word_read & DATA_FLOAT_MASK) ==
|
||||
(data_word & DATA_FLOAT_MASK)) { // 数据相同
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
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);
|
||||
@@ -330,15 +327,8 @@ FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
|
||||
|
||||
// 如果有足够空间,直接写入
|
||||
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
|
||||
fmc_state_enum fmc_status = write_ADDRESS(next_address, data_word);
|
||||
#if EEP_DEBUG
|
||||
u32 data_word_c = *((u32 *)next_address);
|
||||
data_word_c = data_word_c & DATA_FLOAT_MASK;
|
||||
float float_data = *((float *)&data_word_c);
|
||||
@@ -350,7 +340,7 @@ FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
|
||||
return FLASH_EEPROM_OK;
|
||||
} else {
|
||||
// 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
@@ -370,7 +360,7 @@ FlashEepromStatus FlashEEPROM::writeFloat(u8 virtualAddr, float data) {
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::format() {
|
||||
fmc_state_enum fmc_status;
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
printf("擦除页面\r\n");
|
||||
#endif
|
||||
|
||||
@@ -395,9 +385,10 @@ FlashEepromStatus FlashEEPROM::format() {
|
||||
*/
|
||||
FlashEepromStatus FlashEEPROM::save_system_config(bool saved) {
|
||||
u32 CRC_NUM = 0x0000;
|
||||
float data[NUM_SAVED] = {(float)FOC.control_mode, FOC.limit_voltage,
|
||||
FOC.limit_velocity, FOC.rt_angle,
|
||||
FOC.target_angle, FOC.target_velocity};
|
||||
float data[CONFIG_SAVED_NUM] = {
|
||||
(float)FOC.control_mode, FOC.limit_voltage,
|
||||
FOC.limit_velocity, FOC.rt_angle,
|
||||
FOC.target_angle, FOC.target_velocity};
|
||||
|
||||
// 如果系统配置标记已保存,则无需再次保存
|
||||
if (system_config_saved) {
|
||||
@@ -445,10 +436,10 @@ FlashEepromStatus FlashEEPROM::save_system_config(bool saved) {
|
||||
}
|
||||
|
||||
// 创建用于CRC计算的模拟数据数组,模拟实际存储到Flash中的数据格式
|
||||
u32 crc_data_words[NUM_SAVED];
|
||||
u32 crc_data_words[CONFIG_SAVED_NUM];
|
||||
|
||||
// 按照writeFloat函数的方式处理数据
|
||||
for (u8 i = 0; i < NUM_SAVED; i++) {
|
||||
for (u8 i = 0; i < CONFIG_SAVED_NUM; i++) {
|
||||
// 将完整的float数据复制到32位变量中
|
||||
memcpy(&crc_data_words[i], &data[i], SIZE_FLOAT);
|
||||
// 去除最后2位精度
|
||||
@@ -456,7 +447,7 @@ FlashEepromStatus FlashEEPROM::save_system_config(bool saved) {
|
||||
}
|
||||
|
||||
crc_data_register_reset(); // 确保CRC计算从初始状态开始
|
||||
CRC_NUM = crc_block_data_calculate(crc_data_words, NUM_SAVED);
|
||||
CRC_NUM = crc_block_data_calculate(crc_data_words, CONFIG_SAVED_NUM);
|
||||
writeCRC(CRC_NUM, saved);
|
||||
|
||||
EEPROMStatus = FLASH_EEPROM_OK;
|
||||
@@ -501,14 +492,10 @@ FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
|
||||
if (*((u32 *)next_address) != CRC_NUM) {
|
||||
// 如果有足够空间,直接写入crc值
|
||||
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);
|
||||
fmc_lock();
|
||||
#if EEPDEBUG
|
||||
fmc_state_enum fmc_status = write_ADDRESS(next_address, CRC_NUM);
|
||||
#if EEP_DEBUG
|
||||
printf("CRC cmp1,0x%X_0x%x \r\n", CRC_NUM, *((u32 *)next_address));
|
||||
#endif
|
||||
|
||||
// 检查写入是否成功
|
||||
if (fmc_status != FMC_READY) {
|
||||
EEPROMStatus = fmc_status;
|
||||
@@ -516,7 +503,7 @@ FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
|
||||
}
|
||||
} else {
|
||||
// 空间不足,需要格式化页面
|
||||
#if EEPDEBUG
|
||||
#if EEP_DEBUG
|
||||
printf("no enough space\r\n");
|
||||
#endif
|
||||
FlashEepromStatus status = format();
|
||||
@@ -539,4 +526,192 @@ FlashEepromStatus FlashEEPROM::writeCRC(u32 CRC_NUM, bool saved) {
|
||||
EEPROMStatus = FLASH_EEPROM_CRC_ERROR; // 设置EEPROM错误状态
|
||||
return FLASH_EEPROM_CRC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
u8 OTA_SET(u32 addr, bool enable) {
|
||||
fmc_state_enum fmc_status;
|
||||
u32 temp_val[OTA_CONFIG_NUM];
|
||||
u32 data = enable ? OTA_NOT_AVAL : OTA_AVAL;
|
||||
volatile u32 *flash_ptr = (volatile u32 *)addr;
|
||||
temp_val[0] = *flash_ptr;
|
||||
if (temp_val[0] == data) { // 如果相同
|
||||
return FLASH_EEPROM_OK; // 成功
|
||||
}
|
||||
|
||||
fmc_unlock();
|
||||
// 如果不同,且要写0,直接写
|
||||
if (data == OTA_AVAL) {
|
||||
fmc_status = write_ADDRESS(addr, data);
|
||||
fmc_lock();
|
||||
if (fmc_status == FMC_READY) {
|
||||
return FLASH_EEPROM_OK; // 成功可以直接退出
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不同或写入出错,要写1,需要重置,然后再写
|
||||
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
|
||||
temp_val[0] = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
|
||||
temp_val[1] = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
|
||||
temp_val[2] = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
|
||||
temp_val[3] = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
|
||||
temp_val[4] = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
|
||||
temp_val[5] = *flash_ptr;
|
||||
#if EEP_DEBUG
|
||||
printf("OTA_SET\r\n");
|
||||
printf("0x%x_0x%x_0x%x_0x%x\r\n", temp_val[0], temp_val[1], temp_val[2],
|
||||
temp_val[3]);
|
||||
#endif
|
||||
fmc_status = fmc_page_erase(n_APP_LATEST_AVAL_ADDR); // 擦除页
|
||||
if (fmc_status != FMC_READY) {
|
||||
return FLASH_EEPROM_ERASE_ERROR; // 擦除错误退出
|
||||
}
|
||||
for (int i = 0; i < OTA_CONFIG_NUM; i++) {
|
||||
if (temp_val[i] == OTA_AVAL and
|
||||
n_APP_LATEST_AVAL_ADDR + 4 * i != addr) {
|
||||
fmc_status = write_ADDRESS(n_APP_LATEST_AVAL_ADDR + 4 * i,
|
||||
OTA_AVAL); // 把需要写入0的写入0
|
||||
if (fmc_status != FMC_READY) {
|
||||
fmc_lock();
|
||||
return FLASH_EEPROM_WRITE_ERROR; // 写入错误退出
|
||||
}
|
||||
}
|
||||
}
|
||||
fmc_lock();
|
||||
return FLASH_EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 跳转应用处理模块
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void jumpToBOOT() {
|
||||
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置APP为不激活
|
||||
// 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. 设置中断向量表偏移到应用程序起始地址
|
||||
SCB->VTOR = BOOTLOADER_START_ADDR;
|
||||
|
||||
// 6. 设置MSP并跳转
|
||||
uint32_t msp_value = *(__IO uint32_t *)BOOTLOADER_START_ADDR;
|
||||
uint32_t reset_handler = *(__IO uint32_t *)(BOOTLOADER_START_ADDR + 4);
|
||||
typedef void (*AppEntryFunc)(void);
|
||||
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
|
||||
__set_MSP(msp_value);
|
||||
// 7. 跳转
|
||||
app_entry();
|
||||
|
||||
// 如果程序执行到这里,说明跳转失败
|
||||
printf("Jump to application failed!\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将0x08011000地址后0xC000大小区域内的数据搬运到0x08050000地址
|
||||
* @param None
|
||||
* @retval fmc_state_enum: 操作状态
|
||||
*/
|
||||
fmc_state_enum move_app_data() {
|
||||
// 源地址: 0x08011000
|
||||
// 目标地址: 0x08050000
|
||||
// 数据大小: 0xC000 (49152字节)
|
||||
|
||||
uint32_t src_addr = 0x08011000;
|
||||
uint32_t dst_addr = 0x08050000;
|
||||
uint32_t size = 0xC000; // 48KB
|
||||
|
||||
fmc_state_enum fmc_status = FMC_READY;
|
||||
|
||||
// 计算源数据的CRC
|
||||
rcu_periph_clock_enable(RCU_CRC);
|
||||
crc_deinit();
|
||||
crc_data_register_reset();
|
||||
|
||||
// 临时缓冲区用于计算CRC
|
||||
uint32_t word_count = size / 4;
|
||||
uint32_t src_crc, dst_crc;
|
||||
|
||||
// 计算源数据CRC
|
||||
src_crc = crc_block_data_calculate((uint32_t *)src_addr, word_count);
|
||||
|
||||
// 关闭全局中断以防止Flash操作期间的中断干扰
|
||||
__disable_irq();
|
||||
|
||||
fmc_unlock();
|
||||
|
||||
// 首先擦除目标地址的Flash页面
|
||||
// 计算需要擦除的页面数量(GD32C103的Flash页大小为1KB)
|
||||
uint32_t page_size = 1024; // 1KB per page
|
||||
uint32_t num_pages = (size + page_size - 1) / page_size; // 向上取整
|
||||
|
||||
for (uint32_t i = 0; i < num_pages; i++) {
|
||||
uint32_t page_addr = dst_addr + i * page_size;
|
||||
|
||||
// 擦除页面
|
||||
fmc_status = fmc_page_erase(page_addr);
|
||||
if (fmc_status != FMC_READY) {
|
||||
fmc_lock();
|
||||
__enable_irq(); // 重新开启中断
|
||||
return fmc_status;
|
||||
}
|
||||
}
|
||||
|
||||
// 复制数据 - 按字(32位)进行复制以提高效率
|
||||
for (uint32_t offset = 0; offset < size; offset += 4) {
|
||||
uint32_t src_data = *(volatile uint32_t *)(src_addr + offset);
|
||||
|
||||
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
|
||||
if (src_data != 0xFFFFFFFF) {
|
||||
fmc_status = fmc_word_program(dst_addr + offset, src_data);
|
||||
if (fmc_status != FMC_READY) {
|
||||
fmc_lock();
|
||||
__enable_irq(); // 重新开启中断
|
||||
return fmc_status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmc_lock();
|
||||
|
||||
// 重新开启全局中断
|
||||
__enable_irq();
|
||||
|
||||
// 计算目标数据的CRC
|
||||
crc_data_register_reset();
|
||||
dst_crc = crc_block_data_calculate((uint32_t *)dst_addr, word_count);
|
||||
|
||||
// 比较源数据和目标数据的CRC
|
||||
if (src_crc != dst_crc) {
|
||||
// 如果CRC不匹配,可以选择返回错误状态
|
||||
// 这里我们返回一个特殊值表示CRC校验失败
|
||||
return (fmc_state_enum)0xFF; // 自定义错误码表示CRC校验失败
|
||||
}
|
||||
|
||||
// 设置备份应用可用标志
|
||||
OTA_SET(n_APP_BACKUP_AVAL_ADDR, OTA_AVAL);
|
||||
OTA_SET(n_APP_BACKUP_CHECK_ADDR, OTA_AVAL);
|
||||
|
||||
return fmc_status;
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
#define __FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gd32c10x.h" // 添加GD32主头文件以确保外设函数声明可用
|
||||
|
||||
// 修改后 - 强制4字节对齐
|
||||
#define ALIGN_4BYTE(addr) ((addr) & 0xFFFFFFFC) // 4字节对齐
|
||||
|
||||
@@ -69,4 +71,7 @@ class FlashEEPROM {
|
||||
};
|
||||
|
||||
void flash_eeprom_example_main(void);
|
||||
u8 OTA_SET(u32 addr, bool enable);
|
||||
fmc_state_enum move_app_data(void);
|
||||
|
||||
#endif /* __FLASH_H */
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "health.h"
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include "Can.h"
|
||||
#include "DengFOC.h"
|
||||
#include "FOC.h"
|
||||
#include "adc.h"
|
||||
#include "flash.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern sampler sampler;
|
||||
extern CAN_transmiter CAN0_transmiter;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "initial.h"
|
||||
#include "config.h"
|
||||
#include "flash.h"
|
||||
#include "gd32c10x.h"
|
||||
#include "gd32c10x_gpio.h"
|
||||
#include "gd32c10x_rcu.h"
|
||||
#include "gd32c10x_fmc.h"
|
||||
#include <cstdio>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -27,7 +30,6 @@ u8 watchdog_init(u32 time) {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int fputc(int ch, FILE *f) throw() {
|
||||
usart_data_transmit(EVAL_COM0, (uint8_t)ch);
|
||||
while (RESET == usart_flag_get(EVAL_COM0, USART_FLAG_TBE))
|
||||
@@ -91,3 +93,20 @@ u16 get_reset_cause(void) {
|
||||
// printf("cause:%d\r\n", cause);
|
||||
return cause;
|
||||
}
|
||||
|
||||
void OTA_initial(void) {
|
||||
// 确认当前APP可用
|
||||
OTA_SET(n_APP_LATEST_CHECK_ADDR, true);
|
||||
|
||||
volatile u32 *flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
|
||||
u32 back_aval = *flash_ptr;
|
||||
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
|
||||
u32 back_check = *flash_ptr;
|
||||
// 如果BACK不可用
|
||||
if (back_aval == OTA_NOT_AVAL) {
|
||||
move_app_data();
|
||||
} else if (back_aval == OTA_AVAL &&
|
||||
back_check == OTA_NOT_AVAL) { // BACK已刷写,但未检查
|
||||
move_app_data();
|
||||
}
|
||||
}
|
||||
|
||||
+11
-13
@@ -5,23 +5,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "gd32c10x_eval.h"
|
||||
#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函数以重载标准库实现
|
||||
|
||||
u8 USART0_init(void);
|
||||
u8 watchdog_init(u32 time);
|
||||
u16 get_reset_cause(void);
|
||||
void unused_pin_init();
|
||||
// 任务标志定义
|
||||
typedef enum {
|
||||
TASK_MOTOR_CONTROL = 0,
|
||||
@@ -37,6 +25,16 @@ typedef enum {
|
||||
TASK_COUNT
|
||||
} SystemTask;
|
||||
|
||||
void rcu_config(void);
|
||||
static volatile uint32_t timer_delay_count = 0; // volatile 很重要!
|
||||
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();
|
||||
void OTA_initial(void);
|
||||
|
||||
// 任务管理结构
|
||||
typedef struct {
|
||||
volatile u32 taskFlags; // 任务标志位(每个位代表一个任务)
|
||||
|
||||
@@ -83,7 +83,6 @@ void delay_1ms(uint32_t count) {
|
||||
delay = count;
|
||||
while (0U != delay) {
|
||||
fwdgt_counter_reload();
|
||||
fwdgt_counter_reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,4 +176,10 @@ void EXTI5_9_IRQHandler(void) {
|
||||
printf("MCU wake up\r\n");
|
||||
system_soft_reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OTA_initial(){
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user