|
|
|
@ -1,11 +1,11 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2014 Freie Universität Berlin |
|
|
|
|
* Copyright (C) 2014-2016 Freie Universität Berlin |
|
|
|
|
* Copyright (C) 2014 PHYTEC Messtechnik GmbH |
|
|
|
|
* Copyright (C) 2015-2016 Eistec AB |
|
|
|
|
* |
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General |
|
|
|
|
* Public License v2.1. See the file LICENSE in the top level directory for more |
|
|
|
|
* details. |
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser |
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level |
|
|
|
|
* directory for more details. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -24,375 +24,130 @@
|
|
|
|
|
* @} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <stdint.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
#include "cpu.h" |
|
|
|
|
#include "assert.h" |
|
|
|
|
#include "periph/pwm.h" |
|
|
|
|
#include "periph_conf.h" |
|
|
|
|
|
|
|
|
|
/* FTM channel look up tables */ |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
static const uint8_t ftm0chan[] = { |
|
|
|
|
#if PWM_0_CHANNELS > 0 |
|
|
|
|
PWM_0_CH0_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 1 |
|
|
|
|
PWM_0_CH1_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 2 |
|
|
|
|
PWM_0_CH2_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 3 |
|
|
|
|
PWM_0_CH3_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 4 |
|
|
|
|
PWM_0_CH4_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 5 |
|
|
|
|
PWM_0_CH5_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 6 |
|
|
|
|
PWM_0_CH6_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 7 |
|
|
|
|
PWM_0_CH7_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
}; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
static const uint8_t ftm1chan[] = { |
|
|
|
|
#if PWM_1_CHANNELS > 0 |
|
|
|
|
PWM_1_CH0_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 1 |
|
|
|
|
PWM_1_CH1_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 2 |
|
|
|
|
PWM_1_CH2_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 3 |
|
|
|
|
PWM_1_CH3_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 4 |
|
|
|
|
PWM_1_CH4_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 5 |
|
|
|
|
PWM_1_CH5_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 6 |
|
|
|
|
PWM_1_CH6_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 7 |
|
|
|
|
PWM_1_CH7_FTMCHAN, |
|
|
|
|
#endif |
|
|
|
|
}; |
|
|
|
|
#endif |
|
|
|
|
#define PRESCALER_MAX (7U) |
|
|
|
|
|
|
|
|
|
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) |
|
|
|
|
static inline FTM_Type *ftm(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
FTM_Type *ftm; |
|
|
|
|
int channels = 0; |
|
|
|
|
uint32_t pwm_clk = 0; |
|
|
|
|
const uint8_t *ftmchan = NULL; |
|
|
|
|
|
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
channels = PWM_0_CHANNELS; |
|
|
|
|
pwm_clk = PWM_0_CLK; |
|
|
|
|
ftm = PWM_0_DEV; |
|
|
|
|
ftmchan = &ftm0chan[0]; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
channels = PWM_1_CHANNELS; |
|
|
|
|
pwm_clk = PWM_1_CLK; |
|
|
|
|
ftm = PWM_1_DEV; |
|
|
|
|
ftmchan = &ftm1chan[0]; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (mode) { |
|
|
|
|
case PWM_LEFT: |
|
|
|
|
case PWM_RIGHT: |
|
|
|
|
case PWM_CENTER: |
|
|
|
|
break; |
|
|
|
|
return pwm_config[pwm].ftm; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) |
|
|
|
|
{ |
|
|
|
|
uint8_t pre = 0; |
|
|
|
|
|
|
|
|
|
if ((unsigned int)res > (PWM_MAX_VALUE + 1) || (res * freq) > pwm_clk) { |
|
|
|
|
if (pwm >= PWM_NUMOF || ((res * freq) > CLOCK_BUSCLOCK)) { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Try to find a good prescaler value */ |
|
|
|
|
/* The prescaler divides the module clock by a power of two, between 2^0 and 2^7 */ |
|
|
|
|
uint8_t prescaler = 0; |
|
|
|
|
/* (resolution * frequency) is the number of timer ticks per second */ |
|
|
|
|
while ((pwm_clk >> prescaler) > (res * freq)) { |
|
|
|
|
++prescaler; |
|
|
|
|
if (prescaler > 7) { |
|
|
|
|
/* Module clock is too fast to reach the requested frequency using the
|
|
|
|
|
* hardware supported prescaler values */ |
|
|
|
|
/* Note: The frequency might be reachable if the requested resolution
|
|
|
|
|
* is increased. */ |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
/* figure out the clock settings
|
|
|
|
|
* the resulting frequency is calculated by |
|
|
|
|
* ticks := BUS_CLK / 2 ^ pre |
|
|
|
|
* where `ticks` is `freq * res` |
|
|
|
|
* and `pre` must be between [0, 7]. |
|
|
|
|
* |
|
|
|
|
* The resulting prescaler yields a timer frequency, which is the closest |
|
|
|
|
* possible frequency requested. */ |
|
|
|
|
while ((CLOCK_BUSCLOCK >> pre) > (res * freq)) { |
|
|
|
|
++pre; |
|
|
|
|
} |
|
|
|
|
/* The chosen prescaler yields a timer frequency which is the
|
|
|
|
|
* nearest possible frequency less than the requested frequency */ |
|
|
|
|
|
|
|
|
|
/* Turn on the peripheral */ |
|
|
|
|
pwm_poweron(dev); |
|
|
|
|
|
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
#if PWM_0_CHANNELS > 0 |
|
|
|
|
gpio_init_port(PWM_0_CH0_GPIO, PORT_PCR_MUX(PWM_0_CH0_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 1 |
|
|
|
|
gpio_init_port(PWM_0_CH1_GPIO, PORT_PCR_MUX(PWM_0_CH1_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 2 |
|
|
|
|
gpio_init_port(PWM_0_CH2_GPIO, PORT_PCR_MUX(PWM_0_CH2_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 3 |
|
|
|
|
gpio_init_port(PWM_0_CH3_GPIO, PORT_PCR_MUX(PWM_0_CH3_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 4 |
|
|
|
|
gpio_init_port(PWM_0_CH4_GPIO, PORT_PCR_MUX(PWM_0_CH4_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 5 |
|
|
|
|
gpio_init_port(PWM_0_CH5_GPIO, PORT_PCR_MUX(PWM_0_CH5_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 6 |
|
|
|
|
gpio_init_port(PWM_0_CH6_GPIO, PORT_PCR_MUX(PWM_0_CH6_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_0_CHANNELS > 7 |
|
|
|
|
gpio_init_port(PWM_0_CH7_GPIO, PORT_PCR_MUX(PWM_0_CH7_AF)); |
|
|
|
|
#endif |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
#if PWM_1_CHANNELS > 0 |
|
|
|
|
gpio_init_port(PWM_1_CH0_GPIO, PORT_PCR_MUX(PWM_1_CH0_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 1 |
|
|
|
|
gpio_init_port(PWM_1_CH1_GPIO, PORT_PCR_MUX(PWM_1_CH1_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 2 |
|
|
|
|
gpio_init_port(PWM_1_CH2_GPIO, PORT_PCR_MUX(PWM_1_CH2_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 3 |
|
|
|
|
gpio_init_port(PWM_1_CH3_GPIO, PORT_PCR_MUX(PWM_1_CH3_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 4 |
|
|
|
|
gpio_init_port(PWM_1_CH4_GPIO, PORT_PCR_MUX(PWM_1_CH4_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 5 |
|
|
|
|
gpio_init_port(PWM_1_CH5_GPIO, PORT_PCR_MUX(PWM_1_CH5_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 6 |
|
|
|
|
gpio_init_port(PWM_1_CH6_GPIO, PORT_PCR_MUX(PWM_1_CH6_AF)); |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_CHANNELS > 7 |
|
|
|
|
gpio_init_port(PWM_1_CH7_GPIO, PORT_PCR_MUX(PWM_1_CH7_AF)); |
|
|
|
|
#endif |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return 0; |
|
|
|
|
/* make sure the calculated prescaler is valid, else return */ |
|
|
|
|
if (pre > PRESCALER_MAX) { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* configure the used timer */ |
|
|
|
|
pwm_poweron(pwm); |
|
|
|
|
/* disable write protect for changing settings */ |
|
|
|
|
ftm->MODE = FTM_MODE_WPDIS_MASK; |
|
|
|
|
|
|
|
|
|
/* reset timer match value */ |
|
|
|
|
for (int i = 0; i < channels; i++) { |
|
|
|
|
ftm->CONTROLS[i].CnV = 0; |
|
|
|
|
ftm(pwm)->MODE = FTM_MODE_WPDIS_MASK; |
|
|
|
|
/* clear any existing configuration */ |
|
|
|
|
ftm(pwm)->COMBINE = 0; |
|
|
|
|
ftm(pwm)->CNTIN = 0; |
|
|
|
|
ftm(pwm)->SWOCTRL = 0; |
|
|
|
|
/* apply prescaler and set resolution */ |
|
|
|
|
ftm(pwm)->SC = FTM_SC_PS(pre); |
|
|
|
|
ftm(pwm)->MOD = (res - 1); |
|
|
|
|
|
|
|
|
|
/* set CPWMS bit in the SC register in case of center aligned mode */ |
|
|
|
|
if (mode == PWM_CENTER) { |
|
|
|
|
BITBAND_REG32(ftm(pwm)->SC, FTM_SC_CPWMS_SHIFT) = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* reset timer configuration registers */ |
|
|
|
|
ftm->COMBINE = 0; |
|
|
|
|
ftm->CNTIN = 0; |
|
|
|
|
ftm->SWOCTRL = 0; |
|
|
|
|
|
|
|
|
|
/* set prescale and mod registers to matching values for resolution and frequency */ |
|
|
|
|
ftm->SC = FTM_SC_PS(prescaler); |
|
|
|
|
ftm->MOD = res - 1; |
|
|
|
|
|
|
|
|
|
/* set PWM mode */ |
|
|
|
|
uint32_t mode_mask = 0; |
|
|
|
|
switch (mode) { |
|
|
|
|
case PWM_LEFT: |
|
|
|
|
mode_mask = (1 << FTM_CnSC_MSB_SHIFT) | (1 << FTM_CnSC_ELSB_SHIFT); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case PWM_RIGHT: |
|
|
|
|
mode_mask = (1 << FTM_CnSC_MSB_SHIFT) | (1 << FTM_CnSC_ELSA_SHIFT); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case PWM_CENTER: |
|
|
|
|
mode_mask = (1 << FTM_CnSC_MSB_SHIFT); |
|
|
|
|
ftm->SC |= (1 << FTM_SC_CPWMS_SHIFT); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
for (int i = 0; i < channels; i++) { |
|
|
|
|
/* cppcheck thinks ftmchan may be NULL here, but the variable is
|
|
|
|
|
* assigned in all non-returning branches of the switch at the top of |
|
|
|
|
* this function. */ |
|
|
|
|
/* cppcheck-suppress nullPointer ftmchan */ |
|
|
|
|
ftm->CONTROLS[ftmchan[i]].CnSC = mode_mask; |
|
|
|
|
/* setup the configured channels */ |
|
|
|
|
for (int i = 0; i < (int)pwm_config[pwm].chan_numof; i++) { |
|
|
|
|
/* configure the used pin */ |
|
|
|
|
gpio_init_port(pwm_config[pwm].chan[i].pin, |
|
|
|
|
PORT_PCR_MUX(pwm_config[pwm].chan[i].af)); |
|
|
|
|
/* set the given mode */ |
|
|
|
|
ftm(pwm)->CONTROLS[pwm_config[pwm].chan[i].ftm_chan].CnSC = mode; |
|
|
|
|
/* and reset the PWM to 0% duty cycle */ |
|
|
|
|
ftm(pwm)->CONTROLS[pwm_config[pwm].chan[i].ftm_chan].CnV = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* enable timer ergo the PWM generation */ |
|
|
|
|
pwm_start(dev); |
|
|
|
|
/* and now we start the actual waveform generation */ |
|
|
|
|
pwm_start(pwm); |
|
|
|
|
|
|
|
|
|
/* Return actual frequency */ |
|
|
|
|
return (pwm_clk / (1 << prescaler)) / res; |
|
|
|
|
/* finally we need to return the actual applied PWM frequency */ |
|
|
|
|
return (CLOCK_BUSCLOCK >> pre) / res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint8_t pwm_channels(pwm_t dev) |
|
|
|
|
uint8_t pwm_channels(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
case PWM_0: |
|
|
|
|
return PWM_0_CHANNELS; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
case PWM_1: |
|
|
|
|
return PWM_1_CHANNELS; |
|
|
|
|
#endif |
|
|
|
|
default: |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
assert(pwm < PWM_NUMOF); |
|
|
|
|
return pwm_config[pwm].chan_numof; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void pwm_set(pwm_t dev, uint8_t channel, uint16_t value) |
|
|
|
|
void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value) |
|
|
|
|
{ |
|
|
|
|
FTM_Type *ftm; |
|
|
|
|
const uint8_t *ftmchan = NULL; |
|
|
|
|
|
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
if (channel > PWM_0_CHANNELS) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
ftm = PWM_0_DEV; |
|
|
|
|
ftmchan = &ftm0chan[0]; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
if (channel > PWM_1_CHANNELS) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
ftm = PWM_1_DEV; |
|
|
|
|
ftmchan = &ftm1chan[0]; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* clamp value to maximum possible value */ |
|
|
|
|
if (value > PWM_MAX_VALUE) { |
|
|
|
|
value = PWM_MAX_VALUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* cppcheck thinks ftmchan may be NULL here, but the variable is
|
|
|
|
|
* assigned in all non-returning branches of the switch at the top of |
|
|
|
|
* this function. */ |
|
|
|
|
/* cppcheck-suppress nullPointer */ |
|
|
|
|
ftm->CONTROLS[ftmchan[channel]].CnV = value; |
|
|
|
|
assert((pwm < PWM_NUMOF) && (channel < pwm_config[pwm].chan_numof)); |
|
|
|
|
ftm(pwm)->CONTROLS[pwm_config[pwm].chan[channel].ftm_chan].CnV = value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void pwm_start(pwm_t dev) |
|
|
|
|
void pwm_start(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
PWM_0_DEV->SC |= FTM_SC_CLKS(1); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
PWM_1_DEV->SC |= FTM_SC_CLKS(1); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
assert(pwm < PWM_NUMOF); |
|
|
|
|
ftm(pwm)->SC |= FTM_SC_CLKS(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void pwm_stop(pwm_t dev) |
|
|
|
|
void pwm_stop(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
PWM_0_DEV->SC &= ~FTM_SC_CLKS_MASK; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
PWM_1_DEV->SC &= ~FTM_SC_CLKS_MASK; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
assert(pwm < PWM_NUMOF); |
|
|
|
|
ftm(pwm)->SC &= ~(FTM_SC_CLKS_MASK); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void pwm_poweron(pwm_t dev) |
|
|
|
|
void pwm_poweron(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
PWM_0_CLKEN(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
PWM_1_CLKEN(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
assert(pwm < PWM_NUMOF); |
|
|
|
|
int ftm = pwm_config[pwm].ftm_num; |
|
|
|
|
|
|
|
|
|
#ifdef SIM_SCGC6_FTM2_SHIFT |
|
|
|
|
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 1; |
|
|
|
|
#else |
|
|
|
|
if (ftm < 2) { |
|
|
|
|
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 1; |
|
|
|
|
} |
|
|
|
|
else if (ftm == 2) { |
|
|
|
|
BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_FTM2_SHIFT) = 1; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void pwm_poweroff(pwm_t dev) |
|
|
|
|
void pwm_poweroff(pwm_t pwm) |
|
|
|
|
{ |
|
|
|
|
switch (dev) { |
|
|
|
|
#if PWM_0_EN |
|
|
|
|
|
|
|
|
|
case PWM_0: |
|
|
|
|
PWM_0_CLKDIS(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if PWM_1_EN |
|
|
|
|
|
|
|
|
|
case PWM_1: |
|
|
|
|
PWM_1_CLKDIS(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
assert(pwm < PWM_NUMOF); |
|
|
|
|
int ftm = pwm_config[pwm].ftm_num; |
|
|
|
|
|
|
|
|
|
#ifdef SIM_SCGC6_FTM2_SHIFT |
|
|
|
|
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 0; |
|
|
|
|
#else |
|
|
|
|
if (ftm < 2) { |
|
|
|
|
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 0; |
|
|
|
|
} |
|
|
|
|
else if (ftm == 2) { |
|
|
|
|
BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_FTM2_SHIFT) = 0; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|