#include "ang_sensor.h" #include "gd32c10x_dma.h" #include "gd32c10x_gpio.h" #include "gd32c10x_spi.h" #include #include #include #include "initial.h" #define SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15) #define SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15) 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 = 270.0f; constexpr float ANGLE_WRAP_VALUE = 360.0f; constexpr int SIZE_FLOAT = sizeof(float); // DMA传输完成标志 volatile bool spi_dma_tx_complete = false; volatile bool spi_dma_rx_complete = false; /** * @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); // 等待传输完成,超时时间为1000个循环 uint32_t timeout = 1000; 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); } /** * @brief KTH7823 初始化 */ void angle_sensor::KTH7823_init(void) { KTH7823_gpio_init(); // GPIO初始化 KTH7823_spi_init(); // SPI初始化 spi_dma_init(); // DMA初始化 } /** * @brief 角度传感器构造函数 */ angle_sensor::angle_sensor(void) { KTH7823_init(); } /** * @brief 读取传感器数据 * @return 传感器数据 */ float angle_sensor::read_sensorAngle(void) { u16 u16data = FAULT_RECEIVE; SPI_CS_ENABLE(); // 使用DMA发送命令并接收数据 if (!spi_rw_half_word_dma(SPI0, DEFAULT_COMMAND, &u16data)) { SPI_CS_DISABLE(); current_angle_deg = u16data * ANGLE_FACTOR; current_angle_rad = u16data * RAD_FACTOR; return u16data * ANGLE_FACTOR; } else { SPI_CS_DISABLE(); // 处理读取错误 printf("Error reading angle from sensor.\n"); return 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; } std::memmove(velocity, velocity + 1, SIZE_FLOAT * (VEL_FILTER_SIZE - 1)); velocity[VEL_FILTER_SIZE - 1] = delta * VELOCITY_SCALE; 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::getVelocity(void) const { return getRawVelocity() / REDUCTION_RATIO; } /** * @brief 获取速度值(原始级) * @return 速度值(原始级) */ float angle_sensor::getRawVelocity(void) const { float velocity_filted = 0; for (int i = 0; i < VEL_FILTER_SIZE - 1; i++) { velocity_filted += velocity[i]; } return velocity_filted / (VEL_FILTER_SIZE - 1); // return velocity[VEL_FILTER_SIZE - 1]; } /** * @brief 获取角度值(原始级) * @return 角度值(原始级) */ float angle_sensor::getcurrent_sensorangle(void) const { return current_angle_deg; } /** * @brief 重置累积角度值 */ void angle_sensor::reset(void) { m_cumulativeAngle = 0.0f; m_firstUpdate = true; }