DWT,全稱是The Debug Watchpoint and Trace (DWT) unit,用于系統調試及跟蹤,詳細的介紹可以參考ARM官方文檔:ARMv7-M Architecture Reference Manual。本文将使它來實作一個系統的延時功能。
1. 寄存器簡單介紹
要實作延時的功能,總共涉及到三個寄存器:DEMCR 、DWT_CTRL、DWT_CYCCNT,分别用于開啟DWT功能、開啟CYCCNT及獲得系統時鐘計數值。
DEMCR
其官方手冊說明如下,這裡我們隻需要關注其第24位引腳TRCENA。
該寄存器的TRCENA位置位,使能DWT功能
DWT_CTRL寄存器
其包含很多功能,這裡我們隻開啟其循環計數功能。
CYCCNT寄存器
該寄存器位址見上圖,其描述如下:
當DWT的CYCCNTENA位置位後,該寄存器的值與系統周期計數值保持同步,我們可以用它的值來實作一個延時的功能。
2. 延時程式編寫
直接上代碼:
延時函數源檔案:
#include "DWTDelay.h"
// 0xE000EDFC DEMCR RW Debug Exception and Monitor Control Register.
#define DEMCR ( *(unsigned int *)0xE000EDFC )
#define TRCENA ( 0x01 << 24) // DEMCR的DWT使能位
// 0xE0001000 DWT_CTRL RW The Debug Watchpoint and Trace (DWT) unit
#define DWT_CTRL ( *(unsigned int *)0xE0001000 )
#define CYCCNTENA ( 0x01 << 0 ) // DWT的SYCCNT使能位
// 0xE0001004 DWT_CYCCNT RW Cycle Count register,
#define DWT_CYCCNT ( *(unsigned int *)0xE0001004) // 顯示或設定處理器的周期計數值
//#define DWT_DELAY_mS(mSec) DWT_DELAY_uS(mSec*1000)
static int SYSCLK = 0;;
void DWT_INIT(int sys_clk)
{
DEMCR |= TRCENA;
DWT_CTRL |= CYCCNTENA;
SYSCLK = sys_clk; // 儲存目前系統的時鐘周期,eg. 72,000,000(72MHz).
}
// 微秒延時
void DWT_DELAY_uS(int uSec)
{
int ticks_start, ticks_end, ticks_delay;
ticks_start = DWT_CYCCNT;
if ( !SYSCLK )
DWT_INIT( MY_MCU_SYSCLK );
ticks_delay = ( uSec * ( SYSCLK / (1000*1000) ) ); // 将微秒數換算成滴答數
ticks_end = ticks_start + ticks_delay;
if ( ticks_end > ticks_start )
{
while( DWT_CYCCNT < ticks_end );
}
else // 計數溢出,翻轉
{
while( DWT_CYCCNT >= ticks_end ); // 翻轉後的值不會比ticks_end小
while( DWT_CYCCNT < ticks_end );
}
}
延時函數頭檔案:
#ifndef _DWTDELAY_H_
#define _DWTDELAY_H_
// 根據MCU做修改
#define MY_MCU_SYSCLK (72000000)
void DWT_INIT(int sys_clk);
// 微秒延時
void DWT_DELAY_uS(int uSec);
#define DWT_DELAY_mS(mSec) DWT_DELAY_uS( mSec*1000 )
#endif // _DWTDELAY_H_
至此,簡單、好用、精準又不占用CPU其它外設資源的延時函數就實作了。