英飞凌Aurix2G TC3XX STM模块详解
本文主要介绍英飞凌 Aurix2G TC3XX 系列芯片STM模块硬件原理、MCAL相关配置和部分代码实现。
目录
1 模块简介
STM(System Timer)是 Aurix2G TC3XX 内部 64 位的系统定时器,提供最高 100MHz 精度的定时功能,每款芯片的模块数量与 CPU 数量对应,比如 TC375 有 3 个核,同时具有 STM0~STM2 一共 3 个 STM 模块。STM 模块具有如下特性:
- 独立运行的 64 位计数器(100MHz 下最大时间为 5849 年)
- 支持 64 位计数值同步读取
- 支持 32 位连续的特定位置读取,比如读取计数器第 7 到 39 位数据
- 支持利用比较寄存器进行灵活的定时中断请求
- 上电自动启动
- Application Reset 后支持继续运转不归零(System Reset 和 PowerOn Reset 后一定归零的)
STM 是一个上电后自动连续运行的定时器,因此适合作为时间戳功能寄存器。其提供的定时器中断可作为 Wdg 的超时中断使用。但由于其比较中断寄存器特性,每次超时进入中断后需要重新装载定时值,因此不适合作为 OS Counter,会存在累积时间误差。
2 功能介绍
STM 的时钟来自系统时钟,与 CPU 同源,最大支持 100MHz,与系统时钟的倍数关系取决于 STM 分频寄存器 SCU_CCUCON0.STMDIV。关系如下:
f S T M = f P L L 0 S T M D I V \begin{equation} f_{STM} = \frac {f_{PLL0}} {STMDIV} \end{equation} fSTM=STMDIVfPLL0
芯片上电之后,根据时钟寄存器复位值,得出 fPLL0 默认为 100MHz,SCU_CCUCON0.STMDIV 复位值为 3,因此上电之后,在 MCU 时钟初始化及锁相环稳定之前,STM 以默认频率 33.3 MHz 启动并运行。但是我们 MCU 中一般将系统时钟 fPLL0 配置为 300MHz,所以在时钟初始化之后 STM 以 100MHz 运行。
2.1 计时器功能
STM 模块示意图:
每个 STM 模块内部是一个上电自动启动的 64 位系统时钟,提供不同的寄存器(STM_TIM0~STM_TIM5 和 STM_CAP)以读取不同位置的 32 位时刻值。因为 64 位数据在 32 位 CPU 中无法在一条指令内完成,因此 STM 模块提供了高 32 位冻结功能:在 TIM0 到 TIM5 任一寄存器被读取时,STM 会将此刻的高 32 位时刻值冻结一次到 STM_CAP 中,因此通过先读取 STM_TIM0 再读取 STM_CAP 寄存器的方式,组成完成一致的 64 位时刻值。代码实现如下:
#include "IfxStm_reg.h" /* Aurix2G STM寄存器 */
uint64 GetSystemTick()
{
uint64 tick = 0;
tick |= STM0_TIM0.U; /* 获取低32位时刻值 */
tick |= STM0_CAP.U <<32; /* 获取高32位时刻值 */
return tick;
}
这里有些朋友可能会觉得这里写一个函数不方便,习惯写成宏的形式:
#define STM_GETSYSTICK (STM0_TIM0.U | (STM0_CAP.U<<32))
但是这存在一个问题,对于不同的编译器,同行语句的代码指令执行顺序不一定一致,如果编译器先执行 STM0_CAP.U,则执行顺序变成了先读取高 32 位冻结时刻值,再读取低 32 位时刻值,则在 0xFFFFFFFF 这种低 32 位即将归零的临界时刻可能会读取出错误值。
2.2 定时功能
STM 中每个模块提供了两个 32 位比较寄存器,用来实现单词的定时功能。比较寄存器可以与 STM 的 64 位计时器中任意位置的最大 32 位宽度的时刻值进行对比,当值匹配时会产生对应的事件,用于触发中断。比较寄存器示意图如下:
每个比较寄存器有一个起始位置寄存器 MSTART 和一个比较位宽寄存器 MSIZE,MSTART 表示从 64 位计时器中的哪一位开始比较,MSIZE 表示比较的数据宽度。比如图中 Compare Register0 的 MSTART=10,MSIZE=17,表示从计时器的第 10 位往后取 17 位,与比较寄存器STM_CAP0的前 17 位进行比较,匹配则产生中断信号。
如果需要设置定时功能,则需要读取当前时刻值,然后根据定时需求设置比较寄存器的值,最终实现定时功能。比如当前时刻值为 0x1000(单位 Tick),想要设置 0x800Tick 之后触发中断,则需要设置 STM_CAP0 为 0x1800. 对于定时功能,英飞凌原厂 MCAL 中提供了相应接口 Stm_EnableModule()和 Stm_EnableAlarm()。其中 Stm_EnableModule()并非启动 STM 模块,而是进行 STM 内部的比较寄存器和中断的配置,Stm_EnableAlarm()则是用来设置一个闹钟。
/* ModuleNumber: 模块序号,STM0则为0,一般代码中都有宏 */
void Stm_EnableModule(const uint8 ModuleNumber);
/* ModuleNumber: 模块Id,STM0则为0,一般代码中都有宏
* CompareRegisterId:比较寄存器Id,一个STM有两个比较寄存器,一般CAP0都默认分配给Wdg使用
* TimerMode:定时模式,0为单次,1为连续(每次中断中重新装载,具有累积误差)
* Ticks:定时tick值,100MHz下想要定时1秒,则tick = 100 000 000
* Stm_Applicationfunction:回调函数,超时之后中断中会调用
*/
void Stm_EnableAlarm(const uint8 ModuleNumber,
const uint8 CompareRegisterId, const uint8 TimerMode, const uint32 Ticks,
const Stm_CallbackFnPtrType Stm_Applicationfunction);
这里需要注意的是如果设置为连续触发,类似设置闹钟,比如在 5 点设置 1 个小时的闹钟那么我们需要设置为 6 点,如果到了 6 点还需要设置一个小时闹钟则需要再设置为 7 点,STM 的连续触发就是这种机制,它并不像其他定时器的周期触发逻辑,而是在每次触发后,在定时器中断中重新装载比较寄存器的值,实现连续触发,我们在英飞凌原厂 MCAL 代码的 Stm_Isr()中也可以看到该逻辑:
因此正如前文提到,STM 的比较中断逻辑适合作为 EcuM 或者 Wdg 的定时中断,不适合作为 OS Counter 的触发源,会产生累积误差。如果要实现精准连续的定时功能,则需要使用该芯片的其他硬件模块,比如 GPT12、CCU6 以及来自于博世 IP 强大的 GTM 模块,这里就不展开了,后续我们会专门开篇描述这些模块。
2.3 中断机制
STM 的中断触发机制并不复杂,每个 STM 模块有两个比较寄存器,同时每个 STM 模块有两个中断源,而且比较寄存器和中断源的连接也是可配的。功能示意图如下:
从图中我们可以看到每个比较寄存器有一个 CMPxEN 使能开关,一个中断源选择开关 CMPxOS,和一个中断设置和清除开关 CMPxIR。CMPxEN 设置 1 则打开中断,CMPxOS 设置为 0 或者 1 则选择对应的中断源,输出到中断模块 IR 中。另外在Irq模块中需要配置对应的中断,这里就不展开说了,后续会有专门介绍中断的章节。
3 MCAL配置
3.1 时钟配置
在 Mcu -> McuClockSettingConfig_0 -> General 中配置 STM 时钟,这里设置所需频率值,工具会自动计算出对应的 SCU_CCUCON0.STMDIV。
3.2 McuHardwareResourceAllocation配置
MCAL 中所有的硬件资源都需要在 MCU 模块中进行分配,在 Mcu -> McuHardwareResourceAllocationConf_0 -> McuStmAllocationConf 中配置 STM 的硬件分配,如前所述 Cmp0 一般用于 Wdg,Cmp1 可用于 STM 定时功能。(图中为 TC375 配置,有 3 个 STM 模块)
3.3 ResourceM配置
Aurix2G MCAL 中面向多核提供了一个硬件对于核的配置模块 ResourceM,其本身不产生代码,但是配置会影响其他模块生成代码;对于 STM 模块,如果要使用用户定时器功能,则需要在 ResourceM 中配置硬件对于 Cpu 的分配,否则 MCAL 代码中初始化会失败。
这里我们来到 ResourceM -> ResourceMMcalCore_0 中,默认应该是有 STM 的核的分配的。
3.4 STM模块配置
STM 模块内部其实没有什么可配置项,只有一个 Dev,一个 VersionApihe 和一个 ApiMode,Dev 用于开发配置检查,比如前文提到的没分配 ResourceM,初始化会进 Dev;ApiMode 表示对 STM 进行配置时需要处于什么样的用户权限。
4 小结
以上就是关于 Aurix2G TC3XX STM 模块以及 MCAL 相关配置的介绍,总的来说 STM 的特性非常适合作为系统计时器功能,为其他模块提供精准的时间戳;同时也能够为 EcuM、Wdg 等模块或者用户提供定时器功能;但因其定时特性,连续触发存在累积误差,因此不适合作为 Os Counter 使用。
参考资料
Infineon-AURIX_TC3xx_Part1-UserManual-v02_00-EN.pdf