STM32H7串口DMA+空闲中断实现接收和发送不定长度数据
stm32f103芯片的串口一直使用DMA+空闲中断,现在使用stm32h7芯片,打算也使用相同的方法 芯片型号:stm32h743 串口:USART2 代码生成:stm32CubeMX 第一步:使用stm32CubeMX生成代码
第二步:添加自己代码
1.发生空闲中断需要reset DMA重新开始接收数据
HAL_StatusTypeDef HAL_UART_DMAStopRx(UART_HandleTypeDef *huart) { /* Stop UART DMA Rx request if ongoing */ if ((huart->RxState == HAL_UART_STATE_BUSY_RX) && (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))) { CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); /* Abort the UART DMA Rx channel */ if(huart->hdmarx != NULL) { HAL_DMA_Abort(huart->hdmarx); } //UART_EndRxTransfer(huart); /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); /* At end of Rx process, restore huart->RxState to Ready */ huart->RxState = HAL_UART_STATE_READY; } return HAL_OK; }
串口空闲中断
/** * @brief This function handles UART4 global interrupt. */ void USART2_IRQHandler(void) { uint32_t _len_dmarev; uint32_t isrflags; uint32_t cr1its; BaseType_t xHigherPriorityTaskWoken; HAL_UART_IRQHandler(&UART2_Handler); isrflags = READ_REG(UART2_Handler.Instance->ISR); cr1its = READ_REG(UART2_Handler.Instance->CR1); if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET)) { __HAL_UART_CLEAR_IDLEFLAG(&UART2_Handler); _len_dmarev = DMA_BUFFER_LENGTH - __HAL_DMA_GET_COUNTER(UART2_Handler.hdmarx); if(_len_dmarev) { //停止DMA HAL_UART_DMAStopRx(&UART2_Handler); //这个地方非常关键,DMA访问的ram,但是CPU访问的是cache,使用下面函数使ram和cache一致 SCB_InvalidateDCache_by_Addr((uint32_t *)dma_rx_buf, DMA_BUFFER_LENGTH); xQueueSendToBackFromISR(Keyboard_Queue,(void*)&uart_to_keyboard_msg,&xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); HAL_UART_Receive_DMA(&UART2_Handler, dma_rx_buf, DMA_BUFFER_LENGTH); __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_ERR); __HAL_UART_DISABLE_IT(&UART2_Handler, UART_IT_PE); } else { READ_REG(UART2_Handler.Instance->RDR); __HAL_UART_CLEAR_OREFLAG(&UART2_Handler); } } }
发送函数
unsigned int KeyboardRs485TxFrame(uint8_t * buffer,uint32_t len) { UINT16 i;
//拷贝数据到DMA buffer for(i = 0; i < len; i++) { dma_tx_buf[i] = buffer[i]; } //使发送RAM和cache一致 SCB_InvalidateDCache_by_Addr((uint32_t *)dma_tx_buf, DMA_BUFFER_LENGTH); HAL_UART_Transmit_DMA(&UART2_Handler, dma_tx_buf, len); return 0;
}
还有一点需要特别注意:DMA访问的是0x24000000以后区域,定义的发送和接收DMA buffer 一定要在这个区域 可使用下面的编译指令: ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_rx_buf[DMA_BUFFER_LENGTH]) ; ALIGN_32BYTES(attribute((section (".RAM_D2"))) uint8_t dma_tx_buf[DMA_BUFFER_LENGTH]);
上一篇:
通过多线程提高代码的执行效率例子