本帖最后由 xld0932 于 2024-11-12 12:55 编辑
#申请原创# @21小跑堂
1、前言
MM32已经发布了多款基于安谋科技授权的Arm®v8-M 架构“星辰” STAR-MC1内核(兼容 Cortex-M33)处理器,基于STAR-MC1内核,来分享一下有关于DWT的一些常规应用示例,下面以MM32H5480为例。
2、数据监视点和跟踪单元(DWT)
通过MM32H5480芯片的DBG部分的功能框图,我们可以看出其芯片内核带有了数据监视点和跟踪单元(DWT)、指令跟踪宏单元(ITM)、跟踪端口接口单元(TPIU)等等功能;ITM允许通过printf等软件方式生成调试信息,还可以生成时间戳信息,这部分功能,我们在上一篇《MM32H5480通过J-Link实现日志打印的三种方法》有提到;DWT则是可以产生数据跟踪、事件跟踪和概况跟踪信息。
在实际应用的时候,我更多的是使用DWT自带的一个循环计数器来实现精确延时的功能,它可以达到us级别的延时;同时DWT的比较器功能实现对变量或者函数的监测功能,当变量被进行读/写操作或者函数被调用时,可以配置触发DebugMon中断,可以通过DWT的功能实现辅助定位问题。
3、DWT延时功能
首先DWT是属于调试和跟踪部分单元的功能,所以在使用DWT之前我们需要通过配置寄存器来开启这部分功能使能,通过配置DEMCU寄存器的TRCENA位,将这一位置1即可,如下所示:
然后配置DWT_CTRL寄存器,将CYCCNTENA这一位置1,开启DWT的计数功能;在使能CYCCNTENA之前,我们需要将DWT的CYCCNT计数值先清零,如下所示:
代码实现如下:
void PLATFORM_InitDelay(void)
{
DCB->DEMCR &= ~DCB_DEMCR_TRCENA_Msk;
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
DCB->DEMCR |= DCB_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
void PLATFORM_DelayUS(uint32_t us)
{
uint32_t Start = DWT->CYCCNT;
uint32_t Count = SystemCoreClock / 1000000 * us;
while ((DWT->CYCCNT - Start) < Count)
{
}
}
void PLATFORM_DelayMS(uint32_t ms)
{
uint32_t Start = DWT->CYCCNT;
uint32_t Count = SystemCoreClock / 1000 * ms;
while ((DWT->CYCCNT - Start) < Count)
{
}
}
4、DWT比较器功能
通过将DWT_CTRL寄存器的NUMCOMP位的值打印出来,知晓,MM32H5480最多可设置4个数据监视点、数据跟踪或比较器的功能。通过配置DWT_COMP比较寄存器来确定比较对象,通过配置DWT_FUNCTION寄存器来确定比较的属性。需要注意的是,一定要先设置DWT_COMP之后再配置DWT_FUNCTION寄存器,如果是更新DWT_COMP寄存器,则需要先将DWT_FUNCTION寄存器先配置为0,才可以更新;第二个需要注意的是在MCU与调试器断开的时候,DWT的监测功能能够正常运行,如果在MCU与调试器处于连接的状态时,DWT的监测功能可能会跟调试器产生冲突,这个在使用的时候需要注意!!!
下面示例中配置了通过DWT来监测一个变量的写入/赋值操作,和一个函数被调用的监测;当这个被监测变量的值发生改变时,通过配置会产生DebugMon中断;当这个被监测的函数被调用时,通过配置会产生DebugMon中断,具体代码如下所示:
extern uint32_t DWT_TestVar;
void PLATFORM_InitDelay(void)
{
DCB->DEMCR &= ~(DCB_DEMCR_TRCENA_Msk | DCB_DEMCR_MON_EN_Msk);
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
DCB->DEMCR |= (DCB_DEMCR_TRCENA_Msk | DCB_DEMCR_MON_EN_Msk);
DWT->COMP0 = (uint32_t)&DWT_TestVar;
DWT->FUNCTION0 = (8 << DWT_FUNCTION_ID_Pos) | /* Data Address, and Data Address With Value */
(2 << DWT_FUNCTION_DATAVSIZE_Pos) | /* 4 bytes */
(1 << DWT_FUNCTION_ACTION_Pos) | /* Generate debug event */
(5 << DWT_FUNCTION_MATCH_Pos); /* Data Address, writes */
DWT->COMP1 = (uint32_t)(PLATFORM_DelayMS - 1);
DWT->FUNCTION1 = (10 << DWT_FUNCTION_ID_Pos) | /* Instruction Address, Data Address, and Data Address With Value */
(1 << DWT_FUNCTION_DATAVSIZE_Pos) | /* 2 bytes */
(1 << DWT_FUNCTION_ACTION_Pos) | /* Generate debug event */
(2 << DWT_FUNCTION_MATCH_Pos); /* Instruction Address */
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
printf("\r\nDWT_CTRL->NUMCOMP : %ld", (DWT->CTRL & DWT_CTRL_NUMCOMP_Msk) >> DWT_CTRL_NUMCOMP_Pos);
}
uint32_t DWT_TestVar = 0;
int main(void)
{
PLATFORM_Init();
BSP_LED_Init();
while (1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_9, Bit_RESET);
GPIO_WriteBit(GPIOA, GPIO_Pin_10, Bit_RESET);
PLATFORM_DelayMS(1000);
GPIO_WriteBit(GPIOA, GPIO_Pin_9, Bit_SET);
GPIO_WriteBit(GPIOA, GPIO_Pin_10, Bit_SET);
PLATFORM_DelayMS(1000);
DWT_TestVar++;
}
}
void DebugMon_Handler(void)
{
if ((DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk) != 0) /* This bit is read-only and this bit clears to zero when read */
{
printf("\r\nDebugMon interrupt comparator 0.");
}
if ((DWT->FUNCTION1 & DWT_FUNCTION_MATCHED_Msk) != 0)
{
printf("\r\nDebugMon interrupt comparator 1.");
}
}
运行结果:
5、附件
测试程序:
Project.zip
(1.09 MB)
参考文献:
ARMv8-M Architecture Reference Manual B.x.PDF
(12.31 MB)
补充说明:
有细心我网友会发现在上面运行结果的截图中,有2个计算公式及结果的打印,举例了5-20的结果相对于256-20+5的结果,所计算出来的值是一样的,而验证这个的目的是DWT的CYCCNT是一个32位循环计数器,当溢出后又会从0开始计算,所以对于延时函数中的写法做了一个验证。
|