diff --git a/boards/common/arduino-mkr/include/periph_conf_common.h b/boards/common/arduino-mkr/include/periph_conf_common.h index 97cdc606d8..c6f3823fa3 100644 --- a/boards/common/arduino-mkr/include/periph_conf_common.h +++ b/boards/common/arduino-mkr/include/periph_conf_common.h @@ -137,7 +137,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 }; diff --git a/boards/common/arduino-zero/include/periph_conf.h b/boards/common/arduino-zero/include/periph_conf.h index 1f4610bfb2..939219c21a 100644 --- a/boards/common/arduino-zero/include/periph_conf.h +++ b/boards/common/arduino-zero/include/periph_conf.h @@ -189,10 +189,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 }; diff --git a/boards/feather-m0/include/periph_conf.h b/boards/feather-m0/include/periph_conf.h index 9b4dec9af2..ab49e7f4a8 100644 --- a/boards/feather-m0/include/periph_conf.h +++ b/boards/feather-m0/include/periph_conf.h @@ -166,10 +166,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 }; diff --git a/boards/hamilton/include/periph_conf.h b/boards/hamilton/include/periph_conf.h index e8b169c14a..1a34083517 100644 --- a/boards/hamilton/include/periph_conf.h +++ b/boards/hamilton/include/periph_conf.h @@ -186,10 +186,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 }; diff --git a/boards/samd21-xpro/include/periph_conf.h b/boards/samd21-xpro/include/periph_conf.h index a6613925ee..7d64dea3e6 100644 --- a/boards/samd21-xpro/include/periph_conf.h +++ b/boards/samd21-xpro/include/periph_conf.h @@ -226,13 +226,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 }; 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 e27ff9b0fa..29ecf99d83 100644 --- a/boards/same54-xpro/include/periph_conf.h +++ b/boards/same54-xpro/include/periph_conf.h @@ -185,6 +185,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 * @{ diff --git a/boards/saml21-xpro/Makefile.features b/boards/saml21-xpro/Makefile.features index 95f2c897e6..8973c618fb 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 05575a275d..fffab55d02 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -104,6 +104,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 * @{ diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 2c9ab96b4f..fdeea1d36e 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -211,10 +211,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 }; 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 832668c558..dfe6963e84 100644 --- a/boards/serpente/include/periph_conf.h +++ b/boards/serpente/include/periph_conf.h @@ -148,6 +148,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 * @{ 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 }; diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index a10d2521e8..d6247437cd 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" { @@ -216,6 +217,57 @@ 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 */ +} pwm_conf_chan_t; + +/** + * @brief PWM device configuration data structure + */ +typedef struct { + 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; + /** * @brief Available values for SERCOM SPI MISO pad selection */ 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/samd21/periph/pwm.c b/cpu/sam0_common/periph/pwm.c similarity index 64% rename from cpu/samd21/periph/pwm.c rename to cpu/sam0_common/periph/pwm.c index 1806df1f13..7610b8f7ea 100644 --- a/cpu/samd21/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); } diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index 1018355ed1..08abcbd8e5 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 *