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