STM32内核DWT精确延时详解
创始人
2024-11-14 13:05:06
0次

1.概述
在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace),该外设有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数。
最长能记录的时间为:10.74s=2的32次方/400000000
(假设内核频率为400M,内核跳一次的时间大概为1/400M=2.5ns)
当CYCCNT溢出之后,会清0重新开始向上计数。
使能CYCCNT计数的操作步骤:
(1)、先使能DWT外设,这个由另外内核调试寄存器DEMCR的位24控制,写1使能
(2)、使能CYCCNT寄存器之前,先清0
(3)、使能CYCCNT寄存器,这个由DWT_CTRL(代码上宏定义为DWT_CR)的位0控制,写1使能

2.代码

#define  DWT_CR      *(__IO uint32_t *)0xE0001000 #define  DWT_CYCCNT  *(__IO uint32_t *)0xE0001004 #define  DEM_CR      *(__IO uint32_t *)0xE000EDFC  #define  DEM_CR_TRCENA                   (1 << 24) #define  DWT_CR_CYCCNTENA                (1 <<  0)  /**   * @brief  初始化时间戳   * @param  无   * @retval 无   * @note   使用延时函数前,必须调用本函数   */ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) {     /* 使能DWT外设 */     DEM_CR |= (uint32_t)DEM_CR_TRCENA;                      /* DWT CYCCNT寄存器计数清0 */     DWT_CYCCNT = (uint32_t)0u;      /* 使能Cortex-M DWT CYCCNT寄存器 */     DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;        return HAL_OK; }  /**   * @brief  读取当前时间戳   * @param  无   * @retval 当前时间戳,即DWT_CYCCNT寄存器的值   */ uint32_t CPU_TS_TmrRd(void) {           return ((uint32_t)DWT_CYCCNT); } 
/* 获取内核时钟频率 */ #define GET_CPU_ClkFreq()       HAL_RCC_GetSysClockFreq() #define CPU_MHZ                 168 #define SysClockFreq            (CPU_MHZ*1000000)  /**   * @brief  读取当前时间戳   * @param  无   * @retval 当前时间戳,即DWT_CYCCNT寄存器的值   */ uint32_t HAL_GetTick(void) {           return ((uint32_t)DWT_CYCCNT/SysClockFreq*1000); } 

DWT_CYCCNT为内核的计数次数,SysClockFreq为内核时钟频率。
1/SysClockFreq为内核每运行一次耗费的时间,单位为秒。
(1/SysClockFreq) * 1000为将内核每运行一次耗费的时间单位由秒转换为ms。
DWT_CYCCNT / SysClockFreq * 1000即将内核的运行的次数转换为ms值

/**   * @brief  采用CPU的内部计数实现精确延时,32位计数器   * @param  us : 延迟长度,单位1 us   * @retval 无   * @note   使用本函数前必须先调用CPU_TS_TmrInit函数使能计数器,             或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION             最大延时值为8秒,即8*1000*1000   */ void CPU_TS_Tmr_Delay_US(uint32_t us) {   uint32_t ticks;   uint32_t told,tnow,tcnt=0;    /* 在函数内部初始化时间戳寄存器, */   #if (CPU_TS_INIT_IN_DELAY_FUNCTION)     /* 初始化时间戳并清零 */   HAL_InitTick(5); #endif      ticks = us * (GET_CPU_ClkFreq() / 1000000);  /* 需要的节拍数 */         tcnt = 0;   told = (uint32_t)CPU_TS_TmrRd();         /* 刚进入时的计数器值 */    while(1)   {     tnow = (uint32_t)CPU_TS_TmrRd();       if(tnow != told)     {          /* 32位计数器是递增计数器 */           if(tnow > told)       {         tcnt += tnow - told;         }       /* 重新装载 */       else        {         tcnt += UINT32_MAX - told + tnow;        }               told = tnow;        /*时间超过/等于要延迟的时间,则退出 */       if(tcnt >= ticks)break;     }     } } 

ticks = us * (GET_CPU_ClkFreq() / 1000000)的推导过程如下:
GET_CPU_ClkFreq()为内核的时钟频率。
在本程序中CPU的内核频率为168000000,
计算一个时钟运行的秒:(1/168000000)秒
计算一个时钟运行的秒数转换为us:(1/168000000)*1000000=1000000/168000000us
CPU_TS_Tmr_Delay_US(uint32_t us)中函数参数为us单位
假设需要延时500us,那么需要多少个内核时钟
500us=1000000 / 168000000us * X;
X=500us * (168000000us / 1000000);

相关内容

热门资讯

实测交流透视挂!宝玛大厅ai智... 实测交流透视挂!宝玛大厅ai智能透视挂教程,宝玛大厅破解软件经验(本来有挂辅助)1、每一步都需要思考...
总算了解辅助器!朱雀吴江三缺一... 总算了解辅助器!朱雀吴江三缺一ai智能透视辅助挂技巧,朱雀吴江三缺一好像是有挂(有辅助挂细节)朱雀吴...
今日公布透视!九五至尊大厅ai... 今日公布透视!九五至尊大厅ai智能透视插件,九五至尊大厅有没有透视挂窍门(切实有挂技术)1、在九五至...
玩家必看科普开挂!聚闲麻将ai... 玩家必看科普开挂!聚闲麻将ai智能透视辅助挂软件,聚闲麻将总是真的有挂(有辅助挂方式)聚闲麻将能透视...
据报道开挂!旅游娱乐ai智能开... 据报道开挂!旅游娱乐ai智能开挂工具,旅游娱乐辅助工具演示(一直有挂教学)1、全新机制【旅游娱乐ai...
一分钟揭秘开挂!决胜朋来麻将a... 一分钟揭秘开挂!决胜朋来麻将ai智能透视辅助挂教程,决胜朋来麻将真是真的是有挂(有辅助挂总结)1、首...
如何分辨真伪透视!红牛ai智能... 如何分辨真伪透视!红牛ai智能透视攻略,红牛是不是有挂经验(真是有挂技术)1、操作简单,无需红牛手机...
2分钟细说辅助器!江湖大庆麻将... 2分钟细说辅助器!江湖大庆麻将ai智能透视辅助挂攻略,江湖大庆麻将竟然是真的有挂(有辅助挂头条)1、...
总算清楚透视挂!老夫子厅ai智... 总算清楚透视挂!老夫子厅ai智能透视挂技巧,老夫子厅怎么开挂课程(好像发现有挂)老夫子厅破解侠是真的...
解密关于辅助!菜鸟麻将ai智能... 解密关于辅助!菜鸟麻将ai智能透视辅助挂脚本,菜鸟麻将总是存在有挂(有辅助挂存在)1、用户打开应用后...