This commit is contained in:
TuxMonkey
2025-11-16 17:19:14 +08:00
parent de8a0d5117
commit ab01747052
20 changed files with 10796 additions and 234 deletions

View File

@@ -1,5 +1,139 @@
//
// Created by tuxmonkey on 2025/10/28.
//
/**
* @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 "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);
}

View File

@@ -1,8 +1,104 @@
//
// Created by tuxmonkey on 2025/10/28.
//
/**
* @file bsp_dwt.h
* @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>
*/
#ifndef TRONONEH7_SCAFFOLD_BSP_DWT_H
#define TRONONEH7_SCAFFOLD_BSP_DWT_H
#ifndef _BSP_DWT_H
#define _BSP_DWT_H
#endif //TRONONEH7_SCAFFOLD_BSP_DWT_H
#include "main.h"
#include "stdint.h"
#include "bsp_log.h"
typedef struct
{
uint32_t s;
uint16_t ms;
uint16_t us;
} DWT_Time_t;
/**
* @brief 该宏用于计算代码段执行时间,单位为秒/s,返回值为float类型
* 首先需要创建一个float类型的变量,用于存储时间间隔
* 计算得到的时间间隔同时还会通过RTT打印到日志终端,你也可以将你的dt变量添加到查看
*/
#define TIME_ELAPSE(dt, code) \
do \
{ \
float tstart = DWT_GetTimeline_s(); \
code; \
dt = DWT_GetTimeline_s() - tstart; \
LOGINFO("[DWT] " #dt " = %f s\r\n", dt); \
} while (0)
/**
* @brief 初始化DWT,传入参数为CPU频率,单位MHz
*
* @param CPU_Freq_mHz c板为168MHz,A板为180MHz
*/
void DWT_Init(uint32_t CPU_Freq_mHz);
/**
* @brief 获取两次调用之间的时间间隔,单位为秒/s
*
* @param cnt_last 上一次调用的时间戳
* @return float 时间间隔,单位为秒/s
*/
float DWT_GetDeltaT(uint32_t *cnt_last);
/**
* @brief 获取两次调用之间的时间间隔,单位为秒/s,高精度
*
* @param cnt_last 上一次调用的时间戳
* @return double 时间间隔,单位为秒/s
*/
double DWT_GetDeltaT64(uint32_t *cnt_last);
/**
* @brief 获取当前时间,单位为秒/s,即初始化后的时间
*
* @return float 时间轴
*/
float DWT_GetTimeline_s(void);
/**
* @brief 获取当前时间,单位为毫秒/ms,即初始化后的时间
*
* @return float
*/
float DWT_GetTimeline_ms(void);
/**
* @brief 获取当前时间,单位为微秒/us,即初始化后的时间
*
* @return uint64_t
*/
uint64_t DWT_GetTimeline_us(void);
/**
* @brief DWT延时函数,单位为秒/s
* @attention 该函数不受中断是否开启的影响,可以在临界区和关闭中断时使用
* @note 禁止在__disable_irq()和__enable_irq()之间使用HAL_Delay()函数,应使用本函数
*
* @param Delay 延时时间,单位为秒/s
*/
void DWT_Delay(float Delay);
/**
* @brief DWT更新时间轴函数,会被三个timeline函数调用
* @attention 如果长时间不调用timeline函数,则需要手动调用该函数更新时间轴,否则CYCCNT溢出后定时和时间轴不准确
*/
void DWT_SysTimeUpdate(void);
#endif /* BSP_DWT_H_ */

View File

@@ -0,0 +1,54 @@
# bsp_dwt
DWT是stm32内部的一个"隐藏资源",他的用途是给下载器提供准确的定时,从而为调试信息加上时间戳.并在固定的时间间隔将调试数据发送到你的xxlink上.
## 常用功能
### 计算两次进入同一个函数的时间间隔
```c
static uint32_t cnt;
float deltaT;
deltaT=DWT_GetDeltaT(&cnt);
```
### 计算执行某部分代码的耗时
```c
float start,end;
start=DWT_DetTimeline_ms();
// some proc to go...
for(uint8_t i=0;i<10;i++)
foo();
end = DWT_DetTimeline_ms()-start;
```
我们还提供了一个宏用于调试计时:
```c
#define TIME_ELAPSE(dt, code) \
do \
{ \
float tstart = DWT_GetTimeline_s(); \
code; \
dt = DWT_GetTimeline_s() - tstart; \
LOGINFO("[DWT] " #dt " = %f s\r\n", dt); \
} while (0)
```
传入一个float类型的变量,并将你要执行的代码写入第二个参数:
```c
static float my_func_dt;
TIME_ELAPSE(my_func_dt,
Function1(vara);
Function2(some, var);
Function3(your,param);
// something more
);
// my_func_dt can be used for other purpose then;
```