Merge pull request #6564 from haukepetersen/opt_periph_pwmpower
periph/pwm: remove pwm_(start|stop) + doc
This commit is contained in:
commit
fc6b7f0575
@ -35,6 +35,22 @@ static inline FTM_Type *ftm(pwm_t pwm)
|
||||
return pwm_config[pwm].ftm;
|
||||
}
|
||||
|
||||
static void poweron(pwm_t pwm)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
{
|
||||
uint8_t pre = 0;
|
||||
@ -60,7 +76,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
}
|
||||
|
||||
/* configure the used timer */
|
||||
pwm_poweron(pwm);
|
||||
poweron(pwm);
|
||||
/* disable write protect for changing settings */
|
||||
ftm(pwm)->MODE = FTM_MODE_WPDIS_MASK;
|
||||
/* clear any existing configuration */
|
||||
@ -88,7 +104,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
}
|
||||
|
||||
/* and now we start the actual waveform generation */
|
||||
pwm_start(pwm);
|
||||
ftm(pwm)->SC |= FTM_SC_CLKS(1);
|
||||
|
||||
/* finally we need to return the actual applied PWM frequency */
|
||||
return (CLOCK_BUSCLOCK >> pre) / res;
|
||||
@ -106,47 +122,29 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
|
||||
ftm(pwm)->CONTROLS[pwm_config[pwm].chan[channel].ftm_chan].CnV = value;
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
ftm(pwm)->SC |= FTM_SC_CLKS(1);
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
ftm(pwm)->SC &= ~(FTM_SC_CLKS_MASK);
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t pwm)
|
||||
{
|
||||
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
|
||||
poweron(pwm);
|
||||
ftm(pwm)->SC |= FTM_SC_CLKS(1);
|
||||
}
|
||||
|
||||
void pwm_poweroff(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
int ftm = pwm_config[pwm].ftm_num;
|
||||
int ftm_num = pwm_config[pwm].ftm_num;
|
||||
|
||||
/* disable PWM generation */
|
||||
ftm(pwm)->SC &= ~(FTM_SC_CLKS_MASK);
|
||||
|
||||
/* and power of the peripheral */
|
||||
#ifdef SIM_SCGC6_FTM2_SHIFT
|
||||
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 0;
|
||||
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm_num) = 0;
|
||||
#else
|
||||
if (ftm < 2) {
|
||||
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm) = 0;
|
||||
if (ftm_num < 2) {
|
||||
BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_FTM0_SHIFT + ftm_num) = 0;
|
||||
}
|
||||
else if (ftm == 2) {
|
||||
else if (ftm_num == 2) {
|
||||
BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_FTM2_SHIFT) = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -50,7 +50,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
}
|
||||
|
||||
/* power on and configure the timer */
|
||||
pwm_poweron(pwm);
|
||||
LPC_SYSCON->SYSAHBCLKCTRL |= pwm_config[pwm].clk_bit;
|
||||
/* enable the timer and keep it in reset state */
|
||||
dev(pwm)->TCR = BIT0 | BIT1;
|
||||
/* set prescaler */
|
||||
@ -85,27 +85,17 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
|
||||
dev(pwm)->MR[channel] = dev(pwm)->MR3 - value;
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->TCR &= ~(BIT1);
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->TCR |= (BIT1);
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
LPC_SYSCON->SYSAHBCLKCTRL |= pwm_config[pwm].clk_bit;
|
||||
dev(pwm)->TCR &= ~(BIT1);
|
||||
}
|
||||
|
||||
void pwm_poweroff(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->TCR |= (BIT1);
|
||||
LPC_SYSCON->SYSAHBCLKCTRL &= ~(pwm_config[pwm].clk_bit);
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
(PWM_FUNC << PWM_CH2_PIN * 2);
|
||||
|
||||
/* power on PWM1 */
|
||||
pwm_poweron(dev);
|
||||
PCONP |= PCPWM1;
|
||||
|
||||
/* select PWM1 clock */
|
||||
PCLKSEL0 &= ~(BIT13);
|
||||
@ -108,27 +108,17 @@ void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
|
||||
}
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t dev)
|
||||
{
|
||||
assert(dev == PWM_DEV(0));
|
||||
PWM1TCR |= BIT0;
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t dev)
|
||||
{
|
||||
assert(dev == PWM_DEV(0));
|
||||
PWM1TCR &= ~(BIT0);
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t dev)
|
||||
{
|
||||
assert(dev == PWM_DEV(0));
|
||||
PCONP |= PCPWM1;
|
||||
PWM1TCR |= BIT0;
|
||||
}
|
||||
|
||||
void pwm_poweroff(pwm_t dev)
|
||||
{
|
||||
assert(dev == PWM_DEV(0));
|
||||
PWM1TCR &= ~(BIT0);
|
||||
PCONP &= ~(PCPWM1);
|
||||
}
|
||||
|
||||
|
||||
@ -114,34 +114,17 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
|
||||
PWM->PWM_CH_NUM[pwm_chan[channel].hwchan].PWM_CDTYUPD = value;
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t pwm)
|
||||
{
|
||||
assert(pwm == PWM_DEV(0));
|
||||
PWM->PWM_ENA = pwm_chan_mask;
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t pwm)
|
||||
{
|
||||
assert(pwm == PWM_DEV(0));
|
||||
PWM->PWM_ENA = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device is reactivated by by clocking the device block.
|
||||
* Operation continues where it has been stopped by poweroff.
|
||||
*/
|
||||
void pwm_poweron(pwm_t pwm)
|
||||
{
|
||||
assert(pwm == PWM_DEV(0));
|
||||
PMC->PMC_PCER1 = PMC_PCDR1_PID36;
|
||||
PWM->PWM_ENA = pwm_chan_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device is set to power saving mode by disabling the clock.
|
||||
*/
|
||||
void pwm_poweroff(pwm_t pwm)
|
||||
{
|
||||
assert(pwm == PWM_DEV(0));
|
||||
PWM->PWM_ENA = 0;
|
||||
PMC->PMC_PCDR1 = PMC_PCDR1_PID36;
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +87,15 @@ static uint8_t get_prescaler(unsigned int target, int *scale)
|
||||
return target - 1;
|
||||
}
|
||||
|
||||
static void poweron(pwm_t dev)
|
||||
{
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_TCC0 << _num(dev));
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
GCLK_CLKCTRL_ID(_clk_id(dev)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
}
|
||||
|
||||
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
{
|
||||
uint8_t prescaler;
|
||||
@ -113,7 +122,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
}
|
||||
|
||||
/* power on the device */
|
||||
pwm_poweron(dev);
|
||||
poweron(dev);
|
||||
|
||||
/* reset TCC module */
|
||||
_tcc(dev)->CTRLA.reg = TCC_CTRLA_SWRST;
|
||||
@ -142,7 +151,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
_tcc(dev)->PER.reg = (res - 1);
|
||||
while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {}
|
||||
/* start PWM operation */
|
||||
pwm_start(dev);
|
||||
_tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE);
|
||||
/* return the actual frequency the PWM is running at */
|
||||
return f_real;
|
||||
}
|
||||
@ -162,36 +171,17 @@ void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
|
||||
while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << _chan(dev, channel))) {}
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t dev)
|
||||
{
|
||||
_tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE);
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t dev)
|
||||
{
|
||||
_tcc(dev)->CTRLA.reg &= ~(TCC_CTRLA_ENABLE);
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t dev)
|
||||
{
|
||||
int num = _num(dev);
|
||||
if (num < 0) {
|
||||
return;
|
||||
}
|
||||
PM->APBCMASK.reg |= (PM_APBCMASK_TCC0 << num);
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
GCLK_CLKCTRL_ID(_clk_id(dev)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
poweron(dev);
|
||||
_tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE);
|
||||
}
|
||||
|
||||
void pwm_poweroff(pwm_t dev)
|
||||
{
|
||||
int num = _num(dev);
|
||||
if (num < 0) {
|
||||
return;
|
||||
}
|
||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_TCC0 << num);
|
||||
_tcc(dev)->CTRLA.reg &= ~(TCC_CTRLA_ENABLE);
|
||||
|
||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_TCC0 << _num(dev));
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK7 |
|
||||
GCLK_CLKCTRL_ID(_clk_id(dev)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
|
||||
@ -49,7 +49,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
assert((pwm < PWM_NUMOF) && ((freq * res) < bus_clk));
|
||||
|
||||
/* power on the used timer */
|
||||
pwm_poweron(pwm);
|
||||
periph_clk_en(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
|
||||
/* reset configuration and CC channels */
|
||||
dev(pwm)->CR1 = 0;
|
||||
dev(pwm)->CR2 = 0;
|
||||
@ -124,27 +124,17 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
|
||||
dev(pwm)->CCR[pwm_config[pwm].chan[channel].cc_chan] = value;
|
||||
}
|
||||
|
||||
void pwm_start(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->CR1 |= TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
void pwm_stop(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->CR1 &= ~TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
periph_clk_en(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
|
||||
dev(pwm)->CR1 |= TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
void pwm_poweroff(pwm_t pwm)
|
||||
{
|
||||
assert(pwm < PWM_NUMOF);
|
||||
dev(pwm)->CR1 &= ~TIM_CR1_CEN;
|
||||
periph_clk_dis(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,46 @@
|
||||
* @ingroup drivers_periph
|
||||
* @brief Low-level PWM peripheral driver
|
||||
*
|
||||
* This interface enables access to CPU peripherals generating PWM signals. On
|
||||
* most platforms, this interface will be implemented based on hardware timers,
|
||||
* though some CPUs provide dedicated PWM peripherals.
|
||||
*
|
||||
* The characteristics of a PWM signal can be defined by three basic parameters,
|
||||
* namely the frequency, the duty cycle, and the operational mode. This
|
||||
* interface supports basic PWM generation in left-aligned, right-aligned, and
|
||||
* center mode. Additionally the interface supports the definition of the used
|
||||
* resolution, defining the granularity with which one can specify the duty
|
||||
* cycle. This brings more flexibility to the configuration of the frequency,
|
||||
* especially on systems with low system clocks.
|
||||
*
|
||||
* Typically, a single PWM device (e.g. hardware timer) supports PWM signal
|
||||
* generation on multiple pins in parallel. While the duty cycle is selectable
|
||||
* for each channel individually, the frequency and resolution are shared for
|
||||
* all channels.
|
||||
*
|
||||
* The mapping/configuration of PWM devices (timers) and the used pins has to be
|
||||
* done in the board configuration (the board's `periph_conf.h).
|
||||
*
|
||||
* When using the PWM interface, first thing you have to do is initialize the
|
||||
* PWM device with the targeted mode, frequency, and resolution settings. Once
|
||||
* the device is initialized, it will start the generation of PWM signals on all
|
||||
* configured pins immediately, with an initial duty cycle of `0`. Use the
|
||||
* pwm_set() function to change the duty cycle for a given channel. If you
|
||||
* want to disable the PWM generation again, simply call pwm_poweroff().
|
||||
*
|
||||
* @section sec_pm (Low-) power implications
|
||||
*
|
||||
* After initialization, the a PWM peripheral **should** be powered on and
|
||||
* active. When manually stopped using the pwm_poweroff() function, the PWM
|
||||
* generation **should** be stopped for all channels and the PWM peripheral
|
||||
* **should** be fully power off (e.g. through peripheral clock gating). Once
|
||||
* being re-enabled by calling the pwm_poweron() function, the PWM peripheral
|
||||
* **should** transparently continue its previously configured operation,
|
||||
* including the last active duty cycle values.
|
||||
*
|
||||
* While a PWM device is active, some implementations might need to block
|
||||
* certain power modes.
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Low-level PWM peripheral driver interface definitions
|
||||
@ -116,40 +156,25 @@ uint8_t pwm_channels(pwm_t dev);
|
||||
void pwm_set(pwm_t dev, uint8_t channel, uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Start PWM generation on the given device
|
||||
* @brief Resume PWM generation on the given device
|
||||
*
|
||||
* When this function is called, the given PWM device is powered on and
|
||||
* continues its previously configured operation. The duty cycle of each channel
|
||||
* will be the value that was last set.
|
||||
*
|
||||
* This function must not be called before the PWM device was initialized.
|
||||
*
|
||||
* @param[in] dev device to start
|
||||
*/
|
||||
void pwm_start(pwm_t dev);
|
||||
|
||||
/**
|
||||
* @brief Stop PWM generation on the given device
|
||||
*
|
||||
* @param[in] dev device to stop
|
||||
*/
|
||||
void pwm_stop(pwm_t dev);
|
||||
|
||||
/**
|
||||
* @brief Power on the PWM device
|
||||
*
|
||||
* When the device is powered on the first time, no configuration is set. If
|
||||
* the device is powered back on, after having been initialized and powered off
|
||||
* before, the PWM device will continue its operation with the previously set
|
||||
* configuration. So there is no need in re-initializing then.
|
||||
*
|
||||
* @param[in] dev device to power on
|
||||
*/
|
||||
void pwm_poweron(pwm_t dev);
|
||||
|
||||
/**
|
||||
* @brief Power off the given PWM device
|
||||
* @brief Stop PWM generation on the given device
|
||||
*
|
||||
* This function will power off the given PWM device, which on most platforms
|
||||
* means that it will be disabled using clock gating. The implementation must
|
||||
* make sure, that any previously configuration will hold when the device is
|
||||
* being powered back on.
|
||||
* This function stops the PWM generation on all configured channels for the
|
||||
* given device and powers down the given PWM peripheral.
|
||||
*
|
||||
* @param[in] dev device to power off
|
||||
* @param[in] dev device to stop
|
||||
*/
|
||||
void pwm_poweroff(pwm_t dev);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user