概述
GPT(General Purpose Timer)驱动程序负责为 AUTOSAR规范中定义的标准计时器功能提供对应的API。相应的底层定时器引擎是可以是包含在AURIX2G系列处理器中的GTM定时器通道(TOM/ATOM slice)或者GPT12定时器。用户可以基于驱动程序配置实现多个通道,在每个通道上上层程序的可以执行以下操作:
下图是英飞凌针对Autosar MCAL的架构实现,GPT位置如下。

- 启动/停止定时器
- 启用/禁用唤醒功能
- 启用/禁用回调通知
- 单次或连续操作模式
- 使用TOM切片实现的GPT Predef Timer功能。
下图为GPT驱动模块的软硬件调用接口图

GTM(Generic Timer Module)
GPT驱动利用 GTM IP核提供的通道来实现连续定时模式、单次定时模式和预定义定时器。
GPT驱动程序所使用的GTM-TOM/ATOM IP核心硬件功能特性包括:
- 连续递增计数模式
- 单次递增计数模式
- ATOM脉宽调制信号输出模式(SOMP)
GPT驱动程序利用GTM IP模块实现连续定时器模式、单次定时器模式及预定义定时器功能。连续模式与单次模式的逻辑通道仅需占用TOM/ATOM切片中的单个定时器通道。
预定义定时器仅使用GTM IP的TOM切片,原因是TOM作为16位定时器,相较于24位的ATOM更易于派生出16位、24位及32位定时器。若fGTM(GTM模块时钟频率)配置可直接生成目标频率(1MHz对应1微秒预定义定时器,10kHz对应100微秒预定义定时器),则:
- 16位预定义定时器仅需1个TOM通道(x)
- 24位或32位预定义定时器分别需要2个TOM通道(x与x+1)
对于24/32位定时器,通过硬件TRIGOUT特性实现:前一个TOM通道在比较匹配事件发生时触发下一个TOM通道。若fGTM配置无法直接生成目标频率,则需额外增加一个通道(x-1)作为预分频器来产生预定义定时器所需的节拍频率。此时同样利用硬件TRIGOUT特性来实现1微秒/100微秒的节拍频率。
从上面可以得到结论,如果fGTM配置不能直接推导出定时器所需频率,且要实现一个24位/32位的定时器,那么我们需要3个通道,三个通道号需要按顺序依次递增。
我们此次使用了 TOM0_CH0 ,TOM0_CH8 配置成两路的GPT 功能
GTM内部由多个簇(Cluster)组成,有些模块如ATOM、TOM、SPE在多个簇里面存在,每个簇中功能相同,具体的数量取决于芯片型号;而有些模块如CMU、TBU只在主簇(Cluster0)中存在。每个簇有一个独立的输入时钟源,多个输入信号到TIM模块,多个输出经过TOM/ATOM然后从DTM输出;输入/输出信号一般是通过Port与外部进行信号交互,也可与其他模块如Adc、Iom等模块进行交互。
每个簇及其中的模块都有相应的配置寄存器,可直接通过Aurix2G的外设总线进行设置。

时钟方面,fGTM 可在MCU模块中的McuPllDistributionSettingConfig进行直接配置(200Mhz),因为CMU(Clock Management Unit)属于Cluster0,所以可以在GtmClusterConf_0里对其进行分频(2分频)得到fCLS0
CMU(Clock Management Unit)
功能介绍
时钟管理单元(Clock Management Unit, CMU)负责生成计数器和GTM的时钟。CMU由三个子单元组成,包括CFGU 、FXU、EGU,为整个GTM模块生成不同的时钟源。CMU的主时钟源是簇0时钟信号cls0_clk,该信号由寄存器GTM_CLS_CLK_CFG中的位字段CLS0_CLK_DIV的值定义(默认为2)。CMU模块框图如图示。

CFGU(Configurable Clock Generation Unit,可配置时钟生成模块)
可根据用户需求进行较大范围的时钟配置(分频参数为24位宽),是CMU主要的时钟控制单元。其输入源为Cluster0的输入时钟CLS0_CLK,可输出8路不同频率的时钟,供TIM, ATOM, TBU等模块使用,且连接丰富,例如同一ATOM模块内部多个通道可使用不同的CMU_CLK。
每路CMU_CLK与GTM总时钟源之间有3层分频,
第一层经Cluster0分频得到CLS0_CLK,
第二层经过Global Clock Divider得到CMU_GCLK_EN,
然后经过Clock SourceX Divider分频得到CMU_CLKx。
计算公式如下:
- fCMUCLKx:CMU通道x可配置时钟输出,x取0~8
- fGTM:GTM模块主时钟
- CLS0CLKDIV:簇0分频系数,寄存器CLS0_CLK_DIV,只可选1或者2,默认为2,即半分频
- GLOBALDIV:全局分频,为GCLK_NUM/GCLK_DEN的值
- CLKCNTx:CMU时钟通道x分频系数,对应寄存器CLK_CNT
FXU(Fixed Clock Generation Unit)为固定分频时钟,所有通道共用一个时钟源,
时钟源可选CFGU输出的通道时钟或者CMU_GCLK_EN时钟,如图所示其每路分频参数不可配置。
FXU主要供TOM模块使用。当选择CMU_GCLK_EN为时钟源时,计算公式如下:
与可配置CMU时钟的计算公式仅有FXCLKDIV不同。
EGU(External Generation Unit)可供外部外设使用,也可作为第二时钟域输出到其他GTM模块使用。GtmExtClockSetting 配置。
SCU(System Control Unit)
GPT驱动程序的时钟取决于SCU这个IP核。通用定时器需要fGTM和fSPB(System Peripheral Bus)时钟信号。
SCU为所有外设提供时钟,MCU驱动程序负责配置芯片时钟树。为避免因同时写入而发生冲突,使用MCALLIB提供的API执行对所有ENDINIT保护寄存器的更新。
环境与目标
本文使用的为英飞凌提供的开发板KIT_A2G_TC397XA_TFT,芯片为TC397,外部的时钟为20Mhz。

配置目标如下:
- 使用GPT实现1ms的定时器中断,在中断处理函数中累加值,用作系统时标。
- 双通道TOM定时器的软件控制
- CH1 分配TOM0_CH0
- CH2 分配TOM0_CH8
EB-tresos配置 :
一、MCU配置
-
TC3XX支持16-40MHZ的外部晶振或陶瓷振荡器,作为MCU的时钟来源

配置GTM外设为200Mhz频率。(最大值200MHz)

1.1 GtmGlobalConfiguration
访问路径:MCU->GtmGlobalConfiguration

GtmCmuGlobalClockNumerator:配置可配置时钟和固定时钟的全局分子值
GtmCmuGlobalClockDenominator:配置可配置时钟和固定时钟的全局分母值
fGCLK = (GtmCmuGlobalClockNumerator / GtmCmuGlobalClockDenominator+1)*fCLS0
CLS0时钟来自GTM模块系统时钟,GTM的sys_clk来自时钟source0,source0时钟来自PLL0或者backup时钟(可选),默认来自PLL0,PLL0时钟源默认来自外部晶振

这里有两个参数,就是上文中决定全局分频GLOBALDIV的GCLK_NUM和GCLK_DEN,这里一般都配置成1,也就是全局1比1分频。
1.2 GtmClusterConf_0
访问路径:MCU->GtmGlobalConfiguration->GtmGlobalConfiguration0->GTMClusterConf
| GTM Clusters | 12 (CCM0-11) |
| (CCM0-11) | CCM0-4: 200 MHz max CCM5-11: 100 MHz max |

配置fCLS0为fGTM的二分频,即为100Mhz。

1.3 CFGU的分频
一共有8路,和对应的时钟开关。
这里注意CLKCNTx等于配置参数加1,也就是说0代表1比1分频,3表示四分之一分频。
1.4 FixedClock配置
前面提到因为FXU是不可配置分频的,但是可以配置时钟源和开关,就是下面这两个配置参数。

这里我们完成了CMU的时钟配置,
假设我们配置的GTM总时钟为100MHz,结合上面的配置,
Cluster0经过2倍分频得到CLS0_CLK=50MHz,
全局分频配置为1则CMU_GCLK_EN=50MHz。
CMU_CLKx的分频参数全部为1,也就是CMU_CLKx(x=0~7)=50MHz。
FXU时钟源选择CMU_GCLK_EN=50MHz,
则各路CUM_FXCLK根据固定分频比计算得出。
1.6 McuGtmAllocationConf
用来做GPT的定时功能。
McuGtmTomChannelAllocationConf
TOM(Timer Output Module),定时器输出单元TOM是GTM的主要输出模块之一,负责输出Pwm波形,一般每个GTM簇内有一个TOM模块,一个TOM模块内最多16个通道,每个通道可以独立输出,也可以进行关联做Pwm波的相位对齐,TOM[i]_CH[x]_OUT 表示TOMi的通道x输出。TOM模块的模块框图如图所示:

| TOM 6x16 ch. (TOM0-5) | |
| McuGtmTomAllocationConf_[0,1,2,3,4,5] 6个通道 | |
| McuGtmTomChannelAllocationConfto15] 16个通道 |
我们需要 使用 TOM0_0 作为GPT使用 。
| 访问路径: | MCU 模块 |
| 1 | MCU |
| 2 | McuGtmAllocationConf_0 |
| 3 | McuHardwareResourceAllocationConf |
| 4 | McuHardwareResourceAllocationConf_0 |
| 5 | McuGtmAllocationConf_0 |
| 6 | McuGtmTomAllocationConf_0 |
| 7 | McuGtmTomChannelAllocationConf_0 |
这里我们选用Tom0_CH0,将硬件资源分配给GPT

如果 这里我们选用TOM0_CH8,将硬件资源分配给GPT
配置如下图:

McuGtmTomChannelAllocationConf 配置如下:

二、 GPT配置
配置GPT模块General部分,需要我们注意的配置项有以下几个。
GptEnableDisableNotificationApi:使能回调函数的API,此处属于下面回调函数配置的开关。
GptTimeElapsedApi:已经运行时间的计数,例如本例子的1ms假设运行了0.3ms,这个API返回值为0.3ms的Ticks。
GptTimeRemainingApi:剩余时间的计数,例如本例子的1ms假设运行了0.3ms,这个APl返回值为剩余0.7ms的Ticks.

2.1 GptClockReferencePoint
2.2 GptChannelConfiguration
将TOM0_CH0 分配在 GptChannel0 将TOM0_CH8 分配在 GptChannel1,

2.2.1 GptChannelConfiguration0:
General 配置如下:
这里需要注意的配置有以下几个。
GptAssignedHwUnit:选择硬件时钟是GTM还是GPT12。
GptChannelMode:运行模式是连续还是单次触发。


GptNotification 配置如下:
中断函数命名为 IoHwAb_GptNotification0

GtmTimerOutputModuleConfiguration
选择GTM使用的Timer为Tom0Channel0。时钟源选择CMU输出的Fixed_Clock_1。
5 dedicated clocks FX_CLK (1:1, 1:16, 1:256..) 可供选择。
2.2.2 GptChannelConfiguration1:
General 配置如下:

GptNotification 配置如下:
GtmTimerOutputModuleConfiguration

三、 IRQ配置
可以看到 TOM0_CH0中断输出使用的是SR0。
TOM0_CH8中断输出使用的是SR4。




中断优先级配置:

绑定CPU核:

四、 ResourceM配置
分配核0使用资源,添加GPT:GptChannelConfiguration_0。


五、GPT驱动使用与调试
#ifndef TRB_LED
//#define TRB_LED DIO_CHANNEL_33_4
#define TRB_LED DIO_CHANNEL_13_0
#endif
#ifndef HUGO_LED
//#define TRB_LED DIO_CHANNEL_33_4
#define HUGO_LED DIO_CHANNEL_13_1
#endif
LOCAL_INLINE void Gpt_lStartDemo(void);
LOCAL_INLINE void Gpt_l3StartDemo(void);
void Gpt_Demo(void)
{
volatile uint8 LoopVar = 0;
char InputString[10];
/* Initialiase interrupt request configurations */
if( Gpt_DemoCalled == 0U )
{
#if (MCU_GTM_USED == STD_ON)
IrqGtm_Init();
SRC_GTMTOM00.B.SRE = 1;
SRC_GTMTOM04.B.SRE = 1;
#endif
IrqGpt_Init();
SRC_GPT120T6.U |= (unsigned_int)(1<<10);
Gpt_DemoCalled = 1U;
}
/* Initialize GPT driver */
Gpt_Init(&Gpt_Config);
while (LoopVar == 0)
{
print_f("\n");
print_f("\n < >: ............ GPT DRIVER DEMO MENU ............");
print_f("\n <1>: Start continuous timer : LED must start blinking");
print_f("\n <2>: Stop timer: LED must stop blinking");
print_f("\n <.>: Go back to previous menu\n");
print_f("\nEnter option Number: ");
getline(InputString, sizeof InputString - 1);
switch (*InputString)
{
case '1':
print_f("Result = Gpt_lStartDemo;");
Gpt_lStartDemo();
StartResult();
print_f("Result = Pass;");
EndResult();
break;
case '2':
/* Stop the timer, LED blinking stops, remains OFF/ON */
Gpt_StopTimer(0);
StartResult();
print_f("Result = Pass;");
EndResult();
break;
case '3':
print_f("Result = Gpt_l3StartDemo;");
Gpt_l3StartDemo();
StartResult();
print_f("Result = Pass;");
EndResult();
break;
case '.':
/* De-initialize GPT driver */
Gpt_DeInit();
LoopVar = 1;
StartResult();
print_f("Result = Pass;");
EndResult();
break;
default:
print_f("\n\n INVALID OPTION");
StartResult();
print_f("Result = Fail;");
EndResult();
break;
}/* End of switch-case */
}/* End of While loop */
}
void IoHwAb_GptNotification0(void)
{
/* start blinking the LED */
if( Gpt_ChannelNotif[0] == 0)
{
Dio_WriteChannel(TRB_LED, STD_LOW);
Gpt_ChannelNotif[0] = 1;
}
else
{
Dio_WriteChannel(TRB_LED, STD_HIGH);
Gpt_ChannelNotif[0] = 0;
}
}
void HUGO_HELLO(void)
{
print_f("Result = hello;");
/* start blinking the LED */
if( Gpt_ChannelNotif[1] == 0)
{
Dio_WriteChannel(HUGO_LED, STD_LOW);
Gpt_ChannelNotif[1] = 1;
}
else
{
Dio_WriteChannel(HUGO_LED, STD_HIGH);
Gpt_ChannelNotif[1] = 0;
}
}
LOCAL_INLINE void Gpt_lStartDemo(void)
{
/* Enable notification for Timer channel 0 */
Gpt_EnableNotification(0);
/* 16 bit max value in GPT12 timer */
Gpt_StartTimer(0,65535U);
}
LOCAL_INLINE void Gpt_l3StartDemo(void)
{
/* Enable notification for Timer channel 0 */
Gpt_EnableNotification(1);
/* 16 bit max value in GPT12 timer */
Gpt_StartTimer(1,65535U);
}




被折叠的 条评论
为什么被折叠?



