AURIX TC397 Timer PWM 之 GPT12 CCU6

GPT12_Timer_Interrupt

GPT12模块的定时器T3产生500ms中断翻转LED:

  • GPT12(The General Purpose Timer Unit)包含两个GPT块(GPT1和GPT2), 每个块都有几个16-bit定时器
  • GPT1块包含核心定时器T3和两个辅助定时器T2,T4
  • GPT1的所有定时器可以四种模式之一运行: 定时器模式, 门控定时器模式, 计数器模式 或者 增量接口模式.
  • 下面的例子中, T3配置为定时器模式, 向下计数, 发生下溢事件时, T2的值会传输到T3, 就不用在中断中手动重装了
  • GPT12模块基本频率 Fgpt = 100MHz
  • Reload_Value = Fgpt / (Gpt1BlockPrescalerTimerInputPrescalerf) = 100MHz / (16642Hz) = 48828
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "Ifx_Types.h"
#include "IfxGpt12.h"
#include "IfxPort.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define ISR_PRIORITY_GPT12_TIMER    6                       /* Define the GPT12 Timer interrupt priority            */
#define ISR_PROVIDER_GPT12_TIMER    IfxSrc_Tos_cpu0         /* Interrupt provider                                   */
#define RELOAD_VALUE                48828u                  /* Reload value to have an interrupt each 500ms         */
#define LED                         &MODULE_P13, 0          /* LED which toggles in the Interrupt Service Routine   */

/* Macro defining the Interrupt Service Routine */
IFX_INTERRUPT(interruptGpt12, 0, ISR_PRIORITY_GPT12_TIMER);

/* Interrupt Service Routine of the GPT12 */
void interruptGpt12(void)
{
    IfxPort_togglePin(LED);                                                         /* Toggle LED state             */
}

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    /* Initialize the LED */
    IfxPort_setPinModeOutput(LED, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);

    //initGpt12Timer
    /* Initialize the GPT12 module */
    IfxGpt12_enableModule(&MODULE_GPT120);                                          /* Enable the GPT12 module      */
    IfxGpt12_setGpt1BlockPrescaler(&MODULE_GPT120, IfxGpt12_Gpt1BlockPrescaler_16); /* Set GPT1 block prescaler     */

    /* Initialize the Timer T3 */
    IfxGpt12_T3_setMode(&MODULE_GPT120, IfxGpt12_Mode_timer);                       /* Set T3 to timer mode         */
    IfxGpt12_T3_setTimerDirection(&MODULE_GPT120, IfxGpt12_TimerDirection_down);    /* Set T3 count direction       */
    IfxGpt12_T3_setTimerPrescaler(&MODULE_GPT120, IfxGpt12_TimerInputPrescaler_64); /* Set T3 input prescaler       */
    IfxGpt12_T3_setTimerValue(&MODULE_GPT120, RELOAD_VALUE);                        /* Set T3 start value           */

    /* Initialize the Timer T2 */
    IfxGpt12_T2_setMode(&MODULE_GPT120, IfxGpt12_Mode_reload);                      /* Set T2 to reload mode        */
    IfxGpt12_T2_setReloadInputMode(&MODULE_GPT120, IfxGpt12_ReloadInputMode_bothEdgesTxOTL); /* Set reload trigger  */
    IfxGpt12_T2_setTimerValue(&MODULE_GPT120, RELOAD_VALUE);                        /* Set T2 reload value          */

    /* Initialize the interrupt */
    volatile Ifx_SRC_SRCR *src = IfxGpt12_T3_getSrc(&MODULE_GPT120);                /* Get the interrupt address    */
    IfxSrc_init(src, ISR_PROVIDER_GPT12_TIMER, ISR_PRIORITY_GPT12_TIMER);           /* Initialize service request   */
    IfxSrc_enable(src);                                                             /* Enable GPT12 interrupt       */

    IfxGpt12_T3_run(&MODULE_GPT120, IfxGpt12_TimerRun_start);                       /* Start the timer              */

    while(1)
    {
    }
}

GPT12_Timer_Concatenation

GPT12模块的2个16-bit定时器可以级联(concatenation)成一个32bit定时器:

  • GPT2块包含两个定时器: 核心定时器T6和辅助定时器T5
  • GPT2的2个定时器可以三种模式之一运行: 定时器模式, 门控定时器模式, 计数器模式.
  • 一个附加的捕获/重载寄存器(Capture/Reload register, CAPREL)
  • 下面的例子中T5是计数器模式, T6是定时器模式
  • LED每86秒翻转一次, GPT12基本频率100MHz, GPT2预分配设置为2, 定时器T6的频率为100MHz/2=50MHz => 20ns, 32位定时器最大值4294967295*20ns ≈ 86s

Cpu0_Main.c代码如下:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "Ifx_Types.h"
#include "IfxGpt12.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define ISR_PRIORITY_GPT12_T5_INT   10                      /* Define the GPT12 Timer 5 interrupt priority          */
#define ISR_PRIORITY_GPT12_T6_INT   11                      /* Define the GPT12 Timer 6 interrupt priority          */
#define SHIFT_BY_16                 16                      /* Define a shift value                                 */
#define LED                         &MODULE_P13,0           /* LED which toggles in the Interrupt Service Routine   */

uint32 g_timerValue32Bit = 0x00000000;

/* Macro to define Interrupt Service Routine */
IFX_INTERRUPT(GPT12_T5_Int0_Handler, 0, ISR_PRIORITY_GPT12_T5_INT);

/* Interrupt Service Routine of timer T5 gets triggered when the concatenation of both 16-bit timers has an overflow */
void GPT12_T5_Int0_Handler(void)
{
    IfxPort_setPinState(LED, IfxPort_State_toggled);    /* Toggle LED */
}

/* Macro to define Interrupt Service Routine */
IFX_INTERRUPT(GPT12_T6_Int0_Handler, 0, ISR_PRIORITY_GPT12_T6_INT);

/* Interrupt Service Routine of timer T6 gets triggered when the 16 bit timer T6 has an overflow */
void GPT12_T6_Int0_Handler(void)
{
    uint32 timerValueLOW = (uint32)IfxGpt12_T6_getTimerValue(&MODULE_GPT120);     /* Get counter value of timer T6 */
    uint32 timerValueHIGH = (uint32)IfxGpt12_T5_getTimerValue(&MODULE_GPT120);    /* Get counter value of timer T5 */

    /* Concatenation of both 16-bit timers values to one 32 bit timer by adding the shifted value of timer T5
     * to the value of timer T6.
     */
    g_timerValue32Bit = (timerValueHIGH << SHIFT_BY_16) + timerValueLOW;
}

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    /* Initialize LED port pin */
    IfxPort_setPinMode(LED, IfxPort_Mode_outputPushPullGeneral);

    //init_GPT12_module
    /* Enable GPT12 module */
    IfxGpt12_enableModule(&MODULE_GPT120);
    /* Select 2 as prescaler for the GPT2 module -> fastest clock frequency */
    IfxGpt12_setGpt2BlockPrescaler(&MODULE_GPT120, IfxGpt12_Gpt2BlockPrescaler_2);
    /* Set the core timer T6 in timer mode */
    IfxGpt12_T6_setMode(&MODULE_GPT120, IfxGpt12_Mode_timer);
    /* Set the auxiliary timer T5 in counter mode */
    IfxGpt12_T5_setMode(&MODULE_GPT120, IfxGpt12_Mode_counter);
    /* Select the rising and falling edges of Output Toggle Latch of timer T6 */
    IfxGpt12_T5_setCounterInputMode(&MODULE_GPT120, IfxGpt12_CounterInputMode_bothEdgesTxOTL);
    /* Turn remote control on; Timer T5 is controlled by overflow of timer T6 */
    IfxGpt12_T5_setRemoteControl(&MODULE_GPT120, IfxGpt12_TimerRemoteControl_on);

    /* Service request configuration */
    /* Get source pointer of timer T5, initialize and enable */
    volatile Ifx_SRC_SRCR *src = IfxGpt12_T5_getSrc(&MODULE_GPT120);
    IfxSrc_init(src, IfxSrc_Tos_cpu0, ISR_PRIORITY_GPT12_T5_INT);
    IfxSrc_enable(src);
    /* Get source pointer of timer T6, initialize and enable */
    src = IfxGpt12_T6_getSrc(&MODULE_GPT120);
    IfxSrc_init(src, IfxSrc_Tos_cpu0, ISR_PRIORITY_GPT12_T6_INT);
    IfxSrc_enable(src);

    /* Start timer T6 */
    IfxGpt12_T6_run(&MODULE_GPT120, IfxGpt12_TimerRun_start);


    while(1)
    {
    }
}

GPT12_PWM_Generation

参考GPT12_PWM_Generation_1 for KIT_AURIX_TC397_TFT.

用GPT12产生固定频率的PWM和自定义的占空比:

  • GPT1的T3配置为向下计数的定时器模式, 一旦T3下溢出, T3OTL(T3 Output Toggle Latch)翻转, T2(dutyDownTime)和T4(dutyUpTime)的值传递给T3(哪个传递取决于T3OTL的值), T3的中断中翻转LED
  • 得到GPT12的基本频率Fgpt: IfxGpt12_getModuleFrequency(), 100MHz
  • 定时器频率 Ftimer = Fgpt / (GPT1_BLOCK_PRESCALER × TimerInputPrescaler) = 100MHz/(32x32) = 97656.25Hz
  • dutyUpTime = Ftimer x DutyCycle / f = 97656.25Hz * 0.85 / 2 = 41.5
  • dutyDownTime = Ftimer x (1 - DutyCycle) / f

Cpu0_Main.c代码:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "Ifx_Types.h"
#include "IfxGpt12.h"
#include "IfxPort.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define ISR_PRIORITY_GPT12_TIMER    6                       /* Define the GPT12 Timer interrupt priority            */
#define ISR_PROVIDER_GPT12_TIMER    IfxSrc_Tos_cpu0         /* Interrupt provider                                   */
#define PWM_FREQUENCY               2.0f                    /* Frequency of the PWM signal in Hz                    */
#define PWM_DUTY_CYCLE              85                      /* Duty cycle of the PWM signal in percentage           */
#define LED                         &MODULE_P13, 0          /* LED which toggles in the Interrupt Service Routine   */
#define GPT1_BLOCK_PRESCALER        32                      /* GPT1 block prescaler value                           */
#define TIMER_T3_INPUT_PRESCALER    32                      /* Timer input prescaler value                          */

/* Macro to define Interrupt Service Routine */
IFX_INTERRUPT(interruptGpt12, 0, ISR_PRIORITY_GPT12_TIMER);

/* Interrupt Service Routine of the GPT12 */
void interruptGpt12(void)
{
    /* Toggle the state of the LED */
    IfxPort_togglePin(LED);
}

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    /* Initialize the LED */
    IfxPort_setPinModeOutput(LED, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);

    //initGpt12PWM
    /* Enable the GPT12 module */
    IfxGpt12_enableModule(&MODULE_GPT120);
    /* Set GPT1 block prescaler to divide the module frequency */
    IfxGpt12_setGpt1BlockPrescaler(&MODULE_GPT120, IfxGpt12_Gpt1BlockPrescaler_32);
    /* Set the GPT12 timer T3 in timer mode */
    IfxGpt12_T3_setMode(&MODULE_GPT120, IfxGpt12_Mode_timer);
    /* Set the Timer T3 direction   */
    IfxGpt12_T3_setTimerDirection(&MODULE_GPT120, IfxGpt12_TimerDirection_down);
    /* Set timer T3 input prescaler to divide the timer frequency */
    IfxGpt12_T3_setTimerPrescaler(&MODULE_GPT120, IfxGpt12_TimerInputPrescaler_32);

    /* Calculate dutyUpTime and dutyDownTime for reloading timer T3 */
    float32 moduleFreq = IfxGpt12_getModuleFrequency(&MODULE_GPT120);
    float32 fTimer = (moduleFreq / (GPT1_BLOCK_PRESCALER * TIMER_T3_INPUT_PRESCALER));
    uint16 dutyUpTime = (fTimer * (PWM_DUTY_CYCLE / 100.0f)) / PWM_FREQUENCY;
    uint16 dutyDownTime = (fTimer * (1 - (PWM_DUTY_CYCLE / 100.0f))) / PWM_FREQUENCY;

    /* Set timer T3 value */
    IfxGpt12_T3_setTimerValue(&MODULE_GPT120, dutyDownTime);

    /* Timer T2: reloads the value dutyDownTime in timer T3 */
    /* Set the timer T2 in reload mode */
    IfxGpt12_T2_setMode(&MODULE_GPT120, IfxGpt12_Mode_reload);
    /* Set the T2 input parameter: Negative transition (falling edge) of T3 toggle latch T3OTL */
    IfxGpt12_T2_setReloadInputMode(&MODULE_GPT120, IfxGpt12_ReloadInputMode_fallingEdgeTxOTL);
    /* Set timer T2 value (the value that is reloaded in T3 on negative transition) */
    IfxGpt12_T2_setTimerValue(&MODULE_GPT120, dutyDownTime);

    /* Timer T4: reloads the value dutyUpTime in timer T3 */
    /* Set timer T4 in reload mode */
    IfxGpt12_T4_setMode(&MODULE_GPT120, IfxGpt12_Mode_reload);
    /* Set the T4 input parameter: Positive transition (rising edge) of T3 toggle latch T3OTL */
    IfxGpt12_T4_setReloadInputMode(&MODULE_GPT120, IfxGpt12_ReloadInputMode_risingEdgeTxOTL);
    /* Set timer T4 value (the value that is reloaded in T3 on positive transition) */
    IfxGpt12_T4_setTimerValue(&MODULE_GPT120, dutyUpTime);

    /* Configure the GPT12 interrupt */
    volatile Ifx_SRC_SRCR *src = IfxGpt12_T3_getSrc(&MODULE_GPT120);            /* Get interrupt address            */
    IfxSrc_init(src, ISR_PROVIDER_GPT12_TIMER, ISR_PRIORITY_GPT12_TIMER);       /* Initialize the service request   */
    IfxSrc_enable(src);                                                         /* Enable GPT12 interrupt           */

    IfxGpt12_T3_run(&MODULE_GPT120, IfxGpt12_TimerRun_start);                   /* Start the timer T3               */

    while(1)
    {
    }
}

GPT12_PWM_Capture

参考 GPT12_PWM_Capture_1 for KIT_AURIX_TC397_TFT

  • GPT1的定时器T2和T4可以用作核心定时器T3的捕获或重载寄存器
  • 本例中T2(捕获模式)捕获T3(定时器模式)的值
  • T3是16bit定时器, 最大值65535, GPT12基本频率100MHz, GPT1预分配4, T3频率100MHz/4=25MHz, 40ns +1, 溢出时间65535*40≈0.0026s => 381Hz
  • 总增量可以通过比较T2当前值和一个PWM周期前的值(1000为例)来获得, 50Hz PWM周期0.2s, 0.2s内, T3计数0.02s/40ns=500000次, 溢出7次, T2记录的PWM一个周期前的值为1000, T2当前值42255, 总增量为 (65535-1000)+(7-1)*65535+42255 = 500000, PWM频率为25MHz/500000=50Hz
  • 本例中软件模拟PWM产生
  • 用杜邦线连接P00.7(GPT1 T2 输入)和P00.8(PWM信号)

在这里插入图片描述

在这里插入图片描述

Cpu0_Main.c代码如下:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "IfxGpt12.h"
#include "Bsp.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define ISR_PRIORITY_GPT12_T2_INT   10              /* Define the GPT12 Timer 2 interrupt priority                  */
#define ISR_PRIORITY_GPT12_T3_INT   11              /* Define the GPT12 Timer 2 interrupt priority                  */
#define MAX_VAL_16_BIT              0xFFFF          /* Used for calculation of timer value with overflows           */

#define PWM_PIN                     &MODULE_P00,8   /* Pin which is used to generate a simple PWM signal            */
#define PWM_DUTY                    0.5             /* Duty cycle of generated PWM signal, value between 0 and 1    */
#define FACTOR_SEC_TO_USEC          1000000         /* Factor to convert seconds to microseconds                    */

float32 g_generatedPwmFreqHz    = 50.0; /* Global variable for frequency of generated PWM signal                    */
float32 g_measuredPwmFreqHz     = 0.0;  /* Global variable for frequency calculation of PWM signal                  */
uint32  g_cntOverflow           = 0;    /* Global counter variable for the timer overflow between two edges         */
uint32  g_previousCntVal        = 0;    /* Global variable which stores the timer value of the previous interrupt   */

/* Macro to define the Interrupt Service Routine */
IFX_INTERRUPT(GPT12_T2_Int0_Handler, 0, ISR_PRIORITY_GPT12_T2_INT);

/* Interrupt Service Routine of timer T2, gets triggered by rising edge on input pin of timer T2 */
void GPT12_T2_Int0_Handler(void)
{
    uint32 currentCntVal = IfxGpt12_T2_getTimerValue(&MODULE_GPT120); /* Get timer value of timer T2 */
    uint32 finalCntVal = 0; /* Variable to calculate final timer counter value */

    if(g_cntOverflow == 0)
    {
        /* If no overflow detected */
        finalCntVal = currentCntVal - g_previousCntVal; /* Total counter value calculation */
    }
    else
    {
        /* One or more overflows detected */
        /* Add to the current counter value, the amount of counter ticks which passed before the first overflow,
         * plus 65525 (0xFFFF) for each additional overflow since the previous rising edge.
         */
        finalCntVal = (uint32)(currentCntVal + (MAX_VAL_16_BIT - g_previousCntVal) + ((g_cntOverflow - 1) * MAX_VAL_16_BIT));
    }

    /* Calculation of the PWM frequency by dividing the frequency of timer T3 through the final total counter value */
    g_measuredPwmFreqHz = IfxGpt12_T3_getFrequency(&MODULE_GPT120) / finalCntVal;

    g_previousCntVal = currentCntVal;    /* Set g_previousCntVal to currentCntVal for the next calculation */
    g_cntOverflow = 0;                   /* Reset overflow flag */
}

/* Macro to define the Interrupt Service Routine. */
IFX_INTERRUPT(GPT12_T3_Int0_Handler, 0, ISR_PRIORITY_GPT12_T3_INT);

/* Interrupt Service Routine of timer T3, gets triggered after T3 timer overflow */
void GPT12_T3_Int0_Handler(void)
{
    g_cntOverflow++; /* Increase overflow counter */
}


void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    //init_GPT12_module
    /* Enable GPT12 module */
    IfxGpt12_enableModule(&MODULE_GPT120);
    /* Select 4 as prescaler for the GPT1 module -> fastest clock frequency for best accuracy */
    IfxGpt12_setGpt1BlockPrescaler(&MODULE_GPT120, IfxGpt12_Gpt1BlockPrescaler_4);
    /* Set core timer T3 in timer mode */
    IfxGpt12_T3_setMode(&MODULE_GPT120, IfxGpt12_Mode_timer);
    /* Set auxiliary timer T2 in capture mode */
    IfxGpt12_T2_setMode(&MODULE_GPT120, IfxGpt12_Mode_capture);
    /* Select input pin A of timer T2 which is P00.7 (the James Bond pin) */
    IfxGpt12_T2_setInput(&MODULE_GPT120, IfxGpt12_Input_A);
    /* Select rising edge as capture event */
    IfxGpt12_T2_setCaptureInputMode(&MODULE_GPT120, IfxGpt12_CaptureInputMode_risingEdgeTxIN);

    /* Service request configuration */
    /* Get source pointer of timer T2, initialize and enable */
    volatile Ifx_SRC_SRCR *src = IfxGpt12_T2_getSrc(&MODULE_GPT120);
    IfxSrc_init(src, IfxSrc_Tos_cpu0, ISR_PRIORITY_GPT12_T2_INT);
    IfxSrc_enable(src);
    /* Get source pointer of timer T3, initialize and enable */
    src = IfxGpt12_T3_getSrc(&MODULE_GPT120);
    IfxSrc_init(src, IfxSrc_Tos_cpu0, ISR_PRIORITY_GPT12_T3_INT);
    IfxSrc_enable(src);

    /* Initialize time constants */
    initTime();
    /* Initialize PWM_PIN port pin */
    IfxPort_setPinMode(PWM_PIN, IfxPort_Mode_outputPushPullGeneral);

    /* Start timer T3*/
    IfxGpt12_T3_run(&MODULE_GPT120, IfxGpt12_TimerRun_start);

    while(1)
    {
        /* Calculate the total time between two rising edges for the specific frequency */
        sint32 targetWaitTime_us = (1 / g_generatedPwmFreqHz) * FACTOR_SEC_TO_USEC * TimeConst_1us;
        /* Set the pin high to trigger an interrupt */
        IfxPort_setPinState(PWM_PIN, IfxPort_State_high);
        /* Wait for an amount of CPU ticks that represent the calculated microseconds considering the duty cycle */
        wait(PWM_DUTY * targetWaitTime_us);
        /* Set pin state to low */
        IfxPort_setPinState(PWM_PIN, IfxPort_State_low);
        /* Wait for an amount of CPU ticks that represent the calculated microseconds considering the duty cycle */
        wait((1 - PWM_DUTY) * targetWaitTime_us);
    }
}

CCU6_Interrupt

参考 CCU6_Interrupt_1 for KIT_AURIX_TC397_TFT

CCU6每500ms中断一次, 翻转LED:

  • CCU6是一个高分辨率的16-bit捕获和比较单元, 主要用于AC驱动控制, 有定时器T12(3个捕获/比较通道)和定时器T13(1个比较通道), 本例中用T12
  • CCU6可以在计数到预定义的周期值时产生中断
  • 定时器模式下, 默认的时钟频率Fcc6为100MHz, 可以以2的倍数分频, 最多32768分频, 对应3051.75Hz
  • 中断频率fISR = (CCU6 clock frequency) / (period + 1), 其中period的值储存在16-bit寄存器中, 最大值65535
  • fISR=10Hz为例, period=65535, 算出CCU6频率655360Hz, 最接近100MHz/256=390625Hz, 用这个值重新计算period≈39061, fISR=390625/39062≈10Hz
  • 下面的例子fISR=2Hz

Cpu0_Main.c代码如下:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "IfxPort.h"
#include "IfxCcu6_Timer.h"

#define ISR_PRIORITY_CCU6_INT1  40                                          /* Priority for interrupt ISR           */
#define CCU6_TIMER_FREQ         97656                                       /* Timer module frequency in Hz         */
#define CCU6_ISR_FREQ           2                                           /* ISR frequency in Hz                  */
#define CCU6_TIMER_PERIOD       (CCU6_TIMER_FREQ / CCU6_ISR_FREQ) - 1       /* Timer module period in ticks         */

#define LED1                    &MODULE_P13,0                               /* LED D107  */

/* CCU6 */
#define CCU6                    &MODULE_CCU60                               /* CCU6 will be used in this example    */

IfxCcu6_Timer g_timer;                                                      /* Timer structure                      */
uint8 g_counter = 0;                                                        /* Variable to keep count of ISR calls  */

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

IFX_INTERRUPT(isrCCU6Timer, 0, ISR_PRIORITY_CCU6_INT1);

void isrCCU6Timer(void)
{
    IfxPort_togglePin(LED1);
}

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    IfxPort_setPinMode(LED1, IfxPort_Mode_outputPushPullGeneral);
    IfxPort_setPinState(LED1, IfxPort_State_high);

    //initCCU6
    IfxCcu6_Timer_Config timerConfig;                   /* Structure for timer configuration                        */
    IfxCcu6_Timer_initModuleConfig(&timerConfig, CCU6); /* Initialize the timer module structure with default values*/
    /* The Serial Peripheral Bus has a default Frequency of Fcc6 = 100000000 Hz = 100 MHz
     * Possible frequencies for the CCU6 timer are:
     *       - 100000000 Hz = 100 MHz   (Fcc6)
     *       - 50000000 Hz  = 50 MHz    (Fcc6/2)
     *       - 25000000 Hz  = 25 MHz    (Fcc6/4)
     *       - 12500000 Hz  = 12.5 MHz  (Fcc6/8)
     *       - 6250000 Hz   = 6.25 MHz  (Fcc6/16)
     *       - 3125000 Hz   ~ 3 MHz     (Fcc6/32)
     *       - 1562500 Hz   ~ 1.5 MHz   (Fcc6/64)
     *       - 781250 Hz    ~ 780 KHz   (Fcc6/128)
     *       - 390625 Hz    ~ 390 KHz   (Fcc6/256)
     *       - 195312.5 Hz  ~ 200 KHz   (Fcc6/512)
     *       - 97656.25 Hz  ~ 100 KHz   (Fcc6/1024)
     *       - 48828.12 Hz  ~ 50 KHz    (Fcc6/2048)
     *       - 24414.06 Hz  ~ 25 KHz    (Fcc6/4096)
     *       - 12207.03 Hz  ~ 12.5 KHz  (Fcc6/8192)
     *       - 6103.51 Hz   ~ 6 KHz     (Fcc6/16384)
     *       - 3051.75 Hz   ~ 3 KHz     (Fcc6/32768)
     */
    timerConfig.base.t12Frequency = CCU6_TIMER_FREQ;                /* Configure the frequency of the timer module */
    timerConfig.base.t12Period = CCU6_TIMER_PERIOD;                 /* Configure the period of the timer (16-bit)  */
    timerConfig.timer = IfxCcu6_TimerId_t12;                        /* Select the timer to be started              */
    timerConfig.interrupt1.source = IfxCcu6_InterruptSource_t12PeriodMatch; /* Set interrupt source                */
    timerConfig.interrupt1.priority = ISR_PRIORITY_CCU6_INT1;       /* Set the priority of the ISR                 */
    timerConfig.interrupt1.typeOfService = IfxSrc_Tos_cpu0;         /* Set the type of service for the interrupt   */
    timerConfig.trigger.t13InSyncWithT12 = FALSE;                   /* Configure timers synchronization            */
    IfxCcu6_Timer_initModule(&g_timer, &timerConfig);               /* Initialize the CCU6 module                  */

    IfxCcu6_Timer_start(&g_timer);                                  /* Start the timer                             */


    while(1)
    {
    }
}

CCU6_PWM_Generation

参考 CCU6_PWM_Generation_1

用CCU6生成三个中心对齐的PWM信号, 频率固定, 占空比不同:

  • 用CCU6的T12和它的3个比较模块产生20kHz PWM信号, 占空比分别为25%, 50%, 75%, 三个信号中心对齐, 定时器必须被配置为向上和向下计数, 输出引脚P02.1, P02.3, P02.5, 可以用示波器测量
  • 初始化阶段, 使用函数IfxCpu_disableInterrupts()暂时禁止中断, 避免未配置外设的抢占, 初始化完成后用IfxCpu_restoreInterrupts()重新使能中断
  • 目标找到比较值Vcmp, 以产生周期50ms, 占空比50%的PWM信号: CCU6基本频率Fcc6=100MHz, PWM频率20kHz, 每周期需要P=100MHz/20kHz=5000ticks, 25%占空比需要1250ticks, 比较值Vcmp=P-dutycycle=5000-1250=3750

在这里插入图片描述

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "IfxCcu6_PwmHl.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define CCU6_BASE_FREQUENCY     100000000                                   /* CCU6 base frequency, in Hertz        */
#define PWM_FREQUENCY           20000                                       /* PWM signal frequency, in Hertz       */
#define PWM_PERIOD              (CCU6_BASE_FREQUENCY / PWM_FREQUENCY)       /* PWM signal period, in ticks          */

#define NUMBER_OF_CHANNELS      3

#define CHANNEL1_DUTY_CYCLE     25                                          /* PWM Signal 1 Duty cycle, in percent  */
#define CHANNEL2_DUTY_CYCLE     50                                          /* PWM Signal 2 Duty cycle, in percent  */
#define CHANNEL3_DUTY_CYCLE     75                                          /* PWM Signal 3 Duty cycle, in percent  */

#define CHANNEL1_COMPARE_VALUE  ((PWM_PERIOD / 100) * (100 - CHANNEL1_DUTY_CYCLE))
#define CHANNEL2_COMPARE_VALUE  ((PWM_PERIOD / 100) * (100 - CHANNEL2_DUTY_CYCLE))
#define CHANNEL3_COMPARE_VALUE  ((PWM_PERIOD / 100) * (100 - CHANNEL3_DUTY_CYCLE))

IfxCcu6_TimerWithTrigger g_timer;
IfxCcu6_PwmHl g_driver;

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    

    //initCCU6
    boolean interruptState = IfxCpu_disableInterrupts();            /* Disable global interrupts                    */

    /* Timer configuration: timer used as counter */
    IfxCcu6_TimerWithTrigger_Config timerConf;
    IfxCcu6_TimerWithTrigger_initConfig(&timerConf, &MODULE_CCU60); /* Initialize the timer configuration with
                                                                     * default values                               */
    /* User timer configuration */
    timerConf.base.frequency = PWM_FREQUENCY;                       /* Set the desired frequency for the PWM signal */
    timerConf.base.countDir = IfxStdIf_Timer_CountDir_upAndDown;    /* Configure the timer to count up and down, in
                                                                     * order to generate center-aligned PWM signals */
    /* Initialize the timer driver */
    IfxCcu6_TimerWithTrigger_init(&g_timer, &timerConf);

    /* PWM High/Low driver configuration */
    IfxCcu6_PwmHl_Config pwmHlConf;
    IfxCcu6_PwmHl_initConfig(&pwmHlConf);                           /* Initialize the PwmHl configuration with
                                                                     * default values                               */
    /* User PWM High/Low driver configuration */
    pwmHlConf.timer = &g_timer;                                     /* Use the already configured timer             */
    pwmHlConf.base.channelCount = NUMBER_OF_CHANNELS;               /* Configure the driver to use use all three
                                                                     * compare modules available in T12             */
    /* Assign output pins */
    pwmHlConf.cc0 = &IfxCcu60_CC60_P02_0_OUT;
    pwmHlConf.cc1 = &IfxCcu60_CC61_P02_2_OUT;
    pwmHlConf.cc2 = &IfxCcu60_CC62_P02_4_OUT;
    pwmHlConf.cout0 = &IfxCcu60_COUT60_P02_1_OUT;
    pwmHlConf.cout1 = &IfxCcu60_COUT61_P02_3_OUT;
    pwmHlConf.cout2 = &IfxCcu60_COUT62_P02_5_OUT;

    /* Initialize the PwmHl driver */
    IfxCcu6_PwmHl_init(&g_driver, &pwmHlConf);

    /* Instruct the driver to generate center aligned PWM signals */
    IfxCcu6_PwmHl_setMode(&g_driver, Ifx_Pwm_Mode_centerAligned);

    /* Set the duty cycles for the three channels */
    Ifx_TimerValue cmpValues[NUMBER_OF_CHANNELS];
    cmpValues[0] = CHANNEL1_COMPARE_VALUE;                          /* Set the compare value for channel 1          */
    cmpValues[1] = CHANNEL2_COMPARE_VALUE;                          /* Set the compare value for channel 2          */
    cmpValues[2] = CHANNEL3_COMPARE_VALUE;                          /* Set the compare value for channel 3          */

    g_driver.update(&g_driver, cmpValues);                          /* Apply the compare values                     */

    /* Update the timer.
     * This instruction enables the shadow transfer of the compare values, copying the compare values to the
     * compare registers */
    IfxCcu6_TimerWithTrigger_applyUpdate(g_driver.timer);

    /* Restore interrupts to their initial state */
    IfxCpu_restoreInterrupts(interruptState);

    //startPWMGeneration
    IfxCcu6_TimerWithTrigger_run(&g_timer);

    while(1)
    {
    }
}

官方的测试结果:

在这里插入图片描述

CCU6_PWM_Capture

参考 CCU6_PWM_Capture_1 for KIT_AURIX_TC397_TFT

软件模拟PWM通过P02.1引脚输出, 然后用CCU6 T12(P02.0输入, 与P02.1短接)测量频率和占空比:

  • 需要一个中断CCU6_edge_detection_isr捕获PWM, 用两个上升沿计算周期, 上升沿和下降沿计算占空比
  • 另一个中断CCU6_period_match_isr对计数器溢出计数
  • T12最大值65534(16bit-1), T12频率781250Hz => 1.28us, 在65534*1.28us≈0.084s后溢出

周期计算举例:

在这里插入图片描述

高电平时间计算举例:

在这里插入图片描述

Cpu0_Main.c代码如下:

#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "Ifx_Types.h"
#include "IfxCcu6_Icu.h"
#include "Bsp.h"

IFX_ALIGN(4) IfxCpu_syncEvent g_cpuSyncEvent = 0;

#define ISR_PRIORITY_CCU6_RISING_EDGE   1               /* Define the CCU6 rising edge interrupt priority           */
#define ISR_PRIORITY_CCU6_PERIOD_MATCH  2               /* Define the CCU6 period match interrupt priority          */
#define CCU6_INPUT_PIN                  IfxCcu60_CC60INA_P02_0_IN /* Select input port pin P02.0                    */

#define PWM_PIN                         &MODULE_P02,1   /* Pin used to generate a simple PWM signal                 */
#define SEC_TO_USEC                     1000000         /* Factor to convert seconds to microseconds                */
#define MAX_VAL_T12                     (0xFFFF - 1)    /* Maximum number of ticks between two overflows            */

IfxCcu6_Icu_Channel g_icuChannel;           /* CCU6 ICU channel handle                                              */
float32 g_CCU6Frequency_Hz = 0.0;           /* Global variable which stores the CCU6 capture frequency              */

float32 g_generatedPwmFreq_Hz = 5.0;        /* Frequency of the generated PWM signal                                */
float32 g_generatedPwmDutyCycle = 80.0;     /* Duty cycle in percentage of the generated PWM signal                 */
float32 g_measuredPwmFreq_Hz = 0.0;         /* Calculated frequency of the measured PWM signal                      */
float32 g_measuredPwmDutyCycle = 0.0;       /* Calculated duty cycle of the measured PWM signal                     */
uint32  g_cntOverflowPeriod = 0;            /* Counter of timer overflows between two rising edges                  */
uint32  g_cntOverflowHighLevel = 0;         /* Counter of timer overflows between a rising and a falling edge       */
uint32  g_previousCntVal = 0;               /* Global variable to store the timer value of the previous interrupt   */

IFX_INTERRUPT(CCU6_edge_detection_isr, 0, ISR_PRIORITY_CCU6_RISING_EDGE);

/* Interrupt Service Routine of the CCU6, which gets triggered by a rising edge of the input port pin of timer T12 */
void CCU6_edge_detection_isr(void)
{
    uint32  risingEdgeCntVal = 0;           /* Number of ticks between the last overflow and the rising edge        */
    uint32  fallingEdgeCntVal = 0;          /* Number of ticks between the last overflow and the falling edge       */

    /* Check on the occurrence of the rising edge */
    if (g_icuChannel.ccu6->IS.B.ICC60R)
    {
        /* Reset interrupt status flag */
        IfxCcu6_clearInterruptStatusFlag(&MODULE_CCU60, IfxCcu6_InterruptSource_cc60RisingEdge);

        /* Get the captured rising edge counter value from the counter register */
        risingEdgeCntVal = IfxCcu6_getCaptureRegisterValue(g_icuChannel.ccu6, g_icuChannel.channelId);
    }

    /* Check on the occurrence of the falling edge */
    if (g_icuChannel.ccu6->IS.B.ICC60F)
    {
        /* Reset interrupt status flag */
        IfxCcu6_clearInterruptStatusFlag(&MODULE_CCU60, IfxCcu6_InterruptSource_cc60FallingEdge);

        /* Get the captured falling edge counter value from the shadow register */
        fallingEdgeCntVal = IfxCcu6_getCaptureShadowRegisterValue(g_icuChannel.ccu6, g_icuChannel.channelId);
    }

    /* Define a variable to calculate the final timer counter value */
    uint32 finalFreqCntVal, finalDutyCycCntVal = 0;

    /* If no overflow was detected during the period measurement */
    if(g_cntOverflowPeriod == 0)
    {
        finalFreqCntVal = risingEdgeCntVal - g_previousCntVal;      /* Total counter value calculation          */
    }
    /* If one or more overflows were detected during the period measurement */
    else
    {
        /* Add to the current counter value, the amount of counter ticks which passed before the first overflow,
         * plus 65534 (0xFFFF - 1) for each additional overflow occurred between two rising edges.
         */
        finalFreqCntVal = (uint32)(risingEdgeCntVal + (MAX_VAL_T12 - g_previousCntVal) + ((g_cntOverflowPeriod - 1) * MAX_VAL_T12));
    }

    /* If no overflows were detected during signal high level time measurement */
    if(g_cntOverflowHighLevel == 0)
    {
        finalDutyCycCntVal = fallingEdgeCntVal - g_previousCntVal;
    }

    /* If one or more overflows were detected during signal high level time measurement */
    else
    {
        /* Add to the current counter value, the amount of counter ticks which passed before the first overflow,
         * plus 65534 (0xFFFF - 1) for each additional overflow occurred between the rising and the falling edge.
         */
        finalDutyCycCntVal = (uint32)(fallingEdgeCntVal + (MAX_VAL_T12 - g_previousCntVal) + ((g_cntOverflowHighLevel - 1) * MAX_VAL_T12));
    }

    /* The PWM frequency is calculated by dividing the captured frequency with the final total counter value
     *      total number of ticks * (1 / CCU6 frequency) = period of the measured signal =>
     *      => frequency of the measured signal = CCU6 frequency / total number of ticks
     */
    g_measuredPwmFreq_Hz = g_CCU6Frequency_Hz / (float32)finalFreqCntVal;

    /* The PWM duty cycle is calculated by dividing the captured signal high level time by the period */
    g_measuredPwmDutyCycle = 100 * (finalDutyCycCntVal / (float32)finalFreqCntVal);

    g_previousCntVal = risingEdgeCntVal;    /* Update g_previousCntVal for the next calculation                 */
    g_cntOverflowPeriod = 0;                /* Reset overflow counter of the period measurement                 */
    g_cntOverflowHighLevel = 0;             /* Reset overflow counter of the signal high level time measurement */
}

/* Macro to define the Interrupt Service Routine */
IFX_INTERRUPT(CCU6_period_match_isr, 0, ISR_PRIORITY_CCU6_PERIOD_MATCH);

/* Interrupt Service Routine of the CCU6, which gets triggered at each period match event for counting overflows */
void CCU6_period_match_isr(void)
{
    g_cntOverflowPeriod++;

    /* Increments high level time measurement overflows number only if the signal is still high
     * (no falling edge occurrence yet)
     */
    if(IfxCcu6_getInterruptStatusFlag(&MODULE_CCU60, IfxCcu6_InterruptSource_cc60FallingEdge) == FALSE)
    {
        g_cntOverflowHighLevel++;
    }
}

void core0_main(void)
{
    IfxCpu_enableInterrupts();
    
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
    
    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
    //init_CCU6_ICU, Configure the CCU6 for capturing the rising edge of a PWM signal
    IfxCcu6_Icu ccu6Handle;                                             /* CCU6 handle                              */
    IfxCcu6_Icu_Config ccu6Config;                                      /* Create a configuration structure         */

    IfxCcu6_Icu_initModuleConfig(&ccu6Config, &MODULE_CCU60);           /* Fill the structure with default values   */
    IfxCcu6_Icu_initModule(&ccu6Handle, &ccu6Config);                   /* Initialize the module                    */

    /* Store the configured captured frequency in a global variable */
    g_CCU6Frequency_Hz = ccu6Handle.captureFrequency;

    IfxCcu6_Icu_ChannelConfig ccu6ChannelConfig;                        /* Create a channel configuration structure */
    IfxCcu6_Icu_initChannelConfig(&ccu6ChannelConfig, &MODULE_CCU60);   /* Fill the structure with default values   */

    ccu6ChannelConfig.channelId = IfxCcu6_T12Channel_0;                 /* Select Timer T12 channel 0               */

    /* Select the capture mode: IfxCcu6_T12ChannelMode_doubleRegisterCaptureRisingAndFalling
     * With this particular value, the CCU6 stores the T12 value in the CC6xR register when a rising edge is detected,
     * while it stores the T12 value in the CC6xSR shadow register when a falling edge is detected.
     */
    ccu6ChannelConfig.channelMode = IfxCcu6_T12ChannelMode_doubleRegisterCaptureRisingAndFalling;

    /* Service Request 0 for interrupt at any rising or falling edge */
    ccu6ChannelConfig.interrupt1.source = IfxCcu6_InterruptSource_cc60RisingEdge; /* Select the interrupt source    */
    ccu6ChannelConfig.interrupt1.serviceRequest = IfxCcu6_ServiceRequest_0; /* Select the service request output    */
    ccu6ChannelConfig.interrupt1.priority = ISR_PRIORITY_CCU6_RISING_EDGE;  /* Configure the interrupt priority     */
    ccu6ChannelConfig.interrupt1.typeOfService = IfxSrc_Tos_cpu0;           /* Select the type of interrupt service */

    /* Service Request 1 for interrupt at T12 period match */
    ccu6ChannelConfig.interrupt2.source = IfxCcu6_InterruptSource_t12PeriodMatch; /* Select the interrupt source    */
    ccu6ChannelConfig.interrupt2.serviceRequest = IfxCcu6_ServiceRequest_1; /* Select the service request output    */
    ccu6ChannelConfig.interrupt2.priority = ISR_PRIORITY_CCU6_PERIOD_MATCH; /* Configure the interrupt priority     */
    ccu6ChannelConfig.interrupt2.typeOfService = IfxSrc_Tos_cpu0;           /* Select the type of interrupt service */

    /* Configure internal start of timer T12 controlled by the run bit T12R */
    ccu6ChannelConfig.trigger.extInputTrigger = NULL_PTR;

    /* CCU6 ICU pin configuration */
    IfxCcu6_Icu_Pins pins =
    {
        &CCU6_INPUT_PIN,            /* CC60In pin                   */
        NULL_PTR,                   /* CC61In pin not used          */
        NULL_PTR,                   /* CC62In pin not used          */
        NULL_PTR,                   /* CCPOS0In pin not used        */
        NULL_PTR,                   /* CCPOS1In pin not used        */
        NULL_PTR,                   /* CCPOS2In pin not used        */
        IfxPort_InputMode_pullUp,   /* CC6x pin input mode          */
        IfxPort_InputMode_pullUp,   /* CCPOSx pin input mode        */
        NULL_PTR,                   /* T12HR input signal not used  */
        NULL_PTR,                   /* T13HR input signal not used  */
        IfxPort_InputMode_pullUp    /* Pad driver mode              */
    };
    ccu6ChannelConfig.pins = &pins;                                     /* Set the configuration of the port pins   */

    ccu6ChannelConfig.multiInputCaptureEnabled = FALSE;                 /* Disable multiple input capture mode      */

    IfxCcu6_Icu_initChannel(&g_icuChannel, &ccu6ChannelConfig);         /* Initialize the channel                   */

    /* Start the timer T12 by setting the run bit T12R with the associated bit T12RS */
    IfxCcu6_Icu_startCapture(&g_icuChannel);

    initTime();                                                         /* Initialize the time constants            */
    IfxPort_setPinMode(PWM_PIN, IfxPort_Mode_outputPushPullGeneral);    /* Initialize the PWM_PIN port pin          */

    while(1)
    {
        /* Calculate the total time between two rising edges for the specific frequency */
        uint32 targetWaitTime_us = (1 / g_generatedPwmFreq_Hz) * SEC_TO_USEC * TimeConst_1us;

        /* Set the port pin state to high in order to trigger an interrupt */
        IfxPort_setPinState(PWM_PIN, IfxPort_State_high);
        /* Wait time while the signal is in high state */
        wait(g_generatedPwmDutyCycle * targetWaitTime_us / 100);

        /* Set pin state to low */
        IfxPort_setPinState(PWM_PIN, IfxPort_State_low);
        /* Wait time while the signal is in low state */
        wait((100 - g_generatedPwmDutyCycle) * targetWaitTime_us / 100);

    }
}

微信公众号

欢迎扫描关注我的微信公众号, 及时获取最新文章:
在这里插入图片描述

  • 10
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
在GTM模块中,包含了多个子模块,其中包括了TIM、TOM和CCU6。 TIM模块是用于进行PWM波的周期和占空比测量的。TOM模块则是用于产生PWM波的。而CCU6模块是GTM中的定时器和计数器单元,用于实现更复杂的定时和计数功能。GTM是一个通用计时模块,可以用于多种用途,包括高精度的定时和计数应用。GPT是另一个模块,代表通用定时器。它通常用于提供简单的定时功能,例如生成延时或周期性中断。除此之外,GTM还包含了其他模块,例如CMU模块用于产生多个时钟信号,以及DPLL和BRC等模块用于时钟同步和时钟源选择。总的来说,GTM是一个功能强大的计时模块,可以满足多种计时和控制需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [AURIX TC397 Timer PWM 基础知识](https://blog.csdn.net/weifengdq/article/details/109387875)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Autosar MCAL-GTM之TOM](https://blog.csdn.net/weixin_49000276/article/details/128267796)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值