GTM系统架构:时钟管理单元(CMU)、中断路由单元(IRQ)、DMA接口、多通道序列器(MCS)简介

好,咱们接着往下聊。上一章我把GTM的整体框架给你捋了一遍,这一章咱们深入进去,看看几个关键模块到底是怎么工作的。时钟管理单元、中断路由、DMA接口,还有那个听起来很唬人的多通道序列器。嗯,这几个东西,说白了就是GTM的“心脏”、“神经”和“大脑”。

时钟管理单元(CMU)——GTM的心跳

时钟管理单元,英文叫Clock Management Unit,简称CMU。我习惯叫它“时钟管家”。它的任务很简单:给GTM里所有子模块提供时钟。但简单归简单,坑可不少。

CMU内部有好几个时钟源。主时钟来自系统时钟,但CMU可以把它分频,生成好几路不同的时钟。为什么要分频?你想想看,有些定时器通道需要跑得飞快,比如PWM输出,频率可能要到MHz级别。但有些模块,比如MCS,可能跑慢一点就够用了。如果所有模块都用同一个高频时钟,功耗就上去了。所以,CMU的存在就是为了“按需分配”。

核心要点:CMU输出的时钟分为三类:

  • CFGU_CLK(配置时钟)——用于寄存器配置,一般和系统总线时钟同步。我建议你把这个时钟设得稳一点,别乱动。
  • FXU_CLK(固定时钟)——用于TBU(时间基准单元),这个时钟要求非常精确。我在一个项目中遇到过,因为FXU_CLK抖动太大,导致几个ECU之间的时间同步出了问题,排查了两天才找到原因。
  • CMU_CLK(模块时钟)——分给各个定时器通道和MCS用的,可以灵活配置。

这里有个小技巧。CMU里有个叫CLS(Clock Source Select)的寄存器,可以让你选择每个子模块用哪一路时钟。我个人习惯是:把高频外设(比如PWM)挂在独立的、不分频的时钟线上,把低频任务(比如周期中断)挂在分频后的时钟线上。这样既保证了性能,又省了功耗。

注意:千万不要在运行时随意切换CMU的时钟源。我曾经见过一个同事,在PWM正在输出的时候改了时钟分频系数,结果波形直接乱掉了。要改时钟,先停掉对应的模块,改完再重新使能。

中断路由单元(IRQ)——GTM的神经中枢

中断路由单元,IRQ。这玩意儿说白了就是个“信号分配器”。GTM内部有几十个中断源,比如定时器溢出、比较匹配、MCS事件等等。IRQ负责把这些中断信号,路由到CPU的某个中断线上去。

为什么需要路由?因为CPU的中断线是有限的。你不能让每个GTM事件都直接连到CPU,那样CPU会被中断淹死。IRQ的作用就是让你“按需连接”。

IRQ的结构其实不复杂。每个中断源都有一个对应的中断标志位,还有一个使能位。当事件发生时,标志位置1。如果使能位也置1,中断信号就会送到IRQ的仲裁器。仲裁器根据优先级,决定哪个中断先被送到CPU。

我的经验:IRQ的优先级设置一定要谨慎。我在一个项目中,把PWM周期中断设成了最高优先级,结果导致CAN通信中断一直被抢占,报文发不出去。后来我把CAN中断优先级调高,PWM中断调低,问题就解决了。记住:实时性要求高的中断(比如通信、故障处理)优先级要高,周期性任务(比如PWM更新)优先级可以低一些。

IRQ还有一个很实用的功能:中断分组。你可以把多个中断源合并成一个中断信号,送到CPU。比如,你可以把8个定时器通道的溢出中断,合并成一个中断。CPU收到中断后,再通过读取IRQ的状态寄存器,判断具体是哪个通道触发的。这样能减少CPU的中断响应次数,提高效率。

DMA接口——让数据自己跑起来

DMA接口,全称Direct Memory Access。它的作用就是“数据搬运工”。GTM的很多模块,比如定时器通道、MCS,都可以通过DMA接口,直接把数据搬到内存里,或者从内存里搬数据出来。整个过程不需要CPU干预。

为什么要用DMA?举个例子。你有一个定时器通道,每隔10微秒产生一个ADC采样触发信号。ADC采样完成后,数据需要存到内存里。如果每次都用CPU去读ADC结果寄存器,再写到内存,CPU就被占死了。用DMA的话,ADC结果寄存器直接映射到DMA的源地址,内存地址是目标地址,DMA自动完成搬运。CPU可以腾出手来做更重要的计算。

GTM的DMA接口支持多种触发方式:

  • 事件触发——比如定时器比较匹配、溢出事件
  • 软件触发——你手动写一个寄存器,启动DMA传输
  • 外部触发——通过GTM的输入引脚触发

我个人比较喜欢用事件触发。因为这样最自然,事件发生了,数据就自动搬走了。但要注意一点:DMA传输的优先级。如果多个DMA请求同时发生,优先级高的先执行。我曾经在一个项目中,把ADC的DMA优先级设得太低,结果被其他DMA请求一直抢占,导致ADC数据丢失。后来我把ADC的DMA优先级提到最高,问题就解决了。

避坑指南:DMA传输的数据宽度一定要和源/目标寄存器匹配。比如,GTM的定时器计数器是16位的,你DMA配置成32位传输,就会多读两个字节,数据就乱了。我曾经因为这个bug,查了整整一个下午。

多通道序列器(MCS)——GTM的大脑

多通道序列器,MCS。这玩意儿是GTM里最复杂、也最强大的模块。它本质上是一个可编程的微控制器,专门用来处理定时器事件。你可以把它理解成一个“小CPU”,但它比CPU更专一、更高效。

MCS有自己的一套指令集,支持算术运算、逻辑运算、跳转、循环等等。你可以用MCS编写程序,实现复杂的定时器控制逻辑。比如,你可以用MCS实现一个状态机,根据不同的输入信号,切换PWM的输出模式。或者,你可以用MCS实现一个数字滤波器,对输入信号进行去抖处理。

MCS的架构是这样的:

  • 程序存储器——存放你的MCS程序。一般用RAM或者ROM实现。
  • 数据存储器——存放中间变量和结果。
  • 算术逻辑单元(ALU)——执行加减乘除、与或非等操作。
  • 通道接口——MCS可以读写GTM的定时器通道寄存器,实现与定时器的交互。

MCS最牛的地方在于,它可以同时处理多个通道的事件。比如,你可以让一个MCS实例同时管理8个PWM通道。每个通道的事件来了,MCS都能在几个时钟周期内做出响应。这比用CPU中断处理快多了。

我的建议:MCS的程序一定要写得简洁高效。因为MCS的时钟频率一般不高(几十MHz),而且程序存储器有限。我见过有人把MCS程序写得跟PC程序一样复杂,结果程序存储器爆了,跑都跑不起来。记住:MCS是用来做“快而简单”的事情的,复杂逻辑还是交给CPU吧。

MCS还有一个很实用的功能:事件链接。你可以把MCS的输出事件,直接连接到其他GTM模块的输入。比如,MCS可以产生一个事件,触发DMA传输,或者触发另一个定时器通道的启动。这样就能实现“事件链”,一个事件引发一连串动作,完全不需要CPU参与。

注意:MCS的调试比较麻烦。因为它没有标准的调试接口(比如JTAG),你只能通过读写寄存器来观察它的状态。我建议你在写MCS程序时,多留一些状态变量,方便调试时查看。另外,MCS程序一旦跑飞,只能通过复位GTM来恢复。所以,写MCS程序时一定要小心,别写死循环。

好了,这一章的内容就到这里。CMU、IRQ、DMA、MCS,这四个模块是GTM的核心。理解了它们,你就掌握了GTM的“骨架”。下一章,咱们开始讲定时器通道的具体配置,那才是真正干活的地方。