1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_tpm.h"
10
11 /*
12 * $Coverage Justification Reference$
13 *
14 * $Justification tpm_c_ref_1$
15 * Hardware limitations make this code impossible to implement.
16 *
17 * $Justification tpm_c_ref_2$
18 * Because the incoming base is invalid, the second judgment is not continued after the first condition
19 * is established.
20 *
21 * $Justification tpm_c_ref_3$
22 * Hardware limitations, the 32-bit counter register makes counterMax = 0xffffffffu,
23 * and the mod vlue can't be greater than or equal to counterMax after the operation.
24 *
25 * $Justification tpm_c_ref_4$
26 * If the incoming base can not make (1U == (uint8_t)FSL_FEATURE_TPM_POL_HAS_EFFECTn(base) true,
27 * the subsequent register operation is incorrect.
28 *
29 */
30
31 /*******************************************************************************
32 * Definitions
33 ******************************************************************************/
34
35 /* Component ID definition, used by tools. */
36 #ifndef FSL_COMPONENT_ID
37 #define FSL_COMPONENT_ID "platform.drivers.tpm"
38 #endif
39
40 #define TPM_COMBINE_SHIFT (8U)
41
42 #if defined(TPM_RSTS)
43 #define TPM_RESETS_ARRAY TPM_RSTS
44 #endif
45
46 /*******************************************************************************
47 * Prototypes
48 ******************************************************************************/
49
50 /*******************************************************************************
51 * Variables
52 ******************************************************************************/
53 /*! @brief Pointers to TPM bases for each instance. */
54 static TPM_Type *const s_tpmBases[] = TPM_BASE_PTRS;
55
56 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
57 /*! @brief Pointers to TPM clocks for each instance. */
58 static const clock_ip_name_t s_tpmClocks[] = TPM_CLOCKS;
59 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
60
61 /* Array of TPM callback function pointer. */
62 static tpm_callback_t s_tpmCallback[ARRAY_SIZE(s_tpmBases)];
63
64 /* Array to map TPM instance to IRQ number. */
65 static const IRQn_Type s_tpmIRQ[] = TPM_IRQS;
66
67 #if defined(TPM_RESETS_ARRAY)
68 /* Reset array */
69 static const reset_ip_name_t s_tpmResets[] = TPM_RESETS_ARRAY;
70 #endif
71
72 /*******************************************************************************
73 * Code
74 ******************************************************************************/
75 /*!
76 * brief Gets the instance from the base address
77 *
78 * param base TPM peripheral base address
79 * return The TPM instance
80 */
TPM_GetInstance(TPM_Type * base)81 uint32_t TPM_GetInstance(TPM_Type *base)
82 {
83 uint32_t instance;
84 uint32_t tpmArrayCount = (sizeof(s_tpmBases) / sizeof(s_tpmBases[0]));
85
86 /* Find the instance index from base address mappings. */
87 /*
88 * $Branch Coverage Justification$
89 * (instance >= tpmArrayCount) not covered.
90 * The peripheral base address is always valid.
91 */
92 for (instance = 0; instance < tpmArrayCount; instance++)
93 {
94 if (s_tpmBases[instance] == base)
95 {
96 break;
97 }
98 }
99
100 assert(instance < tpmArrayCount);
101
102 return instance;
103 }
104
105 /*!
106 * brief Ungates the TPM clock and configures the peripheral for basic operation.
107 *
108 * note This API should be called at the beginning of the application using the TPM driver.
109 *
110 * param base TPM peripheral base address
111 * param config Pointer to user's TPM config structure.
112 */
TPM_Init(TPM_Type * base,const tpm_config_t * config)113 void TPM_Init(TPM_Type *base, const tpm_config_t *config)
114 {
115 assert(NULL != config);
116
117 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
118 /* Enable the module clock */
119 (void)CLOCK_EnableClock(s_tpmClocks[TPM_GetInstance(base)]);
120 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
121
122 #if defined(TPM_RESETS_ARRAY)
123 RESET_ReleasePeripheralReset(s_tpmResets[TPM_GetInstance(base)]);
124 #endif
125
126 #if defined(FSL_FEATURE_TPM_HAS_GLOBAL) && FSL_FEATURE_TPM_HAS_GLOBAL
127 /* TPM reset is available on certain SoC's */
128 TPM_Reset(base);
129 #endif
130
131 /* Set the clock prescale factor */
132 base->SC = TPM_SC_PS(config->prescale);
133 #if !(defined(FSL_FEATURE_TPM_HAS_NO_CONF) && FSL_FEATURE_TPM_HAS_NO_CONF)
134 /* Setup the counter operation */
135 base->CONF = TPM_CONF_DOZEEN(config->enableDoze) |
136 #if defined(FSL_FEATURE_TPM_HAS_GLOBAL_TIME_BASE_EN) && FSL_FEATURE_TPM_HAS_GLOBAL_TIME_BASE_EN
137 TPM_CONF_GTBEEN(config->useGlobalTimeBase) |
138 #endif
139 #if defined(FSL_FEATURE_TPM_HAS_GLOBAL_TIME_BASE_SYNC) && FSL_FEATURE_TPM_HAS_GLOBAL_TIME_BASE_SYNC
140 TPM_CONF_GTBSYNC(config->syncGlobalTimeBase) |
141 #endif
142 TPM_CONF_CROT(config->enableReloadOnTrigger) |
143 TPM_CONF_CSOT(config->enableStartOnTrigger) | TPM_CONF_CSOO(config->enableStopOnOverflow) |
144 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER
145 TPM_CONF_CPOT(config->enablePauseOnTrigger) |
146 #endif
147 #if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION
148 TPM_CONF_TRGSRC(config->triggerSource) | TPM_CONF_TRGPOL(config->extTriggerPolarity) |
149 #endif
150 TPM_CONF_TRGSEL(config->triggerSelect);
151 if (true == config->enableDebugMode)
152 {
153 base->CONF |= TPM_CONF_DBGMODE_MASK;
154 }
155 else
156 {
157 base->CONF &= ~TPM_CONF_DBGMODE_MASK;
158 }
159 #endif
160 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
161 base->POL = config->chnlPolarity;
162 #endif
163 }
164
165 /*!
166 * brief Stops the counter and gates the TPM clock
167 *
168 * param base TPM peripheral base address
169 */
TPM_Deinit(TPM_Type * base)170 void TPM_Deinit(TPM_Type *base)
171 {
172 #if defined(FSL_FEATURE_TPM_HAS_SC_CLKS) && FSL_FEATURE_TPM_HAS_SC_CLKS
173 /* Stop the counter */
174 base->SC &= ~TPM_SC_CLKS_MASK;
175 #else
176 /* Stop the counter */
177 base->SC &= ~TPM_SC_CMOD_MASK;
178 #endif
179 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
180 /* Gate the TPM clock */
181 (void)CLOCK_DisableClock(s_tpmClocks[TPM_GetInstance(base)]);
182 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
183 }
184
185 /*!
186 * brief Fill in the TPM config struct with the default settings
187 *
188 * The default values are:
189 * code
190 * config->prescale = kTPM_Prescale_Divide_1;
191 * config->useGlobalTimeBase = false;
192 * config->syncGlobalTimeBase = false;
193 * config->dozeEnable = false;
194 * config->dbgMode = false;
195 * config->enableReloadOnTrigger = false;
196 * config->enableStopOnOverflow = false;
197 * config->enableStartOnTrigger = false;
198 *#if FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER
199 * config->enablePauseOnTrigger = false;
200 *#endif
201 * config->triggerSelect = kTPM_Trigger_Select_0;
202 *#if FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION
203 * config->triggerSource = kTPM_TriggerSource_External;
204 * config->extTriggerPolarity = kTPM_ExtTrigger_Active_High;
205 *#endif
206 *#if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
207 * config->chnlPolarity = 0U;
208 *#endif
209 * endcode
210 * param config Pointer to user's TPM config structure.
211 */
TPM_GetDefaultConfig(tpm_config_t * config)212 void TPM_GetDefaultConfig(tpm_config_t *config)
213 {
214 assert(NULL != config);
215
216 /* Initializes the configure structure to zero. */
217 (void)memset(config, 0, sizeof(*config));
218
219 /* TPM clock divide by 1 */
220 config->prescale = kTPM_Prescale_Divide_1;
221 #if !(defined(FSL_FEATURE_TPM_HAS_NO_CONF) && FSL_FEATURE_TPM_HAS_NO_CONF)
222 /* Use internal TPM counter as timebase */
223 config->useGlobalTimeBase = false;
224 /* Disable internal TPM counter sync with global timebase */
225 config->syncGlobalTimeBase = false;
226 /* TPM counter continues in doze mode */
227 config->enableDoze = false;
228 /* TPM counter pauses when in debug mode */
229 config->enableDebugMode = false;
230 /* TPM counter will not be reloaded on input trigger */
231 config->enableReloadOnTrigger = false;
232 /* TPM counter continues running after overflow */
233 config->enableStopOnOverflow = false;
234 /* TPM counter starts immediately once it is enabled */
235 config->enableStartOnTrigger = false;
236 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER
237 config->enablePauseOnTrigger = false;
238 #endif
239 /* Choose trigger select 0 as input trigger for controlling counter operation */
240 config->triggerSelect = kTPM_Trigger_Select_0;
241 #if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION
242 /* Choose external trigger source (high active) to control counter operation */
243 config->triggerSource = kTPM_TriggerSource_External;
244 config->extTriggerPolarity = kTPM_ExtTrigger_Active_High;
245 #endif
246 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
247 /* Default channel polarity is active high */
248 config->chnlPolarity = 0U;
249 #endif
250 #endif
251 }
252
253 /*!
254 * brief Calculates the counter clock prescaler.
255 *
256 * This function calculates the values for SC[PS].
257 *
258 * param base TPM peripheral base address
259 * param counterPeriod_Hz The desired frequency in Hz which corresponding to the time when the counter reaches the
260 * mod value param srcClock_Hz TPM counter clock in Hz
261 *
262 * return Calculated clock prescaler value.
263 */
TPM_CalculateCounterClkDiv(TPM_Type * base,uint32_t counterPeriod_Hz,uint32_t srcClock_Hz)264 tpm_clock_prescale_t TPM_CalculateCounterClkDiv(TPM_Type *base, uint32_t counterPeriod_Hz, uint32_t srcClock_Hz)
265 {
266 uint32_t counterMax = TPM_MAX_COUNTER_VALUE(base);
267 uint32_t i;
268 assert(((srcClock_Hz / 2U) > counterPeriod_Hz) && ((srcClock_Hz / 128U / counterMax) <= counterPeriod_Hz));
269
270 for (i = 0U; i < (uint32_t)kTPM_Prescale_Divide_128; i++)
271 {
272 if ((srcClock_Hz / (1UL << i) / counterMax) < counterPeriod_Hz)
273 {
274 break;
275 }
276 }
277 return (tpm_clock_prescale_t)i;
278 }
279
280 /*!
281 * brief Set parameters for PWM duty cycle and edges for a single tpm channel
282 *
283 * User calls this function to configure the mode, duty cycle and edge of a single PWM signal.
284 *
285 * param base TPM peripheral base address
286 * param mod PWM period
287 * param mode PWM operation mode, options available in enumeration ::tpm_pwm_mode_t
288 * param chnlParams A structure for configuring PWM channel parameters, used to configure the channel.
289 *
290 * return kStatus_Success if the PWM setup was successful,
291 * kStatus_Error on failure
292 */
TPM_SetupSinglePwmChannel(TPM_Type * base,uint32_t mod,tpm_pwm_mode_t mode,tpm_chnl_pwm_signal_param_t chnlParams)293 static status_t TPM_SetupSinglePwmChannel(TPM_Type *base,
294 uint32_t mod,
295 tpm_pwm_mode_t mode,
296 tpm_chnl_pwm_signal_param_t chnlParams)
297 {
298 uint32_t cnv;
299 uint32_t counterMax = TPM_MAX_COUNTER_VALUE(base);
300 uint8_t controlBits;
301 uint8_t chnlId;
302
303 /* MSnB:MSnA field value always be 10, ELSnB:ELSnA field value should config according to the channel params */
304 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_LEVEL_SELECT) && FSL_FEATURE_TPM_HAS_PAUSE_LEVEL_SELECT
305 controlBits =
306 (uint8_t)((uint32_t)kTPM_ChnlMSBMask | TPM_CnSC_ELSB(chnlParams.pauseLevel) | TPM_CnSC_ELSA(chnlParams.level));
307 #else
308 controlBits = ((uint8_t)kTPM_ChnlMSBMask | ((uint8_t)chnlParams.level << TPM_CnSC_ELSA_SHIFT));
309 #endif
310 chnlId = (uint8_t)chnlParams.chnlNumber;
311 /* Return error if requested dutycycle/chnlNumber is greater than the max allowed */
312 /*
313 * $Branch Coverage Justification$
314 * (-1 == (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) not covered.
315 * This function is called inside the TPM_SetupPwm() function.
316 * If you enter an invalid base, the function will not work properly.
317 */
318 if ((chnlId >= (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) ||
319 /*
320 * $Branch Coverage Justification$
321 * (chnlId >= (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) not covered. $ref tpm_c_ref_2$.
322 */
323 (-1 == (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)))
324 {
325 return kStatus_InvalidArgument;
326 }
327 /* Return error if requested dutycycle is greater than the max allowed or MOD equal to 0xFFFF when it want get a
328 * 100% duty cycle PWM signal*/
329 /*
330 * $Branch Coverage Justification$
331 * (mod == counterMax) not covered. $ref tpm_c_ref_3$.
332 */
333 if (((chnlParams.dutyCyclePercent == 100U) && (mod == counterMax)) || (chnlParams.dutyCyclePercent > 100U))
334 {
335 return kStatus_OutOfRange;
336 }
337
338 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
339 if (mode == kTPM_CombinedPwm)
340 {
341 /* Check added for combined mode */
342 /*
343 * $Branch Coverage Justification$
344 * (chnlId >= ((uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2U)) not covered. $ref tpm_c_ref_2$.
345 */
346 if ((chnlId >= ((uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2U)) ||
347 (1U != (uint8_t)FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base)))
348 {
349 /* The instance should support combine mode and the channel number should be the pair number */
350 return kStatus_InvalidArgument;
351 }
352 if (((chnlParams.firstEdgeDelayPercent + chnlParams.dutyCyclePercent) > 100U) ||
353 ((chnlParams.firstEdgeDelayPercent > 0U) && (chnlParams.dutyCyclePercent == 0U)) ||
354 ((chnlParams.firstEdgeDelayPercent == 0U) && (chnlParams.deadTimeValue[0] != 0U)))
355 {
356 /* Return error if the following situation occurs :
357 * firstEdgeDelayPercent + dutyCyclePercent > 100
358 * firstEdgeDelayPercent > 0 and dutyCyclePercent == 0
359 * firstEdgeDelayPercent == 0 and deadTimeValue[0] != 0
360 */
361 return kStatus_OutOfRange;
362 }
363 /* Configure delay of the first edge */
364 uint32_t cnvFirstEdge;
365 /* Configure dutycycle */
366 if (chnlParams.dutyCyclePercent == 0U)
367 {
368 cnvFirstEdge = mod + 1U;
369 cnv = 0;
370 }
371 else if (chnlParams.dutyCyclePercent == 100U)
372 {
373 cnvFirstEdge = 0U;
374 cnv = mod + 1U;
375 }
376 else
377 {
378 cnvFirstEdge = (mod * chnlParams.firstEdgeDelayPercent) / 100U;
379 cnv = (mod * chnlParams.dutyCyclePercent) / 100U;
380 }
381
382 /* Set the combine bit for the channel pair */
383 base->COMBINE |= 1UL << (TPM_COMBINE_SHIFT * chnlId);
384
385 chnlId *= 2U;
386 /* Set deadtime insertion for the channel pair using channel filter register */
387 uint32_t filterVal = base->FILTER;
388 /* Clear the channel pair's filter values */
389 filterVal &=
390 ~(((uint32_t)TPM_FILTER_CH0FVAL_MASK | TPM_FILTER_CH1FVAL_MASK) << (chnlId * TPM_FILTER_CH1FVAL_SHIFT));
391 /* Shift the deadtime insertion value to the right place in the register */
392 filterVal |= (TPM_FILTER_CH0FVAL(chnlParams.deadTimeValue[0]) | TPM_FILTER_CH1FVAL(chnlParams.deadTimeValue[1]))
393 << (chnlId * TPM_FILTER_CH1FVAL_SHIFT);
394 base->FILTER = filterVal;
395
396 /* When switching mode, disable channel n first */
397 TPM_DisableChannel(base, (tpm_chnl_t)chnlId);
398 /* Set the requested PWM mode for channel n, under combine PWM mode, the active level is opposite of
399 * edge-aligned mode */
400 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, controlBits ^ TPM_CnSC_ELSA_MASK);
401 /* Set the channel n value */
402 do
403 {
404 base->CONTROLS[chnlId].CnV = cnvFirstEdge;
405 /*
406 * $Branch Coverage Justification$
407 * (cnvFirstEdge != base->CONTROLS[chnlId].CnV) not covered. $ref tpm_c_ref_1$.
408 */
409 } while (cnvFirstEdge != base->CONTROLS[chnlId].CnV);
410
411 chnlId += 1U;
412 /* When switching mode, disable channel n + 1 */
413 TPM_DisableChannel(base, (tpm_chnl_t)chnlId);
414 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_LEVEL_SELECT) && FSL_FEATURE_TPM_HAS_PAUSE_LEVEL_SELECT
415 /* Select the pause level for second channel */
416 controlBits = (uint8_t)((uint32_t)kTPM_ChnlMSBMask | TPM_CnSC_ELSB(chnlParams.secPauseLevel) |
417 TPM_CnSC_ELSA(chnlParams.level));
418 #endif
419 /* Set the requested PWM mode for channel n + 1 */
420 if (chnlParams.enableComplementary)
421 {
422 /* Change the polarity on the second channel get complementary PWM signals */
423 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, controlBits);
424 }
425 else
426 {
427 /* Second channel use same control bits as first channel */
428 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, controlBits ^ TPM_CnSC_ELSA_MASK);
429 }
430
431 /* Set the channel n+1 value */
432 do
433 {
434 base->CONTROLS[chnlId].CnV = cnvFirstEdge + cnv;
435 /*
436 * $Branch Coverage Justification$
437 * ((cnvFirstEdge + cnv) != base->CONTROLS[chnlId].CnV) not covered. $ref tpm_c_ref_1$.
438 */
439 } while ((cnvFirstEdge + cnv) != base->CONTROLS[chnlId].CnV);
440 }
441 else
442 {
443 #endif
444 /* Configure dutycycle */
445 if (chnlParams.dutyCyclePercent == 100U)
446 {
447 cnv = mod + 1U;
448 }
449 else
450 {
451 cnv = (mod * chnlParams.dutyCyclePercent) / 100U;
452 }
453 /* Fix ERROR050050 When TPM is configured in EPWM mode as PS = 0, the compare event is missed on
454 the first reload/overflow after writing 1 to the CnV register and causes an incorrect duty output.*/
455 #if (defined(FSL_FEATURE_TPM_HAS_ERRATA_050050) && FSL_FEATURE_TPM_HAS_ERRATA_050050)
456 assert(!(mode == kTPM_EdgeAlignedPwm && cnv == 1U && (base->SC & TPM_SC_PS_MASK) == kTPM_Prescale_Divide_1));
457 #endif
458 /* When switching mode, disable channel first */
459 TPM_DisableChannel(base, (tpm_chnl_t)chnlId);
460 /* Set the requested PWM mode, output mode MSnB:MSnA field value set to 10 */
461 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, controlBits);
462 do
463 {
464 base->CONTROLS[chnlId].CnV = cnv;
465 /*
466 * $Branch Coverage Justification$
467 * (cnv != base->CONTROLS[chnlId].CnV) not covered. $ref tpm_c_ref_1$.
468 */
469 } while (cnv != base->CONTROLS[chnlId].CnV);
470
471 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
472 }
473 #endif
474 return kStatus_Success;
475 }
476
477 /*!
478 * brief Configures the PWM signal parameters
479 *
480 * User calls this function to configure the PWM signals period, mode, dutycycle and edge. Use this
481 * function to configure all the TPM channels that will be used to output a PWM signal
482 *
483 * param base TPM peripheral base address
484 * param chnlParams Array of PWM channel parameters to configure the channel(s)
485 * param numOfChnls Number of channels to configure, this should be the size of the array passed in
486 * param mode PWM operation mode, options available in enumeration ::tpm_pwm_mode_t
487 * param pwmFreq_Hz PWM signal frequency in Hz
488 * param srcClock_Hz TPM counter clock in Hz
489 *
490 * return kStatus_Success if the PWM setup was successful,
491 * kStatus_Error on failure
492 */
TPM_SetupPwm(TPM_Type * base,const tpm_chnl_pwm_signal_param_t * chnlParams,uint8_t numOfChnls,tpm_pwm_mode_t mode,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz)493 status_t TPM_SetupPwm(TPM_Type *base,
494 const tpm_chnl_pwm_signal_param_t *chnlParams,
495 uint8_t numOfChnls,
496 tpm_pwm_mode_t mode,
497 uint32_t pwmFreq_Hz,
498 uint32_t srcClock_Hz)
499 {
500 assert(NULL != chnlParams);
501
502 uint32_t mod = 0U;
503 uint32_t counterMax = TPM_MAX_COUNTER_VALUE(base);
504 uint32_t tpmClock = (srcClock_Hz / (1UL << (base->SC & TPM_SC_PS_MASK)));
505 status_t status = kStatus_Success;
506
507 if ((0U == pwmFreq_Hz) || (0U == srcClock_Hz) || (0U == numOfChnls) || (tpmClock < pwmFreq_Hz))
508 {
509 return kStatus_InvalidArgument;
510 }
511
512 switch (mode)
513 {
514 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
515 case kTPM_CombinedPwm:
516 #endif
517 case kTPM_EdgeAlignedPwm:
518 base->SC &= ~TPM_SC_CPWMS_MASK;
519 mod = (tpmClock / pwmFreq_Hz) - 1U;
520
521 /*
522 * $Branch Coverage Justification$
523 * (mod > counterMax) not covered. $ref tpm_c_tpm_3$.
524 */
525 if ((mod > counterMax) || (mod == 0U))
526 {
527 /* The MOD greater than the maximum allowed (some instanse only support 16-bit counter) or smaller than
528 1, probably would require changing clock source to get the desired frequency. */
529 status = kStatus_OutOfRange;
530 }
531 break;
532 case kTPM_CenterAlignedPwm:
533 base->SC |= TPM_SC_CPWMS_MASK;
534 mod = tpmClock / (pwmFreq_Hz * 2u);
535 /*
536 * $Branch Coverage Justification$
537 * (mod > counterMax >> 1U) not covered. $ref tpm_c_tpm_3$.
538 */
539 if ((mod > (counterMax >> 1U)) || (mod == 0U))
540 {
541 /* MOD values have additional requirements under center-aligned MODE, it must be kept in the range
542 * of 0x1 ~ 0x7FFF (under 16-bit counter). */
543 status = kStatus_OutOfRange;
544 }
545 break;
546 default:
547 /* All the cease have been listed above, the default case should not be reached. */
548 status = kStatus_InvalidArgument;
549 break;
550 }
551 if (kStatus_Success != status)
552 {
553 return status;
554 }
555 /* Set the PWM period */
556 base->MOD = mod;
557
558 /* Setup each TPM channel */
559 for (uint8_t i = 0; i < numOfChnls; i++)
560 {
561 /* Setup a single PWM channel */
562 status = TPM_SetupSinglePwmChannel(base, mod, mode, *chnlParams);
563 if (status != kStatus_Success)
564 {
565 return status;
566 }
567 chnlParams++;
568 }
569
570 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
571 /* The TPM's QDCTRL register required to be effective */
572 if (1U == (uint8_t)FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base))
573 {
574 /* Clear quadrature Decoder mode because in quadrature Decoder mode PWM doesn't operate*/
575 base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
576 }
577 #endif
578
579 return kStatus_Success;
580 }
581
582 /*!
583 * brief Update the duty cycle of an active PWM signal
584 *
585 * param base TPM peripheral base address
586 * param chnlNumber The channel number. In combined mode, this represents
587 * the channel pair number
588 * param currentPwmMode The current PWM mode set during PWM setup
589 * param dutyCyclePercent New PWM pulse width, value should be between 0 to 100
590 * 0=inactive signal(0% duty cycle)...
591 * 100=active signal (100% duty cycle)
592 * return kStatus_Success if the PWM setup was successful,
593 * kStatus_Error on failure
594 */
TPM_UpdatePwmDutycycle(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_pwm_mode_t currentPwmMode,uint8_t dutyCyclePercent)595 status_t TPM_UpdatePwmDutycycle(TPM_Type *base,
596 tpm_chnl_t chnlNumber,
597 tpm_pwm_mode_t currentPwmMode,
598 uint8_t dutyCyclePercent)
599 {
600 uint32_t cnv, mod;
601 uint32_t counterMax = TPM_MAX_COUNTER_VALUE(base);
602 uint8_t chnlId = (uint8_t)chnlNumber;
603
604 /* Return error if requested chnlNumber is greater than the max allowed */
605 /* Return error if requested dutycycle/chnlNumber is greater than the max allowed */
606 if ((chnlId >= (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) ||
607 (-1 == (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)))
608 {
609 return kStatus_InvalidArgument;
610 }
611 /* Get the PWM period */
612 mod = base->MOD & counterMax;
613 /* Return error if requested dutycycle is greater than the max allowed */
614 if (((dutyCyclePercent == 100U) && (mod == counterMax)) || (dutyCyclePercent > 100U))
615 {
616 /* MOD can't equal to 0xFFFF otherwise it can't get a 100% duty cycle PWM signal. */
617 return kStatus_OutOfRange;
618 }
619
620 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
621 if (currentPwmMode == kTPM_CombinedPwm)
622 {
623 /* Check added for combined mode */
624 /*
625 * $Branch Coverage Justification$
626 * (chnlId >= ((uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2U)) not covered. $ref tpm_c_ref_2$.
627 */
628 if ((chnlId >= ((uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2U)) ||
629 (1U != (uint8_t)FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base)))
630 {
631 /* The instance should support combine mode and the channel number should be the pair number */
632 return kStatus_InvalidArgument;
633 }
634 uint32_t cnvFirstEdge;
635 cnv = (mod * dutyCyclePercent) / 100U;
636 if ((base->CONTROLS[chnlId * 2U].CnV & counterMax) > mod)
637 {
638 cnvFirstEdge = 0U;
639 }
640 else
641 {
642 cnvFirstEdge = base->CONTROLS[chnlId * 2U].CnV & counterMax;
643 }
644
645 if (((cnvFirstEdge + cnv) > mod) || ((cnv == 0U) && (cnvFirstEdge > 0U)))
646 {
647 /* Return error if the following situation occurs :
648 * firstEdgeDelayPercent + dutyCyclePercent > 100
649 * firstEdgeDelayPercent > 0 and dutyCyclePercent == 0
650 */
651 return kStatus_OutOfRange;
652 }
653 if (cnv == mod)
654 {
655 /* 100% duty cycle */
656 cnv = mod + 1U;
657 }
658 else if (cnv == 0U)
659 {
660 /* 0% duty cycle */
661 cnvFirstEdge = mod + 1U;
662 }
663 else
664 {
665 ; /* Intentional empty */
666 }
667
668 do
669 {
670 base->CONTROLS[chnlId * 2U].CnV = cnvFirstEdge;
671 /*
672 * $Branch Coverage Justification$
673 * (cnvFirstEdge != base->CONTROLS[chnlId * 2U].CnV) not covered. $ref tpm_c_ref_1$.
674 */
675 } while (cnvFirstEdge != base->CONTROLS[chnlId * 2U].CnV);
676 do
677 {
678 base->CONTROLS[(chnlId * 2U) + 1U].CnV = cnvFirstEdge + cnv;
679 } while ((cnvFirstEdge + cnv) != base->CONTROLS[(chnlId * 2U) + 1U].CnV);
680 }
681 else
682 {
683 #endif
684 if (dutyCyclePercent == 100U)
685 {
686 cnv = mod + 1U;
687 }
688 else
689 {
690 cnv = (mod * dutyCyclePercent) / 100U;
691 }
692 /* Fix ERROR050050 */
693 #if (defined(FSL_FEATURE_TPM_HAS_ERRATA_050050) && FSL_FEATURE_TPM_HAS_ERRATA_050050)
694 assert(!(currentPwmMode == kTPM_EdgeAlignedPwm && cnv == 1U &&
695 (base->SC & TPM_SC_PS_MASK) == kTPM_Prescale_Divide_1));
696 #endif
697
698 do
699 {
700 base->CONTROLS[chnlId].CnV = cnv;
701 /*
702 * $Branch Coverage Justification$
703 * (cnv != base->CONTROLS[chnlId].CnV) not covered. $ref tpm_c_ref_1$.
704 */
705 } while (cnv != base->CONTROLS[chnlId].CnV);
706
707 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
708 }
709 #endif
710 return kStatus_Success;
711 }
712
713 /*!
714 * brief Update the edge level selection for a channel
715 *
716 * note When the TPM has PWM pause level select feature (FSL_FEATURE_TPM_HAS_PAUSE_LEVEL_SELECT = 1), the PWM output
717 * cannot be turned off by selecting the output level. In this case, must use TPM_DisableChannel API to close
718 * the PWM output.
719 *
720 * param base TPM peripheral base address
721 * param chnlNumber The channel number
722 * param level The level to be set to the ELSnB:ELSnA field; valid values are 00, 01, 10, 11.
723 * See the appropriate SoC reference manual for details about this field.
724 */
TPM_UpdateChnlEdgeLevelSelect(TPM_Type * base,tpm_chnl_t chnlNumber,uint8_t level)725 void TPM_UpdateChnlEdgeLevelSelect(TPM_Type *base, tpm_chnl_t chnlNumber, uint8_t level)
726 {
727 assert(((uint8_t)chnlNumber < (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) &&
728 (-1 != (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)));
729
730 uint8_t control = TPM_GetChannelContorlBits(base, chnlNumber);
731
732 /* When switching mode, disable channel first */
733 TPM_DisableChannel(base, chnlNumber);
734
735 /* Clear the field and write the new level value */
736 control &= ~(uint8_t)(TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
737 control |= ((uint8_t)level << TPM_CnSC_ELSA_SHIFT) & (TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
738
739 /* Enable channle with new level value */
740 TPM_EnableChannel(base, chnlNumber, control);
741 }
742
743 /*!
744 * brief Enables capturing an input signal on the channel using the function parameters.
745 *
746 * When the edge specified in the captureMode argument occurs on the channel, the TPM counter is captured into
747 * the CnV register. The user has to read the CnV register separately to get this value.
748 *
749 * param base TPM peripheral base address
750 * param chnlNumber The channel number
751 * param captureMode Specifies which edge to capture
752 */
TPM_SetupInputCapture(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_input_capture_edge_t captureMode)753 void TPM_SetupInputCapture(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_input_capture_edge_t captureMode)
754 {
755 assert(((uint8_t)chnlNumber < (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) &&
756 (-1 != (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)));
757
758 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
759 /* The TPM's QDCTRL register required to be effective */
760 if (1U == (uint8_t)FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base))
761 {
762 /* Clear quadrature Decoder mode for channel 0 or 1*/
763 if (((uint32_t)chnlNumber == 0u) || ((uint32_t)chnlNumber == 1u))
764 {
765 base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
766 }
767 }
768 #endif
769
770 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
771 /* The TPM's COMBINE register required to be effective */
772 if (1U == (uint8_t)FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base))
773 {
774 /* Clear the combine bit for chnlNumber */
775 base->COMBINE &= ~((uint32_t)1U << (((uint32_t)chnlNumber / 2U) * TPM_COMBINE_SHIFT));
776 }
777 #endif
778 /*Clear CPWMS bit when the input capture mode is selected */
779 base->SC &= ~TPM_SC_CPWMS_MASK;
780 /* When switching mode, disable channel first */
781 TPM_DisableChannel(base, chnlNumber);
782 /* Enable channel with new requested input capture mode */
783 TPM_EnableChannel(base, chnlNumber, (uint8_t)captureMode);
784 }
785
786 /*!
787 * brief Configures the TPM to generate timed pulses.
788 *
789 * When the TPM counter matches the value of compareVal argument (this is written into CnV reg), the channel
790 * output is changed based on what is specified in the compareMode argument.
791 *
792 * param base TPM peripheral base address
793 * param chnlNumber The channel number
794 * param compareMode Action to take on the channel output when the compare condition is met
795 * param compareValue Value to be programmed in the CnV register.
796 */
TPM_SetupOutputCompare(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_output_compare_mode_t compareMode,uint32_t compareValue)797 void TPM_SetupOutputCompare(TPM_Type *base,
798 tpm_chnl_t chnlNumber,
799 tpm_output_compare_mode_t compareMode,
800 uint32_t compareValue)
801 {
802 assert(((uint8_t)chnlNumber < (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)) &&
803 (-1 != (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)));
804
805 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
806 /* The TPM's QDCTRL register required to be effective */
807 if (1U == (uint8_t)FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base))
808 {
809 /* Clear quadrature Decoder mode for channel 0 or 1 */
810 if (((uint32_t)chnlNumber == 0U) || ((uint32_t)chnlNumber == 1U))
811 {
812 base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
813 }
814 }
815 #endif
816
817 /*Clear CPWMS bit when the output compare mode is selected */
818 base->SC &= ~TPM_SC_CPWMS_MASK;
819 /* When switching mode, disable channel first */
820 TPM_DisableChannel(base, chnlNumber);
821 /* Enable channel with new requested compare mode */
822 TPM_EnableChannel(base, chnlNumber, (uint8_t)compareMode);
823
824 /* Setup the compare value */
825 do
826 {
827 base->CONTROLS[chnlNumber].CnV = compareValue;
828 /*
829 * $Branch Coverage Justification$
830 * (compareValue != base->CONTROLS[chnlNumber].CnV) not covered. $ref tpm_c_ref_1$.
831 */
832 } while (compareValue != base->CONTROLS[chnlNumber].CnV);
833 }
834
835 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
836 /*!
837 * brief Configures the dual edge capture mode of the TPM.
838 *
839 * This function allows to measure a pulse width of the signal on the input of channel of a
840 * channel pair. The filter function is disabled if the filterVal argument passed is zero.
841 *
842 * param base TPM peripheral base address
843 * param chnlPairNumber The TPM channel pair number; options are 0, 1, 2, 3
844 * param edgeParam Sets up the dual edge capture function
845 * param filterValue Filter value, specify 0 to disable filter.
846 */
TPM_SetupDualEdgeCapture(TPM_Type * base,tpm_chnl_t chnlPairNumber,const tpm_dual_edge_capture_param_t * edgeParam,uint32_t filterValue)847 void TPM_SetupDualEdgeCapture(TPM_Type *base,
848 tpm_chnl_t chnlPairNumber,
849 const tpm_dual_edge_capture_param_t *edgeParam,
850 uint32_t filterValue)
851 {
852 assert(NULL != edgeParam);
853 assert(((uint8_t)chnlPairNumber < (uint8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2U) &&
854 (-1 != (int8_t)FSL_FEATURE_TPM_CHANNEL_COUNTn(base)));
855 assert(1U == (uint8_t)FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base));
856
857 uint32_t reg;
858 uint32_t u32flag;
859 uint8_t chnlId = (uint8_t)chnlPairNumber * 2U;
860
861 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
862 /* The TPM's QDCTRL register required to be effective */
863 if (1U == (uint8_t)FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base))
864 {
865 /* Clear quadrature Decoder mode for channel 0 or 1*/
866 if (chnlId == 0u)
867 {
868 base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
869 }
870 }
871 #endif
872
873 /* When switching mode, disable channel first */
874 TPM_DisableChannel(base, (tpm_chnl_t)chnlId);
875 chnlId++;
876 TPM_DisableChannel(base, (tpm_chnl_t)chnlId);
877 chnlId--;
878
879 /* Now, the registers for input mode can be operated. */
880 if (true == edgeParam->enableSwap)
881 {
882 u32flag = TPM_COMBINE_COMBINE0_MASK | TPM_COMBINE_COMSWAP0_MASK;
883 /* Set the combine and swap bits for the channel pair */
884 base->COMBINE |= u32flag << (TPM_COMBINE_SHIFT * (uint32_t)chnlPairNumber);
885
886 /* Input filter setup for channel n+1 input */
887 reg = base->FILTER;
888 reg &= ~((uint32_t)TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * (chnlId + 1U)));
889 reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * (chnlId + 1U)));
890 base->FILTER = reg;
891 }
892 else
893 {
894 reg = base->COMBINE;
895 /* Clear the swap bit for the channel pair */
896 reg &= ~((uint32_t)TPM_COMBINE_COMSWAP0_MASK << ((uint32_t)chnlPairNumber * TPM_COMBINE_COMSWAP0_SHIFT));
897 u32flag = TPM_COMBINE_COMBINE0_MASK;
898
899 /* Set the combine bit for the channel pair */
900 reg |= u32flag << (TPM_COMBINE_SHIFT * (uint32_t)chnlPairNumber);
901 base->COMBINE = reg;
902
903 /* Input filter setup for channel n input */
904 reg = base->FILTER;
905 reg &= ~((uint32_t)TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * chnlId));
906 reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * chnlId));
907 base->FILTER = reg;
908 }
909
910 /* Setup the edge detection from channel n and n+1*/
911 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, (uint8_t)edgeParam->currChanEdgeMode);
912 chnlId++;
913 TPM_EnableChannel(base, (tpm_chnl_t)chnlId, (uint8_t)edgeParam->nextChanEdgeMode);
914 }
915 #endif
916
917 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
918 /*!
919 * brief Configures the parameters and activates the quadrature decode mode.
920 *
921 * param base TPM peripheral base address
922 * param phaseAParams Phase A configuration parameters
923 * param phaseBParams Phase B configuration parameters
924 * param quadMode Selects encoding mode used in quadrature decoder mode
925 */
TPM_SetupQuadDecode(TPM_Type * base,const tpm_phase_params_t * phaseAParams,const tpm_phase_params_t * phaseBParams,tpm_quad_decode_mode_t quadMode)926 void TPM_SetupQuadDecode(TPM_Type *base,
927 const tpm_phase_params_t *phaseAParams,
928 const tpm_phase_params_t *phaseBParams,
929 tpm_quad_decode_mode_t quadMode)
930 {
931 assert(NULL != phaseAParams);
932 assert(NULL != phaseBParams);
933 assert(1U == (uint8_t)FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base));
934
935 /* Disable channel 0 */
936 TPM_DisableChannel(base, kTPM_Chnl_0);
937
938 uint32_t reg;
939
940 /* Set Phase A filter value */
941 reg = base->FILTER;
942 reg &= ~(TPM_FILTER_CH0FVAL_MASK);
943 reg |= TPM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
944 base->FILTER = reg;
945
946 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
947 /*
948 * $Branch Coverage Justification$
949 * (1U != FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base)) not covered. $ref tpm_c_ref_4$.
950 */
951 if (1U == (uint8_t)FSL_FEATURE_TPM_POL_HAS_EFFECTn(base))
952 {
953 /* Set Phase A polarity */
954 if (kTPM_QuadPhaseInvert == phaseAParams->phasePolarity)
955 {
956 base->POL |= TPM_POL_POL0_MASK;
957 }
958 else
959 {
960 base->POL &= ~TPM_POL_POL0_MASK;
961 }
962 }
963 #endif
964
965 /* Disable channel 1 */
966 TPM_DisableChannel(base, kTPM_Chnl_0);
967
968 /* Set Phase B filter value */
969 reg = base->FILTER;
970 reg &= ~(TPM_FILTER_CH1FVAL_MASK);
971 reg |= TPM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
972 base->FILTER = reg;
973 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
974 /*
975 * $Branch Coverage Justification$
976 * (1U != FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base)) not covered. $ref tpm_c_ref_4$.
977 */
978 if (1U == (uint8_t)FSL_FEATURE_TPM_POL_HAS_EFFECTn(base))
979 {
980 /* Set Phase B polarity */
981 if (kTPM_QuadPhaseInvert == phaseBParams->phasePolarity)
982 {
983 base->POL |= TPM_POL_POL1_MASK;
984 }
985 else
986 {
987 base->POL &= ~TPM_POL_POL1_MASK;
988 }
989 }
990 #endif
991
992 /* Set Quadrature mode */
993 reg = base->QDCTRL;
994 reg &= ~(TPM_QDCTRL_QUADMODE_MASK);
995 reg |= TPM_QDCTRL_QUADMODE(quadMode);
996 base->QDCTRL = reg;
997
998 /* Enable Quad decode */
999 base->QDCTRL |= TPM_QDCTRL_QUADEN_MASK;
1000 }
1001
1002 #endif
1003
1004 /*!
1005 * brief Enables the selected TPM interrupts.
1006 *
1007 * param base TPM peripheral base address
1008 * param mask The interrupts to enable. This is a logical OR of members of the
1009 * enumeration ::tpm_interrupt_enable_t
1010 */
TPM_EnableInterrupts(TPM_Type * base,uint32_t mask)1011 void TPM_EnableInterrupts(TPM_Type *base, uint32_t mask)
1012 {
1013 uint32_t chnlInterrupts = (mask & 0xFFU);
1014 uint8_t chnlNumber = 0;
1015
1016 /* Enable the timer overflow interrupt */
1017 if ((uint32_t)kTPM_TimeOverflowInterruptEnable == (mask & (uint32_t)kTPM_TimeOverflowInterruptEnable))
1018 {
1019 base->SC |= TPM_SC_TOIE_MASK;
1020 }
1021
1022 /* Enable the channel interrupts */
1023 while (0U != chnlInterrupts)
1024 {
1025 if (0U != (chnlInterrupts & 0x1u))
1026 {
1027 base->CONTROLS[chnlNumber].CnSC |= TPM_CnSC_CHIE_MASK;
1028 }
1029 chnlNumber++;
1030 chnlInterrupts = chnlInterrupts >> 1U;
1031 }
1032 }
1033
1034 /*!
1035 * brief Disables the selected TPM interrupts.
1036 *
1037 * param base TPM peripheral base address
1038 * param mask The interrupts to disable. This is a logical OR of members of the
1039 * enumeration ::tpm_interrupt_enable_t
1040 */
TPM_DisableInterrupts(TPM_Type * base,uint32_t mask)1041 void TPM_DisableInterrupts(TPM_Type *base, uint32_t mask)
1042 {
1043 uint32_t chnlInterrupts = (mask & 0xFFU);
1044 uint8_t chnlNumber = 0;
1045
1046 /* Disable the timer overflow interrupt */
1047 if ((uint32_t)kTPM_TimeOverflowInterruptEnable == (mask & (uint32_t)kTPM_TimeOverflowInterruptEnable))
1048 {
1049 base->SC &= ~TPM_SC_TOIE_MASK;
1050 }
1051
1052 /* Disable the channel interrupts */
1053 while (0U != chnlInterrupts)
1054 {
1055 if (0U != (chnlInterrupts & 0x1u))
1056 {
1057 base->CONTROLS[chnlNumber].CnSC &= ~TPM_CnSC_CHIE_MASK;
1058 }
1059 chnlNumber++;
1060 chnlInterrupts = chnlInterrupts >> 1U;
1061 }
1062 }
1063
1064 /*!
1065 * brief Gets the enabled TPM interrupts.
1066 *
1067 * param base TPM peripheral base address
1068 *
1069 * return The enabled interrupts. This is the logical OR of members of the
1070 * enumeration ::tpm_interrupt_enable_t
1071 */
TPM_GetEnabledInterrupts(TPM_Type * base)1072 uint32_t TPM_GetEnabledInterrupts(TPM_Type *base)
1073 {
1074 uint32_t enabledInterrupts = 0;
1075 uint32_t u32flag = 1;
1076 int8_t chnlCount = FSL_FEATURE_TPM_CHANNEL_COUNTn(base);
1077
1078 /* The CHANNEL_COUNT macro returns -1 if it cannot match the TPM instance */
1079 assert(chnlCount != -1);
1080
1081 /* Check if timer overflow interrupt is enabled */
1082 if (0U != (base->SC & TPM_SC_TOIE_MASK))
1083 {
1084 enabledInterrupts |= (uint32_t)kTPM_TimeOverflowInterruptEnable;
1085 }
1086
1087 /* Check if the channel interrupts are enabled */
1088 while (chnlCount > 0)
1089 {
1090 chnlCount--;
1091 if (0U != (base->CONTROLS[chnlCount].CnSC & TPM_CnSC_CHIE_MASK))
1092 {
1093 enabledInterrupts |= (u32flag << (uint8_t)chnlCount);
1094 }
1095 }
1096
1097 return enabledInterrupts;
1098 }
1099
1100 /*!
1101 * brief Register callback.
1102 *
1103 * If channel or overflow interrupt is enabled by the user, then a callback can be registered
1104 * which will be invoked when the interrupt is triggered.
1105 *
1106 * param base TPM peripheral base address
1107 * param callback Callback function
1108 */
TPM_RegisterCallBack(TPM_Type * base,tpm_callback_t callback)1109 void TPM_RegisterCallBack(TPM_Type *base, tpm_callback_t callback)
1110 {
1111 uint32_t instance;
1112
1113 instance = TPM_GetInstance(base);
1114
1115 /* Create TPM callback instance. */
1116 s_tpmCallback[instance] = callback;
1117
1118 /* Enable IRQ. */
1119 (void)EnableIRQ(s_tpmIRQ[instance]);
1120 }
1121
1122 #if defined(TPM0)
1123 void TPM0_DriverIRQHandler(void);
TPM0_DriverIRQHandler(void)1124 void TPM0_DriverIRQHandler(void)
1125 {
1126 if (NULL != s_tpmCallback[0])
1127 {
1128 s_tpmCallback[0](TPM0);
1129 }
1130 SDK_ISR_EXIT_BARRIER;
1131 }
1132 #endif
1133
1134 #if defined(TPM1)
1135 void TPM1_DriverIRQHandler(void);
TPM1_DriverIRQHandler(void)1136 void TPM1_DriverIRQHandler(void)
1137 {
1138 if (NULL != s_tpmCallback[1])
1139 {
1140 s_tpmCallback[1](TPM1);
1141 }
1142 SDK_ISR_EXIT_BARRIER;
1143 }
1144 #endif
1145