diff --git a/boards/weio/include/periph_conf.h b/boards/weio/include/periph_conf.h index 8c78669055..8eff676a5f 100644 --- a/boards/weio/include/periph_conf.h +++ b/boards/weio/include/periph_conf.h @@ -20,6 +20,8 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -88,44 +90,30 @@ extern "C" { * @brief PWM configuration * @{ */ -#define PWM_0_EN 1 -#define PWM_0_CHANNELS 3 -#define PWM_1_EN 1 -#define PWM_1_CHANNELS 3 -#define PWM_NUMOF (2U) +static const pwm_conf_t pwm_config[] = { + { + .dev = LPC_CT16B0, + .pins = { + &LPC_IOCON->PIO1_13, + &LPC_IOCON->PIO1_14, + &LPC_IOCON->PIO1_15 + }, + .clk_bit = BIT7, + .af = 0x02 + }, + { + .dev = LPC_CT32B0, + .pins = { + &LPC_IOCON->PIO1_24, + &LPC_IOCON->PIO1_25, + &LPC_IOCON->PIO1_26 + }, + .clk_bit = BIT9, + .af = 0x01 + } +}; -/* PWM0 common configuration */ -#define PWM_0_DEV LPC_CT16B0 -#define PWM_0_CLK BIT7 -/* PWM_0 channel configuration */ -#define PWM_0_CH0_EN 1 -#define PWM_0_CH0_IOCON LPC_IOCON->PIO1_13 -#define PWM_0_CH0_AF 0x82 - -#define PWM_0_CH1_EN 1 -#define PWM_0_CH1_IOCON LPC_IOCON->PIO1_14 -#define PWM_0_CH1_AF 0x82 - -#define PWM_0_CH2_EN 1 -#define PWM_0_CH2_IOCON LPC_IOCON->PIO1_15 -#define PWM_0_CH2_AF 0x82 - -/* PWM1 common configuration */ -#define PWM_1_DEV LPC_CT32B0 -#define PWM_1_CLK BIT9 -/* PWM_1 channel configuration */ - -#define PWM_1_CH0_EN 1 -#define PWM_1_CH0_IOCON LPC_IOCON->PIO1_24 -#define PWM_1_CH0_AF 0x81 - -#define PWM_1_CH1_EN 1 -#define PWM_1_CH1_IOCON LPC_IOCON->PIO1_25 -#define PWM_1_CH1_AF 0x81 - -#define PWM_1_CH2_EN 1 -#define PWM_1_CH2_IOCON LPC_IOCON->PIO1_26 -#define PWM_1_CH2_AF 0x81 +#define PWM_NUMOF (sizeof(pwm_config) / sizeof(pwm_config[0])) /* @} */ #ifdef __cplusplus diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h index f11b8edbba..b27a2b1201 100644 --- a/cpu/lpc11u34/include/periph_cpu.h +++ b/cpu/lpc11u34/include/periph_cpu.h @@ -21,7 +21,7 @@ #define PERIPH_CPU_H #include -#include "periph/dev_enums.h" +#include "cpu.h" #ifdef __cplusplus extern "C" { @@ -61,6 +61,11 @@ typedef uint16_t gpio_t; */ #define GPIO_PIN(port, pin) (gpio_t)((port << 16) | pin) +/** + * @brief Number of PWM channels per PWM peripheral + */ +#define PWM_CHAN_NUMOF (3U) + /** * @brief Override the default GPIO mode values * @{ @@ -99,6 +104,21 @@ typedef enum { /** @} */ #endif /* ndef DOXYGEN */ +/** + * @brief PWM channel configuration + */ + + +/** + * @brief PWM configuration + */ +typedef struct { + LPC_CTxxBx_Type *dev; + __IO uint32_t *pins[PWM_CHAN_NUMOF]; /**< set to NULL if channel is not used */ + uint16_t clk_bit; + uint8_t af; +} pwm_conf_t; + #ifdef __cplusplus } #endif diff --git a/cpu/lpc11u34/periph/pwm.c b/cpu/lpc11u34/periph/pwm.c index da752d2f68..b405ffe64b 100644 --- a/cpu/lpc11u34/periph/pwm.c +++ b/cpu/lpc11u34/periph/pwm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Freie Universität Berlin + * Copyright (C) 2015-2017 Freie Universität Berlin * * 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 @@ -14,219 +14,99 @@ * @brief CPU specific low-level PWM driver implementation for LPC11U34 * * @author Paul RATHGEB + * @author Hauke Petersen * * @} */ #include "bitarithm.h" -#include "periph/gpio.h" -#include "board.h" -#include "periph_conf.h" +#include "periph/pwm.h" /* guard file in case no PWM device is defined */ -#include "periph/pwm.h" -#if (PWM_0_EN || PWM_1_EN) +#ifdef PWM_NUMOF + +static inline LPC_CTxxBx_Type *dev(pwm_t pwm) +{ + return pwm_config[pwm].dev; +} /** * @note The LPC11U34 doesn't support centerized alignements */ -uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) +uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - /* This CPU doesn't support a centerized alignement */ - if (mode == PWM_CENTER) { - return 0; - } - /* Check if the frequency and resolution is applicable */ - if (CLOCK_CORECLOCK / (res * freq) <= 0) { - return 0; - } -#if PWM_0_CH0_EN - PWM_0_CH0_IOCON = (PWM_0_CH0_IOCON & ~(BIT7 | 7)) | PWM_0_CH0_AF; -#endif -#if PWM_0_CH1_EN - PWM_0_CH1_IOCON = (PWM_0_CH1_IOCON & ~(BIT7 | 7)) | PWM_0_CH1_AF; -#endif -#if PWM_0_CH2_EN - PWM_0_CH2_IOCON = (PWM_0_CH2_IOCON & ~(BIT7 | 7)) | PWM_0_CH2_AF; -#endif - /* The configuration involve that the peripheral is powered */ - pwm_poweron(dev); - /* Enable timer and keep it in reset state */ - PWM_0_DEV->TCR = BIT0 | BIT1; - /* Set the prescaler (CLOCK_CORECLOCK / resolution) */ - PWM_0_DEV->PR = (CLOCK_CORECLOCK / (res * freq)); - /* Reset timer on MR3 */ - PWM_0_DEV->MCR = BIT10; + assert((pwm < PWM_NUMOF) && (mode != PWM_CENTER)); - /* Set PWM period */ - PWM_0_DEV->MR0 = res; - PWM_0_DEV->MR1 = res; - PWM_0_DEV->MR2 = res; - PWM_0_DEV->MR3 = res - 1; - - /* Set mode for channels 0..2 */ - PWM_0_DEV->EMR |= ((mode + 1) << 4); - PWM_0_DEV->EMR |= ((mode + 1) << 6); - PWM_0_DEV->EMR |= ((mode + 1) << 8); - - /* Enable PWM channels 0..2 */ - PWM_0_DEV->PWMC = BIT0 | BIT1 | BIT2; -#endif /* PWM_0_EN */ -#if PWM_1_EN - case PWM_1: - /* This CPU doesn't support a centerized alignement */ - if (mode == PWM_CENTER) { - return 0; - } - /* Check if the frequency and resolution is applicable */ - if (CLOCK_CORECLOCK / (res * freq) <= 0) { - return 0; - } -#if PWM_1_CH0_EN - PWM_1_CH0_IOCON = (PWM_1_CH0_IOCON & ~(BIT7 | 7)) | PWM_1_CH0_AF; -#endif -#if PWM_1_CH1_EN - PWM_1_CH1_IOCON = (PWM_1_CH1_IOCON & ~(BIT7 | 7)) | PWM_1_CH1_AF; -#endif -#if PWM_1_CH2_EN - PWM_1_CH2_IOCON = (PWM_1_CH2_IOCON & ~(BIT7 | 7)) | PWM_1_CH2_AF; -#endif - /* The configuration involve that the peripheral is powered */ - pwm_poweron(dev); - /* Enable timer and keep it in reset state */ - PWM_1_DEV->TCR = BIT0 | BIT1; - /* Set the prescaler (CLOCK_CORECLOCK / resolution) */ - PWM_1_DEV->PR = (CLOCK_CORECLOCK / (res * freq)); - /* Reset timer on MR3 */ - PWM_1_DEV->MCR = BIT10; - - /* Set PWM period */ - PWM_1_DEV->MR0 = res; - PWM_1_DEV->MR1 = res; - PWM_1_DEV->MR2 = res; - PWM_1_DEV->MR3 = res - 1; - - /* Set mode for channels 0..2 */ - PWM_1_DEV->EMR |= ((mode + 1) << 4); - PWM_1_DEV->EMR |= ((mode + 1) << 6); - PWM_1_DEV->EMR |= ((mode + 1) << 8); - - /* Enable PWM channels 0..2 */ - PWM_1_DEV->PWMC = BIT0 | BIT1 | BIT2; -#endif /* PWM_1_EN */ + /* make sure the given frequency settings are applicable */ + if (CLOCK_CORECLOCK < (res * freq)) { + return 0; } + /* setup pins */ + for (unsigned i = 0; i < PWM_CHAN_NUMOF; i++) { + if (pwm_config[pwm].pins[i]) { + *(pwm_config[pwm].pins[i]) = pwm_config[pwm].af; + } + } + + /* power on and configure the timer */ + pwm_poweron(pwm); + /* enable the timer and keep it in reset state */ + dev(pwm)->TCR = BIT0 | BIT1; + /* set prescaler */ + dev(pwm)->PR = (CLOCK_CORECLOCK / (res * freq)); + /* reset timer on MR3 */ + dev(pwm)->MCR = BIT10; + + /* set PWM period */ + dev(pwm)->MR0 = res; + dev(pwm)->MR1 = res; + dev(pwm)->MR2 = res; + dev(pwm)->MR3 = (res - 1); + + /* set mode for channels 0, 1, and 2 */ + dev(pwm)->EMR = (((mode + 1) << 4) | ((mode + 1) << 6) | ((mode + 1) << 8)); + + /* enable channels 0, 1, and 2 */ + dev(pwm)->PWMC = (BIT0 | BIT1 | BIT2); + return freq; } -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 (uint8_t)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) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - if (channel <= 2) { - PWM_0_DEV->MR[channel] = PWM_0_DEV->MR3 - value; - } - break; -#endif -#if PWM_1_EN - case PWM_1: - if (channel <= 2) { - PWM_1_DEV->MR[channel] = PWM_1_DEV->MR3 - value; - } - break; -#endif - } + assert((pwm < PWM_NUMOF) && (channel < PWM_CHAN_NUMOF)); + dev(pwm)->MR[channel] = dev(pwm)->MR3 - value; } -void pwm_start(pwm_t dev) +void pwm_start(pwm_t pwm) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - /* Start the counter */ - PWM_0_DEV->TCR &= ~BIT1; - break; -#endif -#if PWM_1_EN - case PWM_1: - /* Start the counter */ - PWM_1_DEV->TCR &= ~BIT1; - break; -#endif - } + assert(pwm < PWM_NUMOF); + dev(pwm)->TCR &= ~(BIT1); } -void pwm_stop(pwm_t dev) +void pwm_stop(pwm_t pwm) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - /* Stop the counter */ - PWM_0_DEV->TCR |= BIT1; - break; -#endif -#if PWM_1_EN - case PWM_1: - /* Stop the counter */ - PWM_1_DEV->TCR |= BIT1; - break; -#endif - } + assert(pwm < PWM_NUMOF); + dev(pwm)->TCR |= (BIT1); } -void pwm_poweron(pwm_t dev) +void pwm_poweron(pwm_t pwm) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - /* Enable clock for PWM_0 */ - LPC_SYSCON->SYSAHBCLKCTRL |= PWM_0_CLK; - break; -#endif -#if PWM_1_EN - case PWM_1: - /* Enable clock for PWM_1 */ - LPC_SYSCON->SYSAHBCLKCTRL |= PWM_1_CLK; - break; -#endif - } + assert(pwm < PWM_NUMOF); + LPC_SYSCON->SYSAHBCLKCTRL |= pwm_config[pwm].clk_bit; } -void pwm_poweroff(pwm_t dev) +void pwm_poweroff(pwm_t pwm) { - switch (dev) { -#if PWM_0_EN - case PWM_0: - /* Disable clock for PWM_0 */ - LPC_SYSCON->SYSAHBCLKCTRL &= ~PWM_0_CLK; - break; -#endif -#if PWM_1_EN - case PWM_1: - /* Disable clock for PWM_1 */ - LPC_SYSCON->SYSAHBCLKCTRL &= ~PWM_1_CLK; - break; -#endif - } + assert(pwm < PWM_NUMOF); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(pwm_config[pwm].clk_bit); } -#endif /* (PWM_0_EN || PWM_1_EN) */ + +#endif /* PWM_NUMOF */