STM32應用:使用Cortex M內嵌DWT達成精確微秒級延時

關鍵字 :STM32DWTSystick
Cortex M核心自帶一個Systick計數器,通常會設置成一毫秒計數一次,並產生一個中斷,當程式需要微秒等級的延遲時,普遍利用下列兩個做法。
  1. while loop空迴圈。
  2. 使用Basic timer如TIM6 / TIM7,設置為一微秒計數一次。

第一個使用while loop空迴圈的方式,主要問題是通常需要多次反覆多次測試設定值,對應到不同時間的延遲適應性低,加上會被編譯器的最佳化影響,需要花在測試設定的時間就更多了一些。
第二個使用Basic timer的方式,主要問題是占用了一個timer,和計數暫存器只提供到16 bits。
本文介紹第三個方式,使用Cortex M核心自帶的DWT Cycle Count Register暫存器來計算延遲,好處除了和核心時脈同步外,也提供了32 bits計數暫存器,不過DWT Cycle Count Register在Cortex M0 / M0+上不提供,所以STM32F0 / L0 / G0需要高精度的延遲計數還是要利用前述的兩個方式。

  大大购相关商品     NUCLEO-G474RE  >>查询存货及售价


本文附件提供了下列三個函式和一個全域變數如下

uint32_t us_tick;

void HAL_DWT_Init(void)
{
us_tick = HAL_RCC_GetHCLKFreq() / (1000 * 1000);
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#if (__CORTEX_M == 7)
DWT->LAR = 0xC5ACCE55;
#endif
DWT->CTRL |= DWT_CTRL_CYCEVTENA_Msk;

return;
}

void HAL_DWT_Refreshustick(void)
{
us_tick = HAL_RCC_GetHCLKFreq() / (1000 * 1000);


return;
}

void HAL_DWT_USDelay(uint32_t us_time)
{
uint32_t usdelay_cnt;

usdelay_cnt = us_time * us_tick;
DWT->CYCCNT = 0;
while (DWT->CYCCNT < usdelay_cnt)
{
}

return;
}

其中,HAL_DWT_Init功用為預先計算以當前的CPU時脈,每微秒需要多少個counter,並且打開CPU的DWT Cycle Count功能,因為DWT Cycle Count的每一個count所消耗的時間和CPU時脈相關,所以若設計上會動態改變CPU時脈時,需要呼叫HAL_DWT_Refreshustick重新計算每微秒需要多少個count,HAL_DWT_USDelay則是延遲計數的函式,因為DWT Cycle Count並不產生中斷,所以需要使用busy wait的方式來等待。

以下分別是等待100μS、10μS和1μS的實際量測圖。

這張是100μS。


這張是10μS


這張是1μS

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★博文作者未開放評論功能