跳转到主要内容

2. CPU运行

动机

在本节中,我们要确保MCU内核、内部RAM和闪存以所需的时钟速度运行。

TouchGFX可在任何MCU速度下运行,但错误的时钟配置可能会导致低于必要的性能。 随后,基于您的开发板,需要配置特定时序参数,如触摸控制器的I2C时钟。 若不能确保MCU以正确的速度运行的情况下,这些配置无法生效。

对于STM32微控制器,您需要设置系统时钟。 然后对该时钟进行分频,以生成FCLK内核时钟和各种外设时钟,如APB1外设时钟。

目标

本节的目标为修改项目,以获得正确的时钟配置。 您还应验证内部RAM和闪存是否以预期速度运行。

验证

以下是本节的验证点:

验证点基本原理
SystemCoreClock的变量值正确微控制器被配置为按所需频率运行。
内部RAM可读微控制器具有预期的内部RAM容量,该区可读,并可以测量速度
可读的内部闪存微控制器具有预期的内部闪存容量,该区可读,并可以测量速度
禁用Cache缓存在禁用Cache缓存的情况下运行,可使系统更简单且易于理解。

先决条件

以下是此步骤的先决条件:

  • 有关硬件上的时钟源的信息。 通常使用晶振,但也可以使用其他解决方案。

执行

现在,我们将逐步调整项目时钟配置,以获取所需的MCU频率。 然后,我们将讨论如何测量内部闪存的读取速度。

系统时钟

在STM32CubeMX中,单击“时钟配置”选项卡。 这将为您提供特定MCU的时钟数概述:

时钟配置

在该示例中,选择HSI作为时钟源。 许多项目使用外部晶振HSE,同时选择合适的分频(/M) 和倍频(/N) 参数。 本指南不做有关时钟配置的介绍。 更改时钟配置后,必须在STM32CubeMX中重新生成项目(点击右上角的“生成代码”)。

内核时钟(HCLK) 可在运行时通过生成的代码进行计算,并保存在变量中。 应用代码可使用此变量在时钟周期和秒单位之间进行正确转换,如启动定时器。 要重新计算时钟参数,您须调用SystemCoreClockUpdate()函数。 在main.c(用户代码段) 中插入一个调用:

SystemCoreClockUpdate

如果在此函数的末尾设置断点,则可以看到基于配置的内核时钟:

SystemCoreClock

另一个测试重点为系统定时器。 该定时器按HCLK时钟运行,该时钟经过分频,以每隔1 ms产生一次中断。 该定时器用于STM32Cube固件,以实现毫秒延迟。

我们可通过在main中插入诸如5秒的延迟来对此进行测试。 用秒表或类似的方法来验证这一点:

测量延迟

闪存与RAM大小和速度

使用系统定时器可轻松检查存储器的读取速度。 系统定时器中断每毫秒对计数变量加一。 通过在一段代码之前和之后读取此变量,我们可以测量代码的运行时间(分辨率为1 ms) 。 此方案可用于测量应用程序中的许多不同位置的时间周期。 该测量不是很精确,但可以在没有示波器等外部设备的情况下完成。

为此,我们首先需要两个易失性变量来保存结果。 如果我们不在此处保存结果,则编译器在某些优化情况下会删除测量代码:

即用于保存测量结果的易失性全局变量

这里提供了一个示例,在该示例中,我们读取了从0x08000000到0x08020000(128 Kb)的闪存,并对代码进行计时:

对读取循环进行计时

您可以使用像这样的代码来验证不同存储器的速度。 在STM32CubeMX中创建设置后,您可以测量读取速度,并记录结果。 随后可以重复测量并验证。 如果要测量存储器带宽(即以kb为单位的读取速度) ,您可以将数据量与测量时间进行比较。

在16 MHz的STM32F429上,如果代码的运行时间为12 ms,则内部闪存的读取速度(使用此方法) 为128kb/0.012s = 10,666 kb/s。

可轻松更改上面的测试代码段,以验证所有内部闪存是否使能并且可读。 只需更改起始和结束地址。

该代码还可以检查内部RAM。 在F429,RAM从地址0x20000000开始。 内核耦合存储区从0x10000000开始。 检查特定MCU的数据手册,以获取相关存储器地址。

您应该对不同的存储器进行一些测量,并记下结果。 对于RAM,请测试读取和写入速度。

链接器脚本

另一个关注点为链接器脚本。 该配置文件将RAM和闪存在系统中的地址告知链接器。 链接器脚本由CubeMX与项目一起生成,但对其进行研究可能会有一些好处。 随后,在大多数情况下,您必须对其进行修改,以适应项目需要。

F7和H7上的缓存

基于ARM Cortex-M7的STM32F7和STM32H7微控制器包括数据和指令缓存。 在平台稳定之前,建议至少禁用数据缓存【D-Cache】。 在许多情况下,数据缓存可显著提高性能,但也会使测试变得复杂。

在拥有稳定的平台后,可启用数据缓存。 此时,由于平台在其他方面正常,因此可以更轻松地锁定问题源自数据缓存管理。

由于MCU内核读取和写入缓存,而诸如DMA2和LTDC之类的外设则直接从存储器读取(而不是读取Cache缓存) ,这使数据缓存变得复杂。 因此,您可能会遇到将数据虽写入帧缓冲,但在显示屏上看不到某些数据的情况。 因为这些数据还在高速缓存,所以LTDC在RAM中找不到新数据, 解决方案就是在某一时刻刷新项目中的缓存,但我们建议稍后再做处理。

可在STM32CubeMX配置中的系统内核部分禁用/使能缓存。

TouchGFX内部DCache状态机

TouchGFX引擎记录当前和最近一次渲染操作,一共有两种状态:HARDWARESOFTWARE。 初始状态设为 HARDWARE ,因为大部分绘图操作由硬件完成。 当发生状态切换时,状态机将调用适当的虚函数来处理缓存失效机制。 当状态从 HARDWARE 转换成SOFTWARE时,状态机将调用虚函数 void touchgfx::HAL::InvalidateCache() ,当状态从 SOFTWARE 转换成 HARDWARE 时,状态机将调用虚函数void touchgfx::HAL::FlushCache()。 这两个函数的功能由用户在派生的HAL类中实现。

TouchGFX引擎内部DCache状态机

如果使用TouchGFX Generator,则会在TouchGFXGeneratedHAL类中创建这些派生方法的实现,通过函数调用DCache失效机制,且无须任何其他操作。

更多读物

此处的链接文档包含有关STM32CubeMX和STM32缓存的更多信息: