1、Cortex-M4内核架构
2、硬件延时
利用计数功能的硬件进行延时,比如单片机片上定时器(Timer),内核滴答定时器(systick)等:
__weak void HAL_IncTick(void) { uwTick++; } __weak uint32_t HAL_GetTick(void) { return uwTick; } void SysTick_Handler(void) { HAL_IncTick(); } __weak void HAL_Delay(__IO uint32_t Delay) { uint32_t tickstart = 0; tickstart = HAL_GetTick(); while((HAL_GetTick() - tickstart) < Delay); }3、DWT(监视点单元,数据跟踪)硬件延时方案
DWT里有一个32位的寄存器叫CYCCNT,它是一个向上计数器,记录的是内核时钟运行的次数,内核时钟跳动一次,该计数器就加1,如果内核时钟是120MHz,那精度就是1/120M = 8.3ns,而单片机程序的运行时间通常都是微秒级别的,所以DWT实现延时的精度是非常高的。
要实现DWT延时的功能,总共涉及到三个内核寄存器:DEMCR 、DWT_CTRL、DWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值;当CYCCNT溢出之后,会清0重新开始向上计数。
如果内核时钟是120MHz,直接使用CYCCNT延时最大值为: 232 * 1/120M = 36S。
注:DWT只在Cortex-M3及以上内核中存在。
①使能DWT,需要向DEMCR寄存器的24位写1,寄存器定义位于core_cm4.h
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; /* 关闭 TRC */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;/* 打开 TRC */
②使能计数器,需要向CTRL寄存器的0位写1:
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; /* 关闭计数功能 */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;/* 打开计数功能 */
③计数器清零:
DWT->CYCCNT = 0;
代码编写:
#include <stdint.h> #include "gd32f30x.h" #include "delay.h" static uint32_t g_sysClock; /** *********************************************************** * @brief DWT初始化配置 * @param * @return *********************************************************** */ void DelayInit(void) { /* 关闭 TRC */ CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; /* 打开 TRC */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; /* 关闭计数功能 */ DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; /* 打开计数功能 */ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; /* 计数清零 */ DWT->CYCCNT = 0; g_sysClock = rcu_clock_freq_get(CK_SYS); } /** *********************************************************** * @brief 微秒级延时函数 * @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us * @return *********************************************************** */ void DelayNus(uint32_t nUs) { uint32_t tickStart = DWT->CYCCNT; /* 转换为nUs对应的时钟跳动次数*/ nUs *= g_sysClock / 1000000; /* 延时等待 */ while ((DWT->CYCCNT - tickStart) < nUs); } /** *********************************************************** * @brief 毫秒级延时函数 * @param nMs,延时时间n毫秒 * @return *********************************************************** */ void DelayNms(uint32_t nMs) { for (uint32_t i = 0; i < nMs; i++) { DelayNus(1000); } } #ifndef _DELAY_H_ #define _DELAY_H_ #include "stdint.h" /** *********************************************************** * @brief DWT初始化配置 * @param * @return *********************************************************** */ void DelayInit(void); /** *********************************************************** * @brief 微秒级延时函数 * @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us * @return *********************************************************** */ void DelayNus(uint32_t nUs); /** *********************************************************** * @brief 毫秒级延时函数 * @param nMs,延时时间n毫秒 * @return *********************************************************** */ void DelayNms(uint32_t nMs); #endif