巧用STM32串列埠DMA的normal和circular模式,達到並行執行效果

2020-10-17 11:01:15
  • 晶片型號:stm32f103rct6;SPI介面ADC;

  • 程式碼功能描述:有xyz3路資料,每路1個雙連結adc採集,從x路依次資料並用串列埠傳送出去,14位元組,2250000bps;

  • 方案1:按照順序執行,依次採集各路資料,然後uart傳送。這樣也行,但是我不喜歡,這樣會影響資料更新的速率,就拿x路來說,要等yz路,串列埠傳送都完成了,x路才開始下一次資料採集。我的目的是儘量提高各路資料更新的速率。方案1不滿足。

  • 方案2:考慮用DMA傳送,釋放CPU。

  • DMA有normal和circular兩種模式。
    circular用法:(STM32CubeMX設定串列埠DMA省略)

  • 在main函數中該初始化的都初始化完畢之後,緊接著一句:
    HAL_UART_Transmit_DMA(&huart1, (uint8_t*)Tx_frame, LENGTH_FRAME);

  • 就呼叫這個函數一次就可以了,DMA一直開啟,一幀資料傳送完畢之後裡面傳送下一幀,中間沒有停頓。這樣確實是快了,也釋放了CPU,各路的資料採集因為缺少了等待串列埠傳送的時間,所以就間接提高的了資料更新速率。但有個致命缺陷:資料採集和資料傳送各玩各的,就是他倆時序對不上,資料採集到一半,一個完整幀資料只更新了一部分,就被DMA挪走了,這樣就把新舊資料一塊傳送出去了,circular模式的DMA才不管資料有沒有完整更新,只管發
    normal用法:

  • 為了解決circular帶來的問題,採用normal模式,就是每發一次就開啟一次DMA,這樣就可以等一幀資料更新完畢之後,再開啟DMA傳送,同樣不會佔用CPU,在DMA傳送資料的時間裡CPU可以開啟下一輪的資料採集。

  • 再HAL庫設定好normal模式後,在資料採集的程式碼後面,比如採集資料程式碼是這樣執行的:

CSX=0;
採集X_ADC_通道1;
採集X_ADC_通道2;
CSX=1;
CSY=0;
採集Y_ADC_通道1;
採集Y_ADC_通道2;
CSY=1;
CSZ=0;
採集Z_ADC_通道1;
採集Z_ADC_通道2;
CSZ=1;
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)Tx_frame, LENGTH_FRAME);
  • 這樣資料採集和資料傳送幾乎是並行執行的,可以大大提高各路資料更新的速率。

STM32的UART使用DMA操作不要入的坑