DWT是ARM Cortex-M系列微控制器中的一个内置外设,它的全名是“Data Watchpoint and Trace”单元,但从其名字中我们并不能直接看出它与定时器的关系。实际上,DWT除了用于数据观察点和跟踪之外,还提供了一个内核级别的周期定时器,这个定时器常被称为DWT定时器或内核定时器。
1。提供内核级别的精确定时:DWT定时器基于Cortex-M的核心时钟,因此它能够提供一个非常精确和稳定的时钟源。这使得它特别适合用于需要高精度计时的应用场景。
2。用于性能测量:通过DWT定时器,开发人员可以测量代码的执行时间,从而评估和优化程序的性能。例如,可以测量中断服务的响应时间,或者某个函数或任务的执行时间。
3。调试支持:除了用于定时和测量,DWT还提供了一些用于调试的特性,如数据观察点。这些特性允许开发人员在特定的内存地址上设置断点,当该地址的数据发生变化时触发断点,这对于调试复杂的系统或算法非常有用。
DWT定时器的工作原理相对简单。它有一个名为CYCCNT的32位计数器,该计数器在每个核心时钟周期递增。这个计数器可以配置为在达到特定值后产生中断。
高精度计时:在许多嵌入式应用中,如实时控制系统、传感器数据采集等,需要高精度的计时。DWT定时器能够提供内核级别的精确计时,满足这些应用的需求。
因为RA4E2属于Cortex-M33内核
是带有DWT定时器的
DWT主要代码如下
#include <stdint.h>
/* Custom Define -------------------------------------------------------------*/
#define DWT_CR *(volatile uint32_t *)0xE0001000
#define DWT_LAR *(volatile uint32_t *)0xE0001FB0
#define DWT_LAR_UNLOCK (uint32_t)0xC5ACCE55
#define DWT_CYCCNT *(volatile uint32_t *)0xE0001004
#define DEM_CR *(volatile uint32_t *)0xE000EDFC
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
/* External Function ---------------------------------------------------------/
void dwtcnt_reset(void);
void dwtcnt_start(void);
void dwtcnt_stop(void);
uint32_t dwtcnt_get_counter(void);
/ External Function ---------------------------------------------------------*/
void DwtInit(void);
void DwtStart(void);
float DwtInterval(void);
void DwtDelay_us(uint32_t usec);
void DwtDelay_ms(uint32_t msec);
void DwtDelay_sec(uint32_t sec);
void DWT_Delay_us(uint32_t uSec);
void DWT_Delay_ms(uint32_t mSec);
void DWT_Delay_sec(uint32_t Sec);
//需要根据MCU进行调整数值
#define BASE_CYCLES_COUNT 35//51ul
#define CLK 216
#define SystemClock CLK*1000000
#define Nop() {__ASM volatile ("NOP");}
static uint32_t SysCClk = 0, start = 0;
static uint32_t Delay_us = 0, Delay_ms = 0;
static void Delay_DWT(uint32_t count);
static void DWT_DelayUpdate(void);
void dwtcnt_reset(void)
{
//uint32_t reg_val = 0;
//reg_val = DEM_CR;
//DEM_CR = reg_val | DEM_CR_TRCENA;
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
DWT_CYCCNT = 0u; // Reset the clock counter
DWT_CR = 0u;
}
void dwtcnt_start(void)
{
//uint32_t reg_val = 0;
//reg_val = DWT_CR;
//DWT_CR = reg_val | 1; // enable the counter
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;// enable the counter
}
void dwtcnt_stop(void)
{
//uint32_t reg_val = 0;
//reg_val = DWT_CR;
//DWT_CR = reg_val & ~(0x01U); // disable the counter
DWT_CR &= ~(0x01U);// disable the counter
}
uint32_t dwtcnt_get_counter(void)
{
return DWT_CYCCNT;
}
// usage
// {
// ....
// dwtcnt_reset(); //reset timer
// dwtcnt_start(); //start timer
// //Code to profile
// ...
// myFunction();
// ...
// dwtcnt_stop(); //stop timer
// numCycles = dwtcnt_get_counter(); //read number of cycles
// ...
// }
static void Delay_DWT(uint32_t count)
{
uint32_t i = 0;
uint32_t n = 0;
while(n<=count)
{
n++;
i=0;
while(i<=CLK*100)
{
i++;
Nop();Nop();Nop();Nop();Nop();
Nop();Nop();Nop();Nop();Nop();
}
}
}
static void DWT_DelayUpdate(void)
{
Delay_ms = SystemClock / 1000;
Delay_us = SystemClock / 1000000;
}
/**
-
[url=home.php?mod=space&uid=2666770]@Brief[/url] Initialize DWT
*/
void DwtInit(void)
{
Delay_DWT(100);
DWT_DelayUpdate();
SysCClk = CLK; // Calculate in us
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
DWT_LAR |= DWT_LAR_UNLOCK;
DWT_CYCCNT = (uint32_t)0u; // Reset the clock counter
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
}
/**
- @brief Start DWT Counter
*/
void DwtStart(void)
{
start = DWT_CYCCNT;
}
/**
- @brief Calculate Interval Base On Previous Start Time
- @retval Interval in us
*/
float DwtInterval(void)
{
return (float)(DWT_CYCCNT - start) / SysCClk;
}
/**
- @brief Function to delay in microsecond
- @param usec Period in microsecond
*/
inline void DwtDelay_us(uint32_t usec)
{
start = DWT_CYCCNT;
while(((DWT_CYCCNT - start) / SysCClk) < usec) {};
}
/**
- @brief Function to delay in millisecond
- @param msec Period in millisecond
*/
inline void DwtDelay_ms(uint32_t msec)
{
start = DWT_CYCCNT;
while(((DWT_CYCCNT - start) / SysCClk) < (msec * 1000)) {};
}
inline void DwtDelay_sec(uint32_t sec)
{
start = DWT_CYCCNT;
while(((DWT_CYCCNT - start) / SysCClk) < (sec * 1000000)){};
}
//非常精确的延时
void DWT_Delay_us(uint32_t uSec)
{
if (uSec == 0) return;
uint32_t Count = DWT_CYCCNT;
uSec *= Delay_us;
uSec -= BASE_CYCLES_COUNT;
while((DWT_CYCCNT - Count) < uSec);
}
void DWT_Delay_ms(uint32_t mSec)
{
if (mSec == 0) return;
uint32_t Count = DWT_CYCCNT;
mSec *= Delay_ms;
mSec -= BASE_CYCLES_COUNT;
while((DWT_CYCCNT - Count) < mSec);
}
void DWT_Delay_sec(uint32_t Sec)
{
uint32_t Count = DWT_CYCCNT;
Sec *= SystemClock;
Sec -= BASE_CYCLES_COUNT;
while((DWT_CYCCNT - Count) < Sec);
}
把这些代码添加到hal_entry.c文件中
添加LED1 和LED2函数
#define LED1_lighting_off R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_02_PIN_07,BSP_IO_LEVEL_LOW)
#define LED1_lighting_up R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_02_PIN_07,BSP_IO_LEVEL_HIGH)
#define LED2_lighting_off R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_01_PIN_13,BSP_IO_LEVEL_LOW)
#define LED2_lighting_up R_IOPORT_PinWrite(&g_ioport_ctrl,BSP_IO_PORT_01_PIN_13,BSP_IO_LEVEL_HIGH)
void led_1_flash(void)
{
LED1_lighting_up;
DwtDelay_ms(500);
LED1_lighting_off;
DwtDelay_ms(500);
}
void led_2_flash(void)
{
LED2_lighting_up;
DwtDelay_ms(500);
LED2_lighting_off;
DwtDelay_ms(500);
}
void led_1_led_2_flash(void)
{
LED2_lighting_up;LED1_lighting_up;
DwtDelay_ms(500);
LED2_lighting_off;LED1_lighting_off;
DwtDelay_ms(500);
}
在hal_entry.c主函数中添加
void hal_entry(void)
{
/* TODO: add your own code here */
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
DwtInit();
while(1)
{
led_1_flash();
led_2_flash();
led_1_led_2_flash();
}
}
观察LED1 LED2
1,LED1单独亮500ms
2, LED2单独亮500ms
3,LED1 LED2一起亮500ms