本帖最后由 会飞的猪_2020 于 2024-2-26 18:52 编辑
Factor.7z
(5.42 MB, 下载次数: 5)
简单做了一个回显,没有实际测过,应该有bug。
今天看到HAL库有HAL_UARTEx_ReceiveToIdle_DMA这个函数,然后上班比较闲,瞎写的。用CubeMX生成的,应该STM32系列的api都差不多。
Hal库自己有回调函数HAL_UARTEx_RxEventCallback。它是弱定义的,这个是空闲中断的回调函数。
然后看了一下hal库的实现,它是会把DMA半满和DMA满中断,也进到这里来。
[C] 纯文本查看 复制代码 /**
* @brief DMA UART receive process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Initialize type of RxEvent that correspond to RxEvent callback execution;
In this case, Rx Event type is Half Transfer */
huart->RxEventType = HAL_UART_RXEVENT_HT;
/* Check current reception Mode :
If Reception till IDLE event has been selected : use Rx Event callback */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Event callback*/
huart->RxEventCallback(huart, huart->RxXferSize / 2U);
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize / 2U);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
else
{
/* In other cases : use Rx Half Complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Half complete callback*/
huart->RxHalfCpltCallback(huart);
#else
/*Call legacy weak Rx Half complete callback*/
HAL_UART_RxHalfCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
进来的时候可以通过判断RxEventType 和ReceptionType 知道到底是哪个。
然后我DMA设置的normal模式,每次在回调函数里面调用HAL_UARTEx_ReceiveToIdle_DMA去切换两个缓冲。
比较奇怪的是,我自己测试,如果串口接收的szie正好等于DMA单个buff的szie的时候,会进来两次回调。
所以会回调判断的时候做了Size == USART1_RX_BUF_SIZE这个判断。
[C] 纯文本查看 复制代码 /**
* @brief 空闲中断回调函数
* @param {UART_HandleTypeDef} *huart
* @param {uint16_t} Size
* @return {*}
*/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
void *pingpong[1] = { 0 };
if (huart->Instance == USART1) {
// 当Size和USART1_RX_BUF_SIZE一样的时候,我测试下来不会触发TC,反而是触发HT。
if (huart->RxEventType == HAL_UART_RXEVENT_IDLE || huart->ReceptionType == HAL_UART_RXEVENT_TC || Size == USART1_RX_BUF_SIZE) {
pingpong_buffer_set_write_done(&uart1_pingpong_handler, Size);
pingpong_buffer_get_write_buf(&uart1_pingpong_handler, pingpong);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, pingpong[0], USART1_RX_BUF_SIZE);
}
}
}
我测试了,打开延时3秒,然后发送两次,它确实可以成功回复两包。说明这个缓冲切换应该是起作用的。
然后如果发送的两次以上的话,我做的逻辑是新的内容覆盖掉老的。
[C] 纯文本查看 复制代码 /**
* @brief 在主循环中调用
* @return {*}
*/
void bsp_uart_loop(void)
{
void *tempbuf[1];
uint32_t size;
if (pingpong_buffer_get_read_buf(&uart1_pingpong_handler, tempbuf, &size)) {
// HAL_Delay(3000); // 延时,用于模拟耗时的操作
// 这里要用阻塞发送,否则的话需要在发送完成中断里面调用pingpong_buffer_set_read_done,不然的话可能这个待发送的buf会被DMA修改。
HAL_UART_Transmit(&huart1, tempbuf[0], size, 0XFFFF);
pingpong_buffer_set_read_done(&uart1_pingpong_handler);
}
}
PS:比较出乎我意料的一点是我的USART1_RX_BUF_SIZE设置的只有10个字节,但是却可以回显大于10个字节的内容。。
我以为不行的,但是实际却可以,没想通是为什么...
|