Browse Source

periph/pwm: remove pwm_(start|stop) + doc

- joined start/stop and poweron/poweroff
- added general documentation
pr/rotary
Hauke Petersen 6 years ago
parent
commit
8064bd9fa9
  1. 60
      cpu/kinetis_common/periph/pwm.c
  2. 16
      cpu/lpc11u34/periph/pwm.c
  3. 16
      cpu/lpc2387/periph/pwm.c
  4. 21
      cpu/sam3/periph/pwm.c
  5. 40
      cpu/samd21/periph/pwm.c
  6. 16
      cpu/stm32_common/periph/pwm.c
  7. 75
      drivers/include/periph/pwm.h

60
cpu/kinetis_common/periph/pwm.c

@ -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

16
cpu/lpc11u34/periph/pwm.c

@ -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);
}

16
cpu/lpc2387/periph/pwm.c

@ -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);
}

21
cpu/sam3/periph/pwm.c

@ -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;
}

40
cpu/samd21/periph/pwm.c

@ -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)
void pwm_poweron(pwm_t dev)
{
poweron(dev);
_tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE);
}
void pwm_stop(pwm_t dev)
void pwm_poweroff(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) {}
}
void pwm_poweroff(pwm_t dev)
{
int num = _num(dev);
if (num < 0) {
return;
}
PM->APBCMASK.reg &= ~(PM_APBCMASK_TCC0 << num);
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) {}

16
cpu/stm32_common/periph/pwm.c

@ -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);
}

75
drivers/include/periph/pwm.h

@ -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 support 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 is to be
* done in the board configuration (the board's `periph_conf.h).
*
* When using the PWM interface, fist 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 for changing 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
*
* @param[in] dev device to start
*/
void pwm_start(pwm_t dev);
/**
* @brief Stop PWM generation on the given device
* @brief Resume 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 this function is called, the given PWM device is powered on and
* continues its previously configured operation for each channel, where each
* will continue with the value that was last set.
*
* 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.
* This function must not be called before the PWM device was initialized.
*
* @param[in] dev device to power on
* @param[in] dev device to start
*/
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 channels configured for the
* given device and powers 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…
Cancel
Save