freeRTOS操作系统机器人实现
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
4.4 KiB

3 days ago
#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