From 824f7aa82b656b541e0bb2437e6b3d5a7c549c44 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 2 May 2020 23:30:08 +0200 Subject: [PATCH 01/12] cpu/sam0_common: move PWM to common code --- cpu/sam0_common/include/periph_cpu_common.h | 18 ++++++++++++++++++ cpu/{samd21 => sam0_common}/periph/pwm.c | 0 cpu/samd21/include/periph_cpu.h | 18 ------------------ 3 files changed, 18 insertions(+), 18 deletions(-) rename cpu/{samd21 => sam0_common}/periph/pwm.c (100%) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index e55e2a109b..de7bb6a364 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -212,6 +212,24 @@ typedef struct { uint8_t gclk_src; /**< GCLK source which supplys SERCOM */ } uart_conf_t; +/** + * @brief PWM channel configuration data structure + */ +typedef struct { + gpio_t pin; /**< GPIO pin */ + gpio_mux_t mux; /**< pin function multiplex value */ + uint8_t chan; /**< TCC channel to use */ +} pwm_conf_chan_t; + +/** + * @brief PWM device configuration data structure + */ +typedef struct { + Tcc *dev; /**< TCC device to use */ + const pwm_conf_chan_t *chan;/**< channel configuration */ + const uint8_t chan_numof; /**< number of channels */ +} pwm_conf_t; + /** * @brief Available values for SERCOM SPI MISO pad selection */ diff --git a/cpu/samd21/periph/pwm.c b/cpu/sam0_common/periph/pwm.c similarity index 100% rename from cpu/samd21/periph/pwm.c rename to cpu/sam0_common/periph/pwm.c diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index aed4f91fab..7f16663f3a 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -70,24 +70,6 @@ enum { */ #define SPI_HWCS(x) (UINT_MAX - 1) -/** - * @brief PWM channel configuration data structure - */ -typedef struct { - gpio_t pin; /**< GPIO pin */ - gpio_mux_t mux; /**< pin function multiplex value */ - uint8_t chan; /**< TCC channel to use */ -} pwm_conf_chan_t; - -/** - * @brief PWM device configuration data structure - */ -typedef struct { - Tcc *dev; /**< TCC device to use */ - const pwm_conf_chan_t *chan;/**< channel configuration */ - const uint8_t chan_numof; /**< number of channels */ -} pwm_conf_t; - /** * @brief Return the numeric id of a SERCOM device derived from its address * From bce7d25f10f47c216c1a50df1e0414b24a3d7f5b Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 01:11:44 +0200 Subject: [PATCH 02/12] cpu/sam0_common: add PWM support for saml2x, samd5x --- cpu/sam0_common/include/periph_cpu_common.h | 46 +++- cpu/sam0_common/include/timer_config.h | 255 ++++++++++++++++++++ cpu/sam0_common/periph/pwm.c | 161 ++++++------ 3 files changed, 377 insertions(+), 85 deletions(-) create mode 100644 cpu/sam0_common/include/timer_config.h diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index de7bb6a364..32dc42e8f3 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -23,6 +23,7 @@ #include "cpu.h" #include "exti_config.h" +#include "timer_config.h" #ifdef __cplusplus extern "C" { @@ -212,22 +213,55 @@ typedef struct { uint8_t gclk_src; /**< GCLK source which supplys SERCOM */ } uart_conf_t; +/** + * @brief Common configuration for timer devices + */ +typedef struct { +#ifdef REV_TCC + Tcc *dev; /**< TCC device to use */ +#endif +#ifdef MCLK + volatile uint32_t *mclk; /**< Pointer to MCLK->APBxMASK.reg */ + uint32_t mclk_mask; /**< MCLK_APBxMASK bits to enable Timer */ +#else + uint32_t pm_mask; /**< PM_APBCMASK bits to enable Timer */ +#endif + uint16_t gclk_id; /**< TCn_GCLK_ID */ +} tcc_cfg_t; + +/** + * @brief Static initializer for timer configuration + */ +#ifdef MCLK +#define TCC_CONFIG(tim) { \ + .dev = tim, \ + .mclk = MCLK_ ## tim, \ + .mclk_mask = MCLK_ ## tim ## _MASK, \ + .gclk_id = tim ## _GCLK_ID, } +#else +#define TCC_CONFIG(tim) { \ + .dev = tim, \ + .pm_mask = PM_APBCMASK_ ## tim, \ + .gclk_id = tim ## _GCLK_ID, } +#endif + /** * @brief PWM channel configuration data structure */ typedef struct { - gpio_t pin; /**< GPIO pin */ - gpio_mux_t mux; /**< pin function multiplex value */ - uint8_t chan; /**< TCC channel to use */ + gpio_t pin; /**< GPIO pin */ + gpio_mux_t mux; /**< pin function multiplex value */ + uint8_t chan; /**< TCC channel to use */ } pwm_conf_chan_t; /** * @brief PWM device configuration data structure */ typedef struct { - Tcc *dev; /**< TCC device to use */ - const pwm_conf_chan_t *chan;/**< channel configuration */ - const uint8_t chan_numof; /**< number of channels */ + tcc_cfg_t tim; /**< timer configuration */ + const pwm_conf_chan_t *chan; /**< channel configuration */ + uint8_t chan_numof; /**< number of channels */ + uint8_t gclk_src; /**< GCLK source which clocks TIMER */ } pwm_conf_t; /** diff --git a/cpu/sam0_common/include/timer_config.h b/cpu/sam0_common/include/timer_config.h new file mode 100644 index 0000000000..4d833bbf3f --- /dev/null +++ b/cpu/sam0_common/include/timer_config.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @ingroup cpu_sam0_common + * @brief Generic Timer MCLK masks. + * @{ + * + * @author Benjamin Valentin + */ + +#ifndef TIMER_CONFIG_H +#define TIMER_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Automatically generated helper defines + * @{ + */ +#ifdef MCLK_APBAMASK_TC0 +#define MCLK_TC0 (&MCLK->APBAMASK.reg) +#define MCLK_TC0_MASK (MCLK_APBAMASK_TC0) +#endif +#ifdef MCLK_APBBMASK_TC0 +#define MCLK_TC0 (&MCLK->APBBMASK.reg) +#define MCLK_TC0_MASK (MCLK_APBBMASK_TC0) +#endif +#ifdef MCLK_APBCMASK_TC0 +#define MCLK_TC0 (&MCLK->APBCMASK.reg) +#define MCLK_TC0_MASK (MCLK_APBCMASK_TC0) +#endif +#ifdef MCLK_APBDMASK_TC0 +#define MCLK_TC0 (&MCLK->APBDMASK.reg) +#define MCLK_TC0_MASK (MCLK_APBDMASK_TC0) +#endif + +#ifdef MCLK_APBAMASK_TC1 +#define MCLK_TC1 (&MCLK->APBAMASK.reg) +#define MCLK_TC1_MASK (MCLK_APBAMASK_TC1) +#endif +#ifdef MCLK_APBBMASK_TC1 +#define MCLK_TC1 (&MCLK->APBBMASK.reg) +#define MCLK_TC1_MASK (MCLK_APBBMASK_TC1) +#endif +#ifdef MCLK_APBCMASK_TC1 +#define MCLK_TC1 (&MCLK->APBCMASK.reg) +#define MCLK_TC1_MASK (MCLK_APBCMASK_TC1) +#endif +#ifdef MCLK_APBDMASK_TC1 +#define MCLK_TC1 (&MCLK->APBDMASK.reg) +#define MCLK_TC1_MASK (MCLK_APBDMASK_TC1) +#endif + +#ifdef MCLK_APBAMASK_TC2 +#define MCLK_TC2 (&MCLK->APBAMASK.reg) +#define MCLK_TC2_MASK (MCLK_APBAMASK_TC2) +#endif +#ifdef MCLK_APBBMASK_TC2 +#define MCLK_TC2 (&MCLK->APBBMASK.reg) +#define MCLK_TC2_MASK (MCLK_APBBMASK_TC2) +#endif +#ifdef MCLK_APBCMASK_TC2 +#define MCLK_TC2 (&MCLK->APBCMASK.reg) +#define MCLK_TC2_MASK (MCLK_APBCMASK_TC2) +#endif +#ifdef MCLK_APBDMASK_TC2 +#define MCLK_TC2 (&MCLK->APBDMASK.reg) +#define MCLK_TC2_MASK (MCLK_APBDMASK_TC2) +#endif + +#ifdef MCLK_APBAMASK_TC3 +#define MCLK_TC3 (&MCLK->APBAMASK.reg) +#define MCLK_TC3_MASK (MCLK_APBAMASK_TC3) +#endif +#ifdef MCLK_APBBMASK_TC3 +#define MCLK_TC3 (&MCLK->APBBMASK.reg) +#define MCLK_TC3_MASK (MCLK_APBBMASK_TC3) +#endif +#ifdef MCLK_APBCMASK_TC3 +#define MCLK_TC3 (&MCLK->APBCMASK.reg) +#define MCLK_TC3_MASK (MCLK_APBCMASK_TC3) +#endif +#ifdef MCLK_APBDMASK_TC3 +#define MCLK_TC3 (&MCLK->APBDMASK.reg) +#define MCLK_TC3_MASK (MCLK_APBDMASK_TC3) +#endif + +#ifdef MCLK_APBAMASK_TC4 +#define MCLK_TC4 (&MCLK->APBAMASK.reg) +#define MCLK_TC4_MASK (MCLK_APBAMASK_TC4) +#endif +#ifdef MCLK_APBBMASK_TC4 +#define MCLK_TC4 (&MCLK->APBBMASK.reg) +#define MCLK_TC4_MASK (MCLK_APBBMASK_TC4) +#endif +#ifdef MCLK_APBCMASK_TC4 +#define MCLK_TC4 (&MCLK->APBCMASK.reg) +#define MCLK_TC4_MASK (MCLK_APBCMASK_TC4) +#endif +#ifdef MCLK_APBDMASK_TC4 +#define MCLK_TC4 (&MCLK->APBDMASK.reg) +#define MCLK_TC4_MASK (MCLK_APBDMASK_TC4) +#endif + +#ifdef MCLK_APBAMASK_TC5 +#define MCLK_TC5 (&MCLK->APBAMASK.reg) +#define MCLK_TC5_MASK (MCLK_APBAMASK_TC5) +#endif +#ifdef MCLK_APBBMASK_TC5 +#define MCLK_TC5 (&MCLK->APBBMASK.reg) +#define MCLK_TC5_MASK (MCLK_APBBMASK_TC5) +#endif +#ifdef MCLK_APBCMASK_TC5 +#define MCLK_TC5 (&MCLK->APBCMASK.reg) +#define MCLK_TC5_MASK (MCLK_APBCMASK_TC5) +#endif +#ifdef MCLK_APBDMASK_TC5 +#define MCLK_TC5 (&MCLK->APBDMASK.reg) +#define MCLK_TC5_MASK (MCLK_APBDMASK_TC5) +#endif + +#ifdef MCLK_APBAMASK_TC6 +#define MCLK_TC6 (&MCLK->APBAMASK.reg) +#define MCLK_TC6_MASK (MCLK_APBAMASK_TC6) +#endif +#ifdef MCLK_APBBMASK_TC6 +#define MCLK_TC6 (&MCLK->APBBMASK.reg) +#define MCLK_TC6_MASK (MCLK_APBBMASK_TC6) +#endif +#ifdef MCLK_APBCMASK_TC6 +#define MCLK_TC6 (&MCLK->APBCMASK.reg) +#define MCLK_TC6_MASK (MCLK_APBCMASK_TC6) +#endif +#ifdef MCLK_APBDMASK_TC6 +#define MCLK_TC6 (&MCLK->APBDMASK.reg) +#define MCLK_TC6_MASK (MCLK_APBDMASK_TC6) +#endif + +#ifdef MCLK_APBAMASK_TC7 +#define MCLK_TC7 (&MCLK->APBAMASK.reg) +#define MCLK_TC7_MASK (MCLK_APBAMASK_TC7) +#endif +#ifdef MCLK_APBBMASK_TC7 +#define MCLK_TC7 (&MCLK->APBBMASK.reg) +#define MCLK_TC7_MASK (MCLK_APBBMASK_TC7) +#endif +#ifdef MCLK_APBCMASK_TC7 +#define MCLK_TC7 (&MCLK->APBCMASK.reg) +#define MCLK_TC7_MASK (MCLK_APBCMASK_TC7) +#endif +#ifdef MCLK_APBDMASK_TC7 +#define MCLK_TC7 (&MCLK->APBDMASK.reg) +#define MCLK_TC7_MASK (MCLK_APBDMASK_TC7) +#endif + +#ifdef MCLK_APBAMASK_TCC0 +#define MCLK_TCC0 (&MCLK->APBAMASK.reg) +#define MCLK_TCC0_MASK (MCLK_APBAMASK_TCC0) +#endif +#ifdef MCLK_APBBMASK_TCC0 +#define MCLK_TCC0 (&MCLK->APBBMASK.reg) +#define MCLK_TCC0_MASK (MCLK_APBBMASK_TCC0) +#endif +#ifdef MCLK_APBCMASK_TCC0 +#define MCLK_TCC0 (&MCLK->APBCMASK.reg) +#define MCLK_TCC0_MASK (MCLK_APBCMASK_TCC0) +#endif +#ifdef MCLK_APBDMASK_TCC0 +#define MCLK_TCC0 (&MCLK->APBDMASK.reg) +#define MCLK_TCC0_MASK (MCLK_APBDMASK_TCC0) +#endif + +#ifdef MCLK_APBAMASK_TCC1 +#define MCLK_TCC1 (&MCLK->APBAMASK.reg) +#define MCLK_TCC1_MASK (MCLK_APBAMASK_TCC1) +#endif +#ifdef MCLK_APBBMASK_TCC1 +#define MCLK_TCC1 (&MCLK->APBBMASK.reg) +#define MCLK_TCC1_MASK (MCLK_APBBMASK_TCC1) +#endif +#ifdef MCLK_APBCMASK_TCC1 +#define MCLK_TCC1 (&MCLK->APBCMASK.reg) +#define MCLK_TCC1_MASK (MCLK_APBCMASK_TCC1) +#endif +#ifdef MCLK_APBDMASK_TCC1 +#define MCLK_TCC1 (&MCLK->APBDMASK.reg) +#define MCLK_TCC1_MASK (MCLK_APBDMASK_TCC1) +#endif + +#ifdef MCLK_APBAMASK_TCC2 +#define MCLK_TCC2 (&MCLK->APBAMASK.reg) +#define MCLK_TCC2_MASK (MCLK_APBAMASK_TCC2) +#endif +#ifdef MCLK_APBBMASK_TCC2 +#define MCLK_TCC2 (&MCLK->APBBMASK.reg) +#define MCLK_TCC2_MASK (MCLK_APBBMASK_TCC2) +#endif +#ifdef MCLK_APBCMASK_TCC2 +#define MCLK_TCC2 (&MCLK->APBCMASK.reg) +#define MCLK_TCC2_MASK (MCLK_APBCMASK_TCC2) +#endif +#ifdef MCLK_APBDMASK_TCC2 +#define MCLK_TCC2 (&MCLK->APBDMASK.reg) +#define MCLK_TCC2_MASK (MCLK_APBDMASK_TCC2) +#endif + +#ifdef MCLK_APBAMASK_TCC3 +#define MCLK_TCC3 (&MCLK->APBAMASK.reg) +#define MCLK_TCC3_MASK (MCLK_APBAMASK_TCC3) +#endif +#ifdef MCLK_APBBMASK_TCC3 +#define MCLK_TCC3 (&MCLK->APBBMASK.reg) +#define MCLK_TCC3_MASK (MCLK_APBBMASK_TCC3) +#endif +#ifdef MCLK_APBCMASK_TCC3 +#define MCLK_TCC3 (&MCLK->APBCMASK.reg) +#define MCLK_TCC3_MASK (MCLK_APBCMASK_TCC3) +#endif +#ifdef MCLK_APBDMASK_TCC3 +#define MCLK_TCC3 (&MCLK->APBDMASK.reg) +#define MCLK_TCC3_MASK (MCLK_APBDMASK_TCC3) +#endif + +#ifdef MCLK_APBAMASK_TCC4 +#define MCLK_TCC4 (&MCLK->APBAMASK.reg) +#define MCLK_TCC4_MASK (MCLK_APBAMASK_TCC4) +#endif +#ifdef MCLK_APBBMASK_TCC4 +#define MCLK_TCC4 (&MCLK->APBBMASK.reg) +#define MCLK_TCC4_MASK (MCLK_APBBMASK_TCC4) +#endif +#ifdef MCLK_APBCMASK_TCC4 +#define MCLK_TCC4 (&MCLK->APBCMASK.reg) +#define MCLK_TCC4_MASK (MCLK_APBCMASK_TCC4) +#endif +#ifdef MCLK_APBDMASK_TCC4 +#define MCLK_TCC4 (&MCLK->APBDMASK.reg) +#define MCLK_TCC4_MASK (MCLK_APBDMASK_TCC4) +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* TIMER_CONFIG_H */ +/** @} */ diff --git a/cpu/sam0_common/periph/pwm.c b/cpu/sam0_common/periph/pwm.c index 1806df1f13..7610b8f7ea 100644 --- a/cpu/sam0_common/periph/pwm.c +++ b/cpu/sam0_common/periph/pwm.c @@ -17,14 +17,11 @@ * * @author Peter Kietzmann * @author Hauke Petersen + * @author Benjamin Valentin * * @} */ -#include -#include - -#include "log.h" #include "cpu.h" #include "board.h" #include "periph/gpio.h" @@ -32,7 +29,7 @@ static inline Tcc *_tcc(pwm_t dev) { - return pwm_config[dev].dev; + return pwm_config[dev].tim.dev; } static inline uint8_t _chan(pwm_t dev, int chan) @@ -40,57 +37,7 @@ static inline uint8_t _chan(pwm_t dev, int chan) return pwm_config[dev].chan[chan].chan; } -static int _clk_id(pwm_t dev) -{ - Tcc *tcc = _tcc(dev); - - if (tcc == TCC0) { - return TCC0_GCLK_ID; - } - - if (tcc == TCC1) { - return TCC1_GCLK_ID; - } - - if (tcc == TCC2) { - return TCC2_GCLK_ID; - } -#ifdef TCC3 - if (tcc == TCC3) { - return TCC3_GCLK_ID; - } -#endif - - assert(0); - return 0; -} - -static uint32_t _apbcmask_tcc(pwm_t dev) -{ - Tcc *tcc = _tcc(dev); - - if (tcc == TCC0) { - return PM_APBCMASK_TCC0; - } - - if (tcc == TCC1) { - return PM_APBCMASK_TCC1; - } - - if (tcc == TCC2) { - return PM_APBCMASK_TCC2; - } -#ifdef TCC3 - if (tcc == TCC3) { - return PM_APBCMASK_TCC3; - } -#endif - - assert(0); - return 0; -} - -static uint8_t get_prescaler(unsigned int target, int *scale) +static uint8_t _get_prescaler(unsigned int target, int *scale) { if (target == 0) { return 0xff; @@ -124,13 +71,68 @@ static uint8_t get_prescaler(unsigned int target, int *scale) return target - 1; } +static uint8_t _get_cc_numof(Tcc *tcc) +{ + switch ((uintptr_t) tcc) { +#ifdef TCC0_CC_NUM + case (uintptr_t)TCC0: + return TCC0_CC_NUM; +#endif +#ifdef TCC1_CC_NUM + case (uintptr_t)TCC1: + return TCC1_CC_NUM; +#endif +#ifdef TCC2_CC_NUM + case (uintptr_t)TCC2: + return TCC2_CC_NUM; +#endif +#ifdef TCC3_CC_NUM + case (uintptr_t)TCC3: + return TCC3_CC_NUM; +#endif +#ifdef TCC4_CC_NUM + case (uintptr_t)TCC4: + return TCC4_CC_NUM; +#endif +#ifdef TCC5_CC_NUM + case (uintptr_t)TCC5: + return TCC5_CC_NUM; +#endif + } + + assert(0); + return 0; +} + static void poweron(pwm_t dev) { - PM->APBCMASK.reg |= _apbcmask_tcc(dev); - GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_GEN_GCLK0 | - GCLK_CLKCTRL_ID(_clk_id(dev))); - while (GCLK->STATUS.bit.SYNCBUSY) {} + const pwm_conf_t *cfg = &pwm_config[dev]; + + sam0_gclk_enable(cfg->gclk_src); +#ifdef MCLK + GCLK->PCHCTRL[cfg->tim.gclk_id].reg = GCLK_PCHCTRL_GEN(cfg->gclk_src) + | GCLK_PCHCTRL_CHEN; + *cfg->tim.mclk |= cfg->tim.mclk_mask; +#else + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN(cfg->gclk_src) + | GCLK_CLKCTRL_ID(cfg->tim.gclk_id); + PM->APBCMASK.reg |= cfg->tim.pm_mask; +#endif +} + +static void poweroff(pwm_t dev) +{ + const pwm_conf_t *cfg = &pwm_config[dev]; + +#ifdef MCLK + GCLK->PCHCTRL[cfg->tim.gclk_id].reg = 0; + *cfg->tim.mclk &= ~cfg->tim.mclk_mask; +#else + PM->APBCMASK.reg &= ~cfg->tim.pm_mask; + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK7 + | GCLK_CLKCTRL_ID(cfg->tim.gclk_id); +#endif } uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) @@ -143,12 +145,14 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) return 0; } + const uint32_t f_src = sam0_gclk_freq(pwm_config[dev].gclk_src); + /* calculate the closest possible clock presacler */ - prescaler = get_prescaler(CLOCK_CORECLOCK / (freq * res), &scale); + prescaler = _get_prescaler(f_src / (freq * res), &scale); if (prescaler == 0xff) { return 0; } - f_real = (CLOCK_CORECLOCK / (scale * res)); + f_real = f_src / (scale * res); /* configure the used pins */ for (unsigned i = 0; i < pwm_config[dev].chan_numof; i++) { @@ -164,6 +168,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) /* reset TCC module */ _tcc(dev)->CTRLA.reg = TCC_CTRLA_SWRST; while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {} + /* set PWM mode */ switch (mode) { case PWM_LEFT: @@ -179,16 +184,20 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {} /* configure the TCC device */ - _tcc(dev)->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val - | TCC_CTRLA_PRESCALER(prescaler)); + _tcc(dev)->CTRLA.reg = TCC_CTRLA_PRESCSYNC_GCLK_Val + | TCC_CTRLA_PRESCALER(prescaler); + /* select the waveform generation mode -> normal PWM */ _tcc(dev)->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM); while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {} + /* set the selected period */ _tcc(dev)->PER.reg = (res - 1); while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {} + /* start PWM operation */ - _tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE); + _tcc(dev)->CTRLA.reg |= TCC_CTRLA_ENABLE; + /* return the actual frequency the PWM is running at */ return f_real; } @@ -206,14 +215,12 @@ void pwm_set(pwm_t dev, uint8_t channel, uint16_t value) } uint8_t chan = _chan(dev, channel); - if (chan < 4) { - _tcc(dev)->CC[chan].reg = value; - while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << chan)) {} - } else { - chan -= 4; - _tcc(dev)->CCB[chan].reg = value; - while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CCB0 << chan)) {} - } + + /* TODO: use OTMX for pin remapping */ + chan %= _get_cc_numof(_tcc(dev)); + + _tcc(dev)->CC[chan].reg = value; + while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << chan)) {} } void pwm_poweron(pwm_t dev) @@ -225,9 +232,5 @@ void pwm_poweron(pwm_t dev) void pwm_poweroff(pwm_t dev) { _tcc(dev)->CTRLA.reg &= ~(TCC_CTRLA_ENABLE); - - PM->APBCMASK.reg &= ~_apbcmask_tcc(dev); - GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK7 | - GCLK_CLKCTRL_ID(_clk_id(dev))); - while (GCLK->STATUS.bit.SYNCBUSY) {} + poweroff(dev); } From 9500b651dc55cde1c5243e3c5ac52ee292a2787e Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 01:12:40 +0200 Subject: [PATCH 03/12] boards/same54-xpro: configure LED0 as PWM output --- boards/same54-xpro/Makefile.features | 1 + boards/same54-xpro/include/periph_conf.h | 29 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/boards/same54-xpro/Makefile.features b/boards/same54-xpro/Makefile.features index 3967e769d1..fbc66c1344 100644 --- a/boards/same54-xpro/Makefile.features +++ b/boards/same54-xpro/Makefile.features @@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_dac FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt +FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart diff --git a/boards/same54-xpro/include/periph_conf.h b/boards/same54-xpro/include/periph_conf.h index bb6ca0c3f0..9d1e44494a 100644 --- a/boards/same54-xpro/include/periph_conf.h +++ b/boards/same54-xpro/include/periph_conf.h @@ -148,6 +148,35 @@ static const uart_conf_t uart_config[] = { #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ +/** + * @name PWM configuration + * @{ + */ +#define PWM_0_EN 1 + +#if PWM_0_EN +/* PWM0 channels */ +static const pwm_conf_chan_t pwm_chan0_config[] = { + /* GPIO pin, MUX value, TCC channel */ + { GPIO_PIN(PC, 18), GPIO_MUX_F, 2 }, +}; +#endif + +/* PWM device configuration */ +static const pwm_conf_t pwm_config[] = { +#if PWM_0_EN + { .tim = TCC_CONFIG(TCC0), + .chan = pwm_chan0_config, + .chan_numof = ARRAY_SIZE(pwm_chan0_config), + .gclk_src = SAM0_GCLK_48MHZ, + }, +#endif +}; + +/* number of devices that are actually defined */ +#define PWM_NUMOF ARRAY_SIZE(pwm_config) +/** @} */ + /** * @name SPI configuration * @{ From b4ff0da7cbae91ebd819e87d468969dc63d58045 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 01:33:20 +0200 Subject: [PATCH 04/12] boards/samd21-xpro: update PWM configuration --- boards/samd21-xpro/include/periph_conf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/samd21-xpro/include/periph_conf.h b/boards/samd21-xpro/include/periph_conf.h index d761c3b7b2..8d8eae4558 100644 --- a/boards/samd21-xpro/include/periph_conf.h +++ b/boards/samd21-xpro/include/periph_conf.h @@ -230,13 +230,13 @@ static const pwm_conf_chan_t pwm_chan2_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC2, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC2), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TC4, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TC4), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif #if PWM_2_EN - {TC6, pwm_chan2_config, ARRAY_SIZE(pwm_chan2_config)}, + {TCC_CONFIG(TC6), pwm_chan2_config, ARRAY_SIZE(pwm_chan2_config), SAM0_GCLK_MAIN}, #endif }; From 6547b36cc0963438b0e7a7172fb1cc9d54dc74d0 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 02:56:16 +0200 Subject: [PATCH 05/12] boards/arduino-zero: update PWM config --- boards/common/arduino-zero/include/periph_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/common/arduino-zero/include/periph_conf.h b/boards/common/arduino-zero/include/periph_conf.h index 5d6053d716..821a374f6d 100644 --- a/boards/common/arduino-zero/include/periph_conf.h +++ b/boards/common/arduino-zero/include/periph_conf.h @@ -193,10 +193,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TCC1, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TCC1), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif }; From 8f568a4eb97eac6d9bd9b1fbfa6bc5704ff2c1a7 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 02:56:16 +0200 Subject: [PATCH 06/12] boards/feather-m0: update PWM config --- boards/feather-m0/include/periph_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/feather-m0/include/periph_conf.h b/boards/feather-m0/include/periph_conf.h index adaccac4fc..0af11c8d6c 100644 --- a/boards/feather-m0/include/periph_conf.h +++ b/boards/feather-m0/include/periph_conf.h @@ -170,10 +170,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TCC2, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TCC2), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif }; From 6e9e9cd6ad344fd6cc8c635f3b10d2d88c91bc77 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 02:56:16 +0200 Subject: [PATCH 07/12] boards/hamilton: update PWM config --- boards/hamilton/include/periph_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/hamilton/include/periph_conf.h b/boards/hamilton/include/periph_conf.h index 68d8881736..96a02c4693 100644 --- a/boards/hamilton/include/periph_conf.h +++ b/boards/hamilton/include/periph_conf.h @@ -201,10 +201,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif }; From b97e6c1e1e393c285844bd79023964d79f025e71 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 02:56:16 +0200 Subject: [PATCH 08/12] boards/samr21-xpro: update PWM config --- boards/samr21-xpro/include/periph_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 847103a57c..6b6b00c168 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -207,10 +207,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif }; From d9aed03fa037db45721035e5082bf362bc0f6219 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 02:56:16 +0200 Subject: [PATCH 09/12] boards/sodaq-autonomo: update PWM config --- boards/sodaq-autonomo/include/periph_conf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/sodaq-autonomo/include/periph_conf.h b/boards/sodaq-autonomo/include/periph_conf.h index f44adb8e30..4e0d13f66f 100644 --- a/boards/sodaq-autonomo/include/periph_conf.h +++ b/boards/sodaq-autonomo/include/periph_conf.h @@ -171,10 +171,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif #if PWM_1_EN - {TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)}, + {TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, #endif }; From 632d68cebf0f6f131dbe148406858dd040fd4bf3 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 3 May 2020 13:39:52 +0200 Subject: [PATCH 10/12] boards/common/arduino-mkr: update PWM configuration --- boards/common/arduino-mkr/include/periph_conf_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/common/arduino-mkr/include/periph_conf_common.h b/boards/common/arduino-mkr/include/periph_conf_common.h index c64724ca5d..3cd41246dd 100644 --- a/boards/common/arduino-mkr/include/periph_conf_common.h +++ b/boards/common/arduino-mkr/include/periph_conf_common.h @@ -141,7 +141,7 @@ static const pwm_conf_chan_t pwm_chan0_config[] = { /* PWM device configuration */ static const pwm_conf_t pwm_config[] = { #if PWM_0_EN - {TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)}, + {TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, #endif }; From d62467a013b0c9113e2127a9829c2c528363921b Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 7 Jun 2020 16:56:59 +0200 Subject: [PATCH 11/12] boards/serpente: add PWM configuration --- boards/serpente/Makefile.features | 1 + boards/serpente/include/periph_conf.h | 41 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/boards/serpente/Makefile.features b/boards/serpente/Makefile.features index 0e20e297ee..d7a00f01b2 100644 --- a/boards/serpente/Makefile.features +++ b/boards/serpente/Makefile.features @@ -5,6 +5,7 @@ CPU_MODEL = samd21e18a FEATURES_PROVIDED += bootloader_arduino FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_spi diff --git a/boards/serpente/include/periph_conf.h b/boards/serpente/include/periph_conf.h index 411abceb5a..4c8087f605 100644 --- a/boards/serpente/include/periph_conf.h +++ b/boards/serpente/include/periph_conf.h @@ -152,6 +152,47 @@ static const uart_conf_t uart_config[] = { #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ +/** + * @name PWM configuration + * @{ + */ +#define PWM_0_EN 1 +#define PWM_1_EN 1 + +#if PWM_0_EN +/* PWM0 channels */ +static const pwm_conf_chan_t pwm_chan0_config[] = { + /* GPIO pin, MUX value, TCC channel */ + { GPIO_PIN(PA, 4), GPIO_MUX_E, 0 }, + { GPIO_PIN(PA, 5), GPIO_MUX_E, 1 }, + { GPIO_PIN(PA, 19), GPIO_MUX_F, 3 }, + { GPIO_PIN(PA, 22), GPIO_MUX_F, 4 }, + { GPIO_PIN(PA, 23), GPIO_MUX_F, 5 }, +}; +#endif +#if PWM_1_EN +/* PWM1 channels */ +static const pwm_conf_chan_t pwm_chan1_config[] = { + /* GPIO pin, MUX value, TCC channel */ + { GPIO_PIN(PA, 6), GPIO_MUX_E, 0 }, + { GPIO_PIN(PA, 7), GPIO_MUX_E, 1 }, +}; +#endif + +/* PWM device configuration */ +static const pwm_conf_t pwm_config[] = { +#if PWM_0_EN + {TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN}, +#endif +#if PWM_1_EN + {TCC_CONFIG(TCC1), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN}, +#endif +}; + +/* number of devices that are actually defined */ +#define PWM_NUMOF ARRAY_SIZE(pwm_config) +/** @} */ + /** * @name SPI configuration * @{ From dfc1e6b6afb1f7b3886c984607486da35138bb6f Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 30 Jun 2020 19:12:43 +0200 Subject: [PATCH 12/12] boards/saml21-xpro: add PWM configuration --- boards/saml21-xpro/Makefile.features | 1 + boards/saml21-xpro/include/periph_conf.h | 29 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/boards/saml21-xpro/Makefile.features b/boards/saml21-xpro/Makefile.features index 12d5fdbcfa..b397b59555 100644 --- a/boards/saml21-xpro/Makefile.features +++ b/boards/saml21-xpro/Makefile.features @@ -5,6 +5,7 @@ CPU_MODEL = saml21j18a FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_dac FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_spi diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index c66a7d4898..c4983db1c6 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -105,6 +105,35 @@ static const uart_conf_t uart_config[] = { #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ +/** + * @name PWM configuration + * @{ + */ +#define PWM_0_EN 1 + +#if PWM_0_EN +/* PWM0 channels */ +static const pwm_conf_chan_t pwm_chan0_config[] = { + /* GPIO pin, MUX value, TCC channel */ + { GPIO_PIN(PB, 10), GPIO_MUX_F, 4 }, +}; +#endif + +/* PWM device configuration */ +static const pwm_conf_t pwm_config[] = { +#if PWM_0_EN + { .tim = TCC_CONFIG(TCC0), + .chan = pwm_chan0_config, + .chan_numof = ARRAY_SIZE(pwm_chan0_config), + .gclk_src = SAM0_GCLK_8MHZ, + }, +#endif +}; + +/* number of devices that are actually defined */ +#define PWM_NUMOF ARRAY_SIZE(pwm_config) +/** @} */ + /** * @name SPI configuration * @{