Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

1206 строки
43 KiB

  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2020 NXP
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_ftm.h"
  9. /* Component ID definition, used by tools. */
  10. #ifndef FSL_COMPONENT_ID
  11. #define FSL_COMPONENT_ID "platform.drivers.ftm"
  12. #endif
  13. /*******************************************************************************
  14. * Prototypes
  15. ******************************************************************************/
  16. /*!
  17. * @brief Gets the instance from the base address
  18. *
  19. * @param base FTM peripheral base address
  20. *
  21. * @return The FTM instance
  22. */
  23. static uint32_t FTM_GetInstance(FTM_Type *base);
  24. /*!
  25. * @brief Sets the FTM register PWM synchronization method
  26. *
  27. * This function will set the necessary bits for the PWM synchronization mode that
  28. * user wishes to use.
  29. *
  30. * @param base FTM peripheral base address
  31. * @param syncMethod Synchronization methods to use to update buffered registers. This is a logical
  32. * OR of members of the enumeration ::ftm_pwm_sync_method_t
  33. */
  34. static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod);
  35. /*!
  36. * @brief Sets the reload points used as loading points for register update
  37. *
  38. * This function will set the necessary bits based on what the user wishes to use as loading
  39. * points for FTM register update. When using this it is not required to use PWM synchnronization.
  40. *
  41. * @param base FTM peripheral base address
  42. * @param reloadPoints FTM reload points. This is a logical OR of members of the
  43. * enumeration ::ftm_reload_point_t
  44. */
  45. static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints);
  46. /*******************************************************************************
  47. * Variables
  48. ******************************************************************************/
  49. /*! @brief Pointers to FTM bases for each instance. */
  50. static FTM_Type *const s_ftmBases[] = FTM_BASE_PTRS;
  51. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  52. /*! @brief Pointers to FTM clocks for each instance. */
  53. static const clock_ip_name_t s_ftmClocks[] = FTM_CLOCKS;
  54. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  55. /*******************************************************************************
  56. * Code
  57. ******************************************************************************/
  58. static uint32_t FTM_GetInstance(FTM_Type *base)
  59. {
  60. uint32_t instance;
  61. uint32_t ftmArrayCount = (sizeof(s_ftmBases) / sizeof(s_ftmBases[0]));
  62. /* Find the instance index from base address mappings. */
  63. for (instance = 0; instance < ftmArrayCount; instance++)
  64. {
  65. if (s_ftmBases[instance] == base)
  66. {
  67. break;
  68. }
  69. }
  70. assert(instance < ftmArrayCount);
  71. return instance;
  72. }
  73. static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod)
  74. {
  75. uint8_t chnlNumber = 0;
  76. uint32_t reg = 0, syncReg = 0;
  77. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  78. assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
  79. syncReg = base->SYNC;
  80. /* Enable PWM synchronization of output mask register */
  81. syncReg |= FTM_SYNC_SYNCHOM_MASK;
  82. reg = base->COMBINE;
  83. for (chnlNumber = 0; chnlNumber < ((uint8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U); chnlNumber++)
  84. {
  85. /* Enable PWM synchronization of registers C(n)V and C(n+1)V */
  86. reg |= (1UL << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
  87. }
  88. base->COMBINE = reg;
  89. reg = base->SYNCONF;
  90. /* Use enhanced PWM synchronization method. Use PWM sync to update register values */
  91. reg |= (FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_CNTINC_MASK | FTM_SYNCONF_INVC_MASK | FTM_SYNCONF_SWOC_MASK);
  92. if ((syncMethod & FTM_SYNC_SWSYNC_MASK) != 0U)
  93. {
  94. /* Enable needed bits for software trigger to update registers with its buffer value */
  95. reg |= (FTM_SYNCONF_SWRSTCNT_MASK | FTM_SYNCONF_SWWRBUF_MASK | FTM_SYNCONF_SWINVC_MASK |
  96. FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWOM_MASK);
  97. }
  98. if ((syncMethod & (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK)) != 0U)
  99. {
  100. /* Enable needed bits for hardware trigger to update registers with its buffer value */
  101. reg |= (FTM_SYNCONF_HWRSTCNT_MASK | FTM_SYNCONF_HWWRBUF_MASK | FTM_SYNCONF_HWINVC_MASK |
  102. FTM_SYNCONF_HWSOC_MASK | FTM_SYNCONF_HWOM_MASK);
  103. /* Enable the appropriate hardware trigger that is used for PWM sync */
  104. if ((syncMethod & FTM_SYNC_TRIG0_MASK) != 0U)
  105. {
  106. syncReg |= FTM_SYNC_TRIG0_MASK;
  107. }
  108. if ((syncMethod & FTM_SYNC_TRIG1_MASK) != 0U)
  109. {
  110. syncReg |= FTM_SYNC_TRIG1_MASK;
  111. }
  112. if ((syncMethod & FTM_SYNC_TRIG2_MASK) != 0U)
  113. {
  114. syncReg |= FTM_SYNC_TRIG2_MASK;
  115. }
  116. }
  117. /* Write back values to the SYNC register */
  118. base->SYNC = syncReg;
  119. /* Write the PWM synch values to the SYNCONF register */
  120. base->SYNCONF = reg;
  121. }
  122. static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints)
  123. {
  124. uint32_t chnlNumber = 0;
  125. uint32_t reg = 0;
  126. int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
  127. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  128. assert(-1 != chnlCount);
  129. /* Need CNTINC bit to be 1 for CNTIN register to update with its buffer value on reload */
  130. base->SYNCONF |= FTM_SYNCONF_CNTINC_MASK;
  131. reg = base->COMBINE;
  132. for (chnlNumber = 0; chnlNumber < ((uint32_t)chnlCount / 2U); chnlNumber++)
  133. {
  134. /* Need SYNCEN bit to be 1 for CnV reg to update with its buffer value on reload */
  135. reg |= (1UL << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
  136. }
  137. base->COMBINE = reg;
  138. /* Set the reload points */
  139. reg = base->PWMLOAD;
  140. /* Enable the selected channel match reload points */
  141. reg &= ~((1UL << (uint32_t)chnlCount) - 1U);
  142. reg |= (reloadPoints & ((1UL << (uint32_t)chnlCount) - 1U));
  143. #if defined(FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD) && (FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD)
  144. /* Enable half cycle match as a reload point */
  145. if ((reloadPoints & (uint32_t)kFTM_HalfCycMatch) != 0U)
  146. {
  147. reg |= FTM_PWMLOAD_HCSEL_MASK;
  148. }
  149. else
  150. {
  151. reg &= ~FTM_PWMLOAD_HCSEL_MASK;
  152. }
  153. #endif /* FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD */
  154. base->PWMLOAD = reg;
  155. /* These reload points are used when counter is in up-down counting mode */
  156. reg = base->SYNC;
  157. if ((reloadPoints & (uint32_t)kFTM_CntMax) != 0U)
  158. {
  159. /* Reload when counter turns from up to down */
  160. reg |= FTM_SYNC_CNTMAX_MASK;
  161. }
  162. else
  163. {
  164. reg &= ~FTM_SYNC_CNTMAX_MASK;
  165. }
  166. if ((reloadPoints & (uint32_t)kFTM_CntMin) != 0U)
  167. {
  168. /* Reload when counter turns from down to up */
  169. reg |= FTM_SYNC_CNTMIN_MASK;
  170. }
  171. else
  172. {
  173. reg &= ~FTM_SYNC_CNTMIN_MASK;
  174. }
  175. base->SYNC = reg;
  176. }
  177. /*!
  178. * brief Ungates the FTM clock and configures the peripheral for basic operation.
  179. *
  180. * note This API should be called at the beginning of the application which is using the FTM driver.
  181. * If the FTM instance has only TPM features, please use the TPM driver.
  182. *
  183. * param base FTM peripheral base address
  184. * param config Pointer to the user configuration structure.
  185. *
  186. * return kStatus_Success indicates success; Else indicates failure.
  187. */
  188. status_t FTM_Init(FTM_Type *base, const ftm_config_t *config)
  189. {
  190. assert(config);
  191. #if defined(FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE)
  192. /* This function does not support the current instance, please use the TPM driver. */
  193. assert((FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE(base) == 0U));
  194. #endif /* FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE */
  195. uint32_t reg;
  196. if ((config->pwmSyncMode & (uint32_t)((uint32_t)FTM_SYNC_TRIG0_MASK | (uint32_t)FTM_SYNC_TRIG1_MASK |
  197. (uint32_t)FTM_SYNC_TRIG2_MASK | (uint32_t)FTM_SYNC_SWSYNC_MASK)) == 0U)
  198. {
  199. /* Invalid PWM sync mode */
  200. return kStatus_Fail;
  201. }
  202. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  203. /* Ungate the FTM clock*/
  204. (void)CLOCK_EnableClock(s_ftmClocks[FTM_GetInstance(base)]);
  205. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  206. /* Configure the fault mode, enable FTM mode and disable write protection */
  207. base->MODE = FTM_MODE_FAULTM(config->faultMode) | FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
  208. /* Configure the update mechanism for buffered registers */
  209. FTM_SetPwmSync(base, config->pwmSyncMode);
  210. /* Setup intermediate register reload points */
  211. FTM_SetReloadPoints(base, config->reloadPoints);
  212. /* Set the clock prescale factor */
  213. base->SC = FTM_SC_PS(config->prescale);
  214. /* Setup the counter operation */
  215. base->CONF = (FTM_CONF_BDMMODE(config->bdmMode) | FTM_CONF_GTBEEN(config->useGlobalTimeBase));
  216. /* Initial state of channel output */
  217. base->OUTINIT = config->chnlInitState;
  218. /* Channel polarity */
  219. base->POL = config->chnlPolarity;
  220. /* Set the external trigger sources */
  221. base->EXTTRIG = config->extTriggers;
  222. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER) && (FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER)
  223. if ((config->extTriggers & (uint32_t)kFTM_ReloadInitTrigger) != 0U)
  224. {
  225. base->CONF |= FTM_CONF_ITRIGR_MASK;
  226. }
  227. else
  228. {
  229. base->CONF &= ~FTM_CONF_ITRIGR_MASK;
  230. }
  231. #endif /* FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER */
  232. /* FTM deadtime insertion control */
  233. base->DEADTIME = (0u |
  234. #if defined(FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE) && (FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE)
  235. /* Has extended deadtime value register) */
  236. FTM_DEADTIME_DTVALEX(config->deadTimeValue >> 6) |
  237. #endif /* FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE */
  238. FTM_DEADTIME_DTPS(config->deadTimePrescale) | FTM_DEADTIME_DTVAL(config->deadTimeValue));
  239. /* FTM fault filter value */
  240. reg = base->FLTCTRL;
  241. reg &= ~FTM_FLTCTRL_FFVAL_MASK;
  242. reg |= FTM_FLTCTRL_FFVAL(config->faultFilterValue);
  243. base->FLTCTRL = reg;
  244. return kStatus_Success;
  245. }
  246. /*!
  247. * brief Gates the FTM clock.
  248. *
  249. * param base FTM peripheral base address
  250. */
  251. void FTM_Deinit(FTM_Type *base)
  252. {
  253. /* Set clock source to none to disable counter */
  254. base->SC &= ~(FTM_SC_CLKS_MASK);
  255. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  256. /* Gate the FTM clock */
  257. (void)CLOCK_DisableClock(s_ftmClocks[FTM_GetInstance(base)]);
  258. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  259. }
  260. /*!
  261. * brief Fills in the FTM configuration structure with the default settings.
  262. *
  263. * The default values are:
  264. * code
  265. * config->prescale = kFTM_Prescale_Divide_1;
  266. * config->bdmMode = kFTM_BdmMode_0;
  267. * config->pwmSyncMode = kFTM_SoftwareTrigger;
  268. * config->reloadPoints = 0;
  269. * config->faultMode = kFTM_Fault_Disable;
  270. * config->faultFilterValue = 0;
  271. * config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
  272. * config->deadTimeValue = 0;
  273. * config->extTriggers = 0;
  274. * config->chnlInitState = 0;
  275. * config->chnlPolarity = 0;
  276. * config->useGlobalTimeBase = false;
  277. * endcode
  278. * param config Pointer to the user configuration structure.
  279. */
  280. void FTM_GetDefaultConfig(ftm_config_t *config)
  281. {
  282. assert(config != NULL);
  283. /* Initializes the configure structure to zero. */
  284. (void)memset(config, 0, sizeof(*config));
  285. /* Divide FTM clock by 1 */
  286. config->prescale = kFTM_Prescale_Divide_1;
  287. /* FTM behavior in BDM mode */
  288. config->bdmMode = kFTM_BdmMode_0;
  289. /* Software trigger will be used to update registers */
  290. config->pwmSyncMode = (uint32_t)kFTM_SoftwareTrigger;
  291. /* No intermediate register load */
  292. config->reloadPoints = 0;
  293. /* Fault control disabled for all channels */
  294. config->faultMode = kFTM_Fault_Disable;
  295. /* Disable the fault filter */
  296. config->faultFilterValue = 0;
  297. /* Divide the system clock by 1 */
  298. config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
  299. /* No counts are inserted */
  300. config->deadTimeValue = 0;
  301. /* No external trigger */
  302. config->extTriggers = 0;
  303. /* Initialization value is 0 for all channels */
  304. config->chnlInitState = 0;
  305. /* Active high polarity for all channels */
  306. config->chnlPolarity = 0;
  307. /* Use internal FTM counter as timebase */
  308. config->useGlobalTimeBase = false;
  309. }
  310. /*!
  311. * brief Configures the PWM signal parameters.
  312. *
  313. * Call this function to configure the PWM signal period, mode, duty cycle, and edge. Use this
  314. * function to configure all FTM channels that are used to output a PWM signal.
  315. *
  316. * param base FTM peripheral base address
  317. * param chnlParams Array of PWM channel parameters to configure the channel(s)
  318. * param numOfChnls Number of channels to configure; This should be the size of the array passed in
  319. * param mode PWM operation mode, options available in enumeration ::ftm_pwm_mode_t
  320. * param pwmFreq_Hz PWM signal frequency in Hz
  321. * param srcClock_Hz FTM counter clock in Hz
  322. *
  323. * return kStatus_Success if the PWM setup was successful
  324. * kStatus_Error on failure
  325. */
  326. status_t FTM_SetupPwm(FTM_Type *base,
  327. const ftm_chnl_pwm_signal_param_t *chnlParams,
  328. uint8_t numOfChnls,
  329. ftm_pwm_mode_t mode,
  330. uint32_t pwmFreq_Hz,
  331. uint32_t srcClock_Hz)
  332. {
  333. assert(NULL != chnlParams);
  334. assert(0U != srcClock_Hz);
  335. assert(0U != pwmFreq_Hz);
  336. assert(0U != numOfChnls);
  337. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  338. assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
  339. uint32_t mod, reg;
  340. uint32_t ftmClock = (srcClock_Hz / (1UL << (base->SC & FTM_SC_PS_MASK)));
  341. uint32_t cnv, cnvFirstEdge;
  342. uint8_t i;
  343. if (mode == kFTM_CenterAlignedPwm)
  344. {
  345. base->SC |= FTM_SC_CPWMS_MASK;
  346. mod = ftmClock / (pwmFreq_Hz * 2U);
  347. }
  348. else
  349. {
  350. base->SC &= ~FTM_SC_CPWMS_MASK;
  351. mod = (ftmClock / pwmFreq_Hz) - 1U;
  352. }
  353. /* Return an error in case we overflow the registers, probably would require changing
  354. * clock source to get the desired frequency */
  355. if (mod > 65535U)
  356. {
  357. return kStatus_Fail;
  358. }
  359. /* Set the PWM period */
  360. base->MOD = mod;
  361. /* Setup each FTM channel */
  362. for (i = 0; i < numOfChnls; i++)
  363. {
  364. /* Return error if requested dutycycle is greater than the max allowed */
  365. if (chnlParams->dutyCyclePercent > 100U)
  366. {
  367. return kStatus_Fail;
  368. }
  369. if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
  370. {
  371. /* Clear the current mode and edge level bits */
  372. reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
  373. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  374. /* Setup the active level */
  375. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  376. /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
  377. reg |= FTM_CnSC_MSB(1U);
  378. /* Update the mode and edge level */
  379. base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
  380. if (chnlParams->dutyCyclePercent == 0U)
  381. {
  382. /* Signal stays low */
  383. cnv = 0;
  384. }
  385. else
  386. {
  387. cnv = (mod * chnlParams->dutyCyclePercent) / 100U;
  388. /* For 100% duty cycle */
  389. if (cnv >= mod)
  390. {
  391. cnv = mod + 1U;
  392. }
  393. }
  394. base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
  395. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  396. /* Set to output mode */
  397. FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
  398. #endif
  399. }
  400. else
  401. {
  402. /* This check is added for combined mode as the channel number should be the pair number */
  403. if (((uint32_t)chnlParams->chnlNumber) >= ((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U))
  404. {
  405. return kStatus_Fail;
  406. }
  407. /* Return error if requested value is greater than the max allowed */
  408. if (chnlParams->firstEdgeDelayPercent > 100U)
  409. {
  410. return kStatus_Fail;
  411. }
  412. /* Configure delay of the first edge */
  413. if (chnlParams->firstEdgeDelayPercent == 0U)
  414. {
  415. /* No delay for the first edge */
  416. cnvFirstEdge = 0;
  417. }
  418. else
  419. {
  420. cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100U;
  421. }
  422. /* Configure dutycycle */
  423. if (chnlParams->dutyCyclePercent == 0U)
  424. {
  425. /* Signal stays low */
  426. cnv = 0;
  427. cnvFirstEdge = 0;
  428. }
  429. else
  430. {
  431. cnv = (mod * chnlParams->dutyCyclePercent) / 100U;
  432. /* For 100% duty cycle */
  433. if (cnv >= mod)
  434. {
  435. cnv = mod + 1U;
  436. }
  437. }
  438. /* Clear the current mode and edge level bits for channel n */
  439. reg = base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC;
  440. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  441. /* Setup the active level for channel n */
  442. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  443. /* Update the mode and edge level for channel n */
  444. base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC = reg;
  445. /* Clear the current mode and edge level bits for channel n + 1 */
  446. reg = base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC;
  447. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  448. /* Setup the active level for channel n + 1 */
  449. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  450. /* Update the mode and edge level for channel n + 1*/
  451. base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC = reg;
  452. /* Set the combine bit for the channel pair */
  453. base->COMBINE |=
  454. (1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlParams->chnlNumber)));
  455. /* Set the channel pair values */
  456. base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnV = cnvFirstEdge;
  457. base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnV = cnvFirstEdge + cnv;
  458. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  459. /* Set to output mode */
  460. FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U), true);
  461. FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U + 1U), true);
  462. #endif /* FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT */
  463. /* Setup for complementary mode. */
  464. if (kFTM_ComplementaryPwm == mode)
  465. {
  466. /* Enable complementary mode. */
  467. FTM_SetComplementaryEnable(base, chnlParams->chnlNumber, true);
  468. /* Enable/disable dead time insertion. */
  469. FTM_SetDeadTimeEnable(base, chnlParams->chnlNumber, chnlParams->enableDeadtime);
  470. }
  471. }
  472. chnlParams++;
  473. }
  474. return kStatus_Success;
  475. }
  476. /*!
  477. * brief Updates the duty cycle of an active PWM signal.
  478. *
  479. * param base FTM peripheral base address
  480. * param chnlNumber The channel/channel pair number. In combined mode, this represents
  481. * the channel pair number
  482. * param currentPwmMode The current PWM mode set during PWM setup
  483. * param dutyCyclePercent New PWM pulse width; The value should be between 0 to 100
  484. * 0=inactive signal(0% duty cycle)...
  485. * 100=active signal (100% duty cycle)
  486. */
  487. void FTM_UpdatePwmDutycycle(FTM_Type *base,
  488. ftm_chnl_t chnlNumber,
  489. ftm_pwm_mode_t currentPwmMode,
  490. uint8_t dutyCyclePercent)
  491. {
  492. uint32_t cnv, cnvFirstEdge = 0, mod;
  493. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  494. assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
  495. mod = base->MOD;
  496. if ((currentPwmMode == kFTM_EdgeAlignedPwm) || (currentPwmMode == kFTM_CenterAlignedPwm))
  497. {
  498. cnv = (mod * dutyCyclePercent) / 100U;
  499. /* For 100% duty cycle */
  500. if (cnv >= mod)
  501. {
  502. cnv = mod + 1U;
  503. }
  504. base->CONTROLS[chnlNumber].CnV = cnv;
  505. }
  506. else
  507. {
  508. /* This check is added for combined mode as the channel number should be the pair number */
  509. if ((uint32_t)chnlNumber >= ((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U))
  510. {
  511. return;
  512. }
  513. cnv = (mod * dutyCyclePercent) / 100U;
  514. cnvFirstEdge = base->CONTROLS[((uint32_t)chnlNumber) * 2U].CnV;
  515. /* For 100% duty cycle */
  516. if (cnv >= mod)
  517. {
  518. cnv = mod + 1U;
  519. }
  520. base->CONTROLS[((uint32_t)chnlNumber * 2U) + 1U].CnV = cnvFirstEdge + cnv;
  521. }
  522. }
  523. /*!
  524. * brief Updates the edge level selection for a channel.
  525. *
  526. * param base FTM peripheral base address
  527. * param chnlNumber The channel number
  528. * param level The level to be set to the ELSnB:ELSnA field; Valid values are 00, 01, 10, 11.
  529. * See the Kinetis SoC reference manual for details about this field.
  530. */
  531. void FTM_UpdateChnlEdgeLevelSelect(FTM_Type *base, ftm_chnl_t chnlNumber, uint8_t level)
  532. {
  533. uint32_t reg = base->CONTROLS[chnlNumber].CnSC;
  534. /* Clear the field and write the new level value */
  535. reg &= ~(FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  536. reg |= ((uint32_t)level << FTM_CnSC_ELSA_SHIFT) & (FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  537. base->CONTROLS[chnlNumber].CnSC = reg;
  538. }
  539. /*!
  540. * brief Configures the PWM mode parameters.
  541. *
  542. * Call this function to configure the PWM signal mode, duty cycle in ticks, and edge. Use this
  543. * function to configure all FTM channels that are used to output a PWM signal.
  544. * Please note that: This API is similar with FTM_SetupPwm() API, but will not set the timer period,
  545. * and this API will set channel match value in timer ticks, not period percent.
  546. *
  547. * param base FTM peripheral base address
  548. * param chnlParams Array of PWM channel parameters to configure the channel(s)
  549. * param numOfChnls Number of channels to configure; This should be the size of the array passed in
  550. * param mode PWM operation mode, options available in enumeration ::ftm_pwm_mode_t
  551. *
  552. * return kStatus_Success if the PWM setup was successful
  553. * kStatus_Error on failure
  554. */
  555. status_t FTM_SetupPwmMode(FTM_Type *base,
  556. const ftm_chnl_pwm_config_param_t *chnlParams,
  557. uint8_t numOfChnls,
  558. ftm_pwm_mode_t mode)
  559. {
  560. assert(chnlParams != NULL);
  561. assert(numOfChnls != 0U);
  562. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  563. assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
  564. uint32_t reg;
  565. uint8_t i;
  566. switch (mode)
  567. {
  568. case kFTM_EdgeAlignedPwm:
  569. case kFTM_ComplementaryPwm:
  570. case kFTM_CombinedPwm:
  571. base->SC &= ~FTM_SC_CPWMS_MASK;
  572. break;
  573. case kFTM_CenterAlignedPwm:
  574. base->SC |= FTM_SC_CPWMS_MASK;
  575. break;
  576. default:
  577. assert(false);
  578. break;
  579. }
  580. /* Setup each FTM channel */
  581. for (i = 0; i < numOfChnls; i++)
  582. {
  583. if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
  584. {
  585. /* Clear the current mode and edge level bits */
  586. reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
  587. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  588. /* Setup the active level */
  589. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  590. /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
  591. reg |= FTM_CnSC_MSB(1U);
  592. /* Update the mode and edge level */
  593. base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
  594. base->CONTROLS[chnlParams->chnlNumber].CnV = chnlParams->dutyValue;
  595. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  596. /* Set to output mode */
  597. FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
  598. #endif
  599. }
  600. else
  601. {
  602. /* This check is added for combined mode as the channel number should be the pair number */
  603. if (((uint32_t)chnlParams->chnlNumber) >= (((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) / 2U))
  604. {
  605. return kStatus_Fail;
  606. }
  607. /* Clear the current mode and edge level bits for channel n */
  608. reg = base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC;
  609. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  610. /* Setup the active level for channel n */
  611. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  612. /* Update the mode and edge level for channel n */
  613. base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC = reg;
  614. /* Clear the current mode and edge level bits for channel n + 1 */
  615. reg = base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC;
  616. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  617. /* Setup the active level for channel n + 1 */
  618. reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
  619. /* Update the mode and edge level for channel n + 1*/
  620. base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC = reg;
  621. /* Set the combine bit for the channel pair */
  622. base->COMBINE |=
  623. (1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlParams->chnlNumber)));
  624. /* Set the channel pair values */
  625. base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnV = chnlParams->firstEdgeValue;
  626. base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnV = chnlParams->dutyValue;
  627. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  628. /* Set to output mode */
  629. FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U), true);
  630. FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U + 1U), true);
  631. #endif /* FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT */
  632. /* Setup for complementary mode. */
  633. if (kFTM_ComplementaryPwm == mode)
  634. {
  635. /* Enable complementary mode. */
  636. FTM_SetComplementaryEnable(base, chnlParams->chnlNumber, true);
  637. }
  638. }
  639. chnlParams++;
  640. }
  641. return kStatus_Success;
  642. }
  643. /*!
  644. * brief Enables capturing an input signal on the channel using the function parameters.
  645. *
  646. * When the edge specified in the captureMode argument occurs on the channel, the FTM counter is
  647. * captured into the CnV register. The user has to read the CnV register separately to get this
  648. * value. The filter function is disabled if the filterVal argument passed in is 0. The filter
  649. * function is available only for channels 0, 1, 2, 3.
  650. *
  651. * param base FTM peripheral base address
  652. * param chnlNumber The channel number
  653. * param captureMode Specifies which edge to capture
  654. * param filterValue Filter value, specify 0 to disable filter. Available only for channels 0-3.
  655. */
  656. void FTM_SetupInputCapture(FTM_Type *base,
  657. ftm_chnl_t chnlNumber,
  658. ftm_input_capture_edge_t captureMode,
  659. uint32_t filterValue)
  660. {
  661. uint32_t reg;
  662. /* Clear the combine bit for the channel pair */
  663. base->COMBINE &=
  664. ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
  665. /* Clear the dual edge capture mode because it's it's higher priority */
  666. base->COMBINE &=
  667. ~(1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
  668. #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
  669. /* Clear the quadrature decoder mode beacause it's higher priority */
  670. base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
  671. #endif
  672. reg = base->CONTROLS[chnlNumber].CnSC;
  673. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  674. reg |= (uint32_t)captureMode;
  675. /* Set the requested input capture mode */
  676. base->CONTROLS[chnlNumber].CnSC = reg;
  677. /* Input filter available only for channels 0, 1, 2, 3 */
  678. if (chnlNumber < kFTM_Chnl_4)
  679. {
  680. reg = base->FILTER;
  681. reg &= ~((uint32_t)FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlNumber));
  682. reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlNumber));
  683. base->FILTER = reg;
  684. }
  685. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  686. /* Set to input mode */
  687. FTM_SetPwmOutputEnable(base, chnlNumber, false);
  688. #endif
  689. }
  690. /*!
  691. * brief Configures the FTM to generate timed pulses.
  692. *
  693. * When the FTM counter matches the value of compareVal argument (this is written into CnV reg),
  694. * the channel output is changed based on what is specified in the compareMode argument.
  695. *
  696. * param base FTM peripheral base address
  697. * param chnlNumber The channel number
  698. * param compareMode Action to take on the channel output when the compare condition is met
  699. * param compareValue Value to be programmed in the CnV register.
  700. */
  701. void FTM_SetupOutputCompare(FTM_Type *base,
  702. ftm_chnl_t chnlNumber,
  703. ftm_output_compare_mode_t compareMode,
  704. uint32_t compareValue)
  705. {
  706. uint32_t reg;
  707. /* Clear the combine bit for the channel pair */
  708. base->COMBINE &=
  709. ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
  710. /* Clear the dual edge capture mode because it's it's higher priority */
  711. base->COMBINE &=
  712. ~(1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
  713. #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
  714. /* Clear the quadrature decoder mode beacause it's higher priority */
  715. base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
  716. #endif
  717. reg = base->CONTROLS[chnlNumber].CnSC;
  718. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  719. reg |= (uint32_t)compareMode;
  720. /* Setup the channel output behaviour when a match occurs with the compare value */
  721. base->CONTROLS[chnlNumber].CnSC = reg;
  722. /* Set output on match to the requested level */
  723. base->CONTROLS[chnlNumber].CnV = compareValue;
  724. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  725. /* Set to output mode */
  726. FTM_SetPwmOutputEnable(base, chnlNumber, true);
  727. #endif
  728. }
  729. /*!
  730. * brief Configures the dual edge capture mode of the FTM.
  731. *
  732. * This function sets up the dual edge capture mode on a channel pair. The capture edge for the
  733. * channel pair and the capture mode (one-shot or continuous) is specified in the parameter
  734. * argument. The filter function is disabled if the filterVal argument passed is zero. The filter
  735. * function is available only on channels 0 and 2. The user has to read the channel CnV registers
  736. * separately to get the capture values.
  737. *
  738. * param base FTM peripheral base address
  739. * param chnlPairNumber The FTM channel pair number; options are 0, 1, 2, 3
  740. * param edgeParam Sets up the dual edge capture function
  741. * param filterValue Filter value, specify 0 to disable filter. Available only for channel pair 0 and 1.
  742. */
  743. void FTM_SetupDualEdgeCapture(FTM_Type *base,
  744. ftm_chnl_t chnlPairNumber,
  745. const ftm_dual_edge_capture_param_t *edgeParam,
  746. uint32_t filterValue)
  747. {
  748. assert(edgeParam);
  749. uint32_t reg;
  750. reg = base->COMBINE;
  751. /* Clear the combine bit for the channel pair */
  752. reg &= ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
  753. /* Enable the DECAPEN bit */
  754. reg |= (1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
  755. reg |= (1UL << (FTM_COMBINE_DECAP0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
  756. base->COMBINE = reg;
  757. /* Setup the edge detection from channel n and n + 1 */
  758. reg = base->CONTROLS[((uint32_t)chnlPairNumber) * 2U].CnSC;
  759. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  760. reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->currChanEdgeMode);
  761. base->CONTROLS[((uint32_t)chnlPairNumber) * 2U].CnSC = reg;
  762. reg = base->CONTROLS[(((uint32_t)chnlPairNumber) * 2U) + 1U].CnSC;
  763. reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
  764. reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->nextChanEdgeMode);
  765. base->CONTROLS[(((uint32_t)chnlPairNumber) * 2U) + 1U].CnSC = reg;
  766. /* Input filter available only for channels 0, 1, 2, 3 */
  767. if (chnlPairNumber < kFTM_Chnl_4)
  768. {
  769. reg = base->FILTER;
  770. reg &= ~((uint32_t)FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlPairNumber));
  771. reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlPairNumber));
  772. base->FILTER = reg;
  773. }
  774. #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
  775. /* Set to input mode */
  776. FTM_SetPwmOutputEnable(base, chnlPairNumber, false);
  777. #endif
  778. }
  779. /*!
  780. * brief Configures the parameters and activates the quadrature decoder mode.
  781. *
  782. * param base FTM peripheral base address
  783. * param phaseAParams Phase A configuration parameters
  784. * param phaseBParams Phase B configuration parameters
  785. * param quadMode Selects encoding mode used in quadrature decoder mode
  786. */
  787. void FTM_SetupQuadDecode(FTM_Type *base,
  788. const ftm_phase_params_t *phaseAParams,
  789. const ftm_phase_params_t *phaseBParams,
  790. ftm_quad_decode_mode_t quadMode)
  791. {
  792. assert(phaseAParams != NULL);
  793. assert(phaseBParams != NULL);
  794. uint32_t reg;
  795. /* Set Phase A filter value if phase filter is enabled */
  796. if (phaseAParams->enablePhaseFilter)
  797. {
  798. reg = base->FILTER;
  799. reg &= ~(FTM_FILTER_CH0FVAL_MASK);
  800. reg |= FTM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
  801. base->FILTER = reg;
  802. }
  803. /* Set Phase B filter value if phase filter is enabled */
  804. if (phaseBParams->enablePhaseFilter)
  805. {
  806. reg = base->FILTER;
  807. reg &= ~(FTM_FILTER_CH1FVAL_MASK);
  808. reg |= FTM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
  809. base->FILTER = reg;
  810. }
  811. #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
  812. /* Set Quadrature decode properties */
  813. reg = base->QDCTRL;
  814. reg &= ~(FTM_QDCTRL_QUADMODE_MASK | FTM_QDCTRL_PHAFLTREN_MASK | FTM_QDCTRL_PHBFLTREN_MASK | FTM_QDCTRL_PHAPOL_MASK |
  815. FTM_QDCTRL_PHBPOL_MASK);
  816. reg |= (FTM_QDCTRL_QUADMODE(quadMode) | FTM_QDCTRL_PHAFLTREN(phaseAParams->enablePhaseFilter) |
  817. FTM_QDCTRL_PHBFLTREN(phaseBParams->enablePhaseFilter) | FTM_QDCTRL_PHAPOL(phaseAParams->phasePolarity) |
  818. FTM_QDCTRL_PHBPOL(phaseBParams->phasePolarity));
  819. base->QDCTRL = reg;
  820. /* Enable Quad decode */
  821. base->QDCTRL |= FTM_QDCTRL_QUADEN_MASK;
  822. #endif
  823. }
  824. /*!
  825. * brief Sets up the working of the FTM fault protection.
  826. *
  827. * FTM can have up to 4 fault inputs. This function sets up fault parameters, fault level, and a filter.
  828. *
  829. * param base FTM peripheral base address
  830. * param faultNumber FTM fault to configure.
  831. * param faultParams Parameters passed in to set up the fault
  832. */
  833. void FTM_SetupFault(FTM_Type *base, ftm_fault_input_t faultNumber, const ftm_fault_param_t *faultParams)
  834. {
  835. assert(faultParams != NULL);
  836. if (faultParams->useFaultFilter)
  837. {
  838. /* Enable the fault filter */
  839. base->FLTCTRL |= ((uint32_t)FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + (uint32_t)faultNumber));
  840. }
  841. else
  842. {
  843. /* Disable the fault filter */
  844. base->FLTCTRL &= ~((uint32_t)FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + (uint32_t)faultNumber));
  845. }
  846. if (faultParams->faultLevel)
  847. {
  848. /* Active low polarity for the fault input pin */
  849. base->FLTPOL |= (1UL << (uint32_t)faultNumber);
  850. }
  851. else
  852. {
  853. /* Active high polarity for the fault input pin */
  854. base->FLTPOL &= ~(1UL << (uint32_t)faultNumber);
  855. }
  856. if (faultParams->enableFaultInput)
  857. {
  858. /* Enable the fault input */
  859. base->FLTCTRL |= ((uint32_t)FTM_FLTCTRL_FAULT0EN_MASK << (uint32_t)faultNumber);
  860. }
  861. else
  862. {
  863. /* Disable the fault input */
  864. base->FLTCTRL &= ~((uint32_t)FTM_FLTCTRL_FAULT0EN_MASK << (uint32_t)faultNumber);
  865. }
  866. }
  867. /*!
  868. * brief Enables the selected FTM interrupts.
  869. *
  870. * param base FTM peripheral base address
  871. * param mask The interrupts to enable. This is a logical OR of members of the
  872. * enumeration ::ftm_interrupt_enable_t
  873. */
  874. void FTM_EnableInterrupts(FTM_Type *base, uint32_t mask)
  875. {
  876. uint32_t chnlInts = (mask & 0xFFU);
  877. uint8_t chnlNumber = 0;
  878. /* Enable the timer overflow interrupt */
  879. if ((mask & (uint32_t)kFTM_TimeOverflowInterruptEnable) != 0U)
  880. {
  881. base->SC |= FTM_SC_TOIE_MASK;
  882. }
  883. /* Enable the fault interrupt */
  884. if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
  885. {
  886. base->MODE |= FTM_MODE_FAULTIE_MASK;
  887. }
  888. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
  889. /* Enable the reload interrupt available only on certain SoC's */
  890. if ((mask & (uint32_t)kFTM_ReloadInterruptEnable) != 0U)
  891. {
  892. base->SC |= FTM_SC_RIE_MASK;
  893. }
  894. #endif
  895. /* Enable the channel interrupts */
  896. while (chnlInts != 0U)
  897. {
  898. if ((chnlInts & 0x1U) != 0U)
  899. {
  900. base->CONTROLS[chnlNumber].CnSC |= FTM_CnSC_CHIE_MASK;
  901. }
  902. chnlNumber++;
  903. chnlInts = chnlInts >> 1U;
  904. }
  905. }
  906. /*!
  907. * brief Disables the selected FTM interrupts.
  908. *
  909. * param base FTM peripheral base address
  910. * param mask The interrupts to enable. This is a logical OR of members of the
  911. * enumeration ::ftm_interrupt_enable_t
  912. */
  913. void FTM_DisableInterrupts(FTM_Type *base, uint32_t mask)
  914. {
  915. uint32_t chnlInts = (mask & 0xFFU);
  916. uint8_t chnlNumber = 0;
  917. /* Disable the timer overflow interrupt */
  918. if ((mask & (uint32_t)kFTM_TimeOverflowInterruptEnable) != 0U)
  919. {
  920. base->SC &= ~FTM_SC_TOIE_MASK;
  921. }
  922. /* Disable the fault interrupt */
  923. if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
  924. {
  925. base->MODE &= ~FTM_MODE_FAULTIE_MASK;
  926. }
  927. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
  928. /* Disable the reload interrupt available only on certain SoC's */
  929. if ((mask & (uint32_t)kFTM_ReloadInterruptEnable) != 0U)
  930. {
  931. base->SC &= ~FTM_SC_RIE_MASK;
  932. }
  933. #endif
  934. /* Disable the channel interrupts */
  935. while (chnlInts != 0U)
  936. {
  937. if ((chnlInts & 0x01U) != 0U)
  938. {
  939. base->CONTROLS[chnlNumber].CnSC &= ~FTM_CnSC_CHIE_MASK;
  940. }
  941. chnlNumber++;
  942. chnlInts = chnlInts >> 1U;
  943. }
  944. }
  945. /*!
  946. * brief Gets the enabled FTM interrupts.
  947. *
  948. * param base FTM peripheral base address
  949. *
  950. * return The enabled interrupts. This is the logical OR of members of the
  951. * enumeration ::ftm_interrupt_enable_t
  952. */
  953. uint32_t FTM_GetEnabledInterrupts(FTM_Type *base)
  954. {
  955. uint32_t enabledInterrupts = 0;
  956. int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
  957. /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
  958. assert(chnlCount != -1);
  959. /* Check if timer overflow interrupt is enabled */
  960. if ((base->SC & FTM_SC_TOIE_MASK) != 0U)
  961. {
  962. enabledInterrupts |= (uint32_t)kFTM_TimeOverflowInterruptEnable;
  963. }
  964. /* Check if fault interrupt is enabled */
  965. if ((base->MODE & FTM_MODE_FAULTIE_MASK) != 0U)
  966. {
  967. enabledInterrupts |= (uint32_t)kFTM_FaultInterruptEnable;
  968. }
  969. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
  970. /* Check if the reload interrupt is enabled */
  971. if ((base->SC & FTM_SC_RIE_MASK) != 0U)
  972. {
  973. enabledInterrupts |= (uint32_t)kFTM_ReloadInterruptEnable;
  974. }
  975. #endif
  976. /* Check if the channel interrupts are enabled */
  977. while (chnlCount > 0)
  978. {
  979. chnlCount--;
  980. if ((base->CONTROLS[chnlCount].CnSC & FTM_CnSC_CHIE_MASK) != 0x00U)
  981. {
  982. enabledInterrupts |= (1UL << (uint32_t)chnlCount);
  983. }
  984. }
  985. return enabledInterrupts;
  986. }
  987. /*!
  988. * brief Gets the FTM status flags.
  989. *
  990. * param base FTM peripheral base address
  991. *
  992. * return The status flags. This is the logical OR of members of the
  993. * enumeration ::ftm_status_flags_t
  994. */
  995. uint32_t FTM_GetStatusFlags(FTM_Type *base)
  996. {
  997. uint32_t statusFlags = 0;
  998. /* Check the timer flag */
  999. if ((base->SC & FTM_SC_TOF_MASK) != 0U)
  1000. {
  1001. statusFlags |= (uint32_t)kFTM_TimeOverflowFlag;
  1002. }
  1003. /* Check fault flag */
  1004. if ((base->FMS & FTM_FMS_FAULTF_MASK) != 0U)
  1005. {
  1006. statusFlags |= (uint32_t)kFTM_FaultFlag;
  1007. }
  1008. /* Check channel trigger flag */
  1009. if ((base->EXTTRIG & FTM_EXTTRIG_TRIGF_MASK) != 0U)
  1010. {
  1011. statusFlags |= (uint32_t)kFTM_ChnlTriggerFlag;
  1012. }
  1013. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
  1014. /* Check reload flag */
  1015. if ((base->SC & FTM_SC_RF_MASK) != 0U)
  1016. {
  1017. statusFlags |= (uint32_t)kFTM_ReloadFlag;
  1018. }
  1019. #endif
  1020. /* Lower 8 bits contain the channel status flags */
  1021. statusFlags |= (base->STATUS & 0xFFU);
  1022. return statusFlags;
  1023. }
  1024. /*!
  1025. * brief Clears the FTM status flags.
  1026. *
  1027. * param base FTM peripheral base address
  1028. * param mask The status flags to clear. This is a logical OR of members of the
  1029. * enumeration ::ftm_status_flags_t
  1030. */
  1031. void FTM_ClearStatusFlags(FTM_Type *base, uint32_t mask)
  1032. {
  1033. /* Clear the timer overflow flag by writing a 0 to the bit while it is set */
  1034. if ((mask & (uint32_t)kFTM_TimeOverflowFlag) != 0U)
  1035. {
  1036. base->SC &= ~FTM_SC_TOF_MASK;
  1037. }
  1038. /* Clear fault flag by writing a 0 to the bit while it is set */
  1039. if ((mask & (uint32_t)kFTM_FaultFlag) != 0U)
  1040. {
  1041. base->FMS &= ~FTM_FMS_FAULTF_MASK;
  1042. }
  1043. /* Clear channel trigger flag */
  1044. if ((mask & (uint32_t)kFTM_ChnlTriggerFlag) != 0U)
  1045. {
  1046. base->EXTTRIG &= ~FTM_EXTTRIG_TRIGF_MASK;
  1047. }
  1048. #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
  1049. /* Check reload flag by writing a 0 to the bit while it is set */
  1050. if ((mask & (uint32_t)kFTM_ReloadFlag) != 0U)
  1051. {
  1052. base->SC &= ~FTM_SC_RF_MASK;
  1053. }
  1054. #endif
  1055. /* Clear the channel status flags by writing a 0 to the bit */
  1056. base->STATUS &= ~(mask & 0xFFU);
  1057. }