| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- #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
|