From bd77f7a9a958a80e025cdacc04d3acb506402358 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Sat, 1 Nov 2025 21:03:57 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=92=E5=BA=A6=E4=BC=A0=E6=84=9F=E5=99=A8?= =?UTF-8?q?=E6=94=B9=E4=BD=BF=E7=94=A8DMA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Robot_V2/device/Can.cpp | 6 - Robot_V2/device/ang_sensor.cpp | 229 ++++++++++++++++++++++++++------- Robot_V2/device/ang_sensor.h | 4 +- Robot_V2/main.cpp | 20 ++- 4 files changed, 194 insertions(+), 65 deletions(-) diff --git a/Robot_V2/device/Can.cpp b/Robot_V2/device/Can.cpp index 09846ba..9ad9f83 100644 --- a/Robot_V2/device/Can.cpp +++ b/Robot_V2/device/Can.cpp @@ -733,9 +733,6 @@ void DMA0_Channel4_IRQHandler(void) { i++) { CAN0_transmiter.receive_message.rx_data[i] = can_rx_buffer[i]; } - - // 接收标志位置1 - CAN0_transmiter.can0_receive_flag = SET; } } @@ -747,8 +744,5 @@ void DMA0_Channel5_IRQHandler(void) { if (dma_interrupt_flag_get(DMA0, DMA_CH5, DMA_INT_FLAG_FTF)) { // 清除DMA传输完成中断标志 dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_G); - - // 发送完成标志位置1 - CAN0_transmiter.can0_send_flag = RESET; } } diff --git a/Robot_V2/device/ang_sensor.cpp b/Robot_V2/device/ang_sensor.cpp index a5cba00..5614dcd 100644 --- a/Robot_V2/device/ang_sensor.cpp +++ b/Robot_V2/device/ang_sensor.cpp @@ -1,57 +1,184 @@ #include "ang_sensor.h" +#include "gd32c10x_dma.h" #include "gd32c10x_gpio.h" #include "gd32c10x_spi.h" +#include + #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 u16 DEFAULT_COMMAND = 0x0000; +constexpr u16 FAULT_RECEIVE = 0xFFFF; + +// DMA传输完成标志 +volatile bool spi_dma_tx_complete = false; +volatile bool spi_dma_rx_complete = false; /** - * @brief Send or read half word through SPI + * @brief Send or read half word through SPI using polling method * * @param[in] spi_periph SPI peripheral * @param[in] i_HalfWord data */ -uint16_t spi_rw_half_word(uint32_t spi_periph, const uint16_t i_HalfWord) { - uint32_t to; - uint16_t data = 0xFFFF; - bool ok = true; +u16 spi_rw_half_word(u32 spi_periph, const u16 i_HalfWord) { + u32 timeout; + u16 received_data = FAULT_RECEIVE; - /* ---------- Send data ---------- */ - to = 200; - while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) && --to) + /* Wait until transmit buffer is empty */ + timeout = 200; + while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) && --timeout) ; - if (to == 0) - ok = false; + if (timeout == 0) + return FAULT_RECEIVE; - if (ok) { - if (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) { - (void)spi_i2s_data_receive(spi_periph); /* throw Dummy */ - } - spi_i2s_data_transmit(spi_periph, i_HalfWord); - /* wait rx succ*/ - to = 200; - while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) && --to) - ; - if (to == 0) - ok = false; - else - data = spi_i2s_data_receive(spi_periph); /* throw Dummy */ + /* Clear RX buffer if not empty */ + if (SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) { + (void)spi_i2s_data_receive(spi_periph); } - /* ---------- wait bsu idle ---------- */ - if (ok) { - to = 200; - while ((SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) && - SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE) && --to) - ; - if (to == 0) - ok = false; - } + /* Send data */ + spi_i2s_data_transmit(spi_periph, i_HalfWord); - return ok ? data : 0xFFFF; + /* Wait for response */ + timeout = 200; + while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) && --timeout) + ; + if (timeout == 0) + return FAULT_RECEIVE; + + /* Read received data */ + received_data = spi_i2s_data_receive(spi_periph); + + /* Wait until SPI is not busy */ + timeout = 200; + while ((SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) && --timeout) + ; + if (timeout == 0) + return FAULT_RECEIVE; + + return received_data; } +/** + * @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, 1, 1); + nvic_irq_enable(DMA0_Channel1_IRQn, 1, 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); + 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 KHT7823_gpio_init(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOB); @@ -71,8 +198,9 @@ void KHT7823_gpio_init(void) { gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_10 | GPIO_PIN_11); } + /** - * @brief Initialize SPI module + * @brief SPI 初始化 * * @details Configures SPI hardware and initializes necessary settings */ @@ -87,7 +215,7 @@ void KHT7823_spi_init(void) { 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); @@ -95,21 +223,28 @@ void KHT7823_spi_init(void) { spi_enable(SPI0); } +/** + * @brief KHT7823 初始化 + */ void KHT7823_init(void) { - KHT7823_gpio_init(); - KHT7823_spi_init(); + KHT7823_gpio_init(); // GPIO初始化 + KHT7823_spi_init(); // SPI初始化 + spi_dma_init(); // DMA初始化 } +/** + * @brief 读取传感器数据 + * @return 传感器数据 + */ float KHT7823_readAngle() { - u16 u16Command = 0x0000; // 读取角度命令 - - float ang = 0; SPI_CS_ENABLE(); - // 发送命令1,同时接收回答1 - u16 u16data = spi_rw_half_word(SPI0, u16Command); - SPI_CS_DISABLE(); - - ang = u16data * ANGLE_FACTOR; - - return ang; + // 使用DMA发送命令并接收数据 + u16 u16data; + if (spi_rw_half_word_dma(SPI0, DEFAULT_COMMAND, &u16data) == 0) { + SPI_CS_DISABLE(); + return u16data * ANGLE_FACTOR; + } else { + SPI_CS_DISABLE(); + return FAULT_RECEIVE; // 错误返回 + } } \ No newline at end of file diff --git a/Robot_V2/device/ang_sensor.h b/Robot_V2/device/ang_sensor.h index f57d4d2..84a6e8a 100644 --- a/Robot_V2/device/ang_sensor.h +++ b/Robot_V2/device/ang_sensor.h @@ -9,8 +9,10 @@ extern "C" { void KHT7823_init(void); u16 spi_rw_half_word(u32 spi_periph, const u16 i_HalfWord); float KHT7823_readAngle(void); +int spi_rw_half_word_dma(uint32_t spi_periph, uint16_t tx_data, uint16_t* rx_data); + #ifdef __cplusplus } #endif -#endif +#endif \ No newline at end of file diff --git a/Robot_V2/main.cpp b/Robot_V2/main.cpp index c7543e9..17fc34f 100644 --- a/Robot_V2/main.cpp +++ b/Robot_V2/main.cpp @@ -9,25 +9,23 @@ #include "systick.h" // 全局变量定义 -CAN_transmiter CAN0_transmiter; //CAN初始化 +CAN_transmiter CAN0_transmiter; //CAN初始化 FOC_Controlroller FOC; // FOC控制初始化 sampler sampler; // 采样器初始化 int main(void) { - systick_config(); // 系统时钟初始化 - USART0_init(); // 调试串口初始化 - User_timer_init(); // Timer初始化 - sampler.init(); // 采样器初始化 - driver_init(); // 电机驱动初始化 - - KHT7823_init(); + systick_config(); // 系统时钟初始化 + USART0_init(); // 调试串口初始化 + User_timer_init(); // Timer初始化 + sampler.init(); // ADC采样器初始化 + KHT7823_init(); // 角度传感器初始化 + driver_init(); // 电机驱动初始化 watchdog_init(5000); while (1) { - /* clear the FWDGT reset flag */ // delay_1ms(100); - fwdgt_counter_reload(); - CAN0_transmiter.communication_check(); + fwdgt_counter_reload(); // 看门狗复位 + CAN0_transmiter.communication_check(); // CAN通信 } }