rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
hal_pwm_lld.c
Go to the documentation of this file.
1/*
2 ChibiOS/HAL - Copyright (C) 2014 Adam J. Porter
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file KE1xF/pwm_lld.c
19 * @brief KINETIS PWM subsystem low level driver source.
20 * @author andreika <prometheus.pcb@gmail.com>
21 *
22 * @addtogroup PWM
23 * @{
24 */
25
26#include "hal.h"
27#include "kinetis_stm32.h"
28
29#if HAL_USE_PWM || defined(__DOXYGEN__)
30
31/*===========================================================================*/
32/* Driver local definitions. */
33/*===========================================================================*/
34
35#ifdef KE1xF
36#define CHANNEL CONTROLS
37#endif /* KE1xF */
38
39
40/*===========================================================================*/
41/* Driver exported variables. */
42/*===========================================================================*/
43
44/**
45 * @brief PWMD1 driver identifier.
46 * @note The driver PWMD1 allocates the timer FTM0 when enabled.
47 */
48#if KINETIS_PWM_USE_FTM0 || defined(__DOXYGEN__)
50#endif
51
52/**
53 * @brief PWMD2 driver identifier.
54 * @note The driver PWMD2 allocates the timer FTM1 when enabled.
55 */
56#if KINETIS_PWM_USE_FTM1 || defined(__DOXYGEN__)
58#endif
59
60/**
61 * @brief PWMD3 driver identifier.
62 * @note The driver PWMD3 allocates the timer FTM2 when enabled.
63 */
64#if KINETIS_PWM_USE_FTM2 || defined(__DOXYGEN__)
66#endif
67
68/**
69 * @brief PWMD4 driver identifier.
70 * @note The driver PWMD4 allocates the timer FTM3 when enabled.
71 */
72#if KINETIS_PWM_USE_FTM3 || defined(__DOXYGEN__)
74#endif
75
76/*===========================================================================*/
77/* Driver local variables and types. */
78/*===========================================================================*/
79
80/*===========================================================================*/
81/* Driver local functions. */
82/*===========================================================================*/
83
85 uint32_t sr;
86
87 sr = pwmp->ftm->SC;
88 pwmp->ftm->SC = sr&(~FTM_SC_TOFx);
89
90 if (((sr & FTM_SC_TOFx) != 0) && /* Timer Overflow */
91 ((sr & FTM_SC_TOIEx) != 0) &&
92 (pwmp->config->callback != NULL)) {
93 pwmp->config->callback(pwmp);
94 }
95
96 uint8_t n=0;
97 for(n=0;n<pwmp->channels;n++) {
98 sr = pwmp->ftm->CHANNEL[n].CnSC;
99 pwmp->ftm->CHANNEL[n].CnSC = sr&(~FTM_CnSC_CHFx);
100 if (((sr & FTM_CnSC_CHFx) != 0) &&
101 ((sr & FTM_CnSC_CHIEx) != 0) &&
102 (pwmp->config->channels[n].callback != NULL)) {
103 pwmp->config->channels[n].callback(pwmp);
104 }
105 }
106}
107
108/*===========================================================================*/
109/* Driver interrupt handlers. */
110/*===========================================================================*/
111
112#if KINETIS_PWM_USE_FTM0
113/**
114 * @brief FTM0 interrupt handler.
115 *
116 * @isr
117 */
118OSAL_IRQ_HANDLER(KINETIS_FTM0_IRQ_VECTOR) {
119 OSAL_IRQ_PROLOGUE();
121 OSAL_IRQ_EPILOGUE();
122}
123#endif /* KINETIS_PWM_USE_FTM0 */
124
125#if KINETIS_PWM_USE_FTM1
126/**
127 * @brief FTM1 interrupt handler.
128 *
129 * @isr
130 */
131OSAL_IRQ_HANDLER(KINETIS_FTM1_IRQ_VECTOR) {
132
133 OSAL_IRQ_PROLOGUE();
135 OSAL_IRQ_EPILOGUE();
136}
137#endif /* KINETIS_PWM_USE_FTM1 */
138
139#if KINETIS_PWM_USE_FTM2
140/**
141 * @brief FTM2 interrupt handler.
142 *
143 * @isr
144 */
145OSAL_IRQ_HANDLER(KINETIS_FTM2_IRQ_VECTOR) {
146
147 OSAL_IRQ_PROLOGUE();
149 OSAL_IRQ_EPILOGUE();
150}
151#endif /* KINETIS_PWM_USE_FTM2 */
152
153#if KINETIS_PWM_USE_FTM3
154/**
155 * @brief FTM3 interrupt handler.
156 *
157 * @isr
158 */
159OSAL_IRQ_HANDLER(KINETIS_FTM3_IRQ_VECTOR) {
160
161 OSAL_IRQ_PROLOGUE();
163 OSAL_IRQ_EPILOGUE();
164}
165#endif /* KINETIS_PWM_USE_FTM3 */
166
167/*===========================================================================*/
168/* Driver exported functions. */
169/*===========================================================================*/
170
171/**
172 * @brief Low level PWM driver initialization.
173 *
174 * @notapi
175 */
176void pwm_lld_init(void) {
177
178#if KINETIS_PWM_USE_FTM0
179 pwmObjectInit(&PWMD1);
180 PWMD1.channels = KINETIS_FTM0_CHANNELS;
181 PWMD1.ftm = FTM0;
182#endif
183
184#if KINETIS_PWM_USE_FTM1
185 pwmObjectInit(&PWMD2);
186 PWMD2.channels = KINETIS_FTM1_CHANNELS;
187 PWMD2.ftm = FTM1;
188#endif
189
190#if KINETIS_PWM_USE_FTM2
191 pwmObjectInit(&PWMD3);
192 PWMD3.channels = KINETIS_FTM2_CHANNELS;
193 PWMD3.ftm = FTM2;
194#endif
195
196#if KINETIS_PWM_USE_FTM3
197 pwmObjectInit(&PWMD4);
198 PWMD4.channels = KINETIS_FTM3_CHANNELS;
199 PWMD4.ftm = FTM3;
200#endif
201}
202
203/**
204 * @brief Configures and activates the PWM peripheral.
205 * @note Starting a driver that is already in the @p PWM_READY state
206 * disables all the active channels.
207 *
208 * @param[in] pwmp pointer to a @p PWMDriver object
209 *
210 * @notapi
211 */
213 uint16_t psc;
214 uint8_t i=0;
215
216 if (pwmp->state == PWM_STOP) {
217 /* Clock activation and timer reset.*/
218#if KINETIS_PWM_USE_FTM0
219 if (&PWMD1 == pwmp) {
220#ifdef KE1xF
222#else
223 SIM->SCGC6 |= SIM_SCGC6_FTM0;
224#endif
225 nvicEnableVector(FTM0_IRQn, KINETIS_PWM_FTM0_PRIORITY);
226 }
227#endif
228
229#if KINETIS_PWM_USE_FTM1
230 if (&PWMD2 == pwmp) {
231#ifdef KE1xF
233#else
234 SIM->SCGC6 |= SIM_SCGC6_FTM1;
235#endif
236 nvicEnableVector(FTM1_IRQn, KINETIS_PWM_FTM1_PRIORITY);
237 }
238#endif
239
240#if KINETIS_PWM_USE_FTM2
241 if (&PWMD3 == pwmp) {
242#ifdef KE1xF
244#else
245 SIM->SCGC3 |= SIM_SCGC3_FTM2;
246#endif
247 nvicEnableVector(FTM2_IRQn, KINETIS_PWM_FTM2_PRIORITY);
248 }
249#endif
250
251#if KINETIS_PWM_USE_FTM3
252 if (&PWMD4 == pwmp) {
253#ifdef KE1xF
255#else
256 SIM->SCGC3 |= SIM_SCGC3_FTM3;
257#endif
258 nvicEnableVector(FTM3_IRQn, KINETIS_PWM_FTM3_PRIORITY);
259 }
260#endif
261 }
262 pwmp->ftm->MODE = FTM_MODE_FTMEN_MASK|FTM_MODE_PWMSYNC_MASK;
263 pwmp->ftm->SYNC = FTM_SYNC_CNTMIN_MASK|FTM_SYNC_CNTMAX_MASK
264 |FTM_SYNC_SWSYNC_MASK;
265 pwmp->ftm->COMBINE = FTM_COMBINE_SYNCEN3_MASK | FTM_COMBINE_SYNCEN2_MASK
266 | FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_SYNCEN0_MASK;
267 pwmp->ftm->SYNCONF = FTM_SYNCONF_SYNCMODE_MASK;
268
269 pwmp->ftm->CNTIN = 0x0000;
270 //~ pwmp->ftm->SC = 0; /* Disable FTM counter.*/
271 pwmp->ftm->CNT = 0x0000; /* Clear count register.*/
272
273 /* Prescaler value calculation.*/
274 psc = (KINETIS_FTM_FREQUENCY / pwmp->config->frequency);
275 //~ /* Prescaler must be power of two between 1 and 128.*/
276 osalDbgAssert(psc <= 128 && !(psc & (psc - 1)), "invalid frequency");
277 //~ /* Prescaler register value determination.
278 //~ Prescaler register value conveniently corresponds to bit position,
279 //~ i.e., register value for prescaler CLK/64 is 6 ((1 << 6) == 64).*/
280 for (i = 0; i < 8; i++) {
281 if (psc == (unsigned)(1 << i)) {
282 break;
283 }
284 }
285
286 /* Set prescaler and clock mode.
287 This also sets the following:
288 CPWMS up-counting mode
289 Timer overflow interrupt disabled
290 DMA disabled.*/
291 pwmp->ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(i);
292 /* Configure period */
293 pwmp->ftm->MOD = pwmp->period-1;
294 pwmp->ftm->PWMLOAD = FTM_PWMLOAD_LDOK_MASK;
295}
296
297/**
298 * @brief Deactivates the PWM peripheral.
299 *
300 * @param[in] pwmp pointer to a @p PWMDriver object
301 *
302 * @notapi
303 */
305
306 /* If in ready state then disables the PWM clock.*/
307 if (pwmp->state == PWM_READY) {
308#if KINETIS_PWM_USE_FTM0
309 if (&PWMD1 == pwmp) {
310#ifdef KE1xF
311 PCC->CLKCFG[PCC_FLEXTMR0_INDEX] &= ~PCC_CLKCFG_CGC(1);
312#else
313 SIM->SCGC6 &= ~SIM_SCGC6_FTM0;
314#endif
315 nvicDisableVector(FTM0_IRQn);
316 }
317#endif
318
319#if KINETIS_PWM_USE_FTM1
320 if (&PWMD2 == pwmp) {
321#ifdef KE1xF
322 PCC->CLKCFG[PCC_FLEXTMR1_INDEX] &= ~PCC_CLKCFG_CGC(1);
323#else
324 SIM->SCGC6 &= ~SIM_SCGC6_FTM1;
325#endif
326 nvicDisableVector(FTM1_IRQn);
327 }
328#endif
329
330#if KINETIS_PWM_USE_FTM2
331 if (&PWMD3 == pwmp) {
332#ifdef KE1xF
333 PCC->CLKCFG[PCC_FLEXTMR2_INDEX] &= ~PCC_CLKCFG_CGC(1);
334#else
335 SIM->SCGC3 &= ~SIM_SCGC3_FTM2;
336#endif
337 nvicDisableVector(FTM2_IRQn);
338 }
339#endif
340
341#if KINETIS_PWM_USE_FTM3
342 if (&PWMD4 == pwmp) {
343#ifdef KE1xF
344 PCC->CLKCFG[PCC_FLEXTMR3_INDEX] &= ~PCC_CLKCFG_CGC(1);
345#else
346 SIM->SCGC3 &= ~SIM_SCGC3_FTM3;
347#endif
348 nvicDisableVector(FTM3_IRQn);
349 }
350#endif
351 /* Disable FTM counter.*/
352 pwmp->ftm->SC = 0;
353 pwmp->ftm->MOD = 0;
354 }
355}
356
357/**
358 * @brief Enables a PWM channel.
359 * @pre The PWM unit must have been activated using @p pwmStart().
360 * @post The channel is active using the specified configuration.
361 * @note The function has effect at the next cycle start.
362 * @note Channel notification is not enabled.
363 *
364 * @param[in] pwmp pointer to a @p PWMDriver object
365 * @param[in] channel PWM channel identifier (0...channels-1)
366 * @param[in] width PWM pulse width as clock pulses number
367 *
368 * @notapi
369 */
372 pwmcnt_t width) {
373 uint32_t mode = FTM_CnSC_MSBx; /* Edge-aligned PWM mode.*/
374
375 switch (pwmp->config->channels[channel].mode & PWM_OUTPUT_MASK) {
376 case PWM_OUTPUT_ACTIVE_HIGH:
377 mode |= FTM_CnSC_ELSBx;
378 break;
379 case PWM_OUTPUT_ACTIVE_LOW:
380 mode |= FTM_CnSC_ELSAx;
381 break;
382 }
383
384 if (pwmp->ftm->CHANNEL[channel].CnSC & FTM_CnSC_CHIEx)
385 mode |= FTM_CnSC_CHIEx;
386
387 pwmp->ftm->CHANNEL[channel].CnSC = mode;
388 pwmp->ftm->CHANNEL[channel].CnV = width;
389 pwmp->ftm->PWMLOAD = FTM_PWMLOAD_LDOK_MASK;
390}
391
392/**
393 * @brief Disables a PWM channel and its notification.
394 * @pre The PWM unit must have been activated using @p pwmStart().
395 * @post The channel is disabled and its output line returned to the
396 * idle state.
397 * @note The function has effect at the next cycle start.
398 *
399 * @param[in] pwmp pointer to a @p PWMDriver object
400 * @param[in] channel PWM channel identifier (0...channels-1)
401 *
402 * @notapi
403 */
405
406 pwmp->ftm->CHANNEL[channel].CnSC = 0;
407 pwmp->ftm->CHANNEL[channel].CnV = 0;
408}
409
410/**
411 * @brief Enables the periodic activation edge notification.
412 * @pre The PWM unit must have been activated using @p pwmStart().
413 * @note If the notification is already enabled then the call has no effect.
414 *
415 * @param[in] pwmp pointer to a @p PWMDriver object
416 *
417 * @notapi
418 */
420 pwmp->ftm->SC |= FTM_SC_TOIEx;
421}
422
423/**
424 * @brief Disables the periodic activation edge notification.
425 * @pre The PWM unit must have been activated using @p pwmStart().
426 * @note If the notification is already disabled then the call has no effect.
427 *
428 * @param[in] pwmp pointer to a @p PWMDriver object
429 *
430 * @notapi
431 */
433 pwmp->ftm->SC &= ~FTM_SC_TOIEx;
434}
435
436/**
437 * @brief Enables a channel de-activation edge notification.
438 * @pre The PWM unit must have been activated using @p pwmStart().
439 * @pre The channel must have been activated using @p pwmEnableChannel().
440 * @note If the notification is already enabled then the call has no effect.
441 *
442 * @param[in] pwmp pointer to a @p PWMDriver object
443 * @param[in] channel PWM channel identifier (0...channels-1)
444 *
445 * @notapi
446 */
449 pwmp->ftm->CHANNEL[channel].CnSC |= FTM_CnSC_CHIEx;
450}
451
452/**
453 * @brief Disables a channel de-activation edge notification.
454 * @pre The PWM unit must have been activated using @p pwmStart().
455 * @pre The channel must have been activated using @p pwmEnableChannel().
456 * @note If the notification is already disabled then the call has no effect.
457 *
458 * @param[in] pwmp pointer to a @p PWMDriver object
459 * @param[in] channel PWM channel identifier (0...channels-1)
460 *
461 * @notapi
462 */
465 pwmp->ftm->CHANNEL[channel].CnSC &= ~FTM_CnSC_CHIEx;
466}
467
468#endif /* HAL_USE_PWM */
469
470/** @} */
uint16_t channel
Definition adc_inputs.h:104
static void pwm_lld_serve_interrupt(PWMDriver *pwmp)
Definition hal_pwm_lld.c:84
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp)
Disables the periodic activation edge notification.
OSAL_IRQ_HANDLER(KINETIS_FTM0_IRQ_VECTOR)
FTM0 interrupt handler.
PWMDriver PWMD2
PWMD2 driver identifier.
Definition hal_pwm_lld.c:57
void pwm_lld_stop(PWMDriver *pwmp)
Deactivates the PWM peripheral.
void pwm_lld_disable_channel_notification(PWMDriver *pwmp, pwmchannel_t channel)
Disables a channel de-activation edge notification.
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel)
Disables a PWM channel and its notification.
void pwm_lld_init(void)
Low level PWM driver initialization.
void pwm_lld_start(PWMDriver *pwmp)
Configures and activates the PWM peripheral.
void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width)
Enables a PWM channel.
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp)
Enables the periodic activation edge notification.
void pwm_lld_enable_channel_notification(PWMDriver *pwmp, pwmchannel_t channel)
Enables a channel de-activation edge notification.
PWMDriver PWMD1
PWMD1 driver identifier.
Definition hal_pwm_lld.c:49
PWMDriver PWMD4
PWMD4 driver identifier.
Definition hal_pwm_lld.c:73
PWMDriver PWMD3
PWMD3 driver identifier.
Definition hal_pwm_lld.c:65
static void CLOCK_EnableClock(clock_ip_name_t name)
Enable the clock for specific IP.
Definition fsl_clock.h:641
@ kCLOCK_Ftm3
Definition fsl_clock.h:277
@ kCLOCK_Ftm1
Definition fsl_clock.h:287
@ kCLOCK_Ftm2
Definition fsl_clock.h:288
@ kCLOCK_Ftm0
Definition fsl_clock.h:286
uint8_t pwmchannel_t
Type of a PWM channel.
uint16_t pwmcnt_t
Type of a PWM counter.
This is needed for better compatibility with STM32 or other CPUs of Kinetis family.
pwmcallback_t callback
Channel callback pointer.
pwmmode_t mode
Channel active logic level.
pwmcallback_t callback
Periodic callback pointer.
PWMChannelConfig channels[PWM_CHANNELS]
Channels configurations.
uint32_t frequency
Timer clock in Hz.
Structure representing a PWM driver.
pwmcnt_t period
Current PWM period in ticks.
PWM_DRIVER_EXT_FIELDS FTM_TypeDef * ftm
Pointer to the FTM registers block.
pwmchannel_t channels
Number of channels in this instance.
const PWMConfig * config
Current driver configuration data.
pwmstate_t state
Driver state.