1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2023 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_sctimer.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.sctimer"
18 #endif
19 #if defined(SCT_RSTS_N) || defined(SCT_RSTS)
20 #define FSL_FEATURE_SCT_HAS_RESET
21 #endif
22 
23 
24 /*! @brief Typedef for interrupt handler. */
25 typedef void (*sctimer_isr_t)(SCT_Type *base);
26 
27 /*******************************************************************************
28  * Prototypes
29  ******************************************************************************/
30 /*!
31  * @brief Gets the instance from the base address
32  *
33  * @param base SCTimer peripheral base address
34  *
35  * @return The SCTimer instance
36  */
37 static uint32_t SCTIMER_GetInstance(SCT_Type *base);
38 
39 /*******************************************************************************
40  * Variables
41  ******************************************************************************/
42 /*! @brief Pointers to SCT bases for each instance. */
43 static SCT_Type *const s_sctBases[] = SCT_BASE_PTRS;
44 
45 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
46 /*! @brief Pointers to SCT clocks for each instance. */
47 static const clock_ip_name_t s_sctClocks[] = SCT_CLOCKS;
48 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
49 
50 #if defined(FSL_FEATURE_SCT_HAS_RESET)
51 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
52 #if defined(FSL_FEATURE_SCT_WRITE_ZERO_ASSERT_RESET) && FSL_FEATURE_SCT_WRITE_ZERO_ASSERT_RESET
53 /*! @brief Pointers to SCT resets for each instance, writing a zero asserts the reset */
54 static const reset_ip_name_t s_sctResets[] = SCT_RSTS_N;
55 #else
56 /*! @brief Pointers to SCT resets for each instance, writing a one asserts the reset */
57 static const reset_ip_name_t s_sctResets[] = SCT_RSTS;
58 #endif
59 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
60 #endif /* FSL_FEATURE_SCT_HAS_RESET */
61 
62 /*!< @brief SCTimer event Callback function. */
63 static sctimer_event_callback_t s_eventCallback[FSL_FEATURE_SCT_NUMBER_OF_EVENTS];
64 
65 /*!< @brief Keep track of SCTimer event number */
66 static uint32_t s_currentEvent;
67 
68 /*!< @brief Keep track of SCTimer state number */
69 static uint32_t s_currentState;
70 
71 /*!< @brief Keep track of SCTimer unify 32-bit or low 16-bit match/capture register number. */
72 static uint32_t s_currentMatch;
73 /*!< @brief Keep track of SCTimer high 16-bit match/capture register number. */
74 static uint32_t s_currentMatchhigh;
75 
76 /*! @brief Pointer to SCTimer IRQ handler */
77 static sctimer_isr_t s_sctimerIsr;
78 
79 /*******************************************************************************
80  * Code
81  ******************************************************************************/
SCTIMER_GetInstance(SCT_Type * base)82 static uint32_t SCTIMER_GetInstance(SCT_Type *base)
83 {
84     uint32_t instance;
85     uint32_t sctArrayCount = (sizeof(s_sctBases) / sizeof(s_sctBases[0]));
86 
87     /* Find the instance index from base address mappings. */
88     for (instance = 0; instance < sctArrayCount; instance++)
89     {
90         if (MSDK_REG_SECURE_ADDR(s_sctBases[instance]) == MSDK_REG_SECURE_ADDR(base))
91         {
92             break;
93         }
94     }
95 
96     assert(instance < sctArrayCount);
97 
98     return instance;
99 }
100 
101 /*!
102  * brief Ungates the SCTimer clock and configures the peripheral for basic operation.
103  *
104  * note This API should be called at the beginning of the application using the SCTimer driver.
105  *
106  * param base   SCTimer peripheral base address
107  * param config Pointer to the user configuration structure.
108  *
109  * return kStatus_Success indicates success; Else indicates failure.
110  */
SCTIMER_Init(SCT_Type * base,const sctimer_config_t * config)111 status_t SCTIMER_Init(SCT_Type *base, const sctimer_config_t *config)
112 {
113     assert(NULL != config);
114 
115     uint32_t i;
116 
117 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
118     /* Enable the SCTimer clock*/
119     CLOCK_EnableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
120 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
121 
122 #if defined(FSL_FEATURE_SCT_HAS_RESET)
123 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
124     /* Reset the module. */
125     RESET_PeripheralReset(s_sctResets[SCTIMER_GetInstance(base)]);
126 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
127 #endif /* FSL_FEATURE_SCT_HAS_RESET */
128 
129     /* Setup the counter operation. For Current Driver interface SCTIMER_Init don't know detail
130      * frequency of input clock, but User know it. So the INSYNC have to set by user level. */
131     base->CONFIG = SCT_CONFIG_CKSEL(config->clockSelect) | SCT_CONFIG_CLKMODE(config->clockMode) |
132                    SCT_CONFIG_UNIFY(config->enableCounterUnify) | SCT_CONFIG_INSYNC(config->inputsync);
133 
134     /* Write to the control register, keep the counters halted. */
135     base->CTRL =
136         SCT_CTRL_BIDIR_L(config->enableBidirection_l) | SCT_CTRL_PRE_L(config->prescale_l) | SCT_CTRL_HALT_L_MASK;
137     /* Clear the counter after changing the PRE value. */
138     base->CTRL |= SCT_CTRL_CLRCTR_L_MASK;
139 
140     if (!(config->enableCounterUnify))
141     {
142         base->CTRL |=
143             SCT_CTRL_BIDIR_H(config->enableBidirection_h) | SCT_CTRL_PRE_H(config->prescale_h) | SCT_CTRL_HALT_H_MASK;
144         base->CTRL |= SCT_CTRL_CLRCTR_H_MASK;
145     }
146 
147     /* Initial state of channel output */
148     base->OUTPUT = config->outInitState;
149 
150     /* Clear the global variables */
151     s_currentEvent     = 0U;
152     s_currentState     = 0U;
153     s_currentMatch     = 0U;
154     s_currentMatchhigh = 0U;
155 
156     /* Clear the callback array */
157     for (i = 0; i < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS; i++)
158     {
159         s_eventCallback[i] = NULL;
160     }
161 
162     /* Save interrupt handler */
163     s_sctimerIsr = SCTIMER_EventHandleIRQ;
164 
165     return kStatus_Success;
166 }
167 
168 /*!
169  * brief Gates the SCTimer clock.
170  *
171  * param base SCTimer peripheral base address
172  */
SCTIMER_Deinit(SCT_Type * base)173 void SCTIMER_Deinit(SCT_Type *base)
174 {
175     /* Halt the counters */
176     base->CTRL |= (SCT_CTRL_HALT_L_MASK | SCT_CTRL_HALT_H_MASK);
177 
178 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
179     /* Disable the SCTimer clock*/
180     CLOCK_DisableClock(s_sctClocks[SCTIMER_GetInstance(base)]);
181 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
182 }
183 
184 /*!
185  * brief  Fills in the SCTimer configuration structure with the default settings.
186  *
187  * The default values are:
188  * code
189  *  config->enableCounterUnify = true;
190  *  config->clockMode = kSCTIMER_System_ClockMode;
191  *  config->clockSelect = kSCTIMER_Clock_On_Rise_Input_0;
192  *  config->enableBidirection_l = false;
193  *  config->enableBidirection_h = false;
194  *  config->prescale_l = 0U;
195  *  config->prescale_h = 0U;
196  *  config->outInitState = 0U;
197  *  config->inputsync  = 0xFU;
198  * endcode
199  * param config Pointer to the user configuration structure.
200  */
SCTIMER_GetDefaultConfig(sctimer_config_t * config)201 void SCTIMER_GetDefaultConfig(sctimer_config_t *config)
202 {
203     assert(NULL != config);
204 
205     /* Initializes the configure structure to zero. */
206     (void)memset(config, 0, sizeof(*config));
207 
208     /* SCT operates as a unified 32-bit counter */
209     config->enableCounterUnify = true;
210     /* System clock clocks the entire SCT module */
211     config->clockMode = kSCTIMER_System_ClockMode;
212     /* This is used only by certain clock modes */
213     config->clockSelect = kSCTIMER_Clock_On_Rise_Input_0;
214     /* Up count mode only for the unified counter */
215     config->enableBidirection_l = false;
216     /* Up count mode only for Counte_H */
217     config->enableBidirection_h = false;
218     /* Prescale factor of 1 */
219     config->prescale_l = 0U;
220     /* Prescale factor of 1 for Counter_H*/
221     config->prescale_h = 0U;
222     /* Clear outputs */
223     config->outInitState = 0U;
224     /* Default value is 0xFU, it can be clear as 0 when speical conditions met.
225      * Condition can be clear as 0: (for all Clock Modes):
226      * (1) The corresponding input is already synchronous to the SCTimer/PWM clock.
227      * (2) The SCTimer/PWM clock frequency does not exceed 100 MHz.
228      * Note: The SCTimer/PWM clock is the bus/system clock for CKMODE 0-2 or asynchronous input
229      * clock for CKMODE3.
230      * Another condition can be clear as 0: (for CKMODE2 only)
231      * (1) The corresponding input is synchronous to the designated CKMODE2 input clock.
232      * (2) The CKMODE2 input clock frequency is less than one-third the frequency of the bus/system clock.
233      * Default value set as 0U, input0~input3 are set as bypasses. */
234     config->inputsync = 0xFU;
235 }
236 
237 /*!
238  * brief Configures the PWM signal parameters.
239  *
240  * Call this function to configure the PWM signal period, mode, duty cycle, and edge. This
241  * function will create 2 events; one of the events will trigger on match with the pulse value
242  * and the other will trigger when the counter matches the PWM period. The PWM period event is
243  * also used as a limit event to reset the counter or change direction. Both events are enabled
244  * for the same state. The state number can be retrieved by calling the function
245  * SCTIMER_GetCurrentStateNumber().
246  * The counter is set to operate as one 32-bit counter (unify bit is set to 1).
247  * The counter operates in bi-directional mode when generating a center-aligned PWM.
248  *
249  * note When setting PWM output from multiple output pins, they all should use the same PWM mode
250  * i.e all PWM's should be either edge-aligned or center-aligned.
251  * When using this API, the PWM signal frequency of all the initialized channels must be the same.
252  * Otherwise all the initialized channels' PWM signal frequency is equal to the last call to the
253  * API's pwmFreq_Hz.
254  *
255  * param base        SCTimer peripheral base address
256  * param pwmParams   PWM parameters to configure the output
257  * param mode        PWM operation mode, options available in enumeration ::sctimer_pwm_mode_t
258  * param pwmFreq_Hz  PWM signal frequency in Hz
259  * param srcClock_Hz SCTimer counter clock in Hz
260  * param event       Pointer to a variable where the PWM period event number is stored
261  *
262  * return kStatus_Success on success
263  *         kStatus_Fail If we have hit the limit in terms of number of events created or if
264  *                      an incorrect PWM dutycylce is passed in.
265  */
SCTIMER_SetupPwm(SCT_Type * base,const sctimer_pwm_signal_param_t * pwmParams,sctimer_pwm_mode_t mode,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz,uint32_t * event)266 status_t SCTIMER_SetupPwm(SCT_Type *base,
267                           const sctimer_pwm_signal_param_t *pwmParams,
268                           sctimer_pwm_mode_t mode,
269                           uint32_t pwmFreq_Hz,
270                           uint32_t srcClock_Hz,
271                           uint32_t *event)
272 {
273     assert(NULL != pwmParams);
274     assert(0U != srcClock_Hz);
275     assert(0U != pwmFreq_Hz);
276     assert((uint32_t)pwmParams->output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
277     assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
278 
279     /* If we do not have enough events available (this function will create two events),
280      * the function will return fail.
281      */
282     status_t status = kStatus_Fail;
283     status_t status2;
284     uint32_t period, pulsePeriod = 0;
285     uint32_t sctClock    = srcClock_Hz / (((base->CTRL & SCT_CTRL_PRE_L_MASK) >> SCT_CTRL_PRE_L_SHIFT) + 1U);
286     uint32_t periodEvent = 0, pulseEvent = 0;
287     uint32_t reg;
288 
289     if ((s_currentEvent + 2U) <= (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
290     {
291         /* Use bi-directional mode for center-aligned PWM */
292         if (mode == kSCTIMER_CenterAlignedPwm)
293         {
294             base->CTRL |= SCT_CTRL_BIDIR_L_MASK;
295         }
296 
297         /* Calculate PWM period match value */
298         if (mode == kSCTIMER_EdgeAlignedPwm)
299         {
300             period = (sctClock / pwmFreq_Hz) - 1U;
301         }
302         else
303         {
304             period = sctClock / (pwmFreq_Hz * 2U);
305         }
306 
307         /* For 100% dutycyle, make pulse period greater than period so the event will never occur */
308         if (pwmParams->dutyCyclePercent >= 100U)
309         {
310             pulsePeriod = period + 2U;
311         }
312         else
313         {
314             pulsePeriod = (uint32_t)(((uint64_t)period * pwmParams->dutyCyclePercent) / 100U);
315         }
316 
317         /* Schedule an event when we reach the PWM period */
318         status =
319             SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, period, 0, kSCTIMER_Counter_U, &periodEvent);
320 
321         /* Schedule an event when we reach the pulse width */
322         status2 = SCTIMER_CreateAndScheduleEvent(base, kSCTIMER_MatchEventOnly, pulsePeriod, 0, kSCTIMER_Counter_U,
323                                                  &pulseEvent);
324 
325         if ((kStatus_Success == status) && (kStatus_Success == status2))
326         {
327             /* Reset the counter when we reach the PWM period */
328             SCTIMER_SetupCounterLimitAction(base, kSCTIMER_Counter_U, periodEvent);
329 
330             /* Return the period event to the user */
331             *event = periodEvent;
332 
333             /* For high-true level */
334             if ((uint32_t)pwmParams->level == (uint32_t)kSCTIMER_HighTrue)
335             {
336                 if (mode == kSCTIMER_EdgeAlignedPwm)
337                 {
338                     /* Set the initial output level to low which is the inactive state */
339                     base->OUTPUT &= ~(1UL << (uint32_t)pwmParams->output);
340                     /* Set the output when we reach the PWM period */
341                     SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, periodEvent);
342                     /* Clear the output when we reach the PWM pulse value */
343                     SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, pulseEvent);
344                 }
345                 else
346                 {
347                     /* Set the initial output level to high which is the active state */
348                     base->OUTPUT |= (1UL << (uint32_t)pwmParams->output);
349                     /* Clear the output when we reach the PWM pulse event */
350                     SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, pulseEvent);
351                     /* Reverse output when down counting */
352                     reg = base->OUTPUTDIRCTRL;
353                     reg &= ~((uint32_t)SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2U * (uint32_t)pwmParams->output));
354                     reg |= (1UL << (2U * (uint32_t)pwmParams->output));
355                     base->OUTPUTDIRCTRL = reg;
356                 }
357             }
358             /* For low-true level */
359             else
360             {
361                 if (mode == kSCTIMER_EdgeAlignedPwm)
362                 {
363                     /* Set the initial output level to high which is the inactive state */
364                     base->OUTPUT |= (1UL << (uint32_t)pwmParams->output);
365                     /* Clear the output when we reach the PWM period */
366                     SCTIMER_SetupOutputClearAction(base, (uint32_t)pwmParams->output, periodEvent);
367                     /* Set the output when we reach the PWM pulse value */
368                     SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, pulseEvent);
369                 }
370                 else
371                 {
372                     /* Set the initial output level to low which is the active state */
373                     base->OUTPUT &= ~(1UL << (uint32_t)pwmParams->output);
374                     /* Set the output when we reach the PWM pulse event */
375                     SCTIMER_SetupOutputSetAction(base, (uint32_t)pwmParams->output, pulseEvent);
376                     /* Reverse output when down counting */
377                     reg = base->OUTPUTDIRCTRL;
378                     reg &= ~((uint32_t)SCT_OUTPUTDIRCTRL_SETCLR0_MASK << (2U * (uint32_t)pwmParams->output));
379                     reg |= (1UL << (2U * (uint32_t)pwmParams->output));
380                     base->OUTPUTDIRCTRL = reg;
381                 }
382             }
383         }
384         else
385         {
386             status = kStatus_Fail;
387         }
388     }
389 
390     return status;
391 }
392 
393 /*!
394  * brief Updates the duty cycle of an active PWM signal.
395  *
396  * Before calling  this function, the counter is set to operate as one 32-bit counter (unify bit is set to 1).
397  *
398  * param base              SCTimer peripheral base address
399  * param output            The output to configure
400  * param dutyCyclePercent  New PWM pulse width; the value should be between 0 to 100
401  * param event             Event number associated with this PWM signal. This was returned to the user by the
402  *                          function SCTIMER_SetupPwm().
403  */
SCTIMER_UpdatePwmDutycycle(SCT_Type * base,sctimer_out_t output,uint8_t dutyCyclePercent,uint32_t event)404 void SCTIMER_UpdatePwmDutycycle(SCT_Type *base, sctimer_out_t output, uint8_t dutyCyclePercent, uint32_t event)
405 
406 {
407     assert(dutyCyclePercent <= 100U);
408     assert((uint32_t)output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
409     assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
410 
411     uint32_t periodMatchReg, pulseMatchReg;
412     uint32_t pulsePeriod = 0, period;
413     bool isHighTrue      = (0U != (base->OUT[output].CLR & (1UL << (event + 1U))));
414 
415     /* Retrieve the match register number for the PWM period */
416     periodMatchReg = base->EV[event].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
417 
418     /* Retrieve the match register number for the PWM pulse period */
419     pulseMatchReg = base->EV[event + 1U].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
420 
421     period = base->MATCH[periodMatchReg];
422 
423     /* Stop the counter before updating match register */
424     SCTIMER_StopTimer(base, (uint32_t)kSCTIMER_Counter_U);
425 
426     /* For 100% dutycyle, make pulse period greater than period so the event will never occur */
427     if (dutyCyclePercent >= 100U)
428     {
429         pulsePeriod = period + 2U;
430 
431         /* Set the initial output level base on output mode */
432         if (isHighTrue)
433         {
434             base->OUTPUT |= (1UL << (uint32_t)output);
435         }
436         else
437         {
438             base->OUTPUT &= ~(1UL << (uint32_t)output);
439         }
440     }
441     else
442     {
443         pulsePeriod = (uint32_t)(((uint64_t)period * dutyCyclePercent) / 100U);
444     }
445 
446     /* Update dutycycle */
447     base->MATCH[pulseMatchReg]    = pulsePeriod;
448     base->MATCHREL[pulseMatchReg] = pulsePeriod;
449 
450     /* Restart the counter */
451     SCTIMER_StartTimer(base, (uint32_t)kSCTIMER_Counter_U);
452 }
453 
454 /*!
455  * brief Create an event that is triggered on a match or IO and schedule in current state.
456  *
457  * This function will configure an event using the options provided by the user. If the event type uses
458  * the counter match, then the function will set the user provided match value into a match register
459  * and put this match register number into the event control register.
460  * The event is enabled for the current state and the event number is increased by one at the end.
461  * The function returns the event number; this event number can be used to configure actions to be
462  * done when this event is triggered.
463  *
464  * param base         SCTimer peripheral base address
465  * param howToMonitor Event type; options are available in the enumeration ::sctimer_event_t
466  * param matchValue   The match value that will be programmed to a match register
467  * param whichIO      The input or output that will be involved in event triggering. This field
468  *                     is ignored if the event type is "match only"
469  * param whichCounter SCTimer counter to use. In 16-bit mode, we can select Counter_L and Counter_H,
470  *                     In 32-bit mode, we can select Counter_U.
471  * param event        Pointer to a variable where the new event number is stored
472  *
473  * return kStatus_Success on success
474  *         kStatus_Error if we have hit the limit in terms of number of events created or
475                          if we have reached the limit in terms of number of match registers
476  */
SCTIMER_CreateAndScheduleEvent(SCT_Type * base,sctimer_event_t howToMonitor,uint32_t matchValue,uint32_t whichIO,sctimer_counter_t whichCounter,uint32_t * event)477 status_t SCTIMER_CreateAndScheduleEvent(SCT_Type *base,
478                                         sctimer_event_t howToMonitor,
479                                         uint32_t matchValue,
480                                         uint32_t whichIO,
481                                         sctimer_counter_t whichCounter,
482                                         uint32_t *event)
483 {
484     uint32_t combMode       = (((uint32_t)howToMonitor & SCT_EV_CTRL_COMBMODE_MASK) >> SCT_EV_CTRL_COMBMODE_SHIFT);
485     uint32_t currentCtrlVal = (uint32_t)howToMonitor;
486     status_t status         = kStatus_Success;
487     uint32_t temp           = 0;
488 
489     if (s_currentEvent < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS)
490     {
491         if (2U == combMode)
492         {
493             base->EV[s_currentEvent].CTRL = currentCtrlVal | SCT_EV_CTRL_IOSEL(whichIO);
494         }
495         else
496         {
497             if ((0U == combMode) || (3U == combMode))
498             {
499                 currentCtrlVal |= SCT_EV_CTRL_IOSEL(whichIO);
500             }
501 
502             if ((kSCTIMER_Counter_L == whichCounter) && (0U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
503             {
504                 if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
505                 {
506                     currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatch);
507 
508                     /* Use Counter_L bits if user wants to setup the Low counter */
509                     base->MATCH_ACCESS16BIT[s_currentMatch].MATCHL       = (uint16_t)matchValue;
510                     base->MATCHREL_ACCESS16BIT[s_currentMatch].MATCHRELL = (uint16_t)matchValue;
511                     base->EV[s_currentEvent].CTRL                        = currentCtrlVal;
512 
513                     /* Increment the match register number */
514                     s_currentMatch++;
515                 }
516                 else
517                 {
518                     /* An error would occur if we have hit the limit in terms of number of match registers */
519                     status = kStatus_Fail;
520                 }
521             }
522             else if ((kSCTIMER_Counter_H == whichCounter) && (0U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
523             {
524                 if (s_currentMatchhigh < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
525                 {
526                     currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatchhigh);
527 
528                     /* Use Counter_H bits if user wants to setup the High counter */
529                     currentCtrlVal |= SCT_EV_CTRL_HEVENT(1U);
530                     temp                               = base->MATCH_ACCESS16BIT[s_currentMatchhigh].MATCHL;
531                     base->MATCH[s_currentMatchhigh]    = temp | (matchValue << 16U);
532                     temp                               = base->MATCHREL_ACCESS16BIT[s_currentMatchhigh].MATCHRELL;
533                     base->MATCHREL[s_currentMatchhigh] = temp | (matchValue << 16U);
534 
535                     base->EV[s_currentEvent].CTRL = currentCtrlVal;
536                     /* Increment the match register number */
537                     s_currentMatchhigh++;
538                 }
539                 else
540                 {
541                     /* An error would occur if we have hit the limit in terms of number of match registers */
542                     status = kStatus_Fail;
543                 }
544             }
545             else if ((kSCTIMER_Counter_U == whichCounter) && (0U != (base->CONFIG & SCT_CONFIG_UNIFY_MASK)))
546             {
547                 if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
548                 {
549                     /* Use Counter_L bits if counter is operating in 32-bit mode */
550                     currentCtrlVal |= SCT_EV_CTRL_MATCHSEL(s_currentMatch);
551 
552                     base->MATCH[s_currentMatch]    = matchValue;
553                     base->MATCHREL[s_currentMatch] = matchValue;
554                     base->EV[s_currentEvent].CTRL  = currentCtrlVal;
555 
556                     /* Increment the match register number */
557                     s_currentMatch++;
558                 }
559                 else
560                 {
561                     /* An error would occur if we have hit the limit in terms of number of match registers */
562                     status = kStatus_Fail;
563                 }
564             }
565             else
566             {
567                 /* The used counter must match the CONFIG[UNIFY] bit selection */
568                 status = kStatus_Fail;
569             }
570         }
571 
572         if (kStatus_Success == status)
573         {
574             /* Enable the event in the current state */
575             base->EV[s_currentEvent].STATE = (1UL << s_currentState);
576 
577             /* Return the event number */
578             *event = s_currentEvent;
579 
580             /* Increment the event number */
581             s_currentEvent++;
582         }
583     }
584     else
585     {
586         /* An error would occur if we have hit the limit in terms of number of events created */
587         status = kStatus_Fail;
588     }
589 
590     return status;
591 }
592 
593 /*!
594  * brief Enable an event in the current state.
595  *
596  * This function will allow the event passed in to trigger in the current state. The event must
597  * be created earlier by either calling the function SCTIMER_SetupPwm() or function
598  * SCTIMER_CreateAndScheduleEvent() .
599  *
600  * param base  SCTimer peripheral base address
601  * param event Event number to enable in the current state
602  *
603  */
SCTIMER_ScheduleEvent(SCT_Type * base,uint32_t event)604 void SCTIMER_ScheduleEvent(SCT_Type *base, uint32_t event)
605 {
606     /* Enable event in the current state */
607     base->EV[event].STATE |= (1UL << s_currentState);
608 }
609 
610 /*!
611  * brief Increase the state by 1
612  *
613  * All future events created by calling the function SCTIMER_ScheduleEvent() will be enabled in this new
614  * state.
615  *
616  * param base  SCTimer peripheral base address
617  *
618  * return kStatus_Success on success
619  *         kStatus_Error if we have hit the limit in terms of states used
620 
621  */
SCTIMER_IncreaseState(SCT_Type * base)622 status_t SCTIMER_IncreaseState(SCT_Type *base)
623 {
624     status_t status = kStatus_Success;
625 
626     /* Return an error if we have hit the limit in terms of states used */
627     if (s_currentState >= (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_STATES)
628     {
629         status = kStatus_Fail;
630     }
631     else
632     {
633         s_currentState++;
634     }
635 
636     return status;
637 }
638 
639 /*!
640  * brief Provides the current state
641  *
642  * User can use this to set the next state by calling the function SCTIMER_SetupNextStateAction().
643  *
644  * param base SCTimer peripheral base address
645  *
646  * return The current state
647  */
SCTIMER_GetCurrentState(SCT_Type * base)648 uint32_t SCTIMER_GetCurrentState(SCT_Type *base)
649 {
650     return s_currentState;
651 }
652 
653 /*!
654  * brief Toggle the output level.
655  *
656  * This change in the output level is triggered by the event number that is passed in by the user.
657  *
658  * param base    SCTimer peripheral base address
659  * param whichIO The output to toggle
660  * param event   Event number that will trigger the output change
661  */
SCTIMER_SetupOutputToggleAction(SCT_Type * base,uint32_t whichIO,uint32_t event)662 void SCTIMER_SetupOutputToggleAction(SCT_Type *base, uint32_t whichIO, uint32_t event)
663 {
664     assert(whichIO < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
665 
666     uint32_t reg;
667 
668     /* Set the same event to set and clear the output */
669     base->OUT[whichIO].CLR |= (1UL << event);
670     base->OUT[whichIO].SET |= (1UL << event);
671 
672     /* Set the conflict resolution to toggle output */
673     reg = base->RES;
674     reg &= ~(((uint32_t)SCT_RES_O0RES_MASK) << (2U * whichIO));
675     reg |= ((uint32_t)(kSCTIMER_ResolveToggle)) << (2U * whichIO);
676     base->RES = reg;
677 }
678 
679 /*!
680  * brief Setup capture of the counter value on trigger of a selected event
681  *
682  * param base            SCTimer peripheral base address
683  * param whichCounter    SCTimer counter to use. In 16-bit mode, we can select Counter_L and Counter_H,
684  *                        In 32-bit mode, we can select Counter_U.
685  * param captureRegister Pointer to a variable where the capture register number will be returned. User
686  *                        can read the captured value from this register when the specified event is triggered.
687  * param event           Event number that will trigger the capture
688  *
689  * return kStatus_Success on success
690  *         kStatus_Error if we have hit the limit in terms of number of match/capture registers available
691  */
SCTIMER_SetupCaptureAction(SCT_Type * base,sctimer_counter_t whichCounter,uint32_t * captureRegister,uint32_t event)692 status_t SCTIMER_SetupCaptureAction(SCT_Type *base,
693                                     sctimer_counter_t whichCounter,
694                                     uint32_t *captureRegister,
695                                     uint32_t event)
696 {
697     status_t status;
698     uint32_t temp = 0;
699 
700     if ((kSCTIMER_Counter_L == whichCounter) || (kSCTIMER_Counter_U == whichCounter))
701     {
702         if (s_currentMatch < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
703         {
704             /* Set the bit to enable event */
705             base->CAPCTRL_ACCESS16BIT[s_currentMatch].CAPCTRLL |= SCT_CAPCTRLL_CAPCTRLL(1UL << event);
706 
707             /* Set this resource to be a capture rather than match */
708             base->REGMODE_ACCESS16BIT.REGMODEL |= SCT_REGMODEL_REGMODEL(1UL << s_currentMatch);
709 
710             /* Return the match register number */
711             *captureRegister = s_currentMatch;
712 
713             /* Increase the match register number */
714             s_currentMatch++;
715 
716             status = kStatus_Success;
717         }
718         else
719         {
720             /* Return an error if we have hit the limit in terms of number of capture/match registers used */
721             status = kStatus_Fail;
722         }
723     }
724     else
725     {
726         if (s_currentMatchhigh < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_MATCH_CAPTURE)
727         {
728             /* Set bit to enable event */
729             temp                              = base->CAPCTRL_ACCESS16BIT[s_currentMatchhigh].CAPCTRLL;
730             base->CAPCTRL[s_currentMatchhigh] = temp | ((uint32_t)((uint32_t)(1UL << event) << 16U) & 0xFFFF0000U);
731             /* Set this resource to be a capture rather than match */
732             temp          = base->REGMODE_ACCESS16BIT.REGMODEL;
733             base->REGMODE = temp | ((uint32_t)((uint32_t)(1UL << s_currentMatchhigh) << 16U) & 0xFFFF0000U);
734 
735             /* Return the match register number */
736             *captureRegister = s_currentMatchhigh;
737 
738             /* Increase the match register number */
739             s_currentMatchhigh++;
740 
741             status = kStatus_Success;
742         }
743         else
744         {
745             /* Return an error if we have hit the limit in terms of number of capture/match registers used */
746             status = kStatus_Fail;
747         }
748     }
749 
750     return status;
751 }
752 
753 /*!
754  * brief Receive noticification when the event trigger an interrupt.
755  *
756  * If the interrupt for the event is enabled by the user, then a callback can be registered
757  * which will be invoked when the event is triggered
758  *
759  * param base     SCTimer peripheral base address
760  * param event    Event number that will trigger the interrupt
761  * param callback Function to invoke when the event is triggered
762  */
763 
SCTIMER_SetCallback(SCT_Type * base,sctimer_event_callback_t callback,uint32_t event)764 void SCTIMER_SetCallback(SCT_Type *base, sctimer_event_callback_t callback, uint32_t event)
765 {
766     s_eventCallback[event] = callback;
767 }
768 
769 /*!
770  * brief SCTimer interrupt handler.
771  *
772  * param base SCTimer peripheral base address.
773  */
SCTIMER_EventHandleIRQ(SCT_Type * base)774 void SCTIMER_EventHandleIRQ(SCT_Type *base)
775 {
776     uint32_t eventFlag = base->EVFLAG;
777     /* Only clear the flags whose interrupt field is enabled */
778     uint32_t clearFlag = (eventFlag & base->EVEN);
779     uint32_t mask      = eventFlag;
780     uint32_t i;
781 
782     /* Invoke the callback for certain events */
783     for (i = 0; i < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_EVENTS; i++)
784     {
785         if ((mask & 0x1U) != 0U)
786         {
787             if (s_eventCallback[i] != NULL)
788             {
789                 s_eventCallback[i]();
790             }
791         }
792         mask >>= 1UL;
793 
794         if (0U == mask)
795         {
796             /* All events have been handled. */
797             break;
798         }
799     }
800 
801     /* Clear event interrupt flag */
802     base->EVFLAG = clearFlag;
803 }
804 
805 #if defined(SCT0)
806 void SCT0_DriverIRQHandler(void);
SCT0_DriverIRQHandler(void)807 void SCT0_DriverIRQHandler(void)
808 {
809     s_sctimerIsr(SCT0);
810     SDK_ISR_EXIT_BARRIER;
811 }
812 #endif
813 
814 #if defined(SCT)
815 void SCT_DriverIRQHandler(void);
SCT_DriverIRQHandler(void)816 void SCT_DriverIRQHandler(void)
817 {
818     s_sctimerIsr(SCT);
819     SDK_ISR_EXIT_BARRIER;
820 }
821 #endif
822