mirror of
https://gitee.com/dlmu-cone/tronone-h7-scaffold
synced 2026-07-23 19:25:09 +08:00
140 lines
3.3 KiB
C
140 lines
3.3 KiB
C
/**
|
|
* @file bsp_dwt.c
|
|
* @brief DWT延时 软件延时库
|
|
* @author TuxMonkey (nqx2004@gmail.com)
|
|
* @version 1.0
|
|
* @date 2025-07-08
|
|
*
|
|
* @copyright Copyright (c) 2025 DLMU-C.ONE
|
|
*
|
|
* @par 修改日志:
|
|
* <table>
|
|
* <tr><th>Date <th>Version <th>Author <th>Description
|
|
* <tr><td>2025-07-08 <td>1.0 <td>TuxMonkey <td>内容
|
|
* </table>
|
|
*/
|
|
|
|
#include "bsp_dwt.h"
|
|
#include "cmsis_os.h"
|
|
|
|
static DWT_Time_t SysTime;
|
|
static uint32_t CPU_FREQ_Hz, CPU_FREQ_Hz_ms, CPU_FREQ_Hz_us;
|
|
static uint32_t CYCCNT_RountCount;
|
|
static uint32_t CYCCNT_LAST;
|
|
static uint64_t CYCCNT64;
|
|
|
|
/**
|
|
* @brief 私有函数,用于检查DWT CYCCNT寄存器是否溢出,并更新CYCCNT_RountCount
|
|
* @attention 此函数假设两次调用之间的时间间隔不超过一次溢出
|
|
*
|
|
* @todo 更好的方案是为dwt的时间更新单独设置一个任务?
|
|
* 不过,使用dwt的初衷是定时不被中断/任务等因素影响,因此该实现仍然有其存在的意义
|
|
*
|
|
*/
|
|
static void DWT_CNT_Update(void)
|
|
{
|
|
static volatile uint8_t bit_locker = 0;
|
|
if (!bit_locker)
|
|
{
|
|
bit_locker = 1;
|
|
volatile uint32_t cnt_now = DWT->CYCCNT;
|
|
if (cnt_now < CYCCNT_LAST)
|
|
CYCCNT_RountCount++;
|
|
|
|
CYCCNT_LAST = DWT->CYCCNT;
|
|
bit_locker = 0;
|
|
}
|
|
}
|
|
|
|
void DWT_Init(uint32_t CPU_Freq_mHz)
|
|
{
|
|
/* 使能DWT外设 */
|
|
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
|
|
|
/* DWT CYCCNT寄存器计数清0 */
|
|
DWT->CYCCNT = (uint32_t) 0u;
|
|
|
|
/* 使能Cortex-M DWT CYCCNT寄存器 */
|
|
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
|
|
|
CPU_FREQ_Hz = CPU_Freq_mHz * 1000000;
|
|
CPU_FREQ_Hz_ms = CPU_FREQ_Hz / 1000;
|
|
CPU_FREQ_Hz_us = CPU_FREQ_Hz / 1000000;
|
|
CYCCNT_RountCount = 0;
|
|
|
|
DWT_CNT_Update();
|
|
}
|
|
|
|
float DWT_GetDeltaT(uint32_t *cnt_last)
|
|
{
|
|
volatile uint32_t cnt_now = DWT->CYCCNT;
|
|
float dt = ((uint32_t) (cnt_now - *cnt_last)) / ((float) (CPU_FREQ_Hz));
|
|
*cnt_last = cnt_now;
|
|
|
|
DWT_CNT_Update();
|
|
|
|
return dt;
|
|
}
|
|
|
|
double DWT_GetDeltaT64(uint32_t *cnt_last)
|
|
{
|
|
volatile uint32_t cnt_now = DWT->CYCCNT;
|
|
double dt = ((uint32_t) (cnt_now - *cnt_last)) / ((double) (CPU_FREQ_Hz));
|
|
*cnt_last = cnt_now;
|
|
|
|
DWT_CNT_Update();
|
|
|
|
return dt;
|
|
}
|
|
|
|
void DWT_SysTimeUpdate(void)
|
|
{
|
|
volatile uint32_t cnt_now = DWT->CYCCNT;
|
|
static uint64_t CNT_TEMP1, CNT_TEMP2, CNT_TEMP3;
|
|
|
|
DWT_CNT_Update();
|
|
|
|
CYCCNT64 = (uint64_t) CYCCNT_RountCount * (uint64_t) UINT32_MAX + (uint64_t) cnt_now;
|
|
CNT_TEMP1 = CYCCNT64 / CPU_FREQ_Hz;
|
|
CNT_TEMP2 = CYCCNT64 - CNT_TEMP1 * CPU_FREQ_Hz;
|
|
SysTime.s = CNT_TEMP1;
|
|
SysTime.ms = CNT_TEMP2 / CPU_FREQ_Hz_ms;
|
|
CNT_TEMP3 = CNT_TEMP2 - SysTime.ms * CPU_FREQ_Hz_ms;
|
|
SysTime.us = CNT_TEMP3 / CPU_FREQ_Hz_us;
|
|
}
|
|
|
|
float DWT_GetTimeline_s(void)
|
|
{
|
|
DWT_SysTimeUpdate();
|
|
|
|
float DWT_Timelinef32 = SysTime.s + SysTime.ms * 0.001f + SysTime.us * 0.000001f;
|
|
|
|
return DWT_Timelinef32;
|
|
}
|
|
|
|
float DWT_GetTimeline_ms(void)
|
|
{
|
|
DWT_SysTimeUpdate();
|
|
|
|
float DWT_Timelinef32 = SysTime.s * 1000 + SysTime.ms + SysTime.us * 0.001f;
|
|
|
|
return DWT_Timelinef32;
|
|
}
|
|
|
|
uint64_t DWT_GetTimeline_us(void)
|
|
{
|
|
DWT_SysTimeUpdate();
|
|
|
|
uint64_t DWT_Timelinef32 = SysTime.s * 1000000 + SysTime.ms * 1000 + SysTime.us;
|
|
|
|
return DWT_Timelinef32;
|
|
}
|
|
|
|
void DWT_Delay(float Delay)
|
|
{
|
|
uint32_t tickstart = DWT->CYCCNT;
|
|
float wait = Delay;
|
|
|
|
while ((DWT->CYCCNT - tickstart) < wait * (float) CPU_FREQ_Hz);
|
|
}
|