hard_imu_uart3.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #include "board.h"
  2. #include "hard_imu_uart3.h"
  3. #include "hpm_dma_drv.h"
  4. #include "hpm_dmamux_drv.h"
  5. // #include "hard_uart_rx_dma_soft_idle.h" // 软件触发 模拟空闲中断 需要连接触发物理接口和rx 且需要2路定时器通道
  6. #include "hpm_uart_drv.h"
  7. #include "hard_hdma_int.h"
  8. #include "test.h"
  9. /* uart0 给控制台打印串口使用了 尽量避开
  10. uart should configure pin function before opening clock
  11. 1、IO 2、时钟 3、串口
  12. 4、手册:源数据 burst 数量,burst 传输的字节数等于(SrcBurstSize * SrcWidth) 这个用法要看手册 单次允许DMA调度传输的最大字节数
  13. 5、AHB外设只能用HDMA??? 31-0 TRANSIZE 源数据的数据量,总传输数据量为(TranSize * SrcWidth)
  14. */
  15. /* hpm6750没有串口空闲中断 无法使用串口空闲加DMA进行接收 所以接收方面使用软件超时
  16. 增加阻塞的读中断次数代替DMA传输 由于增加了FIFO,串口也不会像之前那样频繁中断 假如 thr 12 就是接收12个字节进入一次接收中断
  17. #define UART_SOC_FIFO_SIZE (16U)
  18. 设置的触发中单的长度要小于FIFO长度 不然会导致丢数据 3/4 12字节 以628M主频 512字节 中断43次来说 115200 波特率 要 44.4ms(传输) + 0.014ms(中断) ≈ 44.4ms。
  19. 如果换成460800​ 波特率,处理 512字节​ 数据包的总时间约为 11.1ms。如果每次都是512字节 这对于内环400hz 不成立
  20. 后面看了imu接收的姿态信息是 大概70-80字节 数据包是70字节,在460800波特率下,传输时间约为 1.52ms 也就是不到2ms的姿态包
  21. */
  22. /* ========== 硬件配置 - 根据实际硬件修改 ========== */
  23. #define IMU_UART3 HPM_UART3 /* 使用 UART3 */
  24. #define IMU_UART3_CLK_NAME clock_uart3 /* UART3 时钟 */
  25. #define IMU_UART3_IRQ IRQn_UART3 /* UART3 中断号*/
  26. #define IMU_UART3_IRQ_RANK 2
  27. #define IMU_UART3_BAUD 460800
  28. /*===================软空闲中断 DMA接收 额外配置============================*/
  29. //#define IMU_UART3_RX_TRGM HPM_TRGM2
  30. //#define IMU_UART3_RX_TRGM_PIN IOC_PAD_PD19
  31. //#define IMU_UART3_RX_TRGM_INPUT_SRC HPM_TRGM2_INPUT_SRC_TRGM2_P9 /* Corresponding to Pin setting */
  32. //#define IMU_UART3_RX_TRGM_OUTPUT_GPTMR_IN HPM_TRGM2_OUTPUT_SRC_GPTMR4_IN2 /* Corresponding to GPTMR inst */
  33. //#define IMU_UART3_RX_TRGM_OUTPUT_GPTMR_SYNCI HPM_TRGM2_OUTPUT_SRC_GPTMR4_SYNCI /* Corresponding to GPTMR inst */
  34. //#define IMU_UART3_RX_GPTMR HPM_GPTMR4
  35. //#define IMU_UART3_RX_GPTMR_CLK_NAME clock_gptmr4
  36. //#define IMU_UART3_RX_GPTMR_CMP_CHANNEL IRQn_GPTMR4
  37. //#define IMU_UART3_RX_GPTMR_CAPTURE_CHANNEL 0
  38. //#define IMU_UART3_RX_GPTMR_IRQ 2
  39. /* ========== 缓冲区定义 ========== */
  40. /* DMA 缓冲区必须放在非缓存区域 */
  41. ATTR_PLACE_AT_NONCACHEABLE uint8_t USART3_DMA_Recieve_Buf[UART3_RECIEVE_LENDTH] = {0};
  42. // ATTR_PLACE_AT_NONCACHEABLE uint8_t dma_buf[UART3_RECIEVE_LENDTH] = {0};
  43. ATTR_PLACE_AT_NONCACHEABLE uint8_t USART3_Tx_Buf[UART3_TX_MAX_LENGTH] = {0};
  44. /* ========== 静态变量 ========== */
  45. static volatile uint32_t length;
  46. static volatile bool rec_succ = false;
  47. static volatile bool uart3_rx_fifo_timeout;
  48. static volatile uint16_t rx3_interrupt_count;
  49. /* ========== 静态函数声明 ========== */
  50. static void Initial_UART3(unsigned int bps);
  51. static void DMA_UART3Config(void);
  52. static void UART3NVIC_Configuration(void);
  53. /* ========== 函数实现 ========== */
  54. /**
  55. * @brief IMU UART3 初始化 - 保留原名
  56. */
  57. void imu_uart3_init(unsigned int bps)
  58. {
  59. Initial_UART3(bps);
  60. DMA_UART3Config();
  61. UART3NVIC_Configuration();
  62. }
  63. static void uart3_pin_config(void)
  64. {
  65. HPM_IOC->PAD[IOC_PAD_PB24].FUNC_CTL = IOC_PB24_FUNC_CTL_UART3_RXD;
  66. HPM_IOC->PAD[IOC_PAD_PB25].FUNC_CTL = IOC_PB25_FUNC_CTL_UART3_TXD;
  67. }
  68. /**
  69. * @brief 初始化 UART3 接口 - 保留原名
  70. */
  71. static void Initial_UART3(unsigned int bps)
  72. {
  73. uart_config_t uart_config = {0};
  74. /* 配置IO 使能 UART3 时钟 */
  75. uart3_pin_config();
  76. clock_set_source_divider(IMU_UART3_CLK_NAME, clk_src_osc24m, 1);
  77. clock_add_to_group(IMU_UART3_CLK_NAME, 0);
  78. /* 获取默认 UART 配置 */
  79. uart_default_config(IMU_UART3, &uart_config);
  80. /* 修改配置 */
  81. uart_config.baudrate = bps;
  82. uart_config.word_length = word_length_8_bits; /* 8 位数据 */
  83. uart_config.num_of_stop_bits = stop_bits_1; /* 1 位停止位 */
  84. uart_config.parity = parity_none; /* 无校验 */
  85. uart_config.fifo_enable = true; /* 使能 FIFO */
  86. uart_config.dma_enable = true; /* 使能 DMA */
  87. uart_config.tx_fifo_level = uart_tx_fifo_trg_not_full; // 1个字节起搬 DMA->FIFO->UART输出
  88. uart_config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters; // 16*3/4 = 12字节FIFO 对于512字节的缓冲区需要 42到43次中断
  89. uart_config.src_freq_in_hz = clock_get_frequency(IMU_UART3_CLK_NAME);
  90. /* 初始化 UART */
  91. hpm_stat_t stat = uart_init(IMU_UART3, &uart_config);
  92. if (stat != status_success) {
  93. /* uart failed to be initialized */
  94. printf("failed to initialize uart\n");
  95. while(1);
  96. }
  97. }
  98. /**
  99. * @brief 串口3 DMA 初始化配置
  100. */
  101. void DMA_UART3Config(void)
  102. {
  103. dma_handshake_config_t handshake_config;
  104. dma_channel_config_t channel_config;
  105. /* 使能 DMA 时钟 */
  106. // HDMA 时钟来源于系统总线时钟(AHB)
  107. /* ========== 配置 TX DMA 通道 ========== */
  108. /* 初始化 DMA 通道 */
  109. dma_default_channel_config(IMU_UART3_DMA_CONTROLLER, &channel_config);
  110. /* 配置 DMAMUX:将 UART3 TX 请求连接到 TX DMA 通道 */
  111. dmamux_config(IMU_UART3_DMAMUX_CONTROLLER, IMU_UART3_TX_DMAMUX_CH, IMU_UART3_TX_DMA_REQ, true);
  112. /* 配置 TX 握手参数 */
  113. dma_default_handshake_config(IMU_UART3_DMA_CONTROLLER, &handshake_config);
  114. handshake_config.ch_index = IMU_UART3_TX_DMA_CH;
  115. handshake_config.dst = (uint32_t)&IMU_UART3->THR; /* 目标:发送寄存器 */
  116. handshake_config.dst_fixed = true; /* 目标地址固定 */
  117. handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)USART3_Tx_Buf); /* 源:内存 */ // 建议4字节对齐
  118. handshake_config.src_fixed = false; /* 源地址递增 */
  119. handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE; /* 字节传输 */
  120. handshake_config.size_in_byte = UART3_TX_MAX_LENGTH; /* 传输大小 */
  121. hpm_stat_t stat = dma_setup_handshake(IMU_UART3_DMA_CONTROLLER, &handshake_config, false); // 不触发单次发送搬运
  122. if(stat != status_success)
  123. {
  124. printf("uart3 dma tx config error\r\n");
  125. }
  126. }
  127. /**
  128. * @brief 初始化 USART3 中断优先级 - 保留原名
  129. */
  130. void UART3NVIC_Configuration(void)
  131. {
  132. /*
  133. uart_intr_rx_data_avail_or_timeout // 接收缓冲区非空 或 超时(FIFO)
  134. uart_intr_tx_slot_avail // 发送缓冲区空
  135. uart_intr_rx_line_stat // 接收线状态
  136. uart_intr_modem_stat // 模式状态(流控等)
  137. */
  138. uart_enable_irq(IMU_UART3, uart_intr_rx_data_avail_or_timeout); // 接收中断
  139. intc_m_enable_irq_with_priority(IMU_UART3_IRQ, IMU_UART3_IRQ_RANK);
  140. intc_m_enable_irq_with_priority(IMU_UART3_DMA_IRQ, IMU_UART3_DMA_IRQ_RANK);
  141. }
  142. /**
  143. * @brief UART3 发送 1 字节数据
  144. */
  145. void UART3_Put_Char(unsigned char data)
  146. {
  147. /* 等待发送寄存器空 */
  148. while (!uart_check_status(IMU_UART3, uart_stat_transmitter_empty));
  149. /* 发送数据 */
  150. uart_send_byte(IMU_UART3, data);
  151. /* 等待发送完成 */
  152. while (!uart_check_status(IMU_UART3, uart_stat_transmitter_empty));
  153. }
  154. /**
  155. * @brief 开启 USART3 DMA 发送 - 保留原名
  156. */
  157. void open_usart3_dma_tx(unsigned short count)
  158. {
  159. dma_handshake_config_t handshake_config;
  160. /* 等待上次发送完成 */
  161. // 软件dma传输完成标志 每次调用open_usart3_dma_tx会重新置位硬件TC
  162. uint32_t timeout = 1000000;
  163. while (usart3_tx_isbusy() && timeout--) {
  164. __asm("nop");
  165. }
  166. if (timeout == 0) {
  167. // 超时处理,复位DMA
  168. dma_abort_channel(IMU_UART3_DMA_CONTROLLER, IMU_UART3_TX_DMA_CH);
  169. uart3_tx_dma_done = true; // 强制完成
  170. }
  171. /* 重新配置 TX 传输大小 */
  172. dma_default_handshake_config(IMU_UART3_DMA_CONTROLLER, &handshake_config);
  173. handshake_config.ch_index = IMU_UART3_TX_DMA_CH;
  174. handshake_config.dst = (uint32_t)&IMU_UART3->THR;
  175. handshake_config.dst_fixed = true;
  176. handshake_config.src = core_local_mem_to_sys_address(0, (uint32_t)USART3_Tx_Buf);
  177. handshake_config.src_fixed = false;
  178. handshake_config.data_width = DMA_TRANSFER_WIDTH_BYTE;
  179. handshake_config.size_in_byte = count;
  180. dma_setup_handshake(IMU_UART3_DMA_CONTROLLER, &handshake_config, true); // true表示触发一次
  181. }
  182. /**
  183. * @brief 获取串口发送是否忙碌
  184. */
  185. bool usart3_tx_isbusy(void)
  186. {
  187. return !uart3_tx_dma_done; // 如果没完成,就是忙碌
  188. }
  189. /* ========== 中断服务函数 ========== */
  190. extern void recv_imu_data_hookfunction(const uint8_t *pbuffer,
  191. uint32_t rx_length);
  192. #ifndef UART_DRV_TEST
  193. SDK_DECLARE_EXT_ISR_M(IMU_UART3_IRQ, uart3_isr)
  194. void uart3_isr(void)
  195. {
  196. uint8_t count = 0;
  197. uint8_t irq_id = uart_get_irq_id(IMU_UART3);
  198. if (irq_id == uart_intr_id_rx_data_avail) {
  199. rx3_interrupt_count++;
  200. while (uart_check_status(IMU_UART3, uart_stat_data_ready)) {
  201. USART3_DMA_Recieve_Buf[length++] = uart_read_byte(IMU_UART3);
  202. count++;
  203. /*in order to ensure rx fifo there are remaining bytes*/
  204. if (count > 12) {
  205. break;
  206. }
  207. }
  208. }
  209. if (irq_id == uart_intr_id_rx_timeout) { // 接收超时 FIFO超时4个字符后代表一次接收完毕
  210. // 接收完毕
  211. rx3_interrupt_count++;
  212. while (uart_check_status(IMU_UART3, uart_stat_data_ready)) {
  213. USART3_DMA_Recieve_Buf[length++] = uart_read_byte(IMU_UART3);
  214. }
  215. // recv_imu_data_hookfunction((uint8_t *)USART3_DMA_Recieve_Buf, length);
  216. memset(USART3_Tx_Buf,0,sizeof(USART3_Tx_Buf));
  217. memcpy(USART3_Tx_Buf, USART3_DMA_Recieve_Buf,length);
  218. rec_succ = true;
  219. length = 0;
  220. // uart_rx_fifo_timeout = true;
  221. }
  222. }
  223. #endif
  224. /* uart dma rx_irq tx_dma demo 2026/03/14 pass*/
  225. #ifdef UART3_TEST
  226. void imu_uart3_test(void)
  227. {
  228. // char c = 0;
  229. imu_uart3_init(IMU_UART3_BAUD);
  230. while(1)
  231. {
  232. // c++;
  233. // board_delay_ms(500);
  234. if(rec_succ)
  235. {
  236. rec_succ = false;
  237. // printf(" putchar:%s \r\n",USART3_Tx_Buf);
  238. open_usart3_dma_tx(sizeof(USART3_Tx_Buf));
  239. // memset(USART3_Tx_Buf,0,sizeof(USART3_Tx_Buf));
  240. }
  241. // UART3_Put_Char(c); // pass
  242. // printf(" putchar:%c\r\n",c);
  243. }
  244. }
  245. #endif