diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h index 4faee8bd3a..e44fb4ae55 100644 --- a/cpu/lpc11u34/include/periph_cpu.h +++ b/cpu/lpc11u34/include/periph_cpu.h @@ -20,6 +20,7 @@ #ifndef PERIPH_CPU_H_ #define PERIPH_CPU_H_ +#include #include "periph/dev_enums.h" #ifdef __cplusplus @@ -47,6 +48,40 @@ extern "C" { */ #define ADC_NUMOF (10U) +/** + * @brief Override the default GPIO type + * @{ + */ +#define HAVE_GPIO_T +typedef uint16_t gpio_t; +/** @} */ + +/** + * @brief Define a custom GPIO_PIN macro for the lpc11u34 + */ +#define GPIO_PIN(port, pin) (gpio_t)((port << 16) | pin) + +/** + * @brief Override the default GPIO mode values + * @{ + */ +#define IN (0x0000) +#define OUT (0x0001) +#define PD (0x1 << 3) +#define PU (0x2 << 3) +#define OD (0x1 << 10) + +#define HAVE_GPIO_MODE_T +typedef enum { + GPIO_IN = (IN), /**< in without pull resistor */ + GPIO_IN_PD = (IN | PD), /**< in with pull-down */ + GPIO_IN_PU = (IN | PU), /**< in with pull-up */ + GPIO_OUT = (OUT), /**< push-pull output */ + GPIO_OD = (OUT | OD), /**< open-drain output */ + GPIO_OD_PU = (OUT | OD | PU) /**< open-drain output with pull-up */ +} gpio_mode_t; +/** @} */ + #ifndef DOXYGEN /** * @brief Override the ADC resolution settings diff --git a/cpu/lpc11u34/periph/gpio.c b/cpu/lpc11u34/periph/gpio.c index bbc2bfb287..684e81c6a5 100644 --- a/cpu/lpc11u34/periph/gpio.c +++ b/cpu/lpc11u34/periph/gpio.c @@ -22,446 +22,169 @@ #include "thread.h" #include "periph/gpio.h" -/* Static IOCON registers definition */ -volatile uint32_t * const lpc_pin_registers[] = { - /* PORT 0 (PIO0_0 -> PIO0_23) */ - &LPC_IOCON->RESET_PIO0_0, &LPC_IOCON->PIO0_1, - &LPC_IOCON->PIO0_2, &LPC_IOCON->PIO0_3, - &LPC_IOCON->PIO0_4, &LPC_IOCON->PIO0_5, - &LPC_IOCON->PIO0_6, &LPC_IOCON->PIO0_7, - &LPC_IOCON->PIO0_8, &LPC_IOCON->PIO0_9, - &LPC_IOCON->SWCLK_PIO0_10, &LPC_IOCON->TDI_PIO0_11, - &LPC_IOCON->TMS_PIO0_12, &LPC_IOCON->TDO_PIO0_13, - &LPC_IOCON->TRST_PIO0_14, &LPC_IOCON->SWDIO_PIO0_15, - &LPC_IOCON->PIO0_16, &LPC_IOCON->PIO0_17, - &LPC_IOCON->PIO0_18, &LPC_IOCON->PIO0_19, - &LPC_IOCON->PIO0_20, &LPC_IOCON->PIO0_21, - &LPC_IOCON->PIO0_22, &LPC_IOCON->PIO0_23, - /* PORT 1 (PIO1_0 -> PIO0_31) */ - &LPC_IOCON->PIO1_0, &LPC_IOCON->PIO1_1, - &LPC_IOCON->PIO1_2, &LPC_IOCON->PIO1_3, - &LPC_IOCON->PIO1_4, &LPC_IOCON->PIO1_5, - &LPC_IOCON->PIO1_6, &LPC_IOCON->PIO1_7, - &LPC_IOCON->PIO1_8, &LPC_IOCON->PIO1_9, - &LPC_IOCON->PIO1_10, &LPC_IOCON->PIO1_11, - &LPC_IOCON->PIO1_12, &LPC_IOCON->PIO1_13, - &LPC_IOCON->PIO1_14, &LPC_IOCON->PIO1_15, - &LPC_IOCON->PIO1_16, &LPC_IOCON->PIO1_17, - &LPC_IOCON->PIO1_18, &LPC_IOCON->PIO1_19, - &LPC_IOCON->PIO1_20, &LPC_IOCON->PIO1_21, - &LPC_IOCON->PIO1_22, &LPC_IOCON->PIO1_23, - &LPC_IOCON->PIO1_24, &LPC_IOCON->PIO1_25, - &LPC_IOCON->PIO1_26, &LPC_IOCON->PIO1_27, - &LPC_IOCON->PIO1_28, &LPC_IOCON->PIO1_29, - &LPC_IOCON->PIO1_30, &LPC_IOCON->PIO1_31, -}; +#define PIN_MASK (0x00ff) +#define PORT_SHIFT (8U) -static int8_t flex_int_mapping[GPIO_NUMOF]; +#define MODE_DIR_MASK (0x0001) +#define MODE_IOCON_MASK (0xfff8) -static gpio_isr_ctx_t gpio_config[GPIO_NUMOF]; -static uint8_t gpio_int_id = 0; +#define ISR_NUMOF (8U) -/* static port mappings */ -static const uint8_t gpio_port_map[GPIO_NUMOF] = { -#if GPIO_0_EN - [GPIO_0] = GPIO_0_PORT, -#endif -#if GPIO_1_EN - [GPIO_1] = GPIO_1_PORT, -#endif -#if GPIO_2_EN - [GPIO_2] = GPIO_2_PORT, -#endif -#if GPIO_3_EN - [GPIO_3] = GPIO_3_PORT, -#endif -#if GPIO_4_EN - [GPIO_4] = GPIO_4_PORT, -#endif -#if GPIO_5_EN - [GPIO_5] = GPIO_5_PORT, -#endif -#if GPIO_6_EN - [GPIO_6] = GPIO_6_PORT, -#endif -#if GPIO_7_EN - [GPIO_7] = GPIO_7_PORT, -#endif -#if GPIO_8_EN - [GPIO_8] = GPIO_8_PORT, -#endif -#if GPIO_9_EN - [GPIO_9] = GPIO_9_PORT, -#endif -#if GPIO_10_EN - [GPIO_10] = GPIO_10_PORT, -#endif -#if GPIO_11_EN - [GPIO_11] = GPIO_11_PORT, -#endif -#if GPIO_12_EN - [GPIO_12] = GPIO_12_PORT, -#endif -#if GPIO_13_EN - [GPIO_13] = GPIO_13_PORT, -#endif -#if GPIO_14_EN - [GPIO_14] = GPIO_14_PORT, -#endif -#if GPIO_15_EN - [GPIO_15] = GPIO_15_PORT, -#endif -#if GPIO_16_EN - [GPIO_16] = GPIO_16_PORT, -#endif -#if GPIO_17_EN - [GPIO_17] = GPIO_17_PORT, -#endif -#if GPIO_18_EN - [GPIO_18] = GPIO_18_PORT, -#endif -#if GPIO_19_EN - [GPIO_19] = GPIO_19_PORT, -#endif -#if GPIO_20_EN - [GPIO_20] = GPIO_20_PORT, -#endif -#if GPIO_21_EN - [GPIO_21] = GPIO_21_PORT, -#endif -#if GPIO_22_EN - [GPIO_22] = GPIO_22_PORT, -#endif -#if GPIO_23_EN - [GPIO_23] = GPIO_23_PORT, -#endif -#if GPIO_24_EN - [GPIO_24] = GPIO_24_PORT, -#endif -#if GPIO_25_EN - [GPIO_25] = GPIO_25_PORT, -#endif -#if GPIO_26_EN - [GPIO_26] = GPIO_26_PORT, -#endif -#if GPIO_27_EN - [GPIO_27] = GPIO_27_PORT, -#endif -#if GPIO_28_EN - [GPIO_28] = GPIO_28_PORT, -#endif -#if GPIO_29_EN - [GPIO_29] = GPIO_29_PORT, -#endif -#if GPIO_30_EN - [GPIO_30] = GPIO_30_PORT, -#endif -#if GPIO_31_EN - [GPIO_31] = GPIO_31_PORT, -#endif -}; +#define SYSCTL_PINTMASK (1 << 19) -/* static pin mappings */ -static const uint8_t gpio_pin_map[GPIO_NUMOF] = { -#if GPIO_0_EN - [GPIO_0] = GPIO_0_PIN, -#endif -#if GPIO_1_EN - [GPIO_1] = GPIO_1_PIN, -#endif -#if GPIO_2_EN - [GPIO_2] = GPIO_2_PIN, -#endif -#if GPIO_3_EN - [GPIO_3] = GPIO_3_PIN, -#endif -#if GPIO_4_EN - [GPIO_4] = GPIO_4_PIN, -#endif -#if GPIO_5_EN - [GPIO_5] = GPIO_5_PIN, -#endif -#if GPIO_6_EN - [GPIO_6] = GPIO_6_PIN, -#endif -#if GPIO_7_EN - [GPIO_7] = GPIO_7_PIN, -#endif -#if GPIO_8_EN - [GPIO_8] = GPIO_8_PIN, -#endif -#if GPIO_9_EN - [GPIO_9] = GPIO_9_PIN, -#endif -#if GPIO_10_EN - [GPIO_10] = GPIO_10_PIN, -#endif -#if GPIO_11_EN - [GPIO_11] = GPIO_11_PIN, -#endif -#if GPIO_12_EN - [GPIO_12] = GPIO_12_PIN, -#endif -#if GPIO_13_EN - [GPIO_13] = GPIO_13_PIN, -#endif -#if GPIO_14_EN - [GPIO_14] = GPIO_14_PIN, -#endif -#if GPIO_15_EN - [GPIO_15] = GPIO_15_PIN, -#endif -#if GPIO_16_EN - [GPIO_16] = GPIO_16_PIN, -#endif -#if GPIO_17_EN - [GPIO_17] = GPIO_17_PIN, -#endif -#if GPIO_18_EN - [GPIO_18] = GPIO_18_PIN, -#endif -#if GPIO_19_EN - [GPIO_19] = GPIO_19_PIN, -#endif -#if GPIO_20_EN - [GPIO_20] = GPIO_20_PIN, -#endif -#if GPIO_21_EN - [GPIO_21] = GPIO_21_PIN, -#endif -#if GPIO_22_EN - [GPIO_22] = GPIO_22_PIN, -#endif -#if GPIO_23_EN - [GPIO_23] = GPIO_23_PIN, -#endif -#if GPIO_24_EN - [GPIO_24] = GPIO_24_PIN, -#endif -#if GPIO_25_EN - [GPIO_25] = GPIO_25_PIN, -#endif -#if GPIO_26_EN - [GPIO_26] = GPIO_26_PIN, -#endif -#if GPIO_27_EN - [GPIO_27] = GPIO_27_PIN, -#endif -#if GPIO_28_EN - [GPIO_28] = GPIO_28_PIN, -#endif -#if GPIO_29_EN - [GPIO_29] = GPIO_29_PIN, -#endif -#if GPIO_30_EN - [GPIO_30] = GPIO_30_PIN, -#endif -#if GPIO_31_EN - [GPIO_31] = GPIO_31_PIN, -#endif -}; +/* for efficiency reasons, we define our own custom IOCON_Type */ +typedef struct { + __IO uint32_t PIO[56]; /* 24 of P0 + 32 of P1 */ +} iocon_t; -int gpio_init(gpio_t dev, gpio_mode_t mode) +#define IOCON ((iocon_t *)LPC_IOCON_BASE) + +static gpio_t isrmap[] = { GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, + GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF, GPIO_UNDEF }; + +static gpio_isr_ctx_t isrctx[ISR_NUMOF]; + +static inline int port(gpio_t pin) { - uint8_t port; - uint8_t pin; - - if (dev >= GPIO_NUMOF) { - return -1; - } - - /* Get the port and pin values */ - port = gpio_port_map[dev]; - pin = gpio_pin_map[dev]; - - /* Put pin in the primary function */ - *lpc_pin_registers[pin + (port * 24)] = *lpc_pin_registers[pin + (port * 24)] & ~(0x07); - - /* Disable resistors */ - *lpc_pin_registers[pin + (port * 24)] &= ~(3 << 3); - - /* Set mode */ - switch (mode) { - case GPIO_IN: - LPC_GPIO->DIR[port] &= ~(1 << pin); - break; - case GPIO_IN_PD: - LPC_GPIO->DIR[port] &= ~(1 << pin); - *lpc_pin_registers[pin + (port * 24)] |= (1 << 3); - break; - case GPIO_IN_PU: - LPC_GPIO->DIR[port] &= ~(1 << pin); - *lpc_pin_registers[pin + (port * 24)] |= (2 << 3); - break; - case GPIO_OUT: - LPC_GPIO->DIR[port] |= (1 << pin); - break; - default: - return -1; - } - - return 0; /* all OK */ + return (int)(pin >> PORT_SHIFT); } -int gpio_init_int(gpio_t dev, gpio_mode_t mode, gpio_flank_t flank, - gpio_cb_t cb, void *arg) +static inline int num(gpio_t pin) { - int res; - uint8_t pin; - uint8_t port; + return (pin & PIN_MASK); +} - LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 19); +static inline uint32_t mask(gpio_t pin) +{ + return (1 << num(pin)); +} - if (dev >= GPIO_NUMOF) { - return -1; +static inline int ionum(gpio_t pin) +{ + return (port(pin) * 24) + num(pin); +} + +int gpio_init(gpio_t pin, gpio_mode_t mode) +{ + /* reset any eventually set interrupt configuration */ + for (int i = 0; i < ISR_NUMOF; i++) { + if (isrmap[i] == pin) { + NVIC_DisableIRQ(FLEX_INT0_IRQn + i); + isrmap[i] = GPIO_UNDEF; + } } - if (gpio_int_id > 7) { - return -1; - } - - port = gpio_port_map[dev]; - pin = gpio_pin_map[dev]; - - /* configure pin as input */ - res = gpio_init(dev, mode); - if (res < 0) { - return res; - } - - /* Disable interrupts */ - NVIC_DisableIRQ(gpio_int_id); - /* Register pin as flex interrupt */ - LPC_SYSCON->PINTSEL[gpio_int_id] = (port * 24) + pin; - - /* set callback */ - gpio_config[gpio_int_id].cb = cb; - gpio_config[gpio_int_id].arg = arg; - - /* configure the event that triggers an interrupt */ - switch (flank) { - case GPIO_RISING: - LPC_GPIO_PIN_INT->ISEL &= ~(1 << gpio_int_id); /* Set PMODE=edge sensitive */ - LPC_GPIO_PIN_INT->IENR |= (1 << gpio_int_id); /* Enable rising edge. */ - LPC_GPIO_PIN_INT->IENF &= ~(1 << gpio_int_id); /* Disable falling edge. */ - break; - case GPIO_FALLING: - LPC_GPIO_PIN_INT->ISEL &= ~(1 << gpio_int_id); /* Set PMODE=edge sensitive */ - LPC_GPIO_PIN_INT->IENR &= ~(1 << gpio_int_id); /* Disable rising edge. */ - LPC_GPIO_PIN_INT->IENF |= (1 << gpio_int_id); /* Enable falling edge. */ - break; - case GPIO_BOTH: - LPC_GPIO_PIN_INT->ISEL &= ~(1 << gpio_int_id); /* Set PMODE=edge sensitive */ - LPC_GPIO_PIN_INT->IENR |= (1 << gpio_int_id); /* Enable rising edge. */ - LPC_GPIO_PIN_INT->IENF |= (1 << gpio_int_id); /* Enable falling edge. */ - break; - } - - /* clear any pending requests */ - LPC_GPIO_PIN_INT->RISE = (1 << gpio_int_id); /* Clear rising edge (sort of) flag */ - LPC_GPIO_PIN_INT->FALL = (1 << gpio_int_id); /* Clear falling edge (sort of) flag */ - - NVIC_SetPriority(gpio_int_id, 3); - - flex_int_mapping[dev] = gpio_int_id+1; - - gpio_int_id++; + LPC_GPIO->DIR[port(pin)] &= ~mask(pin); + LPC_GPIO->DIR[port(pin)] |= ((mode & MODE_DIR_MASK) << num(pin)); + IOCON->PIO[ionum(pin)] = (mode & MODE_IOCON_MASK); return 0; } -void gpio_irq_enable(gpio_t dev) +int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, + gpio_cb_t cb, void *arg) { - if (dev >= GPIO_NUMOF) { - return; + /* make sure we have an interrupt channel available */ + int i = 0; + while ((i < ISR_NUMOF) && (isrmap[i] != GPIO_UNDEF) && (isrmap[i] != pin)) { + i++; } - - NVIC_EnableIRQ(flex_int_mapping[dev]-1); -} - -void gpio_irq_disable(gpio_t dev) -{ - uint8_t int_id; - - if (dev >= GPIO_NUMOF) { - return; - } - - int_id = flex_int_mapping[dev] - 1; - - NVIC_DisableIRQ(int_id); -} - -int gpio_read(gpio_t dev) -{ - uint8_t port; - uint8_t pin; - - if (dev >= GPIO_NUMOF) { + if (i == ISR_NUMOF) { return -1; } - port = gpio_port_map[dev]; - pin = gpio_pin_map[dev]; - - if(LPC_GPIO->PIN[port] & (1 << pin)) /* read output data register */ - return 1; - else - return 0; -} - -void gpio_set(gpio_t dev) -{ - uint8_t port; - uint8_t pin; - - if (dev >= GPIO_NUMOF) { - return; + /* do basic pin configuration */ + if (gpio_init(pin, mode) != 0) { + return -1; } - port = gpio_port_map[dev]; - pin = gpio_pin_map[dev]; + /* enable power for GPIO pin interrupt interface */ + LPC_SYSCON->SYSAHBCLKCTRL |= SYSCTL_PINTMASK; - LPC_GPIO->SET[port] = (1 << pin); -} + /* save ISR context */ + isrctx[i].cb = cb; + isrctx[i].arg = arg; + isrmap[i] = pin; -void gpio_clear(gpio_t dev) -{ - uint8_t port; - uint8_t pin; + /* Register pin as flex interrupt */ + LPC_SYSCON->PINTSEL[i] = ionum(pin); - if (dev >= GPIO_NUMOF) { - return; + /* set active flank configuration */ + LPC_GPIO_PIN_INT->ISEL = 0; + switch (flank) { + case GPIO_RISING: + LPC_GPIO_PIN_INT->IENR |= (1 << i); + LPC_GPIO_PIN_INT->IENF &= ~(1 << i); + break; + case GPIO_FALLING: + LPC_GPIO_PIN_INT->IENR &= ~(1 << i); + LPC_GPIO_PIN_INT->IENF |= (1 << i); + break; + case GPIO_BOTH: + LPC_GPIO_PIN_INT->IENR |= (1 << i); + LPC_GPIO_PIN_INT->IENF |= (1 << i); + default: + return -1; } - port = gpio_port_map[dev]; - pin = gpio_pin_map[dev]; + /* clear any pending requests and enable the pin's interrupt */ + LPC_GPIO_PIN_INT->IST = (1 << i); + NVIC_EnableIRQ(FLEX_INT0_IRQn + i); - LPC_GPIO->CLR[port] = (1 << pin); + return 0; } -void gpio_toggle(gpio_t dev) +void gpio_irq_enable(gpio_t pin) { - if (dev >= GPIO_NUMOF) { - return; + for (int i = 0; i < ISR_NUMOF; i++) { + if (isrmap[i] == pin) { + NVIC_EnableIRQ(FLEX_INT0_IRQn + i); + } } - - LPC_GPIO->NOT[gpio_port_map[dev]] = (1 << gpio_pin_map[dev]); } -void gpio_write(gpio_t dev, int value) +void gpio_irq_disable(gpio_t pin) +{ + for (int i = 0; i < ISR_NUMOF; i++) { + if (isrmap[i] == pin) { + NVIC_DisableIRQ(FLEX_INT0_IRQn + i); + } + } +} + +int gpio_read(gpio_t pin) +{ + return (LPC_GPIO->PIN[port(pin)] & mask(pin)) ? 1 : 0; +} + +void gpio_set(gpio_t pin) +{ + LPC_GPIO->SET[port(pin)] = mask(pin); +} + +void gpio_clear(gpio_t pin) +{ + LPC_GPIO->CLR[port(pin)] = mask(pin); +} + +void gpio_toggle(gpio_t pin) +{ + LPC_GPIO->CLR[port(pin)] = mask(pin); +} + +void gpio_write(gpio_t pin, int value) { if (value) { - gpio_set(dev); + LPC_GPIO->SET[port(pin)] = mask(pin); } else { - gpio_clear(dev); + LPC_GPIO->CLR[port(pin)] = mask(pin); } } static inline void isr_common(uint8_t int_id) { - LPC_GPIO_PIN_INT->IST |= (1 << int_id); /* Clear pending interrupt */ - gpio_config[int_id].cb(gpio_config[int_id].arg); + LPC_GPIO_PIN_INT->IST |= (1 << int_id); + isrctx[int_id].cb(isrctx[int_id].arg); if (sched_context_switch_request) { thread_yield();