1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-24 14:03:55 +01:00

Merge pull request #6472 from basilfx/feature/lpc1768_gpio

cpu/lpc1768: add gpio peripheral (+ board adaptions)
This commit is contained in:
Bas Stottelaar 2018-04-03 17:06:47 +02:00 committed by GitHub
commit 77ad70ebb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 476 additions and 90 deletions

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif

View File

@ -1,4 +1,5 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

View File

@ -14,15 +14,33 @@
* @brief Board specific implementations for the mbed LPC1768 board
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Bas Stottelaar <basstottelaar@gmail.com>
*
* @}
*/
#include "board.h"
static void leds_init(void);
#include "periph/gpio.h"
extern void SystemInit(void);
/**
* @brief Initialize the on-board LEDs.
*/
static void leds_init(void)
{
gpio_init(LED0_PIN, GPIO_OUT);
gpio_init(LED1_PIN, GPIO_OUT);
gpio_init(LED2_PIN, GPIO_OUT);
gpio_init(LED3_PIN, GPIO_OUT);
LED0_OFF;
LED1_OFF;
LED2_OFF;
LED3_OFF;
}
void board_init(void)
{
/* initialize core clocks via CMSIS function */
@ -32,24 +50,3 @@ void board_init(void)
/* initialize the boards LEDs */
leds_init();
}
/**
* @brief Initialize the boards on-board LEDs (LED1 to LED4)
*
* The LED initialization is hard-coded in this function. As the LEDs are soldered
* onto the board they are fixed to their CPU pins.
*
* The LEDs are connected to the following pins:
* - LED1: P1.18
* - LED2: P1.20
* - LED3: P1.21
* - LED4: P1.23
*/
static void leds_init(void)
{
/* configure LED pins as output */
LED_PORT->FIODIR |= (LED0_MASK | LED1_MASK | LED2_MASK | LED3_MASK);
/* clear all LEDs */
LED_PORT->FIOCLR = (LED0_MASK | LED1_MASK | LED2_MASK | LED3_MASK);
}

View File

@ -23,10 +23,9 @@
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#include "bitarithm.h"
#include "cpu.h"
#include "periph_conf.h"
#include "periph/gpio.h"
#ifdef __cplusplus
extern "C" {
@ -41,24 +40,18 @@ extern "C" {
#define LED2_PIN GPIO_PIN(1, 21)
#define LED3_PIN GPIO_PIN(1, 23)
#define LED_PORT (LPC_GPIO1)
#define LED0_MASK (BIT18)
#define LED1_MASK (BIT20)
#define LED2_MASK (BIT21)
#define LED3_MASK (BIT23)
#define LED0_ON (LED_PORT->FIOSET = LED0_MASK)
#define LED0_OFF (LED_PORT->FIOCLR = LED0_MASK)
#define LED0_TOGGLE (LED_PORT->FIOPIN ^= LED0_MASK)
#define LED1_ON (LED_PORT->FIOSET = LED1_MASK)
#define LED1_OFF (LED_PORT->FIOCLR = LED1_MASK)
#define LED1_TOGGLE (LED_PORT->FIOPIN ^= LED1_MASK)
#define LED2_ON (LED_PORT->FIOSET = LED2_MASK)
#define LED2_OFF (LED_PORT->FIOCLR = LED2_MASK)
#define LED2_TOGGLE (LED_PORT->FIOPIN ^= LED2_MASK)
#define LED3_ON (LED_PORT->FIOSET = LED3_MASK)
#define LED3_OFF (LED_PORT->FIOCLR = LED3_MASK)
#define LED3_TOGGLE (LED_PORT->FIOPIN ^= LED3_MASK)
#define LED0_ON gpio_set(LED0_PIN)
#define LED0_OFF gpio_clear(LED0_PIN)
#define LED0_TOGGLE gpio_toggle(LED0_PIN)
#define LED1_ON gpio_set(LED1_PIN)
#define LED1_OFF gpio_clear(LED1_PIN)
#define LED1_TOGGLE gpio_toggle(LED1_PIN)
#define LED2_ON gpio_set(LED2_PIN)
#define LED2_OFF gpio_clear(LED2_PIN)
#define LED2_TOGGLE gpio_toggle(LED2_PIN)
#define LED3_ON gpio_set(LED3_PIN)
#define LED3_OFF gpio_clear(LED3_PIN)
#define LED3_TOGGLE gpio_toggle(LED3_PIN)
/** @} */
/**

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2017 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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 boards_mbed_lpc1768
* @{
*
* @file
* @brief Board specific configuration of direct mapped GPIOs
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief GPIO pin configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "LED 0",
.pin = LED0_PIN,
.mode = GPIO_OUT
},
{
.name = "LED 1",
.pin = LED1_PIN,
.mode = GPIO_OUT
},
{
.name = "LED 2",
.pin = LED2_PIN,
.mode = GPIO_OUT
},
{
.name = "LED 3",
.pin = LED3_PIN,
.mode = GPIO_OUT
}
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif

View File

@ -1,4 +1,5 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

View File

@ -21,9 +21,26 @@
#include "board.h"
static void leds_init(void);
#include "periph/gpio.h"
extern void SystemInit(void);
/**
* @brief Initialize the on-board LEDs.
*/
static void leds_init(void)
{
gpio_init(LED0_PIN, GPIO_OUT);
gpio_init(LED1_PIN, GPIO_OUT);
gpio_init(LED2_PIN, GPIO_OUT);
gpio_init(LED3_PIN, GPIO_OUT);
LED0_OFF;
LED1_OFF;
LED2_OFF;
LED3_OFF;
}
void board_init(void)
{
/* initialize core clocks via CMSIS function */
@ -33,26 +50,3 @@ void board_init(void)
/* initialize the boards LEDs */
leds_init();
}
/**
* @brief Initialize the boards on-board LEDs (LED1 to LED4)
*
* The LED initialization is hard-coded in this function. As the LEDs are
* soldered onto the board they are fixed to their CPU pins.
*
* The LEDs are connected to the following pins:
* - LED1: P1.18
* - LED2: P1.20
* - LED3: P1.21
* - LED4: P1.23
*
* The LEDs are active-low (current-sink).
*/
static void leds_init(void)
{
/* configure LED pins as output */
LED_PORT->FIODIR |= (LED0_MASK | LED1_MASK | LED2_MASK | LED3_MASK);
/* turn off all LEDs */
LED_PORT->FIOSET = (LED0_MASK | LED1_MASK | LED2_MASK | LED3_MASK);
}

View File

@ -24,10 +24,9 @@
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#include "bitarithm.h"
#include "cpu.h"
#include "periph_conf.h"
#include "periph/gpio.h"
#ifdef __cplusplus
extern "C" {
@ -42,24 +41,18 @@ extern "C" {
#define LED2_PIN GPIO_PIN(1, 21)
#define LED3_PIN GPIO_PIN(1, 23)
#define LED_PORT (LPC_GPIO1)
#define LED0_MASK (BIT18)
#define LED1_MASK (BIT20)
#define LED2_MASK (BIT21)
#define LED3_MASK (BIT23)
#define LED0_ON (LED_PORT->FIOCLR = LED0_MASK)
#define LED0_OFF (LED_PORT->FIOSET = LED0_MASK)
#define LED0_TOGGLE (LED_PORT->FIOPIN ^= LED0_MASK)
#define LED1_ON (LED_PORT->FIOCLR = LED1_MASK)
#define LED1_OFF (LED_PORT->FIOSET = LED1_MASK)
#define LED1_TOGGLE (LED_PORT->FIOPIN ^= LED1_MASK)
#define LED2_ON (LED_PORT->FIOCLR = LED2_MASK)
#define LED2_OFF (LED_PORT->FIOSET = LED2_MASK)
#define LED2_TOGGLE (LED_PORT->FIOPIN ^= LED2_MASK)
#define LED3_ON (LED_PORT->FIOCLR = LED3_MASK)
#define LED3_OFF (LED_PORT->FIOSET = LED3_MASK)
#define LED3_TOGGLE (LED_PORT->FIOPIN ^= LED3_MASK)
#define LED0_ON gpio_clear(LED0_PIN)
#define LED0_OFF gpio_set(LED0_PIN)
#define LED0_TOGGLE gpio_toggle(LED0_PIN)
#define LED1_ON gpio_clear(LED1_PIN)
#define LED1_OFF gpio_set(LED1_PIN)
#define LED1_TOGGLE gpio_toggle(LED1_PIN)
#define LED2_ON gpio_clear(LED2_PIN)
#define LED2_OFF gpio_set(LED2_PIN)
#define LED2_TOGGLE gpio_toggle(LED2_PIN)
#define LED3_ON gpio_clear(LED3_PIN)
#define LED3_OFF gpio_set(LED3_PIN)
#define LED3_TOGGLE gpio_toggle(LED3_PIN)
/** @} */
/**

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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 boards_seeduino_arch-pro
* @{
*
* @file
* @brief Board specific configuration of direct mapped GPIOs
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief GPIO pin configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "LED 0",
.pin = LED0_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INVERTED
},
{
.name = "LED 1",
.pin = LED1_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INVERTED
},
{
.name = "LED 2",
.pin = LED2_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INVERTED
},
{
.name = "LED 3",
.pin = LED3_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INVERTED
}
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -14,19 +14,54 @@
* @brief CPU specific definitions for internal peripheral handling
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Bas Stottelaar <basstottelaar@gmail.com>
*/
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include <stdint.h>
#include "cpu.h"
#include "periph/dev_enums.h"
#ifdef __cplusplus
extern "C" {
#endif
/* nothing to do here, yet */
/**
* @name Override the default GPIO type
* @{
*/
#define HAVE_GPIO_T
typedef uint8_t gpio_t;
/** @} */
/**
* @brief Define a custom GPIO_PIN macro for the lpc1768
*/
#define GPIO_PIN(port, pin) (gpio_t)((port << 5) | pin)
/**
* @name Override the default GPIO mode values
* @{
*/
#define PIN_DIR_IN (0x00 << 0)
#define PIN_DIR_OUT (0x01 << 0)
#define PIN_MODE_PU (0x00 << 1)
#define PIN_MODE_PD (0x02 << 1)
#define PIN_MODE_NONE (0x03 << 1)
#define PIN_MODE_OD (0x01 << 3)
#define HAVE_GPIO_MODE_T
typedef enum {
GPIO_IN = (PIN_DIR_IN | PIN_MODE_NONE), /**< in without pull-up/down */
GPIO_IN_PD = (PIN_DIR_IN | PIN_MODE_PD), /**< in with pull-down */
GPIO_IN_PU = (PIN_DIR_IN | PIN_MODE_PU), /**< in with pull-up */
GPIO_OUT = (PIN_DIR_OUT | PIN_MODE_NONE), /**< push-pull output */
GPIO_OD = (PIN_DIR_OUT | PIN_MODE_OD), /**< open-drain output */
GPIO_OD_PU = (PIN_DIR_OUT | PIN_MODE_OD | PIN_MODE_PU) /**< open-drain output with pull-up */
} gpio_mode_t;
/** @} */
#ifdef __cplusplus
}

240
cpu/lpc1768/periph/gpio.c Normal file
View File

@ -0,0 +1,240 @@
/*
* Copyright (C) 2017 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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_lpc1768
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
*
* @}
*/
#include "cpu.h"
#include "periph/gpio.h"
/**
* @brief Number of external interrupt lines.
*/
#define NUMOF_IRQS (32)
/**
* @brief Hold one interrupt context per interrupt line
*/
static gpio_isr_ctx_t isr_ctx[NUMOF_IRQS];
static gpio_flank_t isr_state[2][32];
#define PIN_MASK (0x1f)
#define PORT_SHIFT (5U)
static inline int _pin(gpio_t pin)
{
return (pin & PIN_MASK);
}
static inline int _port(gpio_t pin)
{
return (pin >> PORT_SHIFT);
}
static inline LPC_GPIO_TypeDef *_base(gpio_t pin)
{
return (LPC_GPIO_TypeDef *) (LPC_GPIO_BASE + (_port(pin) * 0x20));
}
static inline void _configure_flank(gpio_t pin, gpio_flank_t flank)
{
switch (flank) {
case GPIO_RISING:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR |= (1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR |= (1 << _pin(pin));
}
break;
case GPIO_FALLING:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF |= (1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR &= ~(1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF |= (1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR &= ~(1 << _pin(pin));
}
break;
case GPIO_BOTH:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF |= 1 << _pin(pin);
LPC_GPIOINT->IO0IntEnR |= 1 << _pin(pin);
}
else {
LPC_GPIOINT->IO2IntEnF |= 1 << _pin(pin);
LPC_GPIOINT->IO2IntEnR |= 1 << _pin(pin);
}
break;
}
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
/* check for valid pin */
if (pin == GPIO_UNDEF) {
return -1;
}
if (_port(pin) > 4 || _pin(pin) > 32) {
return -1;
}
/* enable gpio peripheral */
LPC_SC->PCONP |= (1 << 15);
/* pin as output or input */
LPC_GPIO_TypeDef *base = _base(pin);
base->FIODIR &= ~(1 << _pin(pin));
base->FIODIR |= ((mode & 0x01) << _pin(pin));
/* configure pin function */
int reg = 2 * _port(pin) + (_pin(pin) / 16);
int bit = (pin % 16) * 2;
((uint32_t *) &LPC_PINCON->PINSEL0)[reg] &= ~(0x03 << bit);
/* configure pull up/down */
((uint32_t *) &LPC_PINCON->PINMODE0)[reg] &= ~(0x03 << bit);
((uint32_t *) &LPC_PINCON->PINMODE0)[reg] |= (((mode >> 1) & 0x03) << bit);
/* configure open drain */
((uint32_t *) &LPC_PINCON->PINMODE_OD0)[_port(pin)] &= ~(1 << _pin(pin));
((uint32_t *) &LPC_PINCON->PINMODE_OD0)[_port(pin)] |= (((mode >> 3) & 0x01) << _pin(pin));
return 0;
}
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
/* only certain pins can be used as interrupt pins */
if (_port(pin) != 0 && _port(pin) != 2) {
return -1;
}
/* initialize the pin */
int result = gpio_init(pin, mode);
if (result != 0) {
return result;
}
/* store interrupt callback */
isr_ctx[_pin(pin)].cb = cb;
isr_ctx[_pin(pin)].arg = arg;
/* need to store flank configuration for (re)enable irq */
isr_state[_port(pin) >> 1][_pin(pin)] = flank;
/* set flank configuration */
_configure_flank(pin, flank);
/* clear any pending requests and enable the interrupt */
NVIC_ClearPendingIRQ(EINT3_IRQn);
NVIC_EnableIRQ(EINT3_IRQn);
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
assert(_port(pin) == 0 || _port(pin) == 2);
_configure_flank(pin, isr_state[_port(pin) >> 1][_pin(pin)]);
}
void gpio_irq_disable(gpio_t pin)
{
assert(_port(pin) == 0 || _port(pin) == 2);
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR &= ~(1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR &= ~(1 << _pin(pin));
}
}
int gpio_read(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
return (base->FIOPIN & (1 << _pin(pin))) ? 1 : 0;
}
void gpio_set(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOSET = (1 << _pin(pin));
}
void gpio_clear(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOCLR = (1 << _pin(pin));
}
void gpio_toggle(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOPIN ^= (1 << _pin(pin));
}
void gpio_write(gpio_t pin, int value)
{
LPC_GPIO_TypeDef *base = _base(pin);
if (value) {
base->FIOSET = (1 << _pin(pin));
}
else {
base->FIOCLR = (1 << _pin(pin));
}
}
void isr_eint3(void)
{
/* combine all interrupts */
uint32_t status = LPC_GPIOINT->IO0IntStatF | LPC_GPIOINT->IO0IntStatR |
LPC_GPIOINT->IO2IntStatF | LPC_GPIOINT->IO2IntStatR;
/* invoke all handlers */
for (int i = 0; i < NUMOF_IRQS; i++) {
if (status & (1 << i)) {
isr_ctx[i].cb(isr_ctx[i].arg);
LPC_GPIOINT->IO0IntClr |= (1 << i);
LPC_GPIOINT->IO2IntClr |= (1 << i);
}
}
cortexm_isr_end();
}