1、Cortex-M中的DWT
在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace),是用于系统调试及跟踪。
它有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数,内核时钟跳动一次,该计数器就加1,精度非常高,决定内核的频率是多少,如果是F103系列,内核时钟是72M,那精度就是1/72M = 14ns,而程序的运行时间都是微秒级别的,所以14ns的精度是远远够的。最长能记录的时间为:60s=2的32次方/72000000(假设内核频率为72M,内核跳一次的时间大概为1/72M=14ns),而如果是H7这种400M主频的芯片,那它的计时精度高达2.5ns(1/400000000 = 2.5),而如果是 i.MX RT1052这种比较牛逼的处理器,最长能记录的时间为: 8.13s=2的32次方/528000000 (假设内核频率为528M,内核跳一次的时间大概为1/528M=1.9ns) 。当CYCCNT溢出之后,会清0重新开始向上计数。
Cortex-M3权威指南中有这样一句话——“DWT 中有剩余的计数器,它们典型地用于程序代码的“性能速写”(profiling)。通过编程它们,就可以让它们在计数器溢出时发出事件(以跟踪数据包的形式)。最典型地,就是使用 CYCCNT寄存器来测量执行某个任务所花的周期数,这也可以用作时间基准相关的目的(操作系统中统计 CPU使用率可以用到它)。”
DWT介绍:
2、寄存器
要实现延时的功能,总共涉及到三个寄存器:DEMCR 、DWT_CTRL、DWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值。
-
1、DEMCR
想要使能DWT外设,需要由另外的内核调试寄存器DEMCR的位24控制,写1使能。如下:
-
2、DWT_CYCCNT
使能DWT_CYCCNT寄存器之前,先清0。
让我们看看DWT_CYCCNT的基地址,从ARM-Cortex-M手册中可以看到其基地址是0xE000 1004,复位默认值是0,而且它的类型是可读可写的,我们往0xE000 1004这个地址写0就将DWT_CYCCNT清0了。
- 3、CYCCNTENA
它是DWT控制寄存器的第一位,写1使能,则启用CYCCNT计数器,否则CYCCNT计数器将不会工作。
- 4、总结
想要使用DWT的CYCCNT步骤: - 先使能DWT外设,这个由另外内核调试寄存器DEMCR的位24控制,写1使能。
- 使能CYCCNT寄存器之前,先清0。
- 使能CYCCNT寄存器,这个由DWT的CYCCNTENA 控制,也就是DWT控制寄存器的位0控制,写1使能。
3、代码实现
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
volatile static uint32_t cpuclkfeq = 0;
void dwt_init(uint32_t cpuclk)
{
cpuclkfeq = clk;
CoreDebug->DEMCR |= DEM_CR_TRCENA;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CR_CYCCNTENA;
}
uint32_t get_dwt_us(void)
{
return DWT->CYCCNT / (cpuclkfeq / 1000000);
}
void delay_us(uint32_t nus)
{
volatile uint32_t startts, endts, ts;
ts = nus * (cpuclkfeq / (1000 * 1000));
startts = DWT->CYCCNT;
endts = startts + ts;
if (endts > startts)
{
while (DWT->CYCCNT < endts);
}
else
{
while (DWT->CYCCNT > endts);
while (DWT->CYCCNT < endts);
}
}
CoreDebug寄存器定义如下:
#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */
/**
\brief Structure type to access the Core Debug Register (CoreDebug).
*/
typedef struct
{
__IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */
__OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */
__IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */
__IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */
} CoreDebug_Type;
#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */
DWT寄存器定义:
#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */
/**
\brief Structure type to access the Data Watchpoint and Trace Register (DWT).
*/
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */
__IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */
__IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */
__IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */
__IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */
__IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */
__IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */
__IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */
__IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */
__IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */
__IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */
uint32_t RESERVED0[1U];
__IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */
__IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */
__IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */
uint32_t RESERVED1[1U];
__IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */
__IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */
__IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */
uint32_t RESERVED2[1U];
__IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */
__IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */
__IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */
uint32_t RESERVED3[981U];
__OM uint32_t LAR; /*!< Offset: 0xFB0 ( W) Lock Access Register */
__IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */
} DWT_Type;
#define DWT ((DWT_Type *) DWT_BASE) /*!< DWT configuration struct */