You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cortex M0+(SAML21)板周期计数问题:DWT无效求替代方案

解决SAML21(Cortex-M0+)DWT周期计数失效及替代方案

一、先搞定DWT计数为0的问题

你的DWT代码没出有效结果,大概率是这几个原因:

1. 寄存器地址未正确映射

直接用*DEMCR这种裸指针容易出错,Cortex-M0+的调试寄存器应该用CMSIS标准定义来访问,避免地址错误:

#include "core_cm0plus.h"

// 正确的DWT初始化流程
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;  // 开启跟踪功能
DWT->CYCCNT = 0;                                // 重置周期计数器
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;            // 启用周期计数

2. 编译器优化导致代码被“吃掉”

如果你的测试代码段太简单,编译器可能会把它优化掉,导致CYCCNT没有变化。可以给count变量加volatile,或者在关键位置加内存屏障指令确保执行顺序:

volatile uint32_t count;

// 执行测试代码前加屏障
__ISB();
__DSB();

// 你的测试代码段
// .....

// 读取计数前再加屏障
__ISB();
__DSB();
count = DWT->CYCCNT;

3. 调试配置或硬件限制

有些开发板的调试接口(比如SWD)如果没正确配置,可能会导致DWT功能被禁用。确保你在调试器(比如Atmel Studio、OpenOCD)里开启了“Enable Trace”相关选项,或者检查芯片的调试锁有没有解除。


二、类似Arduino millis()的定时器中断方案

如果DWT还是搞不定,用定时器中断实现毫秒级计数是非常可靠的方案,以SAML21的TC定时器为例:

1. 全局计数器与中断服务函数

#include "sam.h"

volatile uint32_t millis_counter = 0;

void TC0_Handler(void) {
    if (TC0->COUNT16.INTFLAG.bit.OVF) {  // 捕获溢出中断
        millis_counter++;
        TC0->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;  // 清除中断标志
    }
}

2. 定时器初始化函数

假设系统时钟是48MHz,我们配置TC0每1ms触发一次中断:

void millis_init(void) {
    // 使能TC0时钟
    MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC0;
    GCLK->PCHCTRL[TC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
    
    // 配置TC0为16位模式,分频为48(48MHz/48=1MHz)
    TC0->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER_DIV48;
    // 设置自动重载值为999(1MHz下,每1000个周期就是1ms)
    TC0->COUNT16.PER.reg = 999;
    // 启用溢出中断
    TC0->COUNT16.INTENSET.reg = TC_INTENSET_OVF;
    // 启用定时器
    TC0->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
    
    // 配置NVIC中断优先级
    NVIC_SetPriority(TC0_IRQn, 3);
    NVIC_EnableIRQ(TC0_IRQn);
}

3. 实现millis()函数

uint32_t millis(void) {
    uint32_t temp;
    // 禁用中断防止读取时计数器被修改
    __disable_irq();
    temp = millis_counter;
    __enable_irq();
    return temp;
}

使用时,先调用millis_init()初始化,之后就可以像Arduino一样用millis()获取自启动以来的毫秒数了。如果需要更精确的周期计数,也可以调整定时器的分频和重载值,或者使用32位模式的定时器。


内容的提问来源于stack exchange,提问作者MarkP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:49:00