/***************************************************************************//** * @file * @brief Timer/counter (TIMER) peripheral API ******************************************************************************* * # License * Copyright 2018 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #ifndef EM_TIMER_H #define EM_TIMER_H #include "em_device.h" #if defined(TIMER_COUNT) && (TIMER_COUNT > 0) #include #include "sl_assert.h" #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * @addtogroup timer * @{ ****************************************************************************** * @deprecated * Deprecated macro TIMER_CH_VALID for SDID 80, new code should use TIMER_REF_CH_VALID.*/ /******************************************************************************* ******************************* DEFINES *********************************** ******************************************************************************/ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /** Validation of TIMER register block pointer reference for assert statements. */ #define TIMER_REF_VALID(ref) TIMER_Valid(ref) /** Validation of TIMER compare/capture channel number. */ #if defined(_SILICON_LABS_32B_SERIES_0) #define TIMER_CH_VALID(ch) ((ch) < 3) #elif defined(_SILICON_LABS_32B_SERIES_1) #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) #define TIMER_CH_VALID(ch) _Pragma("GCC warning \"'TIMER_CH_VALID' macro is deprecated for EFR32xG1, Use TIMER_REF_CH_VALID instead\"") ((ch) < 4) #else #define TIMER_CH_VALID(ch) ((ch) < 4) #endif #elif defined(_SILICON_LABS_32B_SERIES_2) #define TIMER_CH_VALID(ch) ((ch) < 3) #else #error "Unknown device. Undefined number of channels." #endif #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) #define TIMER_REF_CH_VALID(ref, ch) ((ref == TIMER0) ? ((ch) < 3) : ((ch) < 4)) #define TIMER_REF_CH_VALIDATE(ref, ch) TIMER_REF_CH_VALID(ref, ch) #else #define TIMER_REF_CH_VALIDATE(ref, ch) TIMER_CH_VALID(ch) #endif /** @endcond */ /******************************************************************************* ******************************** ENUMS ************************************ ******************************************************************************/ /** Timer compare/capture mode. */ typedef enum { #if defined (_TIMER_CC_CTRL_MODE_MASK) timerCCModeOff = _TIMER_CC_CTRL_MODE_OFF, /**< Channel turned off. */ timerCCModeCapture = _TIMER_CC_CTRL_MODE_INPUTCAPTURE, /**< Input capture. */ timerCCModeCompare = _TIMER_CC_CTRL_MODE_OUTPUTCOMPARE, /**< Output compare. */ timerCCModePWM = _TIMER_CC_CTRL_MODE_PWM /**< Pulse-Width modulation. */ #endif #if defined (_TIMER_CC_CFG_MODE_MASK) timerCCModeOff = _TIMER_CC_CFG_MODE_OFF, /**< Channel turned off. */ timerCCModeCapture = _TIMER_CC_CFG_MODE_INPUTCAPTURE, /**< Input capture. */ timerCCModeCompare = _TIMER_CC_CFG_MODE_OUTPUTCOMPARE, /**< Output compare. */ timerCCModePWM = _TIMER_CC_CFG_MODE_PWM /**< Pulse-Width modulation. */ #endif } TIMER_CCMode_TypeDef; /** Clock select. */ typedef enum { #if defined (_TIMER_CTRL_CLKSEL_MASK) timerClkSelHFPerClk = _TIMER_CTRL_CLKSEL_PRESCHFPERCLK, /**< Prescaled HFPER / HFPERB clock. */ timerClkSelCC1 = _TIMER_CTRL_CLKSEL_CC1, /**< Compare/Capture Channel 1 Input. */ timerClkSelCascade = _TIMER_CTRL_CLKSEL_TIMEROUF /**< Cascaded clocked by underflow or overflow by lower numbered timer. */ #endif #if defined (_TIMER_CFG_CLKSEL_MASK) timerClkSelHFPerClk = _TIMER_CFG_CLKSEL_PRESCEM01GRPACLK, /**< Prescaled EM01GRPA clock. */ timerClkSelCC1 = _TIMER_CFG_CLKSEL_CC1, /**< Compare/Capture Channel 1 Input. */ timerClkSelCascade = _TIMER_CFG_CLKSEL_TIMEROUF /**< Cascaded clocked by underflow or overflow by lower numbered timer. */ #endif } TIMER_ClkSel_TypeDef; /** Input capture edge select. */ typedef enum { /** Rising edges detected. */ timerEdgeRising = _TIMER_CC_CTRL_ICEDGE_RISING, /** Falling edges detected. */ timerEdgeFalling = _TIMER_CC_CTRL_ICEDGE_FALLING, /** Both edges detected. */ timerEdgeBoth = _TIMER_CC_CTRL_ICEDGE_BOTH, /** No edge detection, leave signal as is. */ timerEdgeNone = _TIMER_CC_CTRL_ICEDGE_NONE } TIMER_Edge_TypeDef; /** Input capture event control. */ typedef enum { /** PRS output pulse, interrupt flag, and DMA request set on every capture. */ timerEventEveryEdge = _TIMER_CC_CTRL_ICEVCTRL_EVERYEDGE, /** PRS output pulse, interrupt flag, and DMA request set on every second capture. */ timerEventEvery2ndEdge = _TIMER_CC_CTRL_ICEVCTRL_EVERYSECONDEDGE, /** * PRS output pulse, interrupt flag, and DMA request set on rising edge (if * input capture edge = BOTH). */ timerEventRising = _TIMER_CC_CTRL_ICEVCTRL_RISING, /** * PRS output pulse, interrupt flag, and DMA request set on falling edge (if * input capture edge = BOTH). */ timerEventFalling = _TIMER_CC_CTRL_ICEVCTRL_FALLING } TIMER_Event_TypeDef; /** Input edge action. */ typedef enum { /** No action taken. */ timerInputActionNone = _TIMER_CTRL_FALLA_NONE, /** Start counter without reload. */ timerInputActionStart = _TIMER_CTRL_FALLA_START, /** Stop counter without reload. */ timerInputActionStop = _TIMER_CTRL_FALLA_STOP, /** Reload and start counter. */ timerInputActionReloadStart = _TIMER_CTRL_FALLA_RELOADSTART } TIMER_InputAction_TypeDef; /** Timer mode. */ typedef enum { #if defined (_TIMER_CTRL_MODE_MASK) timerModeUp = _TIMER_CTRL_MODE_UP, /**< Up-counting. */ timerModeDown = _TIMER_CTRL_MODE_DOWN, /**< Down-counting. */ timerModeUpDown = _TIMER_CTRL_MODE_UPDOWN, /**< Up/down-counting. */ timerModeQDec = _TIMER_CTRL_MODE_QDEC /**< Quadrature decoder. */ #endif #if defined (_TIMER_CFG_MODE_MASK) timerModeUp = _TIMER_CFG_MODE_UP, /**< Up-counting. */ timerModeDown = _TIMER_CFG_MODE_DOWN, /**< Down-counting. */ timerModeUpDown = _TIMER_CFG_MODE_UPDOWN, /**< Up/down-counting. */ timerModeQDec = _TIMER_CFG_MODE_QDEC /**< Quadrature decoder. */ #endif } TIMER_Mode_TypeDef; /** Compare/capture output action. */ typedef enum { /** No action. */ timerOutputActionNone = _TIMER_CC_CTRL_CUFOA_NONE, /** Toggle on event. */ timerOutputActionToggle = _TIMER_CC_CTRL_CUFOA_TOGGLE, /** Clear on event. */ timerOutputActionClear = _TIMER_CC_CTRL_CUFOA_CLEAR, /** Set on event. */ timerOutputActionSet = _TIMER_CC_CTRL_CUFOA_SET } TIMER_OutputAction_TypeDef; /** Prescaler. */ typedef enum { #if defined (_TIMER_CTRL_PRESC_MASK) timerPrescale1 = _TIMER_CTRL_PRESC_DIV1, /**< Divide by 1. */ timerPrescale2 = _TIMER_CTRL_PRESC_DIV2, /**< Divide by 2. */ timerPrescale4 = _TIMER_CTRL_PRESC_DIV4, /**< Divide by 4. */ timerPrescale8 = _TIMER_CTRL_PRESC_DIV8, /**< Divide by 8. */ timerPrescale16 = _TIMER_CTRL_PRESC_DIV16, /**< Divide by 16. */ timerPrescale32 = _TIMER_CTRL_PRESC_DIV32, /**< Divide by 32. */ timerPrescale64 = _TIMER_CTRL_PRESC_DIV64, /**< Divide by 64. */ timerPrescale128 = _TIMER_CTRL_PRESC_DIV128, /**< Divide by 128. */ timerPrescale256 = _TIMER_CTRL_PRESC_DIV256, /**< Divide by 256. */ timerPrescale512 = _TIMER_CTRL_PRESC_DIV512, /**< Divide by 512. */ timerPrescale1024 = _TIMER_CTRL_PRESC_DIV1024 /**< Divide by 1024. */ #endif #if defined (_TIMER_CFG_PRESC_MASK) timerPrescale1 = _TIMER_CFG_PRESC_DIV1, /**< Divide by 1. */ timerPrescale2 = _TIMER_CFG_PRESC_DIV2, /**< Divide by 2. */ timerPrescale4 = _TIMER_CFG_PRESC_DIV4, /**< Divide by 4. */ timerPrescale8 = _TIMER_CFG_PRESC_DIV8, /**< Divide by 8. */ timerPrescale16 = _TIMER_CFG_PRESC_DIV16, /**< Divide by 16. */ timerPrescale32 = _TIMER_CFG_PRESC_DIV32, /**< Divide by 32. */ timerPrescale64 = _TIMER_CFG_PRESC_DIV64, /**< Divide by 64. */ timerPrescale128 = _TIMER_CFG_PRESC_DIV128, /**< Divide by 128. */ timerPrescale256 = _TIMER_CFG_PRESC_DIV256, /**< Divide by 256. */ timerPrescale512 = _TIMER_CFG_PRESC_DIV512, /**< Divide by 512. */ timerPrescale1024 = _TIMER_CFG_PRESC_DIV1024 /**< Divide by 1024. */ #endif } TIMER_Prescale_TypeDef; /** Peripheral Reflex System signal. */ typedef uint8_t TIMER_PRSSEL_TypeDef; /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /** Deprecated PRS channel selector. New code should use an integer instead of * using these deprecated enum values. */ #define timerPRSSELCh0 0UL #define timerPRSSELCh1 1UL #define timerPRSSELCh2 2UL #define timerPRSSELCh3 3UL #define timerPRSSELCh4 4UL #define timerPRSSELCh5 5UL #define timerPRSSELCh6 6UL #define timerPRSSELCh7 7UL #define timerPRSSELCh8 8UL #define timerPRSSELCh9 9UL #define timerPRSSELCh10 10UL #define timerPRSSELCh11 11UL /** @endcond */ #if defined (_TIMER_CC_CFG_INSEL_MASK) /** PRS input type */ typedef enum { timerPrsInputNone = 0x0, /**< No PRS input. */ timerPrsInputSync = _TIMER_CC_CFG_INSEL_PRSSYNC, /**< Synchronous PRS selected. */ timerPrsInputAsyncLevel = _TIMER_CC_CFG_INSEL_PRSASYNCLEVEL, /**< Asynchronous level PRS selected. */ timerPrsInputAsyncPulse = _TIMER_CC_CFG_INSEL_PRSASYNCPULSE, /**< Asynchronous pulse PRS selected. */ } TIMER_PrsInput_TypeDef; #endif #if defined(_TIMER_DTFC_DTFA_MASK) || defined(_TIMER_DTFCFG_DTFA_MASK) /** DT (Dead Time) Fault Actions. */ typedef enum { #if defined(_TIMER_DTFC_DTFA_MASK) timerDtiFaultActionNone = _TIMER_DTFC_DTFA_NONE, /**< No action on fault. */ timerDtiFaultActionInactive = _TIMER_DTFC_DTFA_INACTIVE, /**< Set outputs inactive. */ timerDtiFaultActionClear = _TIMER_DTFC_DTFA_CLEAR, /**< Clear outputs. */ timerDtiFaultActionTristate = _TIMER_DTFC_DTFA_TRISTATE /**< Tristate outputs. */ #endif #if defined(_TIMER_DTFCFG_DTFA_MASK) timerDtiFaultActionNone = _TIMER_DTFCFG_DTFA_NONE, /**< No action on fault. */ timerDtiFaultActionInactive = _TIMER_DTFCFG_DTFA_INACTIVE, /**< Set outputs inactive. */ timerDtiFaultActionClear = _TIMER_DTFCFG_DTFA_CLEAR, /**< Clear outputs. */ timerDtiFaultActionTristate = _TIMER_DTFCFG_DTFA_TRISTATE /**< Tristate outputs. */ #endif } TIMER_DtiFaultAction_TypeDef; #endif /******************************************************************************* ******************************* STRUCTS *********************************** ******************************************************************************/ /** TIMER initialization structure. */ typedef struct { /** Start counting when initialization completed. */ bool enable; /** Counter shall keep running during debug halt. */ bool debugRun; /** Prescaling factor, if HFPER / HFPERB clock used. */ TIMER_Prescale_TypeDef prescale; /** Clock selection. */ TIMER_ClkSel_TypeDef clkSel; #if defined(TIMER_CTRL_X2CNT) && (defined(TIMER_CTRL_ATI) || defined(TIMER_CFG_ATI)) /** 2x Count mode, counter increments/decrements by 2, meant for PWM mode. */ bool count2x; /** ATI (Always Track Inputs) makes CCPOL always track * the polarity of the inputs. */ bool ati; #endif /** Action on falling input edge. */ TIMER_InputAction_TypeDef fallAction; /** Action on rising input edge. */ TIMER_InputAction_TypeDef riseAction; /** Counting mode. */ TIMER_Mode_TypeDef mode; /** DMA request clear on active. */ bool dmaClrAct; /** Select X2 or X4 quadrature decode mode (if used). */ bool quadModeX4; /** Determines if only counting up or down once. */ bool oneShot; /** Timer start/stop/reload by other timers. */ bool sync; } TIMER_Init_TypeDef; /** Default configuration for TIMER initialization structure. */ #if defined(TIMER_CTRL_X2CNT) && (defined(TIMER_CTRL_ATI) || defined(TIMER_CFG_ATI)) #define TIMER_INIT_DEFAULT \ { \ true, /* Enable timer when initialization completes. */ \ false, /* Stop counter during debug halt. */ \ timerPrescale1, /* No prescaling. */ \ timerClkSelHFPerClk, /* Select HFPER / HFPERB clock. */ \ false, /* Not 2x count mode. */ \ false, /* No ATI. */ \ timerInputActionNone, /* No action on falling input edge. */ \ timerInputActionNone, /* No action on rising input edge. */ \ timerModeUp, /* Up-counting. */ \ false, /* Do not clear DMA requests when DMA channel is active. */ \ false, /* Select X2 quadrature decode mode (if used). */ \ false, /* Disable one shot. */ \ false /* Not started/stopped/reloaded by other timers. */ \ } #else #define TIMER_INIT_DEFAULT \ { \ true, /* Enable timer when initialization completes. */ \ false, /* Stop counter during debug halt. */ \ timerPrescale1, /* No prescaling. */ \ timerClkSelHFPerClk, /* Select HFPER / HFPERB clock. */ \ timerInputActionNone, /* No action on falling input edge. */ \ timerInputActionNone, /* No action on rising input edge. */ \ timerModeUp, /* Up-counting. */ \ false, /* Do not clear DMA requests when DMA channel is active. */ \ false, /* Select X2 quadrature decode mode (if used). */ \ false, /* Disable one shot. */ \ false /* Not started/stopped/reloaded by other timers. */ \ } #endif /** PRS Output configuration. */ typedef enum { timerPrsOutputPulse = 0, /**< Pulse PRS output from a channel. */ timerPrsOutputLevel = 1, /**< PRS output follows CC out level. */ timerPrsOutputDefault = timerPrsOutputPulse, /**< Default PRS output behavior. */ } TIMER_PrsOutput_t; /** TIMER compare/capture initialization structure. */ typedef struct { /** Input capture event control. */ TIMER_Event_TypeDef eventCtrl; /** Input capture edge select. */ TIMER_Edge_TypeDef edge; /** * Peripheral reflex system trigger selection. Only applicable if @p prsInput * is enabled. */ TIMER_PRSSEL_TypeDef prsSel; /** Counter underflow output action. */ TIMER_OutputAction_TypeDef cufoa; /** Counter overflow output action. */ TIMER_OutputAction_TypeDef cofoa; /** Counter match output action. */ TIMER_OutputAction_TypeDef cmoa; /** Compare/capture channel mode. */ TIMER_CCMode_TypeDef mode; /** Enable digital filter. */ bool filter; /** Select TIMERnCCx (false) or PRS input (true). */ bool prsInput; /** * Compare output initial state. Only used in Output Compare and PWM mode. * When true, the compare/PWM output is set high when the counter is * disabled. When counting resumes, this value will represent the initial * value for the compare/PWM output. If the bit is cleared, the output * will be cleared when the counter is disabled. */ bool coist; /** Invert output from compare/capture channel. */ bool outInvert; /** * PRS output configuration. PRS output from a timer can either be a * pulse output or a level output that follows the CC out value. */ TIMER_PrsOutput_t prsOutput; #if defined(_TIMER_CC_CFG_INSEL_MASK) /** When PRS input is used this field is used to configure the type of * PRS input. */ TIMER_PrsInput_TypeDef prsInputType; #endif } TIMER_InitCC_TypeDef; /** Default configuration for TIMER compare/capture initialization structure. */ #if defined(_TIMER_CC_CFG_INSEL_MASK) #define TIMER_INITCC_DEFAULT \ { \ timerEventEveryEdge, /* Event on every capture. */ \ timerEdgeRising, /* Input capture edge on rising edge. */ \ 0, /* Not used by default, select PRS channel 0. */ \ timerOutputActionNone, /* No action on underflow. */ \ timerOutputActionNone, /* No action on overflow. */ \ timerOutputActionNone, /* No action on match. */ \ timerCCModeOff, /* Disable compare/capture channel. */ \ false, /* Disable filter. */ \ false, /* No PRS input. */ \ false, /* Clear output when counter disabled. */ \ false, /* Do not invert output. */ \ timerPrsOutputDefault, /* Use default PRS output configuration. */ \ timerPrsInputNone /* No PRS input, so input type is none. */ \ } #else #define TIMER_INITCC_DEFAULT \ { \ timerEventEveryEdge, /* Event on every capture. */ \ timerEdgeRising, /* Input capture edge on rising edge. */ \ 0, /* Not used by default, select PRS channel 0. */ \ timerOutputActionNone, /* No action on underflow. */ \ timerOutputActionNone, /* No action on overflow. */ \ timerOutputActionNone, /* No action on match. */ \ timerCCModeOff, /* Disable compare/capture channel. */ \ false, /* Disable filter. */ \ false, /* No PRS input. */ \ false, /* Clear output when counter disabled. */ \ false, /* Do not invert output. */ \ timerPrsOutputDefault, /* Use default PRS output configuration. */ \ } #endif #if defined(_TIMER_DTCTRL_MASK) /** TIMER Dead Time Insertion (DTI) initialization structure. */ typedef struct { /** Enable DTI or leave it disabled until @ref TIMER_EnableDTI() is called. */ bool enable; /** DTI Output Polarity. */ bool activeLowOut; /** DTI Complementary Output Invert. */ bool invertComplementaryOut; /** Enable Automatic Start-up functionality (when debugger exits). */ bool autoRestart; /** Enable/disable PRS as DTI input. */ bool enablePrsSource; /** Select which PRS channel as DTI input. Only valid if @p enablePrsSource is enabled. */ TIMER_PRSSEL_TypeDef prsSel; /** DTI prescaling factor, if HFPER / HFPERB clock used. */ TIMER_Prescale_TypeDef prescale; /** DTI Rise Time */ unsigned int riseTime; /** DTI Fall Time */ unsigned int fallTime; /** DTI outputs enable bit mask, consisting of one bit per DTI output signal, i.e., CC0, CC1, CC2, CDTI0, CDTI1, and CDTI2. This value should consist of one or more TIMER_DTOGEN_DTOGnnnEN flags (defined in \_timer.h) OR'ed together. */ uint32_t outputsEnableMask; /** Enable core lockup as a fault source. */ bool enableFaultSourceCoreLockup; /** Enable debugger as a fault source. */ bool enableFaultSourceDebugger; /** Enable PRS fault source 0 (@p faultSourcePrsSel0). */ bool enableFaultSourcePrsSel0; /** Select which PRS signal to be PRS fault source 0. */ TIMER_PRSSEL_TypeDef faultSourcePrsSel0; /** Enable PRS fault source 1 (@p faultSourcePrsSel1). */ bool enableFaultSourcePrsSel1; /** Select which PRS signal to be PRS fault source 1. */ TIMER_PRSSEL_TypeDef faultSourcePrsSel1; /** Fault Action */ TIMER_DtiFaultAction_TypeDef faultAction; } TIMER_InitDTI_TypeDef; /** Default configuration for TIMER DTI initialization structure. */ #define TIMER_INITDTI_DEFAULT \ { \ true, /* Enable the DTI. */ \ false, /* CC[0|1|2] outputs are active high. */ \ false, /* CDTI[0|1|2] outputs are not inverted. */ \ false, /* No auto restart when debugger exits. */ \ false, /* No PRS source selected. */ \ 0, /* Not used by default, select PRS channel 0. */ \ timerPrescale1, /* No prescaling. */ \ 0, /* No rise time. */ \ 0, /* No fall time. */ \ TIMER_DTOGEN_DTOGCC0EN | TIMER_DTOGEN_DTOGCDTI0EN, /* Enable CC0 and CDTI0. */ \ true, /* Enable core lockup as fault source. */ \ true, /* Enable debugger as fault source. */ \ false, /* Disable PRS fault source 0. */ \ 0, /* Not used by default, select PRS channel 0. */ \ false, /* Disable PRS fault source 1. */ \ 0, /* Not used by default, select PRS channel 0. */ \ timerDtiFaultActionInactive, /* No fault action. */ \ } #endif /* _TIMER_DTCTRL_MASK */ /******************************************************************************* ***************************** PROTOTYPES ********************************** ******************************************************************************/ #if defined(TIMER_STATUS_SYNCBUSY) void TIMER_SyncWait(TIMER_TypeDef * timer); #endif /***************************************************************************//** * @brief * Validate the TIMER register block pointer. * * @param[in] ref * Pointer to the TIMER peripheral register block. * * @return * True if ref points to a valid timer, false otherwise. ******************************************************************************/ __STATIC_INLINE bool TIMER_Valid(const TIMER_TypeDef *ref) { return (ref == TIMER0) #if defined(TIMER1) || (ref == TIMER1) #endif #if defined(TIMER2) || (ref == TIMER2) #endif #if defined(TIMER3) || (ref == TIMER3) #endif #if defined(TIMER4) || (ref == TIMER4) #endif #if defined(TIMER5) || (ref == TIMER5) #endif #if defined(TIMER6) || (ref == TIMER6) #endif #if defined(TIMER7) || (ref == TIMER7) #endif #if defined(WTIMER0) || (ref == WTIMER0) #endif #if defined(WTIMER1) || (ref == WTIMER1) #endif #if defined(WTIMER2) || (ref == WTIMER2) #endif #if defined(WTIMER3) || (ref == WTIMER3) #endif ; } /***************************************************************************//** * @brief * Check whether the TIMER is valid and supports Dead Timer Insertion (DTI). * * @param[in] ref * Pointer to the TIMER peripheral register block. * * @return * True if ref points to a valid timer that supports DTI, false otherwise. ******************************************************************************/ __STATIC_INLINE bool TIMER_SupportsDTI(const TIMER_TypeDef *ref) { (void) ref; return 0 #if defined(TIMER0_DTI) #if (TIMER0_DTI == 1) || (ref == TIMER0) #endif #elif defined(_TIMER_DTCTRL_MASK) || (ref == TIMER0) #endif #if defined(TIMER1_DTI) && (TIMER1_DTI == 1) || (ref == TIMER1) #endif #if defined(TIMER2_DTI) && (TIMER2_DTI == 1) || (ref == TIMER2) #endif #if defined(TIMER3_DTI) && (TIMER3_DTI == 1) || (ref == TIMER3) #endif #if defined(TIMER4_DTI) && (TIMER4_DTI == 1) || (ref == TIMER4) #endif #if defined(TIMER5_DTI) && (TIMER5_DTI == 1) || (ref == TIMER5) #endif #if defined(TIMER6_DTI) && (TIMER6_DTI == 1) || (ref == TIMER6) #endif #if defined(TIMER7_DTI) && (TIMER7_DTI == 1) || (ref == TIMER7) #endif #if defined(WTIMER0) || (ref == WTIMER0) #endif ; } /***************************************************************************//** * @brief * Get the Max count of the timer. * * @param[in] ref * Pointer to the TIMER peripheral register block. * * @return * The max count value of the timer. This is 0xFFFF for 16 bit timers * and 0xFFFFFFFF for 32 bit timers. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_MaxCount(const TIMER_TypeDef *ref) { (void) ref; #if defined(WTIMER_PRESENT) if ((ref == WTIMER0) #if defined(WTIMER1) || (ref == WTIMER1) #endif #if defined(WTIMER2) || (ref == WTIMER2) #endif #if defined(WTIMER3) || (ref == WTIMER3) #endif ) { return 0xFFFFFFFFUL; } #endif /* defined(WTIMER_PRESENT) */ #if defined(_SILICON_LABS_32B_SERIES_2) EFM_ASSERT(TIMER_NUM(ref) != -1); return (uint32_t)((1ULL << TIMER_CNTWIDTH(TIMER_NUM(ref))) - 1); #else return 0xFFFFUL; #endif /* defined(_SILICON_LABS_32B_SERIES_2) */ } /***************************************************************************//** * @brief * Get compare/capture value for the compare/capture channel. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] ch * Compare/capture channel to access. * * @return * Current capture value. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_CaptureGet(TIMER_TypeDef *timer, unsigned int ch) { #if defined (_TIMER_CC_CFG_MASK) if ((timer->CC[ch].CFG & _TIMER_CC_CFG_MODE_MASK) == TIMER_CC_CFG_MODE_INPUTCAPTURE) { return timer->CC[ch].ICF; } else { return timer->CC[ch].OC; } #else return timer->CC[ch].CCV; #endif } /***************************************************************************//** * @brief * Get the buffered compare/capture value for compare/capture channel. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] ch * Compare/capture channel to access. * * @return * Current buffered capture value. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_CaptureBufGet(TIMER_TypeDef *timer, unsigned int ch) { #if defined (_TIMER_CC_CFG_MASK) if ((timer->CC[ch].CFG & _TIMER_CC_CFG_MODE_MASK) == TIMER_CC_CFG_MODE_INPUTCAPTURE) { return timer->CC[ch].ICOF; } else { return timer->CC[ch].OCB; } #else return timer->CC[ch].CCVB; #endif } /***************************************************************************//** * @brief * Set the compare value buffer for the compare/capture channel when operating in * compare or PWM mode. * * @details * The compare value buffer holds the value which will be written to * TIMERn_CCx_CCV on an update event if the buffer has been updated since * the last event. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] ch * Compare/capture channel to access. * * @param[in] val * Value to set in compare value buffer register. ******************************************************************************/ __STATIC_INLINE void TIMER_CompareBufSet(TIMER_TypeDef *timer, unsigned int ch, uint32_t val) { EFM_ASSERT(val <= TIMER_MaxCount(timer)); #if defined (_TIMER_CC_CFG_MASK) EFM_ASSERT(timer->EN & TIMER_EN_EN); timer->CC[ch].OCB = val; #else timer->CC[ch].CCVB = val; #endif } /***************************************************************************//** * @brief * Set the compare value for compare/capture channel when operating in compare * or PWM mode. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] ch * Compare/capture channel to access. * * @param[in] val * Value to set in compare value register. ******************************************************************************/ __STATIC_INLINE void TIMER_CompareSet(TIMER_TypeDef *timer, unsigned int ch, uint32_t val) { EFM_ASSERT(val <= TIMER_MaxCount(timer)); #if defined (_TIMER_CC_CFG_MASK) EFM_ASSERT(timer->EN & TIMER_EN_EN); timer->CC[ch].OC = val; #else timer->CC[ch].CCV = val; #endif } /***************************************************************************//** * @brief * Get the TIMER counter value. * * @param[in] timer * Pointer to TIMER peripheral register block. * * @return * Current TIMER counter value. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_CounterGet(TIMER_TypeDef *timer) { return timer->CNT; } /***************************************************************************//** * @brief * Set the TIMER counter value. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] val * Value to set counter to. ******************************************************************************/ __STATIC_INLINE void TIMER_CounterSet(TIMER_TypeDef *timer, uint32_t val) { EFM_ASSERT(val <= TIMER_MaxCount(timer)); #if defined(TIMER_HAS_SET_CLEAR) bool enabled = (timer->EN & TIMER_EN_EN) != 0UL; timer->EN_SET = TIMER_EN_EN; #endif timer->CNT = val; #if defined(TIMER_HAS_SET_CLEAR) if (!enabled) { TIMER_SyncWait(timer); timer->EN_CLR = TIMER_EN_EN; #if defined(_TIMER_EN_DISABLING_MASK) while (timer->EN & _TIMER_EN_DISABLING_MASK) { } #endif } #endif } /***************************************************************************//** * @brief * Start/stop TIMER. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] enable * Set to true to enable counting; set to false otherwise. ******************************************************************************/ __STATIC_INLINE void TIMER_Enable(TIMER_TypeDef *timer, bool enable) { EFM_ASSERT(TIMER_REF_VALID(timer)); if (enable) { timer->CMD = TIMER_CMD_START; } else { timer->CMD = TIMER_CMD_STOP; } } void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init); void TIMER_InitCC(TIMER_TypeDef *timer, unsigned int ch, const TIMER_InitCC_TypeDef *init); #if defined(_TIMER_DTCTRL_MASK) void TIMER_InitDTI(TIMER_TypeDef *timer, const TIMER_InitDTI_TypeDef *init); /***************************************************************************//** * @brief * Enable or disable DTI unit. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] enable * Set to true to enable DTI unit; set to false otherwise. ******************************************************************************/ __STATIC_INLINE void TIMER_EnableDTI(TIMER_TypeDef *timer, bool enable) { #if defined(TIMER_HAS_SET_CLEAR) uint32_t timerEn = timer->EN & TIMER_EN_EN; TIMER_SyncWait(timer); timer->EN_CLR = TIMER_EN_EN; #if defined(_TIMER_EN_DISABLING_MASK) while (timer->EN & _TIMER_EN_DISABLING_MASK) { } #endif if (enable) { timer->DTCFG_SET = TIMER_DTCFG_DTEN; } else { timer->DTCFG_CLR = TIMER_DTCFG_DTEN; } timer->EN_SET = timerEn; #else EFM_ASSERT(TIMER_SupportsDTI(timer)); if (enable) { timer->DTCTRL |= TIMER_DTCTRL_DTEN; } else { timer->DTCTRL &= ~TIMER_DTCTRL_DTEN; } #endif } /***************************************************************************//** * @brief * Get DTI fault source flags status. * * @note * Event bits are not cleared by this function. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @return * Status of the DTI fault source flags. Returns one or more valid * DTI fault source flags (TIMER_DTFAULT_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_GetDTIFault(TIMER_TypeDef *timer) { EFM_ASSERT(TIMER_SupportsDTI(timer)); return timer->DTFAULT; } /***************************************************************************//** * @brief * Clear DTI fault source flags. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] flags * DTI fault source(s) to clear. Use one or more valid DTI fault * source flags (TIMER_DTFAULT_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE void TIMER_ClearDTIFault(TIMER_TypeDef *timer, uint32_t flags) { EFM_ASSERT(TIMER_SupportsDTI(timer)); #if defined (TIMER_EN_EN) EFM_ASSERT(timer->EN & TIMER_EN_EN); #endif timer->DTFAULTC = flags; } #endif /* _TIMER_DTCTRL_MASK */ /***************************************************************************//** * @brief * Clear one or more pending TIMER interrupts. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] flags * Pending TIMER interrupt source(s) to clear. Use one or more valid * interrupt flags for the TIMER module (TIMER_IF_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE void TIMER_IntClear(TIMER_TypeDef *timer, uint32_t flags) { #if defined (TIMER_HAS_SET_CLEAR) timer->IF_CLR = flags; #else timer->IFC = flags; #endif } /***************************************************************************//** * @brief * Disable one or more TIMER interrupts. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] flags * TIMER interrupt source(s) to disable. Use one or more valid * interrupt flags for the TIMER module (TIMER_IF_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE void TIMER_IntDisable(TIMER_TypeDef *timer, uint32_t flags) { timer->IEN &= ~flags; } /***************************************************************************//** * @brief * Enable one or more TIMER interrupts. * * @note * Depending on the use, a pending interrupt may already be set prior to * enabling the interrupt. To ignore a pending interrupt, consider using * TIMER_IntClear() prior to enabling the interrupt. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] flags * TIMER interrupt source(s) to enable. Use one or more valid * interrupt flags for the TIMER module (TIMER_IF_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE void TIMER_IntEnable(TIMER_TypeDef *timer, uint32_t flags) { timer->IEN |= flags; } /***************************************************************************//** * @brief * Get pending TIMER interrupt flags. * * @note * Event bits are not cleared by this function. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @return * TIMER interrupt source(s) pending. Returns one or more valid * interrupt flags for the TIMER module (TIMER_IF_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_IntGet(TIMER_TypeDef *timer) { return timer->IF; } /***************************************************************************//** * @brief * Get enabled and pending TIMER interrupt flags. * Useful for handling more interrupt sources in the same interrupt handler. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @note * Interrupt flags are not cleared by this function. * * @return * Pending and enabled TIMER interrupt sources. * The return value is the bitwise AND combination of * - the OR combination of enabled interrupt sources in TIMERx_IEN_nnn * register (TIMERx_IEN_nnn) and * - the OR combination of valid interrupt flags of the TIMER module * (TIMERx_IF_nnn). ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_IntGetEnabled(TIMER_TypeDef *timer) { uint32_t ien; /* Store TIMER->IEN in temporary variable in order to define explicit order * of volatile accesses. */ ien = timer->IEN; /* Bitwise AND of pending and enabled interrupts */ return timer->IF & ien; } /***************************************************************************//** * @brief * Set one or more pending TIMER interrupts from SW. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] flags * TIMER interrupt source(s) to set to pending. Use one or more valid * interrupt flags for the TIMER module (TIMER_IF_nnn) OR'ed together. ******************************************************************************/ __STATIC_INLINE void TIMER_IntSet(TIMER_TypeDef *timer, uint32_t flags) { #if defined (TIMER_HAS_SET_CLEAR) timer->IF_SET = flags; #else timer->IFS = flags; #endif } #if defined(_TIMER_DTLOCK_LOCKKEY_LOCK) /***************************************************************************//** * @brief * Lock some TIMER registers to protect them from being * modified. * * @details * Refer to the reference manual for TIMER registers that will be locked. * * @note * If locking the TIMER registers, they must be unlocked prior to using any * TIMER API function that modifies TIMER registers protected by the lock. * * @param[in] timer * Pointer to TIMER peripheral register block. ******************************************************************************/ __STATIC_INLINE void TIMER_Lock(TIMER_TypeDef *timer) { EFM_ASSERT(TIMER0 == timer); #if defined (TIMER_EN_EN) EFM_ASSERT(timer->EN & TIMER_EN_EN); #endif timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_LOCK; } #endif void TIMER_Reset(TIMER_TypeDef *timer); /***************************************************************************//** * @brief * Set the top value buffer for the timer. * * @details * When top value buffer register is updated, value is loaded into * top value register at the next wrap around. This feature is useful * in order to update top value safely when timer is running. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] val * Value to set in top value buffer register. ******************************************************************************/ __STATIC_INLINE void TIMER_TopBufSet(TIMER_TypeDef *timer, uint32_t val) { EFM_ASSERT(val <= TIMER_MaxCount(timer)); #if defined (TIMER_EN_EN) EFM_ASSERT(timer->EN & TIMER_EN_EN); #endif timer->TOPB = val; } /***************************************************************************//** * @brief * Get the top value setting for the timer. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @return * Current top value. ******************************************************************************/ __STATIC_INLINE uint32_t TIMER_TopGet(TIMER_TypeDef *timer) { return timer->TOP; } /***************************************************************************//** * @brief * Set the top value for timer. * * @param[in] timer * Pointer to the TIMER peripheral register block. * * @param[in] val * Value to set in top value register. ******************************************************************************/ __STATIC_INLINE void TIMER_TopSet(TIMER_TypeDef *timer, uint32_t val) { EFM_ASSERT(val <= TIMER_MaxCount(timer)); #if defined (TIMER_EN_EN) EFM_ASSERT(timer->EN & TIMER_EN_EN); #endif timer->TOP = val; } #if defined(TIMER_DTLOCK_LOCKKEY_UNLOCK) /***************************************************************************//** * @brief * Unlock TIMER to enable writing to locked registers again. * * @param[in] timer * Pointer to the TIMER peripheral register block. ******************************************************************************/ __STATIC_INLINE void TIMER_Unlock(TIMER_TypeDef *timer) { EFM_ASSERT(TIMER0 == timer); #if defined (TIMER_EN_EN) EFM_ASSERT(timer->EN & TIMER_EN_EN); #endif timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK; } #endif /** @} (end addtogroup timer) */ #ifdef __cplusplus } #endif #endif /* defined(TIMER_COUNT) && (TIMER_COUNT > 0) */ #endif /* EM_TIMER_H */