blob: 91bd5c2ecb9b532967f14d78fe1cc7f1a44df008 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-01-01 RTT the first version, generic i.MX RT DWT driver
*/
#include "drv_dwt.h"
#ifdef BSP_USING_DWT
#include <rtthread.h>
/* CMSIS standard variable updated by SystemCoreClockUpdate() in the SDK's
* system_<device>.c. Declared extern here to stay device-family-agnostic. */
extern uint32_t SystemCoreClock;
/* CoreDebug and DWT register base addresses (Cortex-M, ARMv7-M / ARMv8-M) */
#define DWT_CTRL (*(volatile rt_uint32_t *)0xE0001000UL) /* DWT Control */
#define DWT_CYCCNT (*(volatile rt_uint32_t *)0xE0001004UL) /* Cycle Count */
#define CoreDebug_DEMCR (*(volatile rt_uint32_t *)0xE000EDFCUL) /* DEMCR */
/* DEMCR: enable DWT and ITM trace */
#define CoreDebug_DEMCR_TRCENA_Msk (1UL << 24)
/* DWT_CTRL: enable cycle counter */
#define DWT_CTRL_CYCCNTENA_Msk (1UL << 0)
/* DWT_CTRL: NOCYCCNT - set if the cycle counter is not implemented */
#define DWT_CTRL_NOCYCCNT_Msk (1UL << 25)
/**
* Initialize the DWT cycle counter.
*/
rt_err_t dwt_init(void)
{
/* Enable DWT trace by setting TRCENA in DEMCR */
CoreDebug_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Check that the cycle counter is implemented on this device */
if (DWT_CTRL & DWT_CTRL_NOCYCCNT_Msk)
{
return -RT_ERROR;
}
/* Reset then enable the cycle counter */
DWT_CYCCNT = 0U;
DWT_CTRL |= DWT_CTRL_CYCCNTENA_Msk;
return RT_EOK;
}
/**
* Read the current DWT cycle counter value.
*/
rt_uint32_t dwt_get_cycles(void)
{
return DWT_CYCCNT;
}
/**
* Convert a cycle count to microseconds using SystemCoreClock.
*/
rt_uint32_t dwt_cycles_to_us(rt_uint32_t cycles)
{
return (rt_uint32_t)((rt_uint64_t)cycles * 1000000UL / SystemCoreClock);
}
/**
* Busy-wait for the requested number of microseconds.
*/
void dwt_delay_us(rt_uint32_t us)
{
rt_uint32_t start = DWT_CYCCNT;
rt_uint32_t ticks = (rt_uint32_t)((rt_uint64_t)us * SystemCoreClock / 1000000UL);
/* Unsigned subtraction handles counter wrap-around correctly */
while ((DWT_CYCCNT - start) < ticks)
{
/* busy wait */
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
/**
* MSH command: dwt_test
* Tests the DWT cycle counter by measuring rt_thread_mdelay(100) and
* a 200 us busy-wait delay, then prints the results over the console.
*/
static void dwt_test(int argc, char **argv)
{
rt_uint32_t t0, t1, elapsed_us;
if (dwt_init() != RT_EOK)
{
rt_kprintf("[DWT] init FAILED: cycle counter not implemented on this device\r\n");
return;
}
rt_kprintf("[DWT] init OK, cycle counter started\r\n");
/* test 1: measure a 100 ms OS delay */
t0 = dwt_get_cycles();
rt_thread_mdelay(100);
t1 = dwt_get_cycles();
elapsed_us = dwt_cycles_to_us(t1 - t0);
rt_kprintf("[DWT] rt_thread_mdelay(100) took %u us\r\n", elapsed_us);
/* test 2: busy-wait 200 us and measure it back */
t0 = dwt_get_cycles();
dwt_delay_us(200);
t1 = dwt_get_cycles();
elapsed_us = dwt_cycles_to_us(t1 - t0);
rt_kprintf("[DWT] dwt_delay_us(200) measured %u us\r\n", elapsed_us);
}
MSH_CMD_EXPORT(dwt_test, test DWT cycle counter and us delay);
#endif /* RT_USING_FINSH */
#endif /* BSP_USING_DWT */
|