使用 DWT CYCCNT 在 STM32MP1 中进行精确时间测量

Posted

技术标签:

【中文标题】使用 DWT CYCCNT 在 STM32MP1 中进行精确时间测量【英文标题】:Precise Time Measurement in STM32MP1 with DWT CYCCNT 【发布时间】:2021-10-30 17:36:33 【问题描述】:

我在生产模式下使用OSD32MP1(基于 STM32MP157c),在 Core A7 上使用 OpenSTLinux,在 M4 上使用 FreeRTOS。其中一项任务是以非常高的速度、非常精确地为 M4 获取的 ADC 数据添加时间戳(认为它的数量级为纳秒到微秒)。请注意,只有测量之间的时间差很重要。

片上 RTC 可用(分配给 A7,但 M4 可以访问寄存器)。然而,亚秒级精度约为 0.003 秒(PREDIV_S 为 255 - 详情请参阅 Reference Manual),因此还不够好。

This、this 和 this *** 帖子导致使用 DWT_CYCCNT 即 CPU 周期计数器来测量时间差。相关部分代码如下:

在 M4 侧:

typedef struct tTimeStamp

    uint32_t nCPUFreq;
    uint32_t nCPUCycles;
    ...
tTimeStamp;

...

tTimeStamp oTimeStamp;

...

oTimeStamp.nCPUCycles = DWT->CYCCNT;
oTimeStamp.nCPUFreq = HAL_RCC_GetSystemCoreClockFreq();

最后 2 个语句在读取 ADC 值之前在 FreeRTOS 任务中运行。时间戳与其他数据一起交给 A7。

在 A7 侧(假设在时间 T0 有 tTimeStamp,然后在时间 T1 有 tTimeStamp):

// Second to NanoSecond Conversion
#define SECTONS 1000000000 

... 

float ComputeTimeDiffNS(tTimeStamp oTS0, tTimeStamp oTS1)

    // to avoid reporting time diff at t0
    // and in case CPU frequency changes
    if (oTS0.nCPUFreq != oTS1.nCPUFreq)
        return -1;
    
    // in case of counter overflow
    if (oTS0.nCPUCycles > oTS1.nCPUCycles)
    
        float fCyclesDiff = float(UINT32_MAX- oTS0.nCPUCycles + oTS1.nCPUCycles);
        return fCyclesDiff * SECTONS / float(oTS0.nCPUFreq) / 2;
    

    // base case 
    else
    
        float fCyclesDiff = float(oTS1.nCPUCycles - oTS0.nCPUCycles);
        return fCyclesDiff * SECTONS / float(oTS0.nCPUFreq);
    

    这是使用 DWT->CYCCNT 和 HAL_RCC_GetSystemCoreClockFreq() 测量非常精确的时差的正确方法吗?有没有更好、更精确的方法? 上述方法给了我两倍的时间。在读取 DWT->CYCCNT 时,我还切换了一个引脚并使用逻辑分析仪测量切换之间的间隔。说这个时间tActual是2ms。然而,上述公式,即 CPU_Cycles / CPU_Frequency 返回 tMeasured = 4ms。

这似乎表明公式应该是 CPU_Cycles / (2*CPU_Frequency)。所以要么频率需要加倍,要么周期需要减半。

在读数中,nCPUFreq 为 208878528(每个 Reference Manual 允许的最大值为 209000000),因此这必须是正确的,不能乘以 2。

CPU_Cycles 可以被 2 分频,但它不会表明 CPU 每个时钟周期要经过 2 个周期吗?这可能吗(CPU 在上升沿和下降沿循环??)

【问题讨论】:

1.这取决于您想要多少精度,以及什么是系统时钟源(HSI?HSE?),以及源时钟精度本身。注意 DWT 计数器,您需要手动启动它,因为它是在调试期间由探针完成的,而不是没有(默认情况下)。 2. 也许系统时钟比你想象的要慢(/2)?有可能吗? 为什么在代码中使用浮点数来浪费循环?原始周期工作得很好......当你做这样的数学时,你也会失去精度。 为什么不使用 M4 上的高速计时器之一? 【参考方案1】:

TLDR:M4 和 A7 之间丢包。

您好,在PatrikFST Forum 的大量帮助下,我最终解决了我自己的问题,他们建议 DWT 应该按照 ARM 指定的方式工作。

原来问题是 M4 和 A7 之间非常一致的丢包率,恰好是 2 倍,导致 CYCCNT 的两倍。我在错误的方向上浪费了太多时间,但最终我了解了数据包计数器的重要性。

请注意,Partrik 还在 STM 的高精度计数器上添加了一些 recommendations:

也许使用 STGENR 是独立于 Cortex-M4 的另一个选项 频率。

STGEN 默认在 HSI 64MHz 上运行,为您提供分辨率 大约 15ns,但 HSI 不是高精度振荡器 (+/-1%)。

或者,在 HSE 24MHz 上使用 STGEN 更精确(几 ppm),但分辨率约为 40ns。

另见这篇文章: https://community.st.com/s/question/0D53W00000oXAqhSAG/how-can-i-get-access-to-m4-timers-from-a7-linux-is-it-possible-

由于使用 AXI 总线通过 Cortex-m4 的异步总线读取 STGEN,它 必须承受一些 ns 的额外延迟。

【讨论】:

以上是关于使用 DWT CYCCNT 在 STM32MP1 中进行精确时间测量的主要内容,如果未能解决你的问题,请参考以下文章

mbedTLS sha256 的性能现实吗?

在皮质 m7 上测量时钟周期数

stm32mp1 Cortex M4开发篇1:stm32CubeIDE开发环境搭建

stm32mp1 芯片手册

stm32mp1 Cortex M4开发篇7:窗口看门狗

手把手教你搭建STM32MP1开发环境