fsl_pwm.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2017 NXP
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * o Redistributions of source code must retain the above copyright notice, this list
  9. * of conditions and the following disclaimer.
  10. *
  11. * o Redistributions in binary form must reproduce the above copyright notice, this
  12. * list of conditions and the following disclaimer in the documentation and/or
  13. * other materials provided with the distribution.
  14. *
  15. * o Neither the name of the copyright holder nor the names of its
  16. * contributors may be used to endorse or promote products derived from this
  17. * software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  23. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  26. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "fsl_pwm.h"
  31. /*******************************************************************************
  32. * Prototypes
  33. ******************************************************************************/
  34. /*!
  35. * @brief Get the instance from the base address
  36. *
  37. * @param base PWM peripheral base address
  38. *
  39. * @return The PWM module instance
  40. */
  41. static uint32_t PWM_GetInstance(PWM_Type *base);
  42. /*******************************************************************************
  43. * Variables
  44. ******************************************************************************/
  45. /*! @brief Pointers to PWM bases for each instance. */
  46. static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;
  47. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  48. /*! @brief Pointers to PWM clocks for each PWM submodule. */
  49. static const clock_ip_name_t s_pwmClocks[][FSL_FEATURE_PWM_SUBMODULE_COUNT] = PWM_CLOCKS;
  50. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  51. /*******************************************************************************
  52. * Code
  53. ******************************************************************************/
  54. static uint32_t PWM_GetInstance(PWM_Type *base)
  55. {
  56. uint32_t instance;
  57. /* Find the instance index from base address mappings. */
  58. for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
  59. {
  60. if (s_pwmBases[instance] == base)
  61. {
  62. break;
  63. }
  64. }
  65. assert(instance < ARRAY_SIZE(s_pwmBases));
  66. return instance;
  67. }
  68. status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)
  69. {
  70. assert(config);
  71. uint16_t reg;
  72. /* Source clock for submodule 0 cannot be itself */
  73. if ((config->clockSource == kPWM_Submodule0Clock) && (subModule == kPWM_Module_0))
  74. {
  75. return kStatus_Fail;
  76. }
  77. /* Reload source select clock for submodule 0 cannot be master reload */
  78. if ((config->reloadSelect == kPWM_MasterReload) && (subModule == kPWM_Module_0))
  79. {
  80. return kStatus_Fail;
  81. }
  82. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  83. /* Ungate the PWM submodule clock*/
  84. CLOCK_EnableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
  85. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  86. /* Clear the fault status flags */
  87. base->FSTS |= PWM_FSTS_FFLAG_MASK;
  88. reg = base->SM[subModule].CTRL2;
  89. /* Setup the submodule clock-source, control source of the INIT signal,
  90. * source of the force output signal, operation in debug & wait modes and reload source select
  91. */
  92. reg &= ~(PWM_CTRL2_CLK_SEL_MASK | PWM_CTRL2_FORCE_SEL_MASK | PWM_CTRL2_INIT_SEL_MASK | PWM_CTRL2_INDEP_MASK |
  93. PWM_CTRL2_WAITEN_MASK | PWM_CTRL2_DBGEN_MASK | PWM_CTRL2_RELOAD_SEL_MASK);
  94. reg |= (PWM_CTRL2_CLK_SEL(config->clockSource) | PWM_CTRL2_FORCE_SEL(config->forceTrigger) |
  95. PWM_CTRL2_INIT_SEL(config->initializationControl) | PWM_CTRL2_DBGEN(config->enableDebugMode) |
  96. PWM_CTRL2_WAITEN(config->enableWait) | PWM_CTRL2_RELOAD_SEL(config->reloadSelect));
  97. /* Setup PWM A & B to be independent or a complementary-pair */
  98. switch (config->pairOperation)
  99. {
  100. case kPWM_Independent:
  101. reg |= PWM_CTRL2_INDEP_MASK;
  102. break;
  103. case kPWM_ComplementaryPwmA:
  104. base->MCTRL &= ~(1U << (PWM_MCTRL_IPOL_SHIFT + subModule));
  105. break;
  106. case kPWM_ComplementaryPwmB:
  107. base->MCTRL |= (1U << (PWM_MCTRL_IPOL_SHIFT + subModule));
  108. break;
  109. default:
  110. break;
  111. }
  112. base->SM[subModule].CTRL2 = reg;
  113. reg = base->SM[subModule].CTRL;
  114. /* Setup the clock prescale, load mode and frequency */
  115. reg &= ~(PWM_CTRL_PRSC_MASK | PWM_CTRL_LDFQ_MASK | PWM_CTRL_LDMOD_MASK);
  116. reg |= (PWM_CTRL_PRSC(config->prescale) | PWM_CTRL_LDFQ(config->reloadFrequency));
  117. /* Setup register reload logic */
  118. switch (config->reloadLogic)
  119. {
  120. case kPWM_ReloadImmediate:
  121. reg |= PWM_CTRL_LDMOD_MASK;
  122. break;
  123. case kPWM_ReloadPwmHalfCycle:
  124. reg |= PWM_CTRL_HALF_MASK;
  125. reg &= ~PWM_CTRL_FULL_MASK;
  126. break;
  127. case kPWM_ReloadPwmFullCycle:
  128. reg &= ~PWM_CTRL_HALF_MASK;
  129. reg |= PWM_CTRL_FULL_MASK;
  130. break;
  131. case kPWM_ReloadPwmHalfAndFullCycle:
  132. reg |= PWM_CTRL_HALF_MASK;
  133. reg |= PWM_CTRL_FULL_MASK;
  134. break;
  135. default:
  136. break;
  137. }
  138. base->SM[subModule].CTRL = reg;
  139. /* Setup the fault filter */
  140. if (base->FFILT & PWM_FFILT_FILT_PER_MASK)
  141. {
  142. /* When changing values for fault period from a non-zero value, first write a value of 0
  143. * to clear the filter
  144. */
  145. base->FFILT &= ~(PWM_FFILT_FILT_PER_MASK);
  146. }
  147. base->FFILT = (PWM_FFILT_FILT_CNT(config->faultFilterCount) | PWM_FFILT_FILT_PER(config->faultFilterPeriod));
  148. /* Issue a Force trigger event when configured to trigger locally */
  149. if (config->forceTrigger == kPWM_Force_Local)
  150. {
  151. base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE(1U);
  152. }
  153. return kStatus_Success;
  154. }
  155. void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule)
  156. {
  157. /* Stop the submodule */
  158. base->MCTRL &= ~(1U << (PWM_MCTRL_RUN_SHIFT + subModule));
  159. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  160. /* Gate the PWM submodule clock*/
  161. CLOCK_DisableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
  162. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  163. }
  164. void PWM_GetDefaultConfig(pwm_config_t *config)
  165. {
  166. assert(config);
  167. /* PWM is paused in debug mode */
  168. config->enableDebugMode = false;
  169. /* PWM is paused in wait mode */
  170. config->enableWait = false;
  171. /* PWM module uses the local reload signal to reload registers */
  172. config->reloadSelect = kPWM_LocalReload;
  173. /* Fault filter count is set to 0 */
  174. config->faultFilterCount = 0;
  175. /* Fault filter period is set to 0 which disables the fault filter */
  176. config->faultFilterPeriod = 0;
  177. /* Use the IP Bus clock as source clock for the PWM submodule */
  178. config->clockSource = kPWM_BusClock;
  179. /* Clock source prescale is set to divide by 1*/
  180. config->prescale = kPWM_Prescale_Divide_1;
  181. /* Local sync causes initialization */
  182. config->initializationControl = kPWM_Initialize_LocalSync;
  183. /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
  184. config->forceTrigger = kPWM_Force_Local;
  185. /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
  186. * This field is not used in Immediate reload mode
  187. */
  188. config->reloadFrequency = kPWM_LoadEveryOportunity;
  189. /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
  190. config->reloadLogic = kPWM_ReloadImmediate;
  191. /* PWM A & PWM B operate as 2 independent channels */
  192. config->pairOperation = kPWM_Independent;
  193. }
  194. status_t PWM_SetupPwm(PWM_Type *base,
  195. pwm_submodule_t subModule,
  196. const pwm_signal_param_t *chnlParams,
  197. uint8_t numOfChnls,
  198. pwm_mode_t mode,
  199. uint32_t pwmFreq_Hz,
  200. uint32_t srcClock_Hz)
  201. {
  202. assert(chnlParams);
  203. assert(pwmFreq_Hz);
  204. assert(numOfChnls);
  205. assert(srcClock_Hz);
  206. uint32_t pwmClock;
  207. uint16_t pulseCnt = 0, pwmHighPulse = 0;
  208. int16_t modulo = 0;
  209. uint8_t i, polarityShift = 0, outputEnableShift = 0;
  210. if (numOfChnls > 2)
  211. {
  212. /* Each submodule has 2 signals; PWM A & PWM B */
  213. return kStatus_Fail;
  214. }
  215. /* Divide the clock by the prescale value */
  216. pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
  217. pulseCnt = (pwmClock / pwmFreq_Hz);
  218. /* Setup each PWM channel */
  219. for (i = 0; i < numOfChnls; i++)
  220. {
  221. /* Calculate pulse width */
  222. pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100;
  223. /* Setup the different match registers to generate the PWM signal */
  224. switch (mode)
  225. {
  226. case kPWM_SignedCenterAligned:
  227. /* Setup the PWM period for a signed center aligned signal */
  228. modulo = pulseCnt >> 1;
  229. /* Indicates the start of the PWM period */
  230. base->SM[subModule].INIT = (-modulo);
  231. /* Indicates the center value */
  232. base->SM[subModule].VAL0 = 0;
  233. /* Indicates the end of the PWM period */
  234. base->SM[subModule].VAL1 = modulo;
  235. /* Setup the PWM dutycycle */
  236. if (chnlParams->pwmChannel == kPWM_PwmA)
  237. {
  238. base->SM[subModule].VAL2 = (-(pwmHighPulse / 2));
  239. base->SM[subModule].VAL3 = (pwmHighPulse / 2);
  240. }
  241. else
  242. {
  243. base->SM[subModule].VAL4 = (-(pwmHighPulse / 2));
  244. base->SM[subModule].VAL5 = (pwmHighPulse / 2);
  245. }
  246. break;
  247. case kPWM_CenterAligned:
  248. /* Setup the PWM period for an unsigned center aligned signal */
  249. /* Indicates the start of the PWM period */
  250. base->SM[subModule].INIT = 0;
  251. /* Indicates the center value */
  252. base->SM[subModule].VAL0 = (pulseCnt / 2);
  253. /* Indicates the end of the PWM period */
  254. base->SM[subModule].VAL1 = pulseCnt;
  255. /* Setup the PWM dutycycle */
  256. if (chnlParams->pwmChannel == kPWM_PwmA)
  257. {
  258. base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2);
  259. base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2);
  260. }
  261. else
  262. {
  263. base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2);
  264. base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2);
  265. }
  266. break;
  267. case kPWM_SignedEdgeAligned:
  268. /* Setup the PWM period for a signed edge aligned signal */
  269. modulo = pulseCnt >> 1;
  270. /* Indicates the start of the PWM period */
  271. base->SM[subModule].INIT = (-modulo);
  272. /* Indicates the center value */
  273. base->SM[subModule].VAL0 = 0;
  274. /* Indicates the end of the PWM period */
  275. base->SM[subModule].VAL1 = modulo;
  276. /* Setup the PWM dutycycle */
  277. if (chnlParams->pwmChannel == kPWM_PwmA)
  278. {
  279. base->SM[subModule].VAL2 = (-modulo);
  280. base->SM[subModule].VAL3 = (-modulo + pwmHighPulse);
  281. }
  282. else
  283. {
  284. base->SM[subModule].VAL4 = (-modulo);
  285. base->SM[subModule].VAL5 = (-modulo + pwmHighPulse);
  286. }
  287. break;
  288. case kPWM_EdgeAligned:
  289. /* Setup the PWM period for a unsigned edge aligned signal */
  290. /* Indicates the start of the PWM period */
  291. base->SM[subModule].INIT = 0;
  292. /* Indicates the center value */
  293. base->SM[subModule].VAL0 = (pulseCnt / 2);
  294. /* Indicates the end of the PWM period */
  295. base->SM[subModule].VAL1 = pulseCnt;
  296. /* Setup the PWM dutycycle */
  297. if (chnlParams->pwmChannel == kPWM_PwmA)
  298. {
  299. base->SM[subModule].VAL2 = 0;
  300. base->SM[subModule].VAL3 = pwmHighPulse;
  301. }
  302. else
  303. {
  304. base->SM[subModule].VAL4 = 0;
  305. base->SM[subModule].VAL5 = pwmHighPulse;
  306. }
  307. break;
  308. default:
  309. break;
  310. }
  311. /* Setup register shift values based on the channel being configured.
  312. * Also setup the deadtime value
  313. */
  314. if (chnlParams->pwmChannel == kPWM_PwmA)
  315. {
  316. polarityShift = PWM_OCTRL_POLA_SHIFT;
  317. outputEnableShift = PWM_OUTEN_PWMA_EN_SHIFT;
  318. base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
  319. }
  320. else
  321. {
  322. polarityShift = PWM_OCTRL_POLB_SHIFT;
  323. outputEnableShift = PWM_OUTEN_PWMB_EN_SHIFT;
  324. base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
  325. }
  326. /* Setup signal active level */
  327. if (chnlParams->level == kPWM_HighTrue)
  328. {
  329. base->SM[subModule].OCTRL &= ~(1U << polarityShift);
  330. }
  331. else
  332. {
  333. base->SM[subModule].OCTRL |= (1U << polarityShift);
  334. }
  335. /* Enable PWM output */
  336. base->OUTEN |= (1U << (outputEnableShift + subModule));
  337. /* Get the next channel parameters */
  338. chnlParams++;
  339. }
  340. return kStatus_Success;
  341. }
  342. void PWM_UpdatePwmDutycycle(PWM_Type *base,
  343. pwm_submodule_t subModule,
  344. pwm_channels_t pwmSignal,
  345. pwm_mode_t currPwmMode,
  346. uint8_t dutyCyclePercent)
  347. {
  348. assert(dutyCyclePercent <= 100);
  349. assert(pwmSignal < 2);
  350. uint16_t pulseCnt = 0, pwmHighPulse = 0;
  351. int16_t modulo = 0;
  352. switch (currPwmMode)
  353. {
  354. case kPWM_SignedCenterAligned:
  355. modulo = base->SM[subModule].VAL1;
  356. pulseCnt = modulo * 2;
  357. /* Calculate pulse width */
  358. pwmHighPulse = (pulseCnt * dutyCyclePercent) / 100;
  359. /* Setup the PWM dutycycle */
  360. if (pwmSignal == kPWM_PwmA)
  361. {
  362. base->SM[subModule].VAL2 = (-(pwmHighPulse / 2));
  363. base->SM[subModule].VAL3 = (pwmHighPulse / 2);
  364. }
  365. else
  366. {
  367. base->SM[subModule].VAL4 = (-(pwmHighPulse / 2));
  368. base->SM[subModule].VAL5 = (pwmHighPulse / 2);
  369. }
  370. break;
  371. case kPWM_CenterAligned:
  372. pulseCnt = base->SM[subModule].VAL1;
  373. /* Calculate pulse width */
  374. pwmHighPulse = (pulseCnt * dutyCyclePercent) / 100;
  375. /* Setup the PWM dutycycle */
  376. if (pwmSignal == kPWM_PwmA)
  377. {
  378. base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2);
  379. base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2);
  380. }
  381. else
  382. {
  383. base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2);
  384. base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2);
  385. }
  386. break;
  387. case kPWM_SignedEdgeAligned:
  388. modulo = base->SM[subModule].VAL1;
  389. pulseCnt = modulo * 2;
  390. /* Calculate pulse width */
  391. pwmHighPulse = (pulseCnt * dutyCyclePercent) / 100;
  392. /* Setup the PWM dutycycle */
  393. if (pwmSignal == kPWM_PwmA)
  394. {
  395. base->SM[subModule].VAL2 = (-modulo);
  396. base->SM[subModule].VAL3 = (-modulo + pwmHighPulse);
  397. }
  398. else
  399. {
  400. base->SM[subModule].VAL4 = (-modulo);
  401. base->SM[subModule].VAL5 = (-modulo + pwmHighPulse);
  402. }
  403. break;
  404. case kPWM_EdgeAligned:
  405. pulseCnt = base->SM[subModule].VAL1;
  406. /* Calculate pulse width */
  407. pwmHighPulse = (pulseCnt * dutyCyclePercent) / 100;
  408. /* Setup the PWM dutycycle */
  409. if (pwmSignal == kPWM_PwmA)
  410. {
  411. base->SM[subModule].VAL2 = 0;
  412. base->SM[subModule].VAL3 = pwmHighPulse;
  413. }
  414. else
  415. {
  416. base->SM[subModule].VAL4 = 0;
  417. base->SM[subModule].VAL5 = pwmHighPulse;
  418. }
  419. break;
  420. default:
  421. break;
  422. }
  423. }
  424. void PWM_SetupInputCapture(PWM_Type *base,
  425. pwm_submodule_t subModule,
  426. pwm_channels_t pwmChannel,
  427. const pwm_input_capture_param_t *inputCaptureParams)
  428. {
  429. uint32_t reg = 0;
  430. switch (pwmChannel)
  431. {
  432. case kPWM_PwmA:
  433. /* Setup the capture paramters for PWM A pin */
  434. reg = (PWM_CAPTCTRLA_INP_SELA(inputCaptureParams->captureInputSel) |
  435. PWM_CAPTCTRLA_EDGA0(inputCaptureParams->edge0) | PWM_CAPTCTRLA_EDGA1(inputCaptureParams->edge1) |
  436. PWM_CAPTCTRLA_ONESHOTA(inputCaptureParams->enableOneShotCapture) |
  437. PWM_CAPTCTRLA_CFAWM(inputCaptureParams->fifoWatermark));
  438. /* Enable the edge counter if using the output edge counter */
  439. if (inputCaptureParams->captureInputSel)
  440. {
  441. reg |= PWM_CAPTCTRLA_EDGCNTA_EN_MASK;
  442. }
  443. /* Enable input capture operation */
  444. reg |= PWM_CAPTCTRLA_ARMA_MASK;
  445. base->SM[subModule].CAPTCTRLA = reg;
  446. /* Setup the compare value when using the edge counter as source */
  447. base->SM[subModule].CAPTCOMPA = PWM_CAPTCOMPA_EDGCMPA(inputCaptureParams->edgeCompareValue);
  448. /* Setup PWM A pin for input capture */
  449. base->OUTEN &= ~(1U << (PWM_OUTEN_PWMA_EN_SHIFT + subModule));
  450. break;
  451. case kPWM_PwmB:
  452. /* Setup the capture paramters for PWM B pin */
  453. reg = (PWM_CAPTCTRLB_INP_SELB(inputCaptureParams->captureInputSel) |
  454. PWM_CAPTCTRLB_EDGB0(inputCaptureParams->edge0) | PWM_CAPTCTRLB_EDGB1(inputCaptureParams->edge1) |
  455. PWM_CAPTCTRLB_ONESHOTB(inputCaptureParams->enableOneShotCapture) |
  456. PWM_CAPTCTRLB_CFBWM(inputCaptureParams->fifoWatermark));
  457. /* Enable the edge counter if using the output edge counter */
  458. if (inputCaptureParams->captureInputSel)
  459. {
  460. reg |= PWM_CAPTCTRLB_EDGCNTB_EN_MASK;
  461. }
  462. /* Enable input capture operation */
  463. reg |= PWM_CAPTCTRLB_ARMB_MASK;
  464. base->SM[subModule].CAPTCTRLB = reg;
  465. /* Setup the compare value when using the edge counter as source */
  466. base->SM[subModule].CAPTCOMPB = PWM_CAPTCOMPB_EDGCMPB(inputCaptureParams->edgeCompareValue);
  467. /* Setup PWM B pin for input capture */
  468. base->OUTEN &= ~(1U << (PWM_OUTEN_PWMB_EN_SHIFT + subModule));
  469. break;
  470. case kPWM_PwmX:
  471. reg = (PWM_CAPTCTRLX_INP_SELX(inputCaptureParams->captureInputSel) |
  472. PWM_CAPTCTRLX_EDGX0(inputCaptureParams->edge0) | PWM_CAPTCTRLX_EDGX1(inputCaptureParams->edge1) |
  473. PWM_CAPTCTRLX_ONESHOTX(inputCaptureParams->enableOneShotCapture) |
  474. PWM_CAPTCTRLX_CFXWM(inputCaptureParams->fifoWatermark));
  475. /* Enable the edge counter if using the output edge counter */
  476. if (inputCaptureParams->captureInputSel)
  477. {
  478. reg |= PWM_CAPTCTRLX_EDGCNTX_EN_MASK;
  479. }
  480. /* Enable input capture operation */
  481. reg |= PWM_CAPTCTRLX_ARMX_MASK;
  482. base->SM[subModule].CAPTCTRLX = reg;
  483. /* Setup the compare value when using the edge counter as source */
  484. base->SM[subModule].CAPTCOMPX = PWM_CAPTCOMPX_EDGCMPX(inputCaptureParams->edgeCompareValue);
  485. /* Setup PWM X pin for input capture */
  486. base->OUTEN &= ~(1U << (PWM_OUTEN_PWMX_EN_SHIFT + subModule));
  487. break;
  488. default:
  489. break;
  490. }
  491. }
  492. void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams)
  493. {
  494. assert(faultParams);
  495. uint16_t reg;
  496. reg = base->FCTRL;
  497. /* Set the faults level-settting */
  498. if (faultParams->faultLevel)
  499. {
  500. reg |= (1U << (PWM_FCTRL_FLVL_SHIFT + faultNum));
  501. }
  502. else
  503. {
  504. reg &= ~(1U << (PWM_FCTRL_FLVL_SHIFT + faultNum));
  505. }
  506. /* Set the fault clearing mode */
  507. if (faultParams->faultClearingMode)
  508. {
  509. /* Use manual fault clearing */
  510. reg &= ~(1U << (PWM_FCTRL_FAUTO_SHIFT + faultNum));
  511. if (faultParams->faultClearingMode == kPWM_ManualSafety)
  512. {
  513. /* Use manual fault clearing with safety mode enabled */
  514. reg |= (1U << (PWM_FCTRL_FSAFE_SHIFT + faultNum));
  515. }
  516. else
  517. {
  518. /* Use manual fault clearing with safety mode disabled */
  519. reg &= ~(1U << (PWM_FCTRL_FSAFE_SHIFT + faultNum));
  520. }
  521. }
  522. else
  523. {
  524. /* Use automatic fault clearing */
  525. reg |= (1U << (PWM_FCTRL_FAUTO_SHIFT + faultNum));
  526. }
  527. base->FCTRL = reg;
  528. /* Set the combinational path option */
  529. if (faultParams->enableCombinationalPath)
  530. {
  531. /* Combinational path from the fault input to the PWM output is available */
  532. base->FCTRL2 &= ~(1U << faultNum);
  533. }
  534. else
  535. {
  536. /* No combinational path available, only fault filter & latch signal can disable PWM output */
  537. base->FCTRL2 |= (1U << faultNum);
  538. }
  539. /* Initially clear both recovery modes */
  540. reg = base->FSTS;
  541. reg &= ~((1U << (PWM_FSTS_FFULL_SHIFT + faultNum)) | (1U << (PWM_FSTS_FHALF_SHIFT + faultNum)));
  542. /* Setup fault recovery */
  543. switch (faultParams->recoverMode)
  544. {
  545. case kPWM_NoRecovery:
  546. break;
  547. case kPWM_RecoverHalfCycle:
  548. reg |= (1U << (PWM_FSTS_FHALF_SHIFT + faultNum));
  549. break;
  550. case kPWM_RecoverFullCycle:
  551. reg |= (1U << (PWM_FSTS_FFULL_SHIFT + faultNum));
  552. break;
  553. case kPWM_RecoverHalfAndFullCycle:
  554. reg |= (1U << (PWM_FSTS_FHALF_SHIFT + faultNum));
  555. reg |= (1U << (PWM_FSTS_FFULL_SHIFT + faultNum));
  556. break;
  557. default:
  558. break;
  559. }
  560. base->FSTS = reg;
  561. }
  562. void PWM_SetupForceSignal(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, pwm_force_signal_t mode)
  563. {
  564. uint16_t shift;
  565. uint16_t reg;
  566. /* DTSRCSEL register has 4 bits per submodule; 2 bits for PWM A and 2 bits for PWM B */
  567. shift = subModule * 4 + pwmChannel * 2;
  568. /* Setup the signal to be passed upon occurrence of a FORCE_OUT signal */
  569. reg = base->DTSRCSEL;
  570. reg &= ~(0x3U << shift);
  571. reg |= (uint16_t)((uint16_t)mode << shift);
  572. base->DTSRCSEL = reg;
  573. }
  574. void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
  575. {
  576. /* Upper 16 bits are for related to the submodule */
  577. base->SM[subModule].INTEN |= (mask & 0xFFFFU);
  578. /* Fault related interrupts */
  579. base->FCTRL |= ((mask >> 16U) & PWM_FCTRL_FIE_MASK);
  580. }
  581. void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
  582. {
  583. base->SM[subModule].INTEN &= ~(mask & 0xFFFF);
  584. base->FCTRL &= ~((mask >> 16U) & PWM_FCTRL_FIE_MASK);
  585. }
  586. uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule)
  587. {
  588. uint32_t enabledInterrupts;
  589. enabledInterrupts = base->SM[subModule].INTEN;
  590. enabledInterrupts |= ((uint32_t)(base->FCTRL & PWM_FCTRL_FIE_MASK) << 16U);
  591. return enabledInterrupts;
  592. }
  593. uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule)
  594. {
  595. uint32_t statusFlags;
  596. statusFlags = base->SM[subModule].STS;
  597. statusFlags |= ((uint32_t)(base->FSTS & PWM_FSTS_FFLAG_MASK) << 16U);
  598. return statusFlags;
  599. }
  600. void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
  601. {
  602. uint16_t reg;
  603. base->SM[subModule].STS = (mask & 0xFFFFU);
  604. reg = base->FSTS;
  605. /* Clear the fault flags and set only the ones we wish to clear as the fault flags are cleared
  606. * by writing a login one
  607. */
  608. reg &= ~(PWM_FSTS_FFLAG_MASK);
  609. reg |= ((mask >> 16U) & PWM_FSTS_FFLAG_MASK);
  610. base->FSTS = reg;
  611. }