/* * Copyright 2017-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_qtmr.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.qtmr" #endif /******************************************************************************* * Prototypes ******************************************************************************/ /*! * @brief Gets the instance from the base address to be used to gate or ungate the module clock * * @param base Quad Timer peripheral base address * * @return The Quad Timer instance */ static uint32_t QTMR_GetInstance(TMR_Type *base); /******************************************************************************* * Variables ******************************************************************************/ /*! @brief Pointers to Quad Timer bases for each instance. */ static TMR_Type *const s_qtmrBases[] = TMR_BASE_PTRS; #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to Quad Timer clocks for each instance. */ static const clock_ip_name_t s_qtmrClocks[] = TMR_CLOCKS; #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /******************************************************************************* * Code ******************************************************************************/ static uint32_t QTMR_GetInstance(TMR_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ for (instance = 0; instance < ARRAY_SIZE(s_qtmrBases); instance++) { if (s_qtmrBases[instance] == base) { break; } } assert(instance < ARRAY_SIZE(s_qtmrBases)); return instance; } /*! * brief Ungates the Quad Timer clock and configures the peripheral for basic operation. * * note This API should be called at the beginning of the application using the Quad Timer driver. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param config Pointer to user's Quad Timer config structure */ void QTMR_Init(TMR_Type *base, qtmr_channel_selection_t channel, const qtmr_config_t *config) { assert(NULL != config); #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable the module clock */ CLOCK_EnableClock(s_qtmrClocks[QTMR_GetInstance(base)]); #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /* Setup the counter sources */ base->CHANNEL[channel].CTRL = (TMR_CTRL_PCS(config->primarySource) | TMR_CTRL_SCS(config->secondarySource)); /* Setup the master mode operation */ base->CHANNEL[channel].SCTRL = (TMR_SCTRL_EEOF(config->enableExternalForce) | TMR_SCTRL_MSTR(config->enableMasterMode)); /* Setup debug mode */ base->CHANNEL[channel].CSCTRL = TMR_CSCTRL_DBG_EN(config->debugMode); base->CHANNEL[channel].FILT &= (uint16_t)(~(TMR_FILT_FILT_CNT_MASK | TMR_FILT_FILT_PER_MASK)); /* Setup input filter */ base->CHANNEL[channel].FILT = (TMR_FILT_FILT_CNT(config->faultFilterCount) | TMR_FILT_FILT_PER(config->faultFilterPeriod)); } /*! * brief Stops the counter and gates the Quad Timer clock * * param base Quad Timer peripheral base address * param channel Quad Timer channel number */ void QTMR_Deinit(TMR_Type *base, qtmr_channel_selection_t channel) { /* Stop the counter */ base->CHANNEL[channel].CTRL &= (uint16_t)(~TMR_CTRL_CM_MASK); #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable the module clock */ CLOCK_DisableClock(s_qtmrClocks[QTMR_GetInstance(base)]); #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } /*! * brief Fill in the Quad Timer config struct with the default settings * * The default values are: * code * config->debugMode = kQTMR_RunNormalInDebug; * config->enableExternalForce = false; * config->enableMasterMode = false; * config->faultFilterCount = 0; * config->faultFilterPeriod = 0; * config->primarySource = kQTMR_ClockDivide_2; * config->secondarySource = kQTMR_Counter0InputPin; * endcode * param config Pointer to user's Quad Timer config structure. */ void QTMR_GetDefaultConfig(qtmr_config_t *config) { assert(NULL != config); /* Initializes the configure structure to zero. */ (void)memset(config, 0, sizeof(*config)); /* Halt counter during debug mode */ config->debugMode = kQTMR_RunNormalInDebug; /* Another counter cannot force state of OFLAG signal */ config->enableExternalForce = false; /* Compare function's output from this counter is not broadcast to other counters */ config->enableMasterMode = false; /* Fault filter count is set to 0 */ config->faultFilterCount = 0; /* Fault filter period is set to 0 which disables the fault filter */ config->faultFilterPeriod = 0; /* Primary count source is IP bus clock divide by 2 */ config->primarySource = kQTMR_ClockDivide_2; /* Secondary count source is counter 0 input pin */ config->secondarySource = kQTMR_Counter0InputPin; } /*! * brief Sets up Quad timer module for PWM signal output. * * The function initializes the timer module according to the parameters passed in by the user. The * function also sets up the value compare registers to match the PWM signal requirements. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param pwmFreqHz PWM signal frequency in Hz * param dutyCyclePercent PWM pulse width, value should be between 0 to 100 * 0=inactive signal(0% duty cycle)... * 100=active signal (100% duty cycle) * param outputPolarity true: invert polarity of the output signal, false: no inversion * param srcClock_Hz Main counter clock in Hz. * * return Returns an error if there was error setting up the signal. */ status_t QTMR_SetupPwm(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz, uint8_t dutyCyclePercent, bool outputPolarity, uint32_t srcClock_Hz) { uint32_t periodCount, highCount, lowCount; uint16_t reg; status_t status; if (dutyCyclePercent <= 100U) { /* Set OFLAG pin for output mode and force out a low on the pin */ base->CHANNEL[channel].SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK); /* Counter values to generate a PWM signal */ periodCount = srcClock_Hz / pwmFreqHz; highCount = periodCount * dutyCyclePercent / 100U; lowCount = periodCount - highCount; if (highCount > 0U) { highCount -= 1U; } if (lowCount > 0U) { lowCount -= 1U; } /* This should not be a 16-bit overflow value. If it is, change to a larger divider for clock source. */ assert(highCount <= 0xFFFFU); assert(lowCount <= 0xFFFFU); /* Setup the compare registers for PWM output */ base->CHANNEL[channel].COMP1 = (uint16_t)lowCount; base->CHANNEL[channel].COMP2 = (uint16_t)highCount; /* Setup the pre-load registers for PWM output */ base->CHANNEL[channel].CMPLD1 = (uint16_t)lowCount; base->CHANNEL[channel].CMPLD2 = (uint16_t)highCount; reg = base->CHANNEL[channel].CSCTRL; /* Setup the compare load control for COMP1 and COMP2. * Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted */ reg &= (uint16_t)(~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK)); reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1)); base->CHANNEL[channel].CSCTRL = reg; if (outputPolarity) { /* Invert the polarity */ base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK; } else { /* True polarity, no inversion */ base->CHANNEL[channel].SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK; } reg = base->CHANNEL[channel].CTRL; reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK; /* Count until compare value is reached and re-initialize the counter, toggle OFLAG output * using alternating compare register */ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); base->CHANNEL[channel].CTRL = reg; status = kStatus_Success; } else { /* Invalid dutycycle */ status = kStatus_Fail; } return status; } /*! * brief Allows the user to count the source clock cycles until a capture event arrives. * * The count is stored in the capture register. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param capturePin Pin through which we receive the input signal to trigger the capture * param inputPolarity true: invert polarity of the input signal, false: no inversion * param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload * param captureMode Specifies which edge of the input signal triggers a capture */ void QTMR_SetupInputCapture(TMR_Type *base, qtmr_channel_selection_t channel, qtmr_input_source_t capturePin, bool inputPolarity, bool reloadOnCapture, qtmr_input_capture_edge_t captureMode) { uint16_t reg; /* Clear the prior value for the input source for capture */ reg = base->CHANNEL[channel].CTRL & (uint16_t)(~TMR_CTRL_SCS_MASK); /* Set the new input source */ reg |= TMR_CTRL_SCS(capturePin); base->CHANNEL[channel].CTRL = reg; /* Clear the prior values for input polarity, capture mode. Set the external pin as input */ reg = base->CHANNEL[channel].SCTRL & (uint16_t)(~(TMR_SCTRL_IPS_MASK | TMR_SCTRL_CAPTURE_MODE_MASK | TMR_SCTRL_OEN_MASK)); /* Set the new values */ reg |= (TMR_SCTRL_IPS(inputPolarity) | TMR_SCTRL_CAPTURE_MODE(captureMode)); base->CHANNEL[channel].SCTRL = reg; /* Setup if counter should reload when a capture occurs */ if (reloadOnCapture) { base->CHANNEL[channel].CSCTRL |= TMR_CSCTRL_ROC_MASK; } else { base->CHANNEL[channel].CSCTRL &= (uint16_t)(~TMR_CSCTRL_ROC_MASK); } } /*! * brief Enables the selected Quad Timer interrupts * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param mask The interrupts to enable. This is a logical OR of members of the * enumeration ::qtmr_interrupt_enable_t */ void QTMR_EnableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask) { uint16_t reg; reg = base->CHANNEL[channel].SCTRL; /* Compare interrupt */ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL) { reg |= TMR_SCTRL_TCFIE_MASK; } /* Overflow interrupt */ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL) { reg |= TMR_SCTRL_TOFIE_MASK; } /* Input edge interrupt */ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL) { /* Restriction: Do not set both SCTRL[IEFIE] and DMA[IEFDE] */ base->CHANNEL[channel].DMA &= ~(uint16_t)TMR_DMA_IEFDE_MASK; reg |= TMR_SCTRL_IEFIE_MASK; } base->CHANNEL[channel].SCTRL = reg; reg = base->CHANNEL[channel].CSCTRL; /* Compare 1 interrupt */ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL) { reg |= TMR_CSCTRL_TCF1EN_MASK; } /* Compare 2 interrupt */ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL) { reg |= TMR_CSCTRL_TCF2EN_MASK; } base->CHANNEL[channel].CSCTRL = reg; } /*! * brief Disables the selected Quad Timer interrupts * * param base Quad Timer peripheral base addres * param channel Quad Timer channel number * param mask The interrupts to enable. This is a logical OR of members of the * enumeration ::qtmr_interrupt_enable_t */ void QTMR_DisableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask) { uint16_t reg; reg = base->CHANNEL[channel].SCTRL; /* Compare interrupt */ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL) { reg &= (uint16_t)(~TMR_SCTRL_TCFIE_MASK); } /* Overflow interrupt */ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL) { reg &= (uint16_t)(~TMR_SCTRL_TOFIE_MASK); } /* Input edge interrupt */ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL) { reg &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK); } base->CHANNEL[channel].SCTRL = reg; reg = base->CHANNEL[channel].CSCTRL; /* Compare 1 interrupt */ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL) { reg &= ~(uint16_t)TMR_CSCTRL_TCF1EN_MASK; } /* Compare 2 interrupt */ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL) { reg &= ~(uint16_t)TMR_CSCTRL_TCF2EN_MASK; } base->CHANNEL[channel].CSCTRL = reg; } /*! * brief Gets the enabled Quad Timer interrupts * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * * return The enabled interrupts. This is the logical OR of members of the * enumeration ::qtmr_interrupt_enable_t */ uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base, qtmr_channel_selection_t channel) { uint32_t enabledInterrupts = 0; uint16_t reg; reg = base->CHANNEL[channel].SCTRL; /* Compare interrupt */ if ((reg & TMR_SCTRL_TCFIE_MASK) != 0U) { enabledInterrupts |= (uint32_t)kQTMR_CompareFlag; } /* Overflow interrupt */ if ((reg & TMR_SCTRL_TOFIE_MASK) != 0U) { enabledInterrupts |= (uint32_t)kQTMR_OverflowInterruptEnable; } /* Input edge interrupt */ if ((reg & TMR_SCTRL_IEFIE_MASK) != 0U) { enabledInterrupts |= (uint32_t)kQTMR_EdgeInterruptEnable; } reg = base->CHANNEL[channel].CSCTRL; /* Compare 1 interrupt */ if ((reg & TMR_CSCTRL_TCF1EN_MASK) != 0U) { enabledInterrupts |= (uint32_t)kQTMR_Compare1InterruptEnable; } /* Compare 2 interrupt */ if ((reg & TMR_CSCTRL_TCF2EN_MASK) != 0U) { enabledInterrupts |= (uint32_t)kQTMR_Compare2InterruptEnable; } return enabledInterrupts; } /*! * brief Gets the Quad Timer status flags * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * * return The status flags. This is the logical OR of members of the * enumeration ::qtmr_status_flags_t */ uint32_t QTMR_GetStatus(TMR_Type *base, qtmr_channel_selection_t channel) { uint32_t statusFlags = 0; uint16_t reg; reg = base->CHANNEL[channel].SCTRL; /* Timer compare flag */ if ((reg & TMR_SCTRL_TCF_MASK) != 0U) { statusFlags |= (uint32_t)kQTMR_CompareFlag; } /* Timer overflow flag */ if ((reg & TMR_SCTRL_TOF_MASK) != 0U) { statusFlags |= (uint32_t)kQTMR_OverflowFlag; } /* Input edge flag */ if ((reg & TMR_SCTRL_IEF_MASK) != 0U) { statusFlags |= (uint32_t)kQTMR_EdgeFlag; } reg = base->CHANNEL[channel].CSCTRL; /* Compare 1 flag */ if ((reg & TMR_CSCTRL_TCF1_MASK) != 0U) { statusFlags |= (uint32_t)kQTMR_Compare1Flag; } /* Compare 2 flag */ if ((reg & TMR_CSCTRL_TCF2_MASK) != 0U) { statusFlags |= (uint32_t)kQTMR_Compare2Flag; } return statusFlags; } /*! * brief Clears the Quad Timer status flags. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param mask The status flags to clear. This is a logical OR of members of the * enumeration ::qtmr_status_flags_t */ void QTMR_ClearStatusFlags(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask) { uint16_t reg; reg = base->CHANNEL[channel].SCTRL; /* Timer compare flag */ if ((mask & (uint32_t)kQTMR_CompareFlag) != 0U) { reg &= (uint16_t)(~TMR_SCTRL_TCF_MASK); } /* Timer overflow flag */ if ((mask & (uint32_t)kQTMR_OverflowFlag) != 0U) { reg &= (uint16_t)(~TMR_SCTRL_TOF_MASK); } /* Input edge flag */ if ((mask & (uint32_t)kQTMR_EdgeFlag) != 0U) { reg &= (uint16_t)(~TMR_SCTRL_IEF_MASK); } base->CHANNEL[channel].SCTRL = reg; reg = base->CHANNEL[channel].CSCTRL; /* Compare 1 flag */ if ((mask & (uint32_t)kQTMR_Compare1Flag) != 0U) { reg &= ~(uint16_t)TMR_CSCTRL_TCF1_MASK; } /* Compare 2 flag */ if ((mask & (uint32_t)kQTMR_Compare2Flag) != 0U) { reg &= ~(uint16_t)TMR_CSCTRL_TCF2_MASK; } base->CHANNEL[channel].CSCTRL = reg; } /*! * brief Sets the timer period in ticks. * * Timers counts from initial value till it equals the count value set here. The counter * will then reinitialize to the value specified in the Load register. * * note * 1. This function will write the time period in ticks to COMP1 or COMP2 register * depending on the count direction * 2. User can call the utility macros provided in fsl_common.h to convert to ticks * 3. This function supports cases, providing only primary source clock without secondary source clock. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param ticks Timer period in units of ticks */ void QTMR_SetTimerPeriod(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks) { /* Set the length bit to reinitialize the counters on a match */ base->CHANNEL[channel].CTRL |= TMR_CTRL_LENGTH_MASK; if ((base->CHANNEL[channel].CTRL & TMR_CTRL_DIR_MASK) != 0U) { /* Counting down */ base->CHANNEL[channel].COMP2 = ticks; } else { /* Counting up */ base->CHANNEL[channel].COMP1 = ticks; } } /*! * brief Enable the Quad Timer DMA. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param mask The DMA to enable. This is a logical OR of members of the * enumeration ::qtmr_dma_enable_t */ void QTMR_EnableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask) { uint16_t reg; reg = base->CHANNEL[channel].DMA; /* Input Edge Flag DMA Enable */ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U) { /* Restriction: Do not set both DMA[IEFDE] and SCTRL[IEFIE] */ base->CHANNEL[channel].SCTRL &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK); reg |= TMR_DMA_IEFDE_MASK; } /* Comparator Preload Register 1 DMA Enable */ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U) { reg |= TMR_DMA_CMPLD1DE_MASK; } /* Comparator Preload Register 2 DMA Enable */ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U) { reg |= TMR_DMA_CMPLD2DE_MASK; } base->CHANNEL[channel].DMA = reg; } /*! * brief Disable the Quad Timer DMA. * * param base Quad Timer peripheral base address * param channel Quad Timer channel number * param mask The DMA to enable. This is a logical OR of members of the * enumeration ::qtmr_dma_enable_t */ void QTMR_DisableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask) { uint16_t reg; reg = base->CHANNEL[channel].DMA; /* Input Edge Flag DMA Enable */ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U) { reg &= ~(uint16_t)TMR_DMA_IEFDE_MASK; } /* Comparator Preload Register 1 DMA Enable */ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U) { reg &= ~(uint16_t)TMR_DMA_CMPLD1DE_MASK; } /* Comparator Preload Register 2 DMA Enable */ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U) { reg &= ~(uint16_t)TMR_DMA_CMPLD2DE_MASK; } base->CHANNEL[channel].DMA = reg; }