天天看點

STM32H743基于HAL庫實作序列槽中斷發送+DMA空閑中斷接收

1、STM32H743與STM32F1xx系列單片機在配置DMA資料流的不同:

STM32H743單片機在配置DMA資料流時,DMA1的7個資料流沒有限定用于對用的通道。也就是說序列槽接收的DMA通道可以任意選擇一個資料流。

STM32H743基于HAL庫實作序列槽中斷發送+DMA空閑中斷接收

STM32F1xx則有DMA資料流和通道選擇表,隻能在對應的通道使用序列槽的DMA傳輸功能(具體内容參考SMT32F1xx的參考手冊)。

2、HAL庫

不同于标準庫,HAL庫提供了封裝程度更加深的庫接口。HAL庫的結構:

STM32H743基于HAL庫實作序列槽中斷發送+DMA空閑中斷接收

使用HAL庫的思路:使用STM32cubeMX配置得到初始化工程——>在main.c和stm32h7xx_it.c檔案中實作使用者代碼——>開啟或關閉中斷(有時需要)——>實作中斷回調函數

需要注意的是:HAL庫在進行中斷的函數中,不僅清空了中斷标志位,還關閉了中斷。這需要每次調用HAL提供的函數開啟中斷,在中斷函數的回調函數中進行中斷内容。是以,中斷函數除了HAL庫的中斷處理函數外,一般不需要添加額外的代碼。使用者進行中斷的代碼添加在中斷回調函數中就可以。

3、序列槽初始化過程分析

MX_USART1_UART_Init();//配置序列槽結構體:huart1;調用初始化函數:HAL_UART_Init()
//(總的來說是MX_xx——>HAL;MX開頭表示有STM32CubeMX軟體生成的代碼,HAL開頭表示由HAL庫提供的接口函數)
//初始化回調函數,調用HAL_UART_MspInit(huart);晶片解決方案函數
——>#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
    UART_InitCallbacksToDefault(huart);

    if (huart->MspInitCallback == NULL)
    {
      huart->MspInitCallback = HAL_UART_MspInit;
    }

    /* Init the low level hardware */
    huart->MspInitCallback(huart);
#else
    /* Init the low level hardware : GPIO, CLOCK */
    HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
  }
//配置序列槽寄存器
——>UART_SetConfig(huart)
//清空中斷标志位
——>CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
//使能序列槽
——>__HAL_UART_ENABLE(huart);
——>序列槽初始化函數結束,退出
           

 總的來說:初始換函數完成了四個部分:第一個是從模闆接口函數調用HAL庫初始化函數;第二個是配置中斷回調函數;第三個是配置序列槽模式;第四個是清空中斷标志位,使能序列槽。

4、DMA初始化代碼分析

HAL_DMA_Init(&hdma_usart1_rx);//DMA初始化函數入口
//根據配置内容初始化DMA
——>/* Get the CR register value */
    registerValue = ((DMA_Stream_TypeDef   *)hdma->Instance)->CR;

    /* Clear CHSEL, MBURST, PBURST, PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR, CT and DBM bits */
    registerValue &= ((uint32_t)~(DMA_SxCR_MBURST | DMA_SxCR_PBURST | \
                        DMA_SxCR_PL    | DMA_SxCR_MSIZE  | DMA_SxCR_PSIZE  | \
                        DMA_SxCR_MINC  | DMA_SxCR_PINC   | DMA_SxCR_CIRC   | \
                        DMA_SxCR_DIR   | DMA_SxCR_CT     | DMA_SxCR_DBM));

    /* Prepare the DMA Stream configuration */
    registerValue |=  hdma->Init.Direction           |
            hdma->Init.PeriphInc           | hdma->Init.MemInc           |
            hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment |
            hdma->Init.Mode                | hdma->Init.Priority;
//完成不同模式下的寄存器值配置
(代碼太多,在HAL庫中可以找到)
//此時的DMA對應的資料流已經完成對序列槽請求的配置,可以認為已經準備好
——>就緒狀态,等待中斷調用
——>如果序列槽為空閑中斷模式,則DMA的中斷可以不開。此時DMA隻是實作資料搬運的功能。
           

以上内容全部是HAL庫和STM32CubeMX軟體實作,不需要使用者自己實作。

5、使用者需要調用的函數和處理的中斷回調函數

前面提到,HAL庫提供的接口函數中,執行一遍後,會将中斷關閉。意思就是完成此次的需求後,回複到初始化狀态,當下次需要時,重新調用則會開始新的一次。

a)序列槽阻塞式發送資料和接收資料的HAL庫接口函數有:

(#) Blocking mode API's are :
        (+) HAL_UART_Transmit()
        (+) HAL_UART_Receive()
           

 b)序列槽中斷式發送資料和接收資料的HAL庫接口函數有:

(#) Non-Blocking mode API's with Interrupt are :
     (+) HAL_UART_Transmit_IT()
     (+) HAL_UART_Receive_IT()
     (+) HAL_UART_IRQHandler()
           

c)序列槽DMA發送資料和接收資料的HAL庫接口函數有:

(#) Non-Blocking mode API's with DMA are :
        (+) HAL_UART_Transmit_DMA()
        (+) HAL_UART_Receive_DMA()
        (+) HAL_UART_DMAPause()
        (+) HAL_UART_DMAResume()
        (+) HAL_UART_DMAStop()
           

d)序列槽中斷回調函數有:(包括中斷和終止的回調)

(#) A set of Transfer Complete Callbacks are provided in Non_Blocking mode:
        (+) HAL_UART_TxHalfCpltCallback()
        (+) HAL_UART_TxCpltCallback()
        (+) HAL_UART_RxHalfCpltCallback()
        (+) HAL_UART_RxCpltCallback()
        (+) HAL_UART_ErrorCallback()

    (#) Non-Blocking mode transfers could be aborted using Abort API's :
        (+) HAL_UART_Abort()
        (+) HAL_UART_AbortTransmit()
        (+) HAL_UART_AbortReceive()
        (+) HAL_UART_Abort_IT()
        (+) HAL_UART_AbortTransmit_IT()
        (+) HAL_UART_AbortReceive_IT()

    (#) For Abort services based on interrupts (HAL_UART_Abortxxx_IT), a set of Abort Complete Callbacks are provided:
        (+) HAL_UART_AbortCpltCallback()
        (+) HAL_UART_AbortTransmitCpltCallback()
        (+) HAL_UART_AbortReceiveCpltCallback()
           

以上,就是序列槽+DMA+空閑中斷在HAL庫下開發的分析過程。

到了實際應用過程,分兩步:首先,調用HAL提供的序列槽接收/發送資料接口,其次在序列槽中斷的回調函數中添加資料儲存或清空的代碼。

重要提示:不知為啥,HAL庫中序列槽的空閑中斷需要使用者手動開啟,還要配置一個接收模式的标志變量reception為空閑接收模式。并且在中斷函數中還要調用HAL庫提供的中斷開啟函數再次開啟空閑中斷和配置接收模式為空閑接收。通過代碼分析,可以知道空閑中斷的回調函數是:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
	HAL_UART_DMAStop(&huart1);
	do_for_usart1_recv_idle(Size);
	flag=0x01;
	HAL_UART_Receive_DMA(&huart1,usartRecvDataArr,BUFFERSIZE);
	huart1.ReceptionType=HAL_UART_RECEPTION_TOIDLE;
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
}
           

總結:使用HAL庫分三步,第一步是分析HAL庫提供的初始化過程中是否實作了需要的功能,比如空閑中斷沒開,就需要手動開啟;第二步,确定調用阻塞還是非阻塞函數,發送和接收資料;第三步:找到中斷回調函數,在回調函數中确定是否再次開啟序列槽接收或發送,完成資料處理的代碼。

至此,序列槽就能實作DMA+中斷接收資料,序列槽中斷發送資料。可分别進入不同的回調函數。