#include "bsp_uart.h" #ifdef USE_UART extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart2_rx; #ifdef CONFIG_UART_IT_IDLEDMA static TUartTab g_ptUartTab[] = { {&huart2, &hdma_usart2_rx}, {&huart1, &hdma_usart1_rx}, {&huart2, &hdma_usart2_rx}, {&huart3, &hdma_usart3_rx}, {&huart4, &hdma_usart4_rx}, {&huart5, &hdma_usart5_rx}, {&huart6, &hdma_usart6_rx}, {&huart7, &hdma_usart7_rx} }; #else static TUartTab g_ptUartTab[] = { {&huart2, NULL}, {&huart1, NULL}, {&huart2, NULL}, {&huart3, NULL}, {&huart4, NULL}, {&huart5, NULL}, {&huart6, NULL}, {&huart7, NULL} }; #endif static void bsp_uart_set_baudrate(UART_HandleTypeDef *_pUartHandle, uint32_t _uiBaudRate) { _pUartHandle->Init.BaudRate = _uiBaudRate; if (HAL_UART_Init(_pUartHandle) != HAL_OK) { Error_Handler(); } } TUartUserData *UART_userdata_init(int _iID, uint32_t _uiBaudRate, uint32_t _uiSize) { if (_iID < 0 || _iID >= (sizeof(g_ptUartTab)/sizeof(g_ptUartTab[0]))) return NULL; TUartUserData *ptUartUserData = (TUartUserData *)RD_CALLOC(1, sizeof(TUartUserData)); ptUartUserData->m_buf_size = (_uiSize == 0) ? CONFIG_UART_BUFFER_SIZE : _uiSize; #ifdef CONFIG_UART_IT_IDLEDMA uint8_t *pDMABuf = (uint8_t *)RD_CALLOC(1, ptUartUserData->m_buf_size); ptUartUserData->m_dma_rx_buf = pDMABuf; ptUartUserData->m_last_dma_pos = 0; ptUartUserData->m_hdma_rx = g_ptUartTab[_iID].m_hdma_rx; #endif ptUartUserData->m_uart = g_ptUartTab[_iID].m_uart; bsp_uart_set_baudrate(g_ptUartTab[_iID].m_uart, _uiBaudRate); return ptUartUserData; } void UART_IT_init(TComCtrl *_ptComCtrl) { TUartUserData *ptUartUserData = (TUartUserData *)_ptComCtrl->m_pUserData; #ifdef CONFIG_UART_IT_IDLEDMA // 开启串口空闲中断 (IDLE Interrupt) // 这是核心!DMA 负责搬运,IDLE 负责通知“一帧结束了” __HAL_UART_ENABLE_IT(ptUartUserData->m_uart, UART_IT_IDLE); // 启动 DMA 接收 (Circular 模式) // 注意:这里不需要在中断里重启 DMA,因为 Circular 模式会自动循环 if (HAL_UART_Receive_DMA(ptUartUserData->m_uart, ptUartUserData->m_dma_rx_buf, ptUartUserData->m_buf_size) != HAL_OK) { Error_Handler(); } #else HAL_UART_Receive_IT(ptUartUserData->m_uart, &ptUartUserData->m_temp, 1); #endif } void UART_DMA_RX_IRQHandler(TComCtrl *_ptComCtrl) { #ifdef CONFIG_UART_IT_IDLEDMA TUartUserData *ptUartUserData = (TUartUserData *)_ptComCtrl->m_pUserData; // 1. 检查是否是空闲中断 (IDLE) if (__HAL_UART_GET_FLAG(ptUartUserData->m_uart, UART_FLAG_IDLE) != RESET) { // 2. 清除空闲标志 (必须先读 SR 再读 DR,HAL 宏已封装好) __HAL_UART_CLEAR_IDLEFLAG(ptUartUserData->m_uart); // 3. 计算本次接收了多少数据 // 公式:总长度 - DMA 当前剩余未传输的数量 uint16_t current_pos = ptUartUserData->m_buf_size - __HAL_DMA_GET_COUNTER(ptUartUserData->m_hdma_rx); uint16_t data_len = 0; if (current_pos >= ptUartUserData->m_last_dma_pos) { data_len = current_pos - ptUartUserData->m_last_dma_pos; if (data_len > 0) { rd_ComRecvProc(_ptComCtrl, (const char*)&ptUartUserData->m_dma_rx_buf[ptUartUserData->m_last_dma_pos], data_len); } } else { // DMA 指针发生了回绕 (Wrap around) // 分两段拷贝:[last_pos -> End] 和 [0 -> current_pos] uint16_t part1 = ptUartUserData->m_buf_size - ptUartUserData->m_last_dma_pos; uint16_t part2 = current_pos; if (part1 > 0) { rd_ComRecvProc(_ptComCtrl, (const char*)&ptUartUserData->m_dma_rx_buf[ptUartUserData->m_last_dma_pos], part1); } if (part2 > 0) { rd_ComRecvProc(_ptComCtrl, (const char*)&ptUartUserData->m_dma_rx_buf[0], part2); } } ptUartUserData->m_last_dma_pos = current_pos; // 更新位置 } #endif } void UART_RX_IRQHandler(TComCtrl *_ptComCtrl) { #ifndef CONFIG_UART_IT_IDLEDMA TUartUserData *ptUartUserData = (TUartUserData *)_ptComCtrl->m_pUserData; rd_ComRecvProc(_ptComCtrl, (const char*)&ptUartUserData->m_temp, 1); HAL_UART_Receive_IT(ptUartUserData->m_uart, &ptUartUserData->m_temp, 1); #endif } #endif