void us_ticker_set_interrupt(timestamp_t timestamp) { /* We get here absolute interrupt time which takes into account counter overflow. * Since we use additional count-down timer to generate interrupt we need to calculate * load value based on time-stamp. */ const uint32_t now_ticks = us_ticker_read(); uint32_t delta_ticks = timestamp >= now_ticks ? timestamp - now_ticks : (uint32_t)((uint64_t) timestamp + 0xFFFFFFFF - now_ticks); if (delta_ticks == 0) { /* The requested delay is less than the minimum resolution of this counter. */ delta_ticks = 1; } us_ticker_int_counter = (uint32_t)(delta_ticks >> 16); us_ticker_int_remainder = (uint16_t)(0xFFFF & delta_ticks); TPM_StopTimer(TPM2); TPM2->CNT = 0; if (us_ticker_int_counter > 0) { TPM2->MOD = 0xFFFF; us_ticker_int_counter--; } else { TPM2->MOD = us_ticker_int_remainder; us_ticker_int_remainder = 0; } /* Clear the count and set match value */ TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag); TPM_EnableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable); TPM_StartTimer(TPM2, kTPM_SystemClock); }
/************************************************************************************ ************************************************************************************* * Public functions ************************************************************************************* ************************************************************************************/ void StackTimer_Init(void (*cb)(void)) { IRQn_Type irqId; #if FSL_FEATURE_SOC_FTM_COUNT FTM_Type *ftmBaseAddr = (FTM_Type*)mFtmBase[gStackTimerInstance_c]; FTM_Init(ftmBaseAddr, &mFtmConfig); FTM_StopTimer(ftmBaseAddr); ftmBaseAddr->MOD = 0xFFFF; /* Configure channel to Software compare; output pin not used */ FTM_SetupOutputCompare(ftmBaseAddr, (ftm_chnl_t)gStackTimerChannel_c, kFTM_NoOutputSignal, 0x01); /* Install ISR */ irqId = mFtmIrqId[gStackTimerInstance_c]; FTM_EnableInterrupts(ftmBaseAddr, kFTM_TimeOverflowInterruptEnable | (1 << gStackTimerChannel_c)); #else TPM_Type *tpmBaseAddr = (TPM_Type*)mTpmBase[gStackTimerInstance_c]; TPM_Init(tpmBaseAddr, &mTpmConfig); TPM_StopTimer(tpmBaseAddr); /* Set the timer to be in free-running mode */ tpmBaseAddr->MOD = 0xFFFF; /* Configure channel to Software compare; output pin not used */ TPM_SetupOutputCompare(tpmBaseAddr, (tpm_chnl_t)gStackTimerChannel_c, kTPM_NoOutputSignal, 0x01); /* Install ISR */ irqId = mTpmIrqId[gStackTimerInstance_c]; TPM_EnableInterrupts(tpmBaseAddr, kTPM_TimeOverflowInterruptEnable | (1 << gStackTimerChannel_c)); #endif /* Overwrite old ISR */ OSA_InstallIntHandler(irqId, cb); /* set interrupt priority */ NVIC_SetPriority(irqId, gStackTimer_IsrPrio_c >> (8 - __NVIC_PRIO_BITS)); NVIC_ClearPendingIRQ(irqId); NVIC_EnableIRQ(irqId); }
/*! * @brief Main function */ int main(void) { tpm_config_t tpmInfo; tpm_chnl_pwm_signal_param_t tpmParam; tpm_pwm_level_select_t pwmLevel = kTPM_LowTrue; /* Configure tpm params with frequency 24kHZ */ tpmParam.chnlNumber = (tpm_chnl_t)BOARD_TPM_CHANNEL; tpmParam.level = pwmLevel; tpmParam.dutyCyclePercent = updatedDutycycle; /* Board pin, clock, debug console init */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); /* Select the clock source for the TPM counter as kCLOCK_PllFllSelClk */ CLOCK_SetTpmClock(1U); /* Print a note to terminal */ PRINTF("\r\nTPM example to output center-aligned PWM signal\r\n"); PRINTF("\r\nYou will see a change in LED brightness if an LED is connected to the TPM pin"); PRINTF("\r\nIf no LED is connected to the TPM pin, then probe the signal using an oscilloscope"); TPM_GetDefaultConfig(&tpmInfo); /* Initialize TPM module */ TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo); TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, 24000U, TPM_SOURCE_CLOCK); /* Enable channel interrupt flag.*/ TPM_EnableInterrupts(BOARD_TPM_BASEADDR, TPM_CHANNEL_INTERRUPT_ENABLE); /* Enable at the NVIC */ EnableIRQ(TPM_INTERRUPT_NUMBER); TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock); while (1) { /* Use interrupt to update the PWM dutycycle */ if (true == tpmIsrFlag) { /* Disable interrupt to retain current dutycycle for a few seconds */ TPM_DisableInterrupts(BOARD_TPM_BASEADDR, TPM_CHANNEL_INTERRUPT_ENABLE); tpmIsrFlag = false; /* Disable channel output before updating the dutycycle */ TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, 0U); /* Update PWM duty cycle */ TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, kTPM_CenterAlignedPwm, updatedDutycycle); /* Start channel output with updated dutycycle */ TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, pwmLevel); /* Delay to view the updated PWM dutycycle */ delay(); /* Enable interrupt flag to update PWM dutycycle */ TPM_EnableInterrupts(BOARD_TPM_BASEADDR, TPM_CHANNEL_INTERRUPT_ENABLE); } } }