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