uint32_t TPM_GetEnabledInterrupts(TPM_Type *base) { uint32_t enabledInterrupts = 0; int8_t chnlCount = FSL_FEATURE_TPM_CHANNEL_COUNTn(base); /* The CHANNEL_COUNT macro returns -1 if it cannot match the TPM instance */ assert(chnlCount != -1); /* Check if timer overflow interrupt is enabled */ if (base->SC & TPM_SC_TOIE_MASK) { enabledInterrupts |= kTPM_TimeOverflowInterruptEnable; } /* Check if the channel interrupts are enabled */ while (chnlCount > 0) { chnlCount--; if (base->CONTROLS[chnlCount].CnSC & TPM_CnSC_CHIE_MASK) { enabledInterrupts |= (1U << chnlCount); } } return enabledInterrupts; }
void TPM_UpdateChnlEdgeLevelSelect(TPM_Type *base, tpm_chnl_t chnlNumber, uint8_t level) { assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); uint32_t reg = base->CONTROLS[chnlNumber].CnSC & ~(TPM_CnSC_CHF_MASK); /* When switching mode, disable channel first */ base->CONTROLS[chnlNumber].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Clear the field and write the new level value */ reg &= ~(TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); reg |= ((uint32_t)level << TPM_CnSC_ELSA_SHIFT) & (TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); base->CONTROLS[chnlNumber].CnSC = reg; /* Wait till mode change is acknowledged */ reg &= (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); while (reg != (base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } }
void TPM_UpdatePwmDutycycle(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_pwm_mode_t currentPwmMode, uint8_t dutyCyclePercent) { assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); uint16_t cnv, mod; mod = base->MOD; #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE if (currentPwmMode == kTPM_CombinedPwm) { uint16_t cnvFirstEdge; /* This check is added for combined mode as the channel number should be the pair number */ if (chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2)) { return; } cnv = (mod * dutyCyclePercent) / 100; cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV; /* For 100% duty cycle */ if (cnv >= mod) { cnv = mod + 1; } base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv; } else { #endif cnv = (mod * dutyCyclePercent) / 100; /* For 100% duty cycle */ if (cnv >= mod) { cnv = mod + 1; } base->CONTROLS[chnlNumber].CnV = cnv; #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE } #endif }
void TPM_SetupOutputCompare(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_output_compare_mode_t compareMode, uint32_t compareValue) { assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL /* Clear quadrature Decoder mode for channel 0 or 1 */ if (chnlNumber == 0 || chnlNumber == 1) { base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; } #endif /* When switching mode, disable channel first */ base->CONTROLS[chnlNumber].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Setup the channel output behaviour when a match occurs with the compare value */ base->CONTROLS[chnlNumber].CnSC |= compareMode; /* Setup the compare value */ base->CONTROLS[chnlNumber].CnV = compareValue; /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } }
void TPM_SetupInputCapture(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_input_capture_edge_t captureMode) { assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)); #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL /* Clear quadrature Decoder mode for channel 0 or 1*/ if (chnlNumber == 0 || chnlNumber == 1) { base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; } #endif #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE /* Clear the combine bit for chnlNumber */ base->COMBINE &= ~(1U << TPM_COMBINE_COMBINE1_SHIFT *(chnlNumber/2)); #endif /* When switching mode, disable channel first */ base->CONTROLS[chnlNumber].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the requested input capture mode */ base->CONTROLS[chnlNumber].CnSC |= captureMode; /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } }
void TPM_SetupDualEdgeCapture(TPM_Type *base, tpm_chnl_t chnlPairNumber, const tpm_dual_edge_capture_param_t *edgeParam, uint32_t filterValue) { assert(edgeParam); assert(chnlPairNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base)/2); uint32_t reg; /* Clear quadrature Decoder mode for channel 0 or 1*/ #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL if (chnlPairNumber == 0) { base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; } #endif /* Unlock: When switching mode, disable channel first */ base->CONTROLS[chnlPairNumber * 2].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlPairNumber * 2].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } base->CONTROLS[chnlPairNumber * 2 + 1].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlPairNumber * 2 + 1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Now, the registers for input mode can be operated. */ if (edgeParam->enableSwap) { /* Set the combine and swap bits for the channel pair */ base->COMBINE |= (TPM_COMBINE_COMBINE0_MASK | TPM_COMBINE_COMSWAP0_MASK) << (TPM_COMBINE_SHIFT * chnlPairNumber); /* Input filter setup for channel n+1 input */ reg = base->FILTER; reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1))); reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1))); base->FILTER = reg; } else { reg = base->COMBINE; /* Clear the swap bit for the channel pair */ reg &= ~(TPM_COMBINE_COMSWAP0_MASK << (TPM_COMBINE_COMSWAP0_SHIFT * chnlPairNumber)); /* Set the combine bit for the channel pair */ reg |= TPM_COMBINE_COMBINE0_MASK << (TPM_COMBINE_SHIFT * chnlPairNumber); base->COMBINE = reg; /* Input filter setup for channel n input */ reg = base->FILTER; reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber)); reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber)); base->FILTER = reg; } /* Setup the edge detection from channel n */ base->CONTROLS[chnlPairNumber * 2].CnSC |= edgeParam->currChanEdgeMode; /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[chnlPairNumber * 2].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Setup the edge detection from channel n+1 */ base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC |= edgeParam->nextChanEdgeMode; /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } }
status_t TPM_SetupPwm(TPM_Type *base, const tpm_chnl_pwm_signal_param_t *chnlParams, uint8_t numOfChnls, tpm_pwm_mode_t mode, uint32_t pwmFreq_Hz, uint32_t srcClock_Hz) { assert(chnlParams); assert(pwmFreq_Hz); assert(numOfChnls); assert(srcClock_Hz); uint32_t mod; uint32_t tpmClock = (srcClock_Hz / (1U << (base->SC & TPM_SC_PS_MASK))); uint16_t cnv; uint8_t i; #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL /* Clear quadrature Decoder mode because in quadrature Decoder mode PWM doesn't operate*/ base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK; #endif switch (mode) { case kTPM_EdgeAlignedPwm: #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE case kTPM_CombinedPwm: #endif base->SC &= ~TPM_SC_CPWMS_MASK; mod = (tpmClock / pwmFreq_Hz) - 1; break; case kTPM_CenterAlignedPwm: base->SC |= TPM_SC_CPWMS_MASK; mod = tpmClock / (pwmFreq_Hz * 2); break; default: return kStatus_Fail; } /* Return an error in case we overflow the registers, probably would require changing * clock source to get the desired frequency */ if (mod > 65535U) { return kStatus_Fail; } /* Set the PWM period */ base->MOD = mod; /* Setup each TPM channel */ for (i = 0; i < numOfChnls; i++) { /* Return error if requested dutycycle is greater than the max allowed */ if (chnlParams->dutyCyclePercent > 100) { return kStatus_Fail; } #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE if (mode == kTPM_CombinedPwm) { uint16_t cnvFirstEdge; /* This check is added for combined mode as the channel number should be the pair number */ if (chnlParams->chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2)) { return kStatus_Fail; } /* Return error if requested value is greater than the max allowed */ if (chnlParams->firstEdgeDelayPercent > 100) { return kStatus_Fail; } /* Configure delay of the first edge */ if (chnlParams->firstEdgeDelayPercent == 0) { /* No delay for the first edge */ cnvFirstEdge = 0; } else { cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100; } /* Configure dutycycle */ if (chnlParams->dutyCyclePercent == 0) { /* Signal stays low */ cnv = 0; cnvFirstEdge = 0; } else { cnv = (mod * chnlParams->dutyCyclePercent) / 100; /* For 100% duty cycle */ if (cnv >= mod) { cnv = mod + 1; } } /* Set the combine bit for the channel pair */ base->COMBINE |= (1U << (TPM_COMBINE_COMBINE0_SHIFT + (TPM_COMBINE_SHIFT * chnlParams->chnlNumber))); /* When switching mode, disable channel n first */ base->CONTROLS[chnlParams->chnlNumber * 2].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlParams->chnlNumber * 2].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the requested PWM mode for channel n, PWM output requires mode select to be set to 2 */ base->CONTROLS[chnlParams->chnlNumber * 2].CnSC |= ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[chnlParams->chnlNumber * 2].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the channel pair values */ base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge; /* When switching mode, disable channel n + 1 first */ base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the requested PWM mode for channel n + 1, PWM output requires mode select to be set to 2 */ base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC |= ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the channel pair values */ base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv; } else { #endif if (chnlParams->dutyCyclePercent == 0) { /* Signal stays low */ cnv = 0; } else { cnv = (mod * chnlParams->dutyCyclePercent) / 100; /* For 100% duty cycle */ if (cnv >= mod) { cnv = mod + 1; } } /* When switching mode, disable channel first */ base->CONTROLS[chnlParams->chnlNumber].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK); /* Wait till mode change to disable channel is acknowledged */ while ((base->CONTROLS[chnlParams->chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } /* Set the requested PWM mode, PWM output requires mode select to be set to 2 */ base->CONTROLS[chnlParams->chnlNumber].CnSC |= ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT)); /* Wait till mode change is acknowledged */ while (!(base->CONTROLS[chnlParams->chnlNumber].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK))) { } base->CONTROLS[chnlParams->chnlNumber].CnV = cnv; #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE } #endif chnlParams++; } return kStatus_Success; }
/*FUNCTION********************************************************************** * * Function Name : SMARTCARD_DRV_InterfaceClockInit * Description : This function initializes clock module used for card clock generation * *END**************************************************************************/ static uint16_t SMARTCARD_DRV_InterfaceClockInit(uint8_t clockModuleInstance, uint8_t clockModuleChannel, uint32_t cardClk) { #if defined(EMVSIM_INSTANCE_COUNT) assert(clockModuleInstance < EMVSIM_INSTANCE_COUNT); EMVSIM_Type * base = g_emvsimBase[clockModuleInstance]; uint32_t emvsimClkMhz = 0; uint8_t emvsimPRSCValue; /* Retrieve EMV SIM clock */ emvsimClkMhz = CLOCK_SYS_GetEmvsimFreq(clockModuleInstance)/1000000; /* Calculate MOD value */ emvsimPRSCValue = (emvsimClkMhz*1000)/(cardClk/1000); /* Set clock prescaler */ EMVSIM_HAL_SetClockPrescaler(base, emvsimPRSCValue); /* Enable smart card clock */ EMVSIM_HAL_EnableCardClock(base); return cardClk; #elif defined(FTM_INSTANCE_COUNT) assert(clockModuleInstance < FTM_INSTANCE_COUNT); ftm_user_config_t ftmInfo; uint32_t periph_clk_mhz = 0; uint16_t ftmModValue; FTM_Type * ftmBase = g_ftmBase[clockModuleInstance]; uint32_t chnlPairnum = FTM_HAL_GetChnPairIndex(clockModuleChannel); /* Retrieve FTM system clock */ periph_clk_mhz = CLOCK_SYS_GetBusClockFreq()/1000000; /* Calculate MOD value */ ftmModValue = ((periph_clk_mhz*1000/2)/(cardClk/1000)) -1; /* Clear FTM driver user configuration */ memset(&ftmInfo, 0, sizeof(ftmInfo)); ftmInfo.BDMMode = kFtmBdmMode_11; ftmInfo.syncMethod = kFtmUseSoftwareTrig; /* Initialize FTM driver */ FTM_DRV_Init(clockModuleInstance, &ftmInfo); /* Reset FTM prescaler to 'Divide by 1', i.e., to be same clock as peripheral clock */ FTM_HAL_SetClockPs(ftmBase, kFtmDividedBy1); /* Disable FTM counter firstly */ FTM_HAL_SetClockSource(ftmBase, kClock_source_FTM_None); /* Set initial counter value */ FTM_HAL_SetCounterInitVal(ftmBase, 0); /* Set MOD value */ FTM_HAL_SetMod(ftmBase, ftmModValue); /* Other initializations to defaults */ FTM_HAL_SetCpwms(ftmBase, 0); FTM_HAL_SetDualChnCombineCmd(ftmBase, chnlPairnum, false); FTM_HAL_SetDualEdgeCaptureCmd(ftmBase, chnlPairnum, false); /* Configure mode to output compare, tougle output on match */ FTM_HAL_SetChnEdgeLevel(ftmBase, clockModuleChannel, kFtmToggleOnMatch); FTM_HAL_SetChnMSnBAMode(ftmBase, clockModuleChannel, 1); /* Configure a match value to toggle output at */ FTM_HAL_SetChnCountVal(ftmBase, clockModuleChannel, 1); /* Set clock source to start the counter */ FTM_HAL_SetClockSource(ftmBase, kClock_source_FTM_SystemClk); /* Re-calculate the actually configured smartcard clock and return to caller */ return (uint32_t)(((periph_clk_mhz*1000/2)/(FTM_HAL_GetMod(ftmBase)+1))*1000); #elif defined(TPM_INSTANCE_COUNT) assert(clockModuleInstance < TPM_INSTANCE_COUNT); assert(clockModuleChannel < FSL_FEATURE_TPM_CHANNEL_COUNTn(clockModuleInstance)); /* Initialize TPM driver parameter */ tpm_pwm_param_t param = { kTpmCenterAlignedPWM, /* mode */ kTpmHighTrue, /* edgeMode */ cardClk, /* uFrequencyHZ */ 50 /* uDutyCyclePercent */ }; /* Initialize TPM driver */ tpm_general_config_t driverInfo; memset(&driverInfo, 0, sizeof(driverInfo)); driverInfo.isDBGMode = true; TPM_DRV_Init(clockModuleInstance, &driverInfo); /* Set TPM clock source, the user will have to call the Clocking API's to set the * TPM module clock before calling this function */ TPM_DRV_SetClock(clockModuleInstance, kTpmClockSourceModuleClk, kTpmDividedBy1); /* Start TPM in PWM mode to generate smart card clock */ TPM_DRV_PwmStart(clockModuleInstance, ¶m, clockModuleChannel); return cardClk; #else return 0; #endif }