- 在CAN通信类中添加了CAN_Sleep()和CAN_Wakeup()方法,支持设备进入低功耗模式 - 优化CAN通信检查逻辑,通过解析接收数据的首字节和末字节实现多种控制命令 - 支持远程复位电机、保存角度、清零角度、进入睡眠等操作 - 解决CAN发送邮箱满时可能导致的通信阻塞问题,增加重初始化机制 - 调整mailbox不可用计数逻辑,防止持续打印错误信息 refactor(flash): 移除软件CRC计算模块,改用硬件CRC外设 - 删除自定义CRC.cpp和CRC.h文件及其相关类实现 - 使用GD32硬件CRC模块替代软件算法,提高效率和可靠性 - 更新FlashEEPROM类中的CRC校验方式,调用crc_block_data_calculate进行计算 - 修正Flash地址遍历范围以适配新CRC逻辑及页面管理策略 - 修改save_angle接口签名,不再手动传入角度值,改为内部读取FOC实时角度 feat(timer): 新增RTC闹钟中断处理函数声明 - 在Timer.h中声明rtc_set_wakeup_interval和RTC_ALARM_IRQHandler - 为后续实现基于RTC的定时唤醒功能做准备 chore(config): 同步csolution工具版本更新并调整组件配置 - 更新RTE_Components.h生成工具版本至2.12.0 - 启用BKP、CRC、RTC等标准外设组件宏定义 - 从项目配置文件中移除旧CRC源文件引用 - 添加SystemCoreClockUpdate调用确保系统时钟同步 refactor(main): 主循环任务调度重构并增强初始化流程 - 将主循环中的任务处理提取为独立do_task函数,提升代码可读性 - 提前执行电机初始化,并根据看门狗复位标志决定是否立即进入深度睡眠 - 调整EEPROM初始化顺序,保证依赖关系正确 - 添加sys/initial.h头文件包含以支持新增系统初始化逻辑
307 lines
8.7 KiB
C++
307 lines
8.7 KiB
C++
#include "ang_sensor.h"
|
||
#include "Filter.h"
|
||
#include "core_cmFunc.h"
|
||
#include "gd32c10x_can.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_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;
|
||
|
||
angle_sensor KTH7823; // 角度传感器初始化
|
||
extern FlashEEPROM flashEEP;
|
||
extern EncoderAngleKalman Angle_kalman;
|
||
extern EncoderVelocityKalman Vel_kalman;
|
||
extern CAN_transmiter CAN0_transmiter; // CAN初始化
|
||
|
||
/**
|
||
* @brief SPI DMA initialization
|
||
*/
|
||
void spi_dma_init(void) {
|
||
dma_parameter_struct dma_init_struct;
|
||
|
||
// 使能DMA时钟
|
||
rcu_periph_clock_enable(RCU_DMA0);
|
||
|
||
// 初始化发送DMA通道
|
||
dma_deinit(DMA0, DMA_CH2);
|
||
dma_struct_para_init(&dma_init_struct);
|
||
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
|
||
dma_init_struct.memory_addr = (uint32_t)0; // 实际地址将在传输时设置
|
||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
|
||
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
|
||
dma_init_struct.number = 1;
|
||
dma_init_struct.periph_addr = (uint32_t)(&SPI_DATA(SPI0));
|
||
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
|
||
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
|
||
dma_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
dma_init(DMA0, DMA_CH2, &dma_init_struct);
|
||
|
||
// 初始化接收DMA通道
|
||
dma_deinit(DMA0, DMA_CH1);
|
||
dma_struct_para_init(&dma_init_struct);
|
||
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
|
||
dma_init_struct.memory_addr = (uint32_t)0; // 实际地址将在传输时设置
|
||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
|
||
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
|
||
dma_init_struct.number = 1;
|
||
dma_init_struct.periph_addr = (uint32_t)(&SPI_DATA(SPI0));
|
||
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
|
||
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
|
||
dma_init_struct.priority = DMA_PRIORITY_HIGH;
|
||
dma_init(DMA0, DMA_CH1, &dma_init_struct);
|
||
|
||
// 使能SPI的DMA发送和接收功能
|
||
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
|
||
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
|
||
|
||
// 配置DMA中断
|
||
nvic_irq_enable(DMA0_Channel2_IRQn, 0, 1);
|
||
nvic_irq_enable(DMA0_Channel1_IRQn, 0, 1);
|
||
|
||
// 使能DMA传输完成中断
|
||
dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);
|
||
dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);
|
||
}
|
||
|
||
/**
|
||
* @brief Send or read half word through SPI using DMA
|
||
*
|
||
* @param[in] spi_periph SPI peripheral
|
||
* @param[in] tx_data Data to transmit
|
||
* @param[out] rx_data Pointer to store received data
|
||
* @return 0 if success, -1 if error
|
||
*/
|
||
int spi_rw_half_word_dma(uint32_t spi_periph, uint16_t tx_data,
|
||
uint16_t *rx_data) {
|
||
// 重置完成标志
|
||
spi_dma_tx_complete = false;
|
||
spi_dma_rx_complete = false;
|
||
|
||
// 配置发送DMA
|
||
dma_channel_disable(DMA0, DMA_CH2);
|
||
dma_memory_address_config(DMA0, DMA_CH2, (uint32_t)&tx_data);
|
||
dma_transfer_number_config(DMA0, DMA_CH2, 1);
|
||
dma_channel_enable(DMA0, DMA_CH2);
|
||
|
||
// 配置接收DMA
|
||
dma_channel_disable(DMA0, DMA_CH1);
|
||
dma_memory_address_config(DMA0, DMA_CH1, (uint32_t)rx_data);
|
||
dma_transfer_number_config(DMA0, DMA_CH1, 1);
|
||
dma_channel_enable(DMA0, DMA_CH1);
|
||
|
||
// 等待传输完成,超时时间为100个循环
|
||
uint32_t timeout = 100;
|
||
while ((!spi_dma_tx_complete || !spi_dma_rx_complete) && --timeout) {
|
||
// 空循环等待DMA传输完成
|
||
}
|
||
|
||
// 检查是否超时
|
||
if (timeout == 0) {
|
||
// 禁用DMA通道
|
||
dma_channel_disable(DMA0, DMA_CH2);
|
||
dma_channel_disable(DMA0, DMA_CH1);
|
||
printf("SPI DMA transfer timeout\r\n");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief DMA0_Channel2中断处理函数
|
||
* @param 无
|
||
*/
|
||
extern "C" void DMA0_Channel2_IRQHandler(void) {
|
||
if (dma_interrupt_flag_get(DMA0, DMA_CH2, DMA_INT_FLAG_FTF)) {
|
||
dma_interrupt_flag_clear(DMA0, DMA_CH2, DMA_INT_FLAG_FTF);
|
||
spi_dma_tx_complete = true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief DMA0_Channel1中断处理函数
|
||
* @param 无
|
||
*/
|
||
extern "C" void DMA0_Channel1_IRQHandler(void) {
|
||
if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)) {
|
||
dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FTF);
|
||
spi_dma_rx_complete = true;
|
||
}
|
||
}
|
||
/**
|
||
* @brief 角度传感器初始化
|
||
* @param 无
|
||
*/
|
||
void KTH7823_gpio_init(void) {
|
||
rcu_periph_clock_enable(RCU_GPIOA);
|
||
rcu_periph_clock_enable(RCU_GPIOB);
|
||
rcu_periph_clock_enable(RCU_SPI0);
|
||
rcu_periph_clock_enable(RCU_AF);
|
||
/* 关闭 JTAG,仅保留 SWD(释放 PA15、PB3、PB4) */
|
||
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
|
||
|
||
/* -------- SPI0 全 remap:PB3/4/5 + PA15 -------- */
|
||
gpio_pin_remap_config(GPIO_SPI0_REMAP, ENABLE);
|
||
/* PA15 → NSS, 推挽输出 */
|
||
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
|
||
/* PB3 → SCK, PB5 → MOSI, 推挽输出 */
|
||
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
|
||
GPIO_PIN_3 | GPIO_PIN_5);
|
||
/* PB4 → MISO, 浮空输入 */
|
||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ,
|
||
GPIO_PIN_4 | GPIO_PIN_10 | GPIO_PIN_11);
|
||
}
|
||
|
||
/**
|
||
* @brief SPI 初始化
|
||
*
|
||
* @details Configures SPI hardware and initializes necessary settings
|
||
*/
|
||
void KTH7823_spi_init(void) {
|
||
spi_parameter_struct spi_init_str;
|
||
spi_struct_para_init(&spi_init_str);
|
||
|
||
/* SPI参数:16bit, 主机, 全双工, CPOL=1 CPHA=1, MSB first */
|
||
spi_init_str.device_mode = SPI_MASTER;
|
||
spi_init_str.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||
spi_init_str.frame_size = SPI_FRAMESIZE_16BIT;
|
||
spi_init_str.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
|
||
spi_init_str.nss = SPI_NSS_SOFT;
|
||
spi_init_str.endian = SPI_ENDIAN_MSB;
|
||
|
||
spi_init_str.prescale = 24; /* 5MHz @ 120MHz */
|
||
spi_init(SPI0, &spi_init_str);
|
||
spi_nss_output_enable(SPI0);
|
||
spi_nssp_mode_enable(SPI0);
|
||
spi_enable(SPI0);
|
||
}
|
||
|
||
|
||
/**
|
||
* @ 角度传感器类 初始化
|
||
* @return 0:初始化成功 1:初始化失败
|
||
*/
|
||
u8 angle_sensor::init(void) {
|
||
KTH7823_gpio_init(); // GPIO初始化
|
||
KTH7823_spi_init(); // SPI初始化
|
||
spi_dma_init(); // DMA初始化
|
||
return 0;
|
||
}
|
||
/**
|
||
* @ 角度传感器类 设置当前角度
|
||
* @param angle 输出级角度值
|
||
* @return 0成功/1失败
|
||
*/
|
||
u8 angle_sensor::angle_set(float angle){
|
||
m_cumulativeAngle = angle*REDUCTION_RATIO; // 从Flash读取上次保存的角度
|
||
m_firstUpdate = true;
|
||
return 0;
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief 读取传感器数据
|
||
* @return 传感器数据
|
||
*/
|
||
inline float angle_sensor::read_sensorAngle(void) {
|
||
uint16_t raw_data;
|
||
|
||
ANG_SPI_CS_ENABLE();
|
||
u8 result = spi_rw_half_word_dma(SPI0, DEFAULT_COMMAND, &raw_data);
|
||
ANG_SPI_CS_DISABLE();
|
||
|
||
if (result == 0) {
|
||
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
|
||
float angle_deg = (float)raw_data * ANGLE_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;
|
||
}
|
||
/**
|
||
* @brief 更新传感器角度(输出级)
|
||
* @return 累积角度值
|
||
*/
|
||
float angle_sensor::update(void) {
|
||
read_sensorAngle();
|
||
|
||
if (m_firstUpdate) {
|
||
m_lastAngle = current_angle_deg;
|
||
m_firstUpdate = false;
|
||
return m_cumulativeAngle;
|
||
}
|
||
|
||
// 计算角度变化
|
||
float delta = current_angle_deg - m_lastAngle;
|
||
|
||
// 处理角度绕回情况(0度和360度之间的跳变)
|
||
// 如果变化超过180度,说明发生了绕回
|
||
if (delta > ANGLE_WRAP_THRESHOLD) {
|
||
// 从接近360度绕回到接近0度
|
||
delta -= ANGLE_WRAP_VALUE;
|
||
} else if (delta < -ANGLE_WRAP_THRESHOLD) {
|
||
// 从接近0度绕到接近360度
|
||
delta += ANGLE_WRAP_VALUE;
|
||
}
|
||
|
||
m_cumulativeAngle += delta;
|
||
m_lastAngle = current_angle_deg;
|
||
|
||
return m_cumulativeAngle;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取累积角度值(输出级)
|
||
* @return 累积角度值
|
||
*/
|
||
float angle_sensor::getAngle(void) const {
|
||
return m_cumulativeAngle / REDUCTION_RATIO;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取累积角度值(原始级)
|
||
* @return 累积角度值
|
||
*/
|
||
float angle_sensor::getRawAngle(void) const { return m_cumulativeAngle; }
|
||
|
||
/**
|
||
* @brief 获取角度值(原始级)
|
||
* @return 角度值(原始级)
|
||
*/
|
||
float angle_sensor::getcurrent_sensorangle(void) const {
|
||
return current_angle_deg;
|
||
}
|