#include "board.h" #include "hard_imu_uart3.h" #include "hpm_dma_drv.h" #include "hpm_dmamux_drv.h" // #include "hard_uart_rx_dma_soft_idle.h" // 软件触发 模拟空闲中断 需要连接触发物理接口和rx 且需要2路定时器通道 #include "hpm_uart_drv.h" #include "hard_hdma_int.h" #include "test.h" /* uart0 给控制台打印串口使用了 尽量避开 uart should configure pin function before opening clock 1、IO 2、时钟 3、串口 4、手册:源数据 burst 数量,burst 传输的字节数等于(SrcBurstSize * SrcWidth) 这个用法要看手册 单次允许DMA调度传输的最大字节数 5、AHB外设只能用HDMA??? 31-0 TRANSIZE 源数据的数据量,总传输数据量为(TranSize * SrcWidth) */ /* hpm6750没有串口空闲中断 无法使用串口空闲加DMA进行接收 所以接收方面使用软件超时 增加阻塞的读中断次数代替DMA传输 由于增加了FIFO,串口也不会像之前那样频繁中断 假如 thr 12 就是接收12个字节进入一次接收中断 #define UART_SOC_FIFO_SIZE (16U) 设置的触发中单的长度要小于FIFO长度 不然会导致丢数据 3/4 12字节 以628M主频 512字节 中断43次来说 115200 波特率 要 44.4ms(传输) + 0.014ms(中断) ≈ 44.4ms。 如果换成460800​ 波特率,处理 512字节​ 数据包的总时间约为 11.1ms。如果每次都是512字节 这对于内环400hz 不成立 后面看了imu接收的姿态信息是 大概70-80字节 数据包是70字节,在460800波特率下,传输时间约为 1.52ms 也就是不到2ms的姿态包 */ /* ========== 硬件配置 - 根据实际硬件修改 ========== */ #define IMU_UART3 HPM_UART3 /* 使用 UART3 */ #define IMU_UART3_CLK_NAME clock_uart3 /* UART3 时钟 */ #define IMU_UART3_IRQ IRQn_UART3 /* UART3 中断号*/ #define IMU_UART3_IRQ_RANK 2 #define IMU_UART3_BAUD 460800 /*===================软空闲中断 DMA接收 额外配置============================*/ //#define IMU_UART3_RX_TRGM HPM_TRGM2 //#define IMU_UART3_RX_TRGM_PIN IOC_PAD_PD19 //#define IMU_UART3_RX_TRGM_INPUT_SRC HPM_TRGM2_INPUT_SRC_TRGM2_P9 /* Corresponding to Pin setting */ //#define IMU_UART3_RX_TRGM_OUTPUT_GPTMR_IN HPM_TRGM2_OUTPUT_SRC_GPTMR4_IN2 /* Corresponding to GPTMR inst */ //#define IMU_UART3_RX_TRGM_OUTPUT_GPTMR_SYNCI HPM_TRGM2_OUTPUT_SRC_GPTMR4_SYNCI /* Corresponding to GPTMR inst */ //#define IMU_UART3_RX_GPTMR HPM_GPTMR4 //#define IMU_UART3_RX_GPTMR_CLK_NAME clock_gptmr4 //#define IMU_UART3_RX_GPTMR_CMP_CHANNEL IRQn_GPTMR4 //#define IMU_UART3_RX_GPTMR_CAPTURE_CHANNEL 0 //#define IMU_UART3_RX_GPTMR_IRQ 2 /* ========== 缓冲区定义 ========== */ /* DMA 缓冲区必须放在非缓存区域 */ ATTR_PLACE_AT_NONCACHEABLE uint8_t USART3_DMA_Recieve_Buf[UART3_RECIEVE_LENDTH] = {0}; // ATTR_PLACE_AT_NONCACHEABLE uint8_t dma_buf[UART3_RECIEVE_LENDTH] = {0}; ATTR_PLACE_AT_NONCACHEABLE uint8_t USART3_Tx_Buf[UART3_TX_MAX_LENGTH] = {0}; /* ========== 静态变量 ========== */ static volatile uint32_t length; static volatile bool rec_succ = false; static volatile bool uart3_rx_fifo_timeout; static volatile uint16_t rx3_interrupt_count; /* ========== 静态函数声明 ========== */ static void Initial_UART3(unsigned int bps); static void DMA_UART3Config(void); static void UART3NVIC_Configuration(void); /* ========== 函数实现 ========== */ /** * @brief IMU UART3 初始化 - 保留原名 */ void imu_uart3_init(unsigned int bps) { Initial_UART3(bps); DMA_UART3Config(); UART3NVIC_Configuration(); } static void uart3_pin_config(void) { HPM_IOC->PAD[IOC_PAD_PB24].FUNC_CTL = IOC_PB24_FUNC_CTL_UART3_RXD; HPM_IOC->PAD[IOC_PAD_PB25].FUNC_CTL = IOC_PB25_FUNC_CTL_UART3_TXD; } /** * @brief 初始化 UART3 接口 - 保留原名 */ static void Initial_UART3(unsigned int bps) { uart_config_t uart_config = {0}; /* 配置IO 使能 UART3 时钟 */ uart3_pin_config(); clock_set_source_divider(IMU_UART3_CLK_NAME, clk_src_osc24m, 1); clock_add_to_group(IMU_UART3_CLK_NAME, 0); /* 获取默认 UART 配置 */ uart_default_config(IMU_UART3, &uart_config); /* 修改配置 */ uart_config.baudrate = bps; uart_config.word_length = word_length_8_bits; /* 8 位数据 */ uart_config.num_of_stop_bits = stop_bits_1; /* 1 位停止位 */ uart_config.parity = parity_none; /* 无校验 */ uart_config.fifo_enable = true; /* 使能 FIFO */ uart_config.dma_enable = true; /* 使能 DMA */ uart_config.tx_fifo_level = uart_tx_fifo_trg_not_full; // 1个字节起搬 DMA->FIFO->UART输出 uart_config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters; // 16*3/4 = 12字节FIFO 对于512字节的缓冲区需要 42到43次中断 uart_config.src_freq_in_hz = clock_get_frequency(IMU_UART3_CLK_NAME); /* 初始化 UART */ hpm_stat_t stat = uart_init(IMU_UART3, &uart_config); if (stat != status_success) { /* uart failed to be initialized */ printf("failed to initialize uart\n"); while(1); } } /** * @brief 串口3 DMA 初始化配置 */ void DMA_UART3Config(void) { dma_handshake_config_t handshake_config; dma_channel_config_t channel_config; /* 使能 DMA 时钟 */ // HDMA 时钟来源于系统总线时钟(AHB) /* ========== 配置 TX DMA 通道 ========== */ /* 初始化 DMA 通道 */ dma_default_channel_config(IMU_UART3_DMA_CONTROLLER, &channel_config); /* 配置 DMAMUX:将 UART3 TX 请求连接到 TX DMA 通道 */ dmamux_config(IMU_UART3_DMAMUX_CONTROLLER, IMU_UART3_TX_DMAMUX_CH, IMU_UART3_TX_DMA_REQ, true); /* 配置 TX 握手参数 */ dma_default_handshake_config(IMU_UART3_DMA_CONTROLLER, &handshake_config); handshake_config.ch_index = IMU_UART3_TX_DMA_CH; handshake_config.dst = (uint32_t)&IMU_UART3->THR; /* 目标:发送寄存器 */ handshake_config.dst_fixed = true; /* 目标地址固定 */ handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)USART3_Tx_Buf); /* 源:内存 */ // 建议4字节对齐 handshake_config.src_fixed = false; /* 源地址递增 */ handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE; /* 字节传输 */ handshake_config.size_in_byte = UART3_TX_MAX_LENGTH; /* 传输大小 */ hpm_stat_t stat = dma_setup_handshake(IMU_UART3_DMA_CONTROLLER, &handshake_config, false); // 不触发单次发送搬运 if(stat != status_success) { printf("uart3 dma tx config error\r\n"); } } /** * @brief 初始化 USART3 中断优先级 - 保留原名 */ void UART3NVIC_Configuration(void) { /* uart_intr_rx_data_avail_or_timeout // 接收缓冲区非空 或 超时(FIFO) uart_intr_tx_slot_avail // 发送缓冲区空 uart_intr_rx_line_stat // 接收线状态 uart_intr_modem_stat // 模式状态(流控等) */ uart_enable_irq(IMU_UART3, uart_intr_rx_data_avail_or_timeout); // 接收中断 intc_m_enable_irq_with_priority(IMU_UART3_IRQ, IMU_UART3_IRQ_RANK); intc_m_enable_irq_with_priority(IMU_UART3_DMA_IRQ, IMU_UART3_DMA_IRQ_RANK); } /** * @brief UART3 发送 1 字节数据 */ void UART3_Put_Char(unsigned char data) { /* 等待发送寄存器空 */ while (!uart_check_status(IMU_UART3, uart_stat_transmitter_empty)); /* 发送数据 */ uart_send_byte(IMU_UART3, data); /* 等待发送完成 */ while (!uart_check_status(IMU_UART3, uart_stat_transmitter_empty)); } /** * @brief 开启 USART3 DMA 发送 - 保留原名 */ void open_usart3_dma_tx(unsigned short count) { dma_handshake_config_t handshake_config; /* 等待上次发送完成 */ // 软件dma传输完成标志 每次调用open_usart3_dma_tx会重新置位硬件TC uint32_t timeout = 1000000; while (usart3_tx_isbusy() && timeout--) { __asm("nop"); } if (timeout == 0) { // 超时处理,复位DMA dma_abort_channel(IMU_UART3_DMA_CONTROLLER, IMU_UART3_TX_DMA_CH); uart3_tx_dma_done = true; // 强制完成 } /* 重新配置 TX 传输大小 */ dma_default_handshake_config(IMU_UART3_DMA_CONTROLLER, &handshake_config); handshake_config.ch_index = IMU_UART3_TX_DMA_CH; handshake_config.dst = (uint32_t)&IMU_UART3->THR; handshake_config.dst_fixed = true; handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)USART3_Tx_Buf); handshake_config.src_fixed = false; handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE; handshake_config.size_in_byte = count; dma_setup_handshake(IMU_UART3_DMA_CONTROLLER, &handshake_config, true); // true表示触发一次 } /** * @brief 获取串口发送是否忙碌 */ bool usart3_tx_isbusy(void) { return !uart3_tx_dma_done; // 如果没完成,就是忙碌 } /* ========== 中断服务函数 ========== */ extern void recv_imu_data_hookfunction(const uint8_t *pbuffer, uint32_t rx_length); #ifndef UART_DRV_TEST SDK_DECLARE_EXT_ISR_M(IMU_UART3_IRQ, uart3_isr) void uart3_isr(void) { uint8_t count = 0; uint8_t irq_id = uart_get_irq_id(IMU_UART3); if (irq_id == uart_intr_id_rx_data_avail) { rx3_interrupt_count++; while (uart_check_status(IMU_UART3, uart_stat_data_ready)) { USART3_DMA_Recieve_Buf[length++] = uart_read_byte(IMU_UART3); count++; /*in order to ensure rx fifo there are remaining bytes*/ if (count > 12) { break; } } } if (irq_id == uart_intr_id_rx_timeout) { // 接收超时 FIFO超时4个字符后代表一次接收完毕 // 接收完毕 rx3_interrupt_count++; while (uart_check_status(IMU_UART3, uart_stat_data_ready)) { USART3_DMA_Recieve_Buf[length++] = uart_read_byte(IMU_UART3); } // recv_imu_data_hookfunction((uint8_t *)USART3_DMA_Recieve_Buf, length); memset(USART3_Tx_Buf,0,sizeof(USART3_Tx_Buf)); memcpy(USART3_Tx_Buf, USART3_DMA_Recieve_Buf,length); rec_succ = true; length = 0; // uart_rx_fifo_timeout = true; } } #endif /* uart dma rx_irq tx_dma demo 2026/03/14 pass*/ #ifdef UART3_TEST void imu_uart3_test(void) { // char c = 0; imu_uart3_init(IMU_UART3_BAUD); while(1) { // c++; // board_delay_ms(500); if(rec_succ) { rec_succ = false; // printf(" putchar:%s \r\n",USART3_Tx_Buf); open_usart3_dma_tx(sizeof(USART3_Tx_Buf)); // memset(USART3_Tx_Buf,0,sizeof(USART3_Tx_Buf)); } // UART3_Put_Char(c); // pass // printf(" putchar:%c\r\n",c); } } #endif