恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
AURIX TC3xx GTM实战:从零配置TOM输出PWM
首页
资讯中心
/
AURIX TC3xx GTM实战:从零配置TOM输出PWM
AURIX TC3xx GTM实战:从零配置TOM输出PWM
发布时间:2026/9/28 8:56:05
1. 从零上手AURIX TC3xx的GTM为什么PWM输出值得单独拎出来讲搞嵌入式这行的朋友对PWM肯定不陌生STM32上用CubeMX点几下就能出波形Arduino一行analogWrite就完事。但换到英飞凌AURIX TC3xx平台很多人第一次打开iLLD文档就懵了——GTM、TOM、ATOM、CMU、TBU、TIM、SPE、PWM模块一大堆缩写扑面而来光是搞清楚信号从哪个引脚出来、经过哪些子模块就够喝一壶的。我自己从STM32转到AURIX做汽车电子项目的时候第一个任务就是用电机的PWM调速信号驱动一个H桥。当时觉得这有什么难的结果在TC377的板子上折腾了整整两天才让示波器上出现第一道方波。踩过的坑包括GTM全局时钟没使能、TOM通道的CMU时钟源选错、输出引脚被Port模块的Alt功能锁死、死区时间配置反了导致上下桥臂直通。这些问题在STM32上几乎不会遇到因为HAL库帮你把底层全封好了但在AURIX上iLLD虽然提供了封装你仍然需要理解GTM内部的时钟树和信号路由否则出了问题根本无从排查。这篇内容就是把我这几年的实操经验整理出来从GTM的架构讲起一步步走到TOM模块输出PWM的完整代码实现。不管你是刚接触AURIX的新手还是从其他MCU平台转过来的老鸟只要跟着走一遍应该能在半天内让TC3xx的板子输出稳定的PWM波形。我会把每个配置参数为什么这么选、时钟怎么算、引脚怎么映射都讲清楚代码基于iLLD库可以直接拿去改改就用。2. GTM模块架构拆解PWM信号到底是怎么从内部走到引脚上的2.1 GTM全局结构一览不只是个定时器GTM全称Generic Timer Module直译过来叫通用定时器模块但你要是把它当成STM32的TIM来理解那就大错特错了。GTM更像是一个可编程的定时器协处理器集群内部包含多个子模块各司其职又互相协作。在TC3xx系列里GTM是整个芯片最复杂的片上外设之一时钟频率可以跑到100MHz甚至更高取决于具体型号和配置。从顶层看GTM内部主要包含这几大块CMUClock Management Unit时钟管理单元负责给GTM内部各个子模块分配时钟。它可以从多个时钟源选择输入经过分频后产生不同频率的时钟给不同子模块用。CMU配置错了后面全白搭。TBUTime Base Unit时基单元提供一个全局的时间基准通常是一个24位的自由运行计数器。有些应用用它做全局时间戳。TIMTimer Input Module输入捕获模块用来测量外部信号的频率、占空比、周期等。做PWM输入捕获或者轮速信号采集就靠它。TOMTimer Output Module输出比较模块这是我们今天的主角PWM输出主要靠它。TOM有多个通道组每组有8个通道每个通道可以独立配置输出比较行为。ATOMARU-connected Timer Output Module和TOM类似也是输出模块但它连接了ARUAdvanced Routing Unit可以和其他子模块做数据交互适合做复杂的电机控制如FOC。SPESensor Pattern Evaluation传感器模式评估模块用于处理一些特定传感器信号。MCSMulti Channel Sequencer多通道序列器可以编程执行一系列操作适合做复杂的定时任务。对于PWM输出这个需求我们主要跟TOM打交道。但别急着跳过CMU因为TOM的时钟来源就是CMU分配的CMU没配好TOM就是个死物。2.2 TOM模块内部一个通道组是怎么工作的TOM在TC3xx里通常有多个实例比如TOM0、TOM1、TOM2等具体数量看型号。每个TOM实例包含若干个通道组每个通道组有8个通道Channel 0~7。每个通道内部有一个比较寄存器CM0和CM1配合一个计数器CN0工作。TOM通道输出PWM的基本原理是这样的CN0从0开始向上计数同时和CM0、CM1两个比较值做比较。当CN0等于CM0时输出信号翻转一次当CN0等于CM1时再翻转一次。通过调整CM0和CM1的值就能控制PWM的周期和占空比。这种双比较值的结构比STM32的单比较值灵活得多可以轻松实现相位偏移、中心对齐等高级功能。每个TOM通道组还有一个SOURShadow Output Register和一个OUTOutput Register用于控制输出信号的最终状态。信号从TOM通道出来之后还要经过Port模块的引脚映射才能到达物理引脚。这中间的路由关系是TOM通道输出 - TOM通道组的输出选择 - Port模块的Alt功能选择 - 物理引脚。2.3 时钟树PWM频率的根基很多人配置PWM时最头疼的就是算频率。在STM32上你只需要知道APB总线频率和预分频系数就行。但在AURIX上GTM的时钟树要复杂一些。GTM的时钟来源通常是系统PLL产生的某个时钟经过CMU的分频后分配给各个子模块。CMU内部有多个分频器可以给不同的子模块配置不同的时钟频率。对于TOM模块它使用的是CMU配置的某个时钟分频输出。具体来说CMU有一个叫做GTM_CMU_CLK_0到GTM_CMU_CLK_7的多个时钟输出每个都可以独立配置分频系数。TOM通道组可以选择其中一个作为自己的时钟源。此外TOM通道内部还有一个8位的预分频器叫做TOM_CH_CLK_DIV可以进一步分频。所以最终的PWM频率计算公式是PWM频率 GTM模块时钟 / CMU分频系数 / TOM通道预分频系数 / PWM周期计数值其中PWM周期计数值就是CM1的值假设从0计数到CM1。举个例子如果GTM模块时钟是100MHzCMU分频系数设为1TOM通道预分频设为1CM1设为9999那么PWM频率就是100MHz / 1 / 1 / 10000 10kHz。这个计算过程看起来简单但实际配置时容易搞混的是CMU的分频系数是写寄存器的值加1TOM通道预分频也是类似。iLLD库对这些做了封装但如果你直接看寄存器手册一定要注意这些细节。2.4 为什么选TOM而不是ATOM或CCU6有朋友可能会问AURIX里还有CCU6模块那个不是专门做PWM的吗确实CCU6在电机控制里用得很多特别是做BLDC的六步换相。但CCU6的PWM输出通道数量有限而且它的设计更偏向于三相电机控制对于需要多路独立PWM的应用比如同时控制多个舵机或者多路LED调光TOM更合适。ATOM虽然功能更强但配置也更复杂而且它主要面向需要ARU数据交互的场景。如果你只是输出简单的PWM波形用ATOM属于杀鸡用牛刀。TOM的配置相对直接通道数量多每个通道独立性强是做通用PWM输出的首选。3. 动手前的准备工作环境、工具和硬件确认3.1 硬件平台确认在开始写代码之前先确认你手头的硬件。TC3xx系列有很多型号比如TC377、TC387、TC397等不同型号的GTM实例数量和引脚分配可能不同。我手头用的是TC377的评估板TOM0和TOM1都可用引脚方面P02.0到P02.7映射到了TOM0的通道0到7。你需要做的是确认你的芯片型号和封装找到数据手册里的Pinout章节确定你想用的引脚对应哪个TOM通道确认该引脚没有被其他功能占用比如默认的JTAG引脚或者模拟输入引脚注意TC3xx的很多引脚在上电后有默认功能如果默认功能不是GPIO或者你想要的Alt功能需要先通过Port模块的配置寄存器把引脚切换到正确的模式。这一步漏了后面代码写得再对也没波形。3.2 开发环境搭建我用的开发环境是AURIX Development Studio免费配合iLLD库。如果你用的是Tasking或者HighTec编译器代码基本兼容但工程配置需要自己调整。iLLD库的版本建议用1.0.1.11.0或更新版本老版本里有些TOM的API可能不完整。工程创建步骤大致如下在AURIX Development Studio里新建一个TC3xx的工程选择对应的芯片型号把iLLD库添加到工程路径中确认链接脚本里的内存分配够用GTM的配置代码不大一般不会超3.3 必备调试工具示波器这是必须的没有示波器你根本不知道波形出没出来、频率对不对。我用的是普通的100MHz带宽数字示波器测PWM足够了。逻辑分析仪如果要同时看多路PWM的相位关系逻辑分析仪更方便。万用表测引脚电压确认引脚有没有被正确驱动。实操心得第一次调试时建议先把PWM频率设低一点比如1kHz这样即使示波器带宽不够也能看到清晰的波形。等确认波形出来了再调到目标频率。4. 核心代码实现一步步配置TOM输出PWM4.1 整体配置流程配置TOM输出PWM的流程可以概括为以下几步使能GTM模块时钟配置CMU给TOM分配合适的时钟配置TOM通道组的时钟源和预分频配置TOM通道的比较值和输出行为配置Port引脚为TOM输出功能启动TOM通道下面我以TOM0的通道0为例输出一个10kHz、占空比50%的PWM。假设GTM模块时钟为100MHz。4.2 时钟参数计算先算参数。目标PWM频率10kHzGTM时钟100MHz。如果CMU分频设为1TOM通道预分频设为1那么PWM周期计数值 100MHz / 10kHz 10000。也就是说CN0从0计数到9999总共10000个时钟周期。占空比50%意味着高电平时间和低电平时间相等。在TOM的双比较值模式下我们可以让CM0 5000CM1 9999。这样CN0从0到4999时输出一种状态从5000到9999时输出另一种状态。但具体哪个比较值对应高电平取决于输出配置。TOM通道有一个OUT寄存器的SL位Signal Level可以控制输出的极性。我一般习惯让CM0对应上升沿CM1对应下降沿这样占空比 CM0 / (CM11)。4.3 代码实现下面是基于iLLD库的完整代码示例。我尽量把注释写详细方便你理解每个参数的含义。#include Ifx_Types.h #include IfxCpu.h #include IfxScuWdt.h #include IfxGtm_Tom_Pwm.h #include IfxPort.h // 定义使用的TOM和通道 #define TOM_MODULE MODULE_GTM.TOM0 #define TOM_CHANNEL IfxGtm_Tom_Ch_0 #define TOM_CHANNEL_OUTPUT IfxGtm_Tom_Ch_0 // 定义输出引脚 #define PWM_PIN IfxPort_P02_0 #define PWM_PIN_MODE IfxPort_Mode_outputPushPullAlt1 #define PWM_PIN_PAD_DRIVER IfxPort_PadDriver_cmosAutomotiveSpeed1 // PWM参数 #define PWM_FREQ_HZ 10000 // 目标频率10kHz #define PWM_DUTY_PERCENT 50 // 占空比50% // GTM模块时钟频率根据实际配置调整 #define GTM_MODULE_CLK_HZ 100000000 // 100MHz // TOM通道配置结构体 IfxGtm_Tom_Pwm_Config g_tomConfig; IfxGtm_Tom_Pwm_Driver g_tomDriver; void initPwm(void) { // 第一步使能GTM模块时钟 // 注意这一步在iLLD里通常由IfxGtm_enable()完成 IfxGtm_enable(MODULE_GTM); // 第二步配置CMU时钟 // 这里我们配置CMU_CLK_0分频系数为1 // 具体使用哪个CMU时钟输出需要和后面的TOM配置对应 IfxGtm_Cmu_setClkFrequency(MODULE_GTM, IfxGtm_Cmu_Clk_0, GTM_MODULE_CLK_HZ); IfxGtm_Cmu_enableClk(MODULE_GTM, IfxGtm_Cmu_Clk_0); // 第三步初始化TOM PWM配置结构体为默认值 IfxGtm_Tom_Pwm_initConfig(g_tomConfig, MODULE_GTM); // 第四步填充配置参数 g_tomConfig.tom TOM_MODULE; // 选择TOM0 g_tomConfig.tomChannel TOM_CHANNEL; // 选择通道0 g_tomConfig.period GTM_MODULE_CLK_HZ / PWM_FREQ_HZ; // 周期计数值 10000 g_tomConfig.dutyCycle (g_tomConfig.period * PWM_DUTY_PERCENT) / 100; // 占空比计数值 5000 g_tomConfig.clock IfxGtm_Tom_Ch_ClkSrc_cmuClock0; // 时钟源选择CMU_CLK_0 g_tomConfig.pin.outputPin PWM_PIN; // 输出引脚 g_tomConfig.pin.outputPinMode PWM_PIN_MODE; // 引脚模式 g_tomConfig.pin.padDriver PWM_PIN_PAD_DRIVER; // 引脚驱动能力 g_tomConfig.synchronousUpdateEnabled TRUE; // 使能同步更新 g_tomConfig.isPinDriverEnabled TRUE; // 使能引脚驱动 // 第五步初始化TOM PWM驱动 IfxGtm_Tom_Pwm_init(g_tomDriver, g_tomConfig); // 第六步启动PWM输出 IfxGtm_Tom_Pwm_start(g_tomDriver, TRUE); } int main(void) { // 关闭看门狗 IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword()); IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword()); // 初始化PWM initPwm(); // 主循环 while(1) { // 这里可以添加其他任务 // PWM会持续输出不需要CPU干预 } return 0; }4.4 代码关键点解析上面这段代码看起来不长但每一行都有讲究。我挑几个容易出问题的地方展开说。CMU时钟配置IfxGtm_Cmu_setClkFrequency这个函数的第二个参数是CMU时钟输出的编号第三个参数是频率。iLLD会根据你给的频率自动计算分频系数。但要注意这个函数设置的频率不能超过GTM模块的输入时钟频率否则会配置失败。如果你不确定GTM模块的输入时钟是多少可以先查芯片手册的时钟章节或者用IfxGtm_Cmu_getClkFrequency读一下当前值。周期和占空比的计算g_tomConfig.period设置的是PWM的周期计数值也就是CN0从0计数到多少。g_tomConfig.dutyCycle设置的是占空比计数值。iLLD内部会根据这两个值计算CM0和CM1。但要注意dutyCycle的值不能大于period否则输出会异常。时钟源选择g_tomConfig.clock这个参数指定TOM通道使用哪个CMU时钟。这里我们选了IfxGtm_Tom_Ch_ClkSrc_cmuClock0对应前面配置的CMU_CLK_0。如果你前面配置的是CMU_CLK_1这里就要改成IfxGtm_Tom_Ch_ClkSrc_cmuClock1。两者必须对应否则时钟频率不对PWM频率也就错了。引脚配置g_tomConfig.pin.outputPin指向你要用的引脚。outputPinMode指定引脚的Alt功能编号。TC3xx的每个引脚可以复用好几种功能Alt1到Alt7不等。具体你的引脚对应哪个Alt功能要查数据手册的Pinout表。我用的P02.0对应Alt1就是TOM0_0的输出。注意IfxGtm_Tom_Pwm_init函数内部会自动配置Port引脚但前提是你给的outputPinMode是正确的。如果引脚没配好示波器上就是一条直线。4.5 验证波形代码烧进去之后把示波器探头接到P02.0引脚上。如果一切正常你应该能看到一个10kHz、占空比50%的方波。如果没波形先别急着改代码按下面的顺序排查用万用表测引脚电压如果是0V或者3.3V固定不变说明引脚没被TOM驱动检查Port引脚配置是否正确可以用调试器读Port寄存器的值检查GTM模块时钟是否使能读GTM_CLS_CLK_CFG寄存器检查CMU时钟是否使能读GTM_CMU_CLK_EN寄存器检查TOM通道是否启动读TOM0_TGC0_GLB_CTRL寄存器5. 进阶玩法让PWM更灵活、更可靠5.1 动态调整占空比实际项目里PWM的占空比往往需要动态调整比如电机调速、LED调光。在TOM里你可以直接写CM0寄存器来改变占空比不需要停止PWM。// 动态修改占空比 void setPwmDutyCycle(uint32 dutyPercent) { uint32 period g_tomConfig.period; uint32 duty (period * dutyPercent) / 100; // 直接写CM0寄存器 IfxGtm_Tom_Ch_setCompareZero(TOM_MODULE, TOM_CHANNEL, duty); }但要注意直接写CM0可能会导致当前周期出现一个不完整的脉冲。如果对波形连续性有要求应该使用同步更新机制让新值在下一个周期开始时生效。iLLD提供了IfxGtm_Tom_Ch_setCompareZeroShadow函数写入影子寄存器在周期结束时自动更新。5.2 多通道同步输出有些应用需要多路PWM同步输出比如三相电机控制。TOM的同一个通道组内的8个通道可以共享同一个计数器CN0这样它们天然就是同步的。你只需要配置每个通道的CM0和CM1就能得到多路同步PWM。如果需要不同通道组之间同步可以通过GTM的TBU或者ARU来实现。不过对于大多数应用同一个通道组内的同步已经够用了。5.3 死区时间配置做H桥或者半桥驱动时上下桥臂的PWM之间需要插入死区时间防止直通短路。TOM模块本身不直接生成死区但可以通过配置两个通道的相位差来实现。具体做法是通道0输出上桥臂PWM通道1输出下桥臂PWM。通道1的CM0和CM1相对于通道0偏移一个死区时间值。这样两个通道的输出就不会同时为高电平。实操心得死区时间的大小取决于你的MOS管或IGBT的开关速度。一般IGBT的死区时间在1~3微秒MOS管可以短一些几百纳秒。死区时间设太小起不到保护作用设太大又会影响输出效率。我一般先用示波器看上下桥臂的波形确认没有重叠后再微调。5.4 PWM故障保护在电机控制里PWM故障保护是个硬需求。比如过流时硬件应该立即封锁PWM输出而不是等软件响应。TC3xx的GTM支持通过外部触发信号来紧急停止PWM输出这个功能叫做Emergency Stop。配置方法是把某个输入引脚配置为GTM的紧急停止触发源然后在TOM通道配置里使能紧急停止功能。一旦触发信号有效TOM通道会立即把输出拉到安全电平高阻或者低电平可配置。这个功能在调试时可能造成困惑——如果你发现PWM突然没了先检查紧急停止引脚是不是被触发了。6. 常见问题与排查技巧实录6.1 波形出不来按这个顺序查排查步骤检查内容常见问题1引脚是否有输出引脚被其他功能占用或Port配置错误2GTM模块时钟是否使能IfxGtm_enable没调用3CMU时钟是否使能CMU_CLK_0没使能或频率设置错误4TOM通道是否启动IfxGtm_Tom_Pwm_start没调用或参数为FALSE5周期和占空比是否合理period为0或dutyCycle大于period6时钟源是否匹配TOM通道选的CMU时钟和实际配置的不一致6.2 频率不对算一下这几个值如果波形出来了但频率不对大概率是时钟计算有问题。按下面的公式重新算一遍实际PWM频率 CMU时钟频率 / TOM通道预分频 / (CM1 1)其中CMU时钟频率是你通过IfxGtm_Cmu_setClkFrequency设置的频率TOM通道预分频在iLLD里默认是1。如果你改了预分频记得把它算进去。还有一种可能是GTM模块的输入时钟和你以为的不一样。比如你以为是100MHz实际是80MHz。这时候可以用调试器读GTM_CMU_CLK_0寄存器的值反推实际频率。6.3 占空比不准注意这几个细节占空比不准通常有这几个原因CM0和CM1的配置反了有些配置下CM0对应下降沿CM1对应上升沿占空比计算方式就反了输出极性配置错误TOM通道的SL位控制输出极性配反了占空比就是反的同步更新未使能动态改占空比时如果没使能同步更新新值可能在一个周期中间生效导致那个周期占空比异常6.4 多路PWM互相干扰如果你发现配置了多路PWM后某一路的波形影响了另一路检查一下是不是用了同一个TOM通道组的不同通道。同一个通道组内的通道共享CN0计数器如果两个通道的CM1值不同它们会互相影响。解决办法是让同一个通道组内的所有通道使用相同的CM1值即相同的PWM周期只改变CM0来调整占空比。6.5 引脚驱动能力不够TC3xx的引脚驱动能力可以配置从最弱到最强有好几档。如果你驱动的负载比较重比如直接驱动LED或者光耦可能需要把驱动能力调强。在iLLD里通过padDriver参数配置我一般用IfxPort_PadDriver_cmosAutomotiveSpeed1速度等级1驱动能力中等。如果波形上升沿太慢可以试试Speed2或Speed3。注意驱动能力越强EMI辐射也越大。在汽车电子项目里一般会在满足信号完整性要求的前提下尽量用低的驱动等级。7. 从PWM输出延伸出去GTM还能做什么TOM输出PWM只是GTM功能的冰山一角。把GTM用熟了之后你会发现它在汽车电子和工业控制里几乎无处不在。比如TIM模块可以做PWM输入捕获用来测量轮速传感器的信号频率。我做过一个项目用TIM同时捕获四路轮速信号计算每个轮子的转速再通过CAN发给整车控制器。TIM的输入捕获精度很高配合GTM的100MHz时钟测出来的频率误差在0.1%以内。ATOM模块配合ARU可以做更复杂的电机控制。比如FOC算法里需要根据转子位置实时计算三相PWM的占空比ATOM可以在不占用CPU的情况下自动更新PWM值CPU只需要在电流环中断里算一次就行。MCS模块可以编程执行一系列定时操作比如生成特定时序的脉冲序列用于驱动某些特殊传感器或者执行器。这些高级功能我后续会单独写文章展开今天先把PWM输出这个基础打牢。毕竟不管多复杂的应用PWM输出都是最常用的功能之一把这部分吃透了后面的学习曲线会平缓很多。最后分享一个我调试GTM时的小习惯每次配置一个新的GTM功能我都会先用调试器把相关的寄存器读出来和手册里的复位值对比确认每个寄存器的值都符合预期。这个习惯帮我省了很多瞎猜的时间因为GTM的寄存器太多了光靠看代码很难发现哪里配漏了。