2026-05-23 22:46:32 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @file device/ang_sensor.cpp
|
|
|
|
|
|
* @brief 底层设备驱动与外设封装源文件
|
|
|
|
|
|
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2025-10-31 01:17:52 +08:00
|
|
|
|
#include "ang_sensor.h"
|
2026-01-04 22:26:22 +08:00
|
|
|
|
#include "Can.h"
|
2025-11-22 23:59:43 +08:00
|
|
|
|
#include "Filter.h"
|
2026-01-20 01:28:52 +08:00
|
|
|
|
#include "config.h"
|
2026-01-04 22:26:22 +08:00
|
|
|
|
#include "flash.h"
|
2025-11-01 21:03:57 +08:00
|
|
|
|
#include "gd32c10x_dma.h"
|
2025-10-09 21:09:33 +08:00
|
|
|
|
#include "gd32c10x_gpio.h"
|
2025-10-14 00:49:58 +08:00
|
|
|
|
#include "gd32c10x_spi.h"
|
2025-11-03 02:38:43 +08:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
#include <cstring>
|
2025-11-01 21:03:57 +08:00
|
|
|
|
#include <stdint.h>
|
2025-11-22 23:59:43 +08:00
|
|
|
|
|
2026-03-15 02:38:50 +08:00
|
|
|
|
// ANG_SENS 调试宏定义
|
|
|
|
|
|
#if ANG_SENS_DEBUG
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief ANG_SENS_DEBUG_PRINT 宏定义 */
|
2026-03-15 02:38:50 +08:00
|
|
|
|
#define ANG_SENS_DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
|
|
|
|
|
#else
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief ANG_SENS_DEBUG_PRINT 宏定义 */
|
2026-03-15 02:38:50 +08:00
|
|
|
|
#define ANG_SENS_DEBUG_PRINT(fmt, ...) ((void)0)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief ANG_SPI_CS_ENABLE 宏定义 */
|
2025-12-08 02:48:59 +08:00
|
|
|
|
#define ANG_SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief ANG_SPI_CS_DISABLE 宏定义 */
|
2025-12-08 02:48:59 +08:00
|
|
|
|
#define ANG_SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief DRV_SPI_CS_ENABLE 宏定义 */
|
2025-12-08 02:48:59 +08:00
|
|
|
|
#define DRV_SPI_CS_ENABLE() gpio_bit_reset(GPIOB, GPIO_PIN_14)
|
2026-05-23 22:46:32 +08:00
|
|
|
|
/** @brief DRV_SPI_CS_DISABLE 宏定义 */
|
2025-12-08 02:48:59 +08:00
|
|
|
|
#define DRV_SPI_CS_DISABLE() gpio_bit_set(GPIOB, GPIO_PIN_14)
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2026-05-24 01:21:41 +08:00
|
|
|
|
// 全局角度传感器单例:系统只有一个 KTH7823 角度传感器。
|
|
|
|
|
|
// 初始化顺序由 main::hardware_init() 调用 KTH7823.init() 保证。
|
2025-11-22 23:59:43 +08:00
|
|
|
|
angle_sensor KTH7823; // 角度传感器初始化
|
2025-12-16 22:39:39 +08:00
|
|
|
|
extern FlashEEPROM flashEEP;
|
2025-12-05 00:46:19 +08:00
|
|
|
|
extern EncoderAngleKalman Angle_kalman;
|
|
|
|
|
|
extern EncoderVelocityKalman Vel_kalman;
|
2026-03-15 02:38:50 +08:00
|
|
|
|
extern CAN_transmiter CAN0_transmiter; // CAN 初始化
|
2025-11-22 23:59:43 +08:00
|
|
|
|
|
2025-11-01 21:03:57 +08:00
|
|
|
|
/**
|
2026-09-01 02:46:25 +08:00
|
|
|
|
* @brief Send or read half word through SPI by register polling
|
2025-11-01 21:03:57 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @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
|
2026-09-01 02:46:25 +08:00
|
|
|
|
* @note 单半字轮询收发。DMA 版本(已移除)每次传输需要:重配 2 个 DMA
|
|
|
|
|
|
* 通道(约 10 次寄存器写) + 2 次 FTF 中断 + 忙等完成标志,而 16bit
|
|
|
|
|
|
* @5MHz 帧本身只有 3.2μs——DMA 的准备与中断开销和传输时间同量级。
|
|
|
|
|
|
* 轮询同样忙等帧时间,但砍掉了全部 DMA 开销与 40k 次/秒的中断。
|
2025-11-01 21:03:57 +08:00
|
|
|
|
*/
|
2026-09-01 02:46:25 +08:00
|
|
|
|
int spi_rw_half_word_polling(uint32_t spi_periph, uint16_t tx_data,
|
|
|
|
|
|
uint16_t *rx_data) {
|
|
|
|
|
|
u32 timeout = 1000;
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2026-09-01 02:46:25 +08:00
|
|
|
|
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE) == RESET) {
|
|
|
|
|
|
if (--timeout == 0U) {
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
2025-11-01 21:03:57 +08:00
|
|
|
|
}
|
2026-09-01 02:46:25 +08:00
|
|
|
|
spi_i2s_data_transmit(spi_periph, tx_data);
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2026-09-01 02:46:25 +08:00
|
|
|
|
timeout = 1000;
|
|
|
|
|
|
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE) == RESET) {
|
|
|
|
|
|
if (--timeout == 0U) {
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
2025-11-01 21:03:57 +08:00
|
|
|
|
}
|
2026-09-01 02:46:25 +08:00
|
|
|
|
*rx_data = spi_i2s_data_receive(spi_periph);
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2026-09-01 02:46:25 +08:00
|
|
|
|
// 等待移位完成再返回:调用方返回后立即拉高 CS,
|
|
|
|
|
|
// 若最后一位仍在移位会截断帧
|
|
|
|
|
|
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS) != RESET) {
|
|
|
|
|
|
}
|
2025-11-01 21:03:57 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 角度传感器初始化
|
|
|
|
|
|
* @param 无
|
|
|
|
|
|
*/
|
2025-11-01 23:41:32 +08:00
|
|
|
|
void KTH7823_gpio_init(void) {
|
2025-10-09 21:09:33 +08:00
|
|
|
|
rcu_periph_clock_enable(RCU_GPIOA);
|
2025-10-30 20:20:14 +08:00
|
|
|
|
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);
|
2025-09-23 00:27:51 +08:00
|
|
|
|
|
2025-10-30 20:20:14 +08:00
|
|
|
|
/* -------- 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,
|
2025-10-31 01:17:52 +08:00
|
|
|
|
GPIO_PIN_4 | GPIO_PIN_10 | GPIO_PIN_11);
|
2025-09-23 00:27:51 +08:00
|
|
|
|
}
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2025-09-23 00:27:51 +08:00
|
|
|
|
/**
|
2025-11-01 21:03:57 +08:00
|
|
|
|
* @brief SPI 初始化
|
2025-09-23 00:27:51 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @details Configures SPI hardware and initializes necessary settings
|
|
|
|
|
|
*/
|
2025-11-01 23:41:32 +08:00
|
|
|
|
void KTH7823_spi_init(void) {
|
2025-10-30 20:20:14 +08:00
|
|
|
|
spi_parameter_struct spi_init_str;
|
|
|
|
|
|
spi_struct_para_init(&spi_init_str);
|
2025-09-23 00:27:51 +08:00
|
|
|
|
|
2026-03-15 02:38:50 +08:00
|
|
|
|
/* SPI 参数:16bit, 主机,全双工,CPOL=1 CPHA=1, MSB first */
|
2025-10-30 20:20:14 +08:00
|
|
|
|
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;
|
2025-11-01 21:03:57 +08:00
|
|
|
|
|
2025-10-31 01:17:52 +08:00
|
|
|
|
spi_init_str.prescale = 24; /* 5MHz @ 120MHz */
|
2025-10-30 20:20:14 +08:00
|
|
|
|
spi_init(SPI0, &spi_init_str);
|
|
|
|
|
|
spi_nss_output_enable(SPI0);
|
|
|
|
|
|
spi_nssp_mode_enable(SPI0);
|
|
|
|
|
|
spi_enable(SPI0);
|
2025-09-23 00:27:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-01 21:03:57 +08:00
|
|
|
|
/**
|
2026-01-04 22:26:22 +08:00
|
|
|
|
* @ 角度传感器类 初始化
|
|
|
|
|
|
* @return 0:初始化成功 1:初始化失败
|
2025-11-01 21:03:57 +08:00
|
|
|
|
*/
|
2025-12-16 22:39:39 +08:00
|
|
|
|
u8 angle_sensor::init(void) {
|
2026-03-15 02:38:50 +08:00
|
|
|
|
KTH7823_gpio_init(); // GPIO 初始化
|
|
|
|
|
|
KTH7823_spi_init(); // SPI 初始化
|
2025-12-08 02:48:59 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2026-03-09 01:35:26 +08:00
|
|
|
|
|
2025-12-16 22:39:39 +08:00
|
|
|
|
/**
|
2026-01-04 22:26:22 +08:00
|
|
|
|
* @ 角度传感器类 设置当前角度
|
|
|
|
|
|
* @param angle 输出级角度值
|
2026-03-15 02:38:50 +08:00
|
|
|
|
* @return 0 成功/1 失败
|
2025-12-16 22:39:39 +08:00
|
|
|
|
*/
|
2026-01-04 22:26:22 +08:00
|
|
|
|
u8 angle_sensor::angle_set(float angle) {
|
2026-03-09 01:35:26 +08:00
|
|
|
|
m_cumulativeAngle = angle * REDUCTION_RATIO;
|
2025-12-20 19:53:52 +08:00
|
|
|
|
m_firstUpdate = true;
|
2025-12-16 22:39:39 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-01 21:03:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 读取传感器数据
|
|
|
|
|
|
* @return 传感器数据
|
|
|
|
|
|
*/
|
2025-11-23 18:31:47 +08:00
|
|
|
|
inline float angle_sensor::read_sensorAngle(void) {
|
2025-12-08 02:48:59 +08:00
|
|
|
|
uint16_t raw_data;
|
2025-11-01 23:41:32 +08:00
|
|
|
|
|
2025-12-08 02:48:59 +08:00
|
|
|
|
ANG_SPI_CS_ENABLE();
|
2026-09-01 02:46:25 +08:00
|
|
|
|
u8 result = spi_rw_half_word_polling(SPI0, DEFAULT_COMMAND, &raw_data);
|
2025-12-08 02:48:59 +08:00
|
|
|
|
ANG_SPI_CS_DISABLE();
|
|
|
|
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
|
2026-01-20 01:28:52 +08:00
|
|
|
|
float angle_deg = -(float)raw_data * ANGLESENS_FACTOR + ANGLESENS_OFFSET;
|
2025-12-08 02:48:59 +08:00
|
|
|
|
current_angle_deg = angle_deg;
|
|
|
|
|
|
current_angle_rad = angle_deg * DEG2RAD; // M_PI/180.0f
|
|
|
|
|
|
return angle_deg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-15 02:38:50 +08:00
|
|
|
|
// 仅在调试模式下输出错误,避免发布版本中的 I/O 开销
|
2025-12-08 02:48:59 +08:00
|
|
|
|
if (result != 0) {
|
2026-03-15 02:38:50 +08:00
|
|
|
|
ANG_SENS_DEBUG_PRINT("Error reading angle from sensor.\n");
|
2025-12-08 02:48:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (float)FAULT_RECEIVE;
|
2025-11-02 01:54:01 +08:00
|
|
|
|
}
|
2026-03-09 01:35:26 +08:00
|
|
|
|
|
2025-11-03 02:38:43 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 更新传感器角度(输出级)
|
|
|
|
|
|
* @return 累积角度值
|
|
|
|
|
|
*/
|
2025-11-02 01:54:01 +08:00
|
|
|
|
float angle_sensor::update(void) {
|
2025-11-08 21:04:35 +08:00
|
|
|
|
read_sensorAngle();
|
2025-11-02 01:54:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (m_firstUpdate) {
|
2025-11-08 21:04:35 +08:00
|
|
|
|
m_lastAngle = current_angle_deg;
|
2025-11-02 01:54:01 +08:00
|
|
|
|
m_firstUpdate = false;
|
|
|
|
|
|
return m_cumulativeAngle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算角度变化
|
2025-11-08 21:04:35 +08:00
|
|
|
|
float delta = current_angle_deg - m_lastAngle;
|
2025-11-02 01:54:01 +08:00
|
|
|
|
|
2026-03-15 02:38:50 +08:00
|
|
|
|
// 处理角度绕回情况(0 度和 360 度之间的跳变)
|
|
|
|
|
|
// 如果变化超过 300 度,说明发生了绕回
|
2025-11-06 02:07:15 +08:00
|
|
|
|
if (delta > ANGLE_WRAP_THRESHOLD) {
|
2026-03-15 02:38:50 +08:00
|
|
|
|
// 从接近 360 度绕回到接近 0 度
|
2025-11-06 02:07:15 +08:00
|
|
|
|
delta -= ANGLE_WRAP_VALUE;
|
|
|
|
|
|
} else if (delta < -ANGLE_WRAP_THRESHOLD) {
|
2026-03-15 02:38:50 +08:00
|
|
|
|
// 从接近 0 度绕到接近 360 度
|
2025-11-06 02:07:15 +08:00
|
|
|
|
delta += ANGLE_WRAP_VALUE;
|
2025-11-02 01:54:01 +08:00
|
|
|
|
}
|
2025-11-06 02:07:15 +08:00
|
|
|
|
|
2025-11-03 02:38:43 +08:00
|
|
|
|
m_cumulativeAngle += delta;
|
2025-11-08 21:04:35 +08:00
|
|
|
|
m_lastAngle = current_angle_deg;
|
2025-11-02 01:54:01 +08:00
|
|
|
|
return m_cumulativeAngle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 02:38:43 +08:00
|
|
|
|
/**
|
2026-03-15 02:38:50 +08:00
|
|
|
|
* @brief 获取累积角度值 (输出级)
|
2025-11-03 02:38:43 +08:00
|
|
|
|
* @return 累积角度值
|
|
|
|
|
|
*/
|
|
|
|
|
|
float angle_sensor::getAngle(void) const {
|
2025-11-08 02:15:14 +08:00
|
|
|
|
return m_cumulativeAngle / REDUCTION_RATIO;
|
2025-11-03 02:38:43 +08:00
|
|
|
|
}
|
2025-11-02 01:54:01 +08:00
|
|
|
|
|
2025-11-03 02:38:43 +08:00
|
|
|
|
/**
|
2026-03-15 02:38:50 +08:00
|
|
|
|
* @brief 获取累积角度值 (原始级)
|
2025-11-03 02:38:43 +08:00
|
|
|
|
* @return 累积角度值
|
|
|
|
|
|
*/
|
|
|
|
|
|
float angle_sensor::getRawAngle(void) const { return m_cumulativeAngle; }
|
|
|
|
|
|
|
2025-11-08 21:04:35 +08:00
|
|
|
|
/**
|
2026-03-15 02:38:50 +08:00
|
|
|
|
* @brief 获取角度值 (原始级)
|
|
|
|
|
|
* @return 角度值 (原始级)
|
2025-11-08 21:04:35 +08:00
|
|
|
|
*/
|
2026-03-09 01:35:26 +08:00
|
|
|
|
float angle_sensor::getcurrent_sensorangle(void) const{
|
2025-11-08 21:04:35 +08:00
|
|
|
|
return current_angle_deg;
|
2026-08-16 02:13:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 设置电角度零位校准角
|
|
|
|
|
|
* @param[in] angle 校准角(度)
|
|
|
|
|
|
* @return 0 成功
|
|
|
|
|
|
*/
|
|
|
|
|
|
u8 angle_sensor::set_calibration(float angle) {
|
|
|
|
|
|
calibration_angle = normalizeAngle360(angle);
|
|
|
|
|
|
return 0;
|
2026-03-15 02:38:50 +08:00
|
|
|
|
}
|