Skip to main content

2. CPU运行

动机

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

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

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

目标

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

验证

以下是本节的验证点:

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

先决条件

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

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

执行

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

系统时钟

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

时钟配置

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

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

SystemCoreClockUpdate

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

SystemCoreClock

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

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

测量延迟

闪存与RAM大小和速度

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

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

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

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

对读取循环进行计时

您可以使用像这样的代码来验证不同存储器的速度。 在CubeMX中创建设置后,您可以测量读取速度,并记录结果。 随后可以重复测量并验证。 如果要测量存储器带宽(即以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中找不到新数据, 解决方案就是在某一时刻刷新项目中的缓存,但我们建议稍后再做处理。

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

TouchGFX internal DCache State Machine

TouchGFX engine keeps track of the current and last rendering operation, there are two states HARDWARE and SOFTWARE. The initial state is set to HARDWARE as the mijority of draw operations are done by hardware. When a state switch occurs the state machine will call the appropriate virtual function to handle cache invalidation. When the state transit from HARDWARE to SOFTWARE it will call the virtual method void touchgfx::HAL::InvalidateCache() and when the state transitions from SOFTWARE to HARDWARE it will call the virtual method void touchgfx::HAL::FlushCache(). The functionality of these two functions is left for the user to implement in the derived HAL class.

TouchGFX engine internal DCache State Machine

If using TouchGFX Generator the implementation of these derived methods will be created in the TouchGFXGeneratedHAL class with function calls to DCache invalidation and no further action is needed.

Further Readings

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

Further reading