From d05151fdef59ff586350ccd0b0f24e06d3709db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Herthel?= <rene.herthel@haw-hamburg.de> Date: Mon, 13 Apr 2015 14:25:42 +0200 Subject: [PATCH] cpu/mega2560: initial import of a gpio driver --- boards/arduino-mega2560/Makefile.features | 1 + boards/arduino-mega2560/include/periph_conf.h | 26 -- cpu/atmega2560/include/periph_cpu.h | 27 +- cpu/atmega2560/periph/Makefile | 1 + cpu/atmega2560/periph/gpio.c | 259 ++++++++++++++++++ 5 files changed, 285 insertions(+), 29 deletions(-) create mode 100644 cpu/atmega2560/periph/gpio.c diff --git a/boards/arduino-mega2560/Makefile.features b/boards/arduino-mega2560/Makefile.features index 675243084d..098dfa3e53 100644 --- a/boards/arduino-mega2560/Makefile.features +++ b/boards/arduino-mega2560/Makefile.features @@ -1,2 +1,3 @@ FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_gpio FEATURES_MCU_GROUP = avr8 diff --git a/boards/arduino-mega2560/include/periph_conf.h b/boards/arduino-mega2560/include/periph_conf.h index 22549013bc..19f1d3dc1f 100644 --- a/boards/arduino-mega2560/include/periph_conf.h +++ b/boards/arduino-mega2560/include/periph_conf.h @@ -227,12 +227,6 @@ extern "C" { #define UART3_RECEIVED_DATA (UART3_CTRL_STAT_A & (1 << UART3_RX_COMPLETE)) #define UART3_DTREG_EMPTY (UART3_CTRL_STAT_A & (1 << UART3_DATA_EMPTY)) - - -/* TODO: add defines for device agnostic implementation */ -/** @} */ - - /** * @brief ADC configuration */ @@ -261,26 +255,6 @@ extern "C" { #define I2C_0_EN 0 #define I2C_0_EN 0 -/** - * @brief GPIO configuration - */ -#define GPIO_0_EN 0 -#define GPIO_1_EN 0 -#define GPIO_2_EN 0 -#define GPIO_3_EN 0 -#define GPIO_4_EN 0 -#define GPIO_5_EN 0 -#define GPIO_6_EN 0 -#define GPIO_7_EN 0 -#define GPIO_8_EN 0 -#define GPIO_9_EN 0 -#define GPIO_10_EN 0 -#define GPIO_11_EN 0 -#define GPIO_12_EN 0 -#define GPIO_13_EN 0 -#define GPIO_14_EN 0 -#define GPIO_15_EN 0 - #ifdef __cplusplus } #endif diff --git a/cpu/atmega2560/include/periph_cpu.h b/cpu/atmega2560/include/periph_cpu.h index f4b1548294..7d38894e90 100644 --- a/cpu/atmega2560/include/periph_cpu.h +++ b/cpu/atmega2560/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Freie Universität Berlin + * Copyright (C) 2015 HAW Hamburg * * 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 @@ -13,19 +13,40 @@ * @file * @brief CPU specific definitions for internal peripheral handling * - * @author Hauke Petersen <hauke.peterse@fu-berlin.de> + * @author René Herthel <rene-herthel@outlook.de> */ #ifndef PERIPH_CPU_H_ #define PERIPH_CPU_H_ #include "periph/dev_enums.h" +#include <avr/io.h> #ifdef __cplusplus extern "C" { #endif -/* nothing defined here so far... */ +/** + * @brief Define a CPU specific GPIO pin generator macro + */ +#define GPIO(x, y) ((x << 4) | y) + +/** + * @brief Available ports on the ATmega2560 family + */ +enum { + PORT_A = 0, /**< port A */ + PORT_B = 1, /**< port B */ + PORT_C = 2, /**< port C */ + PORT_D = 3, /**< port D */ + PORT_E = 4, /**< port E */ + PORT_F = 5, /**< port F */ + PORT_G = 6, /**< port G */ + PORT_H = 7, /**< port H */ + PORT_J = 8, /**< port J */ + PORT_K = 9, /**< port K */ + PORT_L = 10 /**< port L */ +}; #ifdef __cplusplus } diff --git a/cpu/atmega2560/periph/Makefile b/cpu/atmega2560/periph/Makefile index 87a55ed684..6d1887b640 100644 --- a/cpu/atmega2560/periph/Makefile +++ b/cpu/atmega2560/periph/Makefile @@ -1,2 +1,3 @@ MODULE = periph + include $(RIOTBASE)/Makefile.base diff --git a/cpu/atmega2560/periph/gpio.c b/cpu/atmega2560/periph/gpio.c new file mode 100644 index 0000000000..275e1dc7eb --- /dev/null +++ b/cpu/atmega2560/periph/gpio.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2015 HAW Hamburg + + * + * 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 driver_periph + * @{ + * + * @file + * @brief Low-level GPIO driver implementation for ATmega2560 + * + * @author René Herthel <rene-herthel@outlook.de> + * + * @} + */ + + +#include <stdio.h> + +#include <avr/interrupt.h> + +#include "cpu.h" +#include "periph/gpio.h" +#include "periph_conf.h" + +#define GPIO_BASE_PORT_A (0x20) +#define GPIO_OFFSET_PORT_H (0xCB) +#define GPIO_OFFSET_PIN_PORT (0x02) +#define GPIO_OFFSET_PIN_PIN (0x03) +#define GPIO_EXT_INT_NUMOF (7U) + +typedef struct { + gpio_cb_t cb; + void *arg; +} gpio_state_t; + +static gpio_state_t config[GPIO_EXT_INT_NUMOF]; + +/** + * @brief Extract the pin number of the given pin + */ +static inline uint8_t _pin_num(gpio_t pin) +{ + return (pin & 0x0f); +} + +/** + * @brief Extract the port number of the given pin + */ +static inline uint8_t _port_num(gpio_t pin) +{ + return (pin >> 4) & 0x0f; +} + +/** + * @brief Generate the PORTx address of the give pin. + */ +static inline uint16_t _port_addr(gpio_t pin) +{ + uint8_t port_num = _port_num(pin); + uint16_t port_addr = port_num * GPIO_OFFSET_PIN_PIN; + + port_addr += GPIO_BASE_PORT_A; + port_addr += GPIO_OFFSET_PIN_PORT; + + if (port_num > PORT_G) { + port_addr += GPIO_OFFSET_PORT_H; + } + + return port_addr; +} + +/** + * @brief Generate the DDRx address of the given pin + */ +static inline uint8_t _ddr_addr(gpio_t pin) +{ + return (_port_addr(pin) - 0x01); +} + +/** + * @brief Generate the PINx address of the given pin. + */ +static inline uint8_t _pin_addr(gpio_t pin) +{ + return (_port_addr(pin) - 0x02); +} + +int gpio_init(gpio_t pin, gpio_dir_t dir, gpio_pp_t pullup) +{ + int res; + + if (dir == GPIO_DIR_OUT) { + _SFR_MEM8(_ddr_addr(pin)) |= (1 << _pin_num(pin)); + res = bit_is_set(_SFR_MEM8(_ddr_addr(pin)), _pin_num(pin)); + } + else { + _SFR_MEM8(_ddr_addr(pin)) &= ~(1 << _pin_num(pin)); + res = bit_is_clear(_SFR_MEM8(_ddr_addr(pin)), _pin_num(pin)); + } + + return (res == 0) ? -1 : 0; +} + +int gpio_init_int(gpio_t pin, gpio_pp_t pullup, gpio_flank_t flank, + gpio_cb_t cb, void *arg) +{ + uint8_t pin_num = _pin_num(pin); + + if ((_port_num(pin) == PORT_D && pin_num > 3) + || (_port_num(pin) == PORT_E && pin_num < 4)) { + return -1; + } + + if (gpio_init(pin, GPIO_DIR_IN, pullup) < 0) { + return -1; + } + + gpio_set(pin); + + /* clear global interrupt flag */ + cli(); + + EIMSK |= (1 << pin_num); + + /* configure the flank */ + switch (flank) { + case GPIO_RISING: + if (pin_num < 4) { + EICRA |= (3 << pin_num * 2); + } + else { + EICRB |= (3 << (pin_num * 2) % 4); + } + break; + case GPIO_FALLING: + if (pin_num < 4) { + EICRA |= (2 << pin_num * 2); + } + else { + EICRB |= (2 << (pin_num * 2) % 4); + } + break; + case GPIO_BOTH: + if (pin_num < 4) { + EICRA |= (1 << pin_num * 2); + } + else { + EICRB |= (1 << (pin_num * 2) % 4); + } + break; + default: + return -1; + }; + + /* set callback */ + config[pin_num].cb = cb; + config[pin_num].arg = arg; + + /* set global interrupt flag */ + sei(); + + return 0; +} + +void gpio_irq_enable(gpio_t pin) +{ + EIMSK |= (1 << _pin_num(pin)); +} + +void gpio_irq_disable(gpio_t pin) +{ + EIMSK &= ~(1 << _pin_num(pin)); +} + +int gpio_read(gpio_t pin) +{ + return (_SFR_MEM8(_pin_addr(pin)) & (1 << _pin_num(pin))); +} + +void gpio_set(gpio_t pin) +{ + _SFR_MEM8(_port_addr(pin)) |= (1 << _pin_num(pin)); +} + +void gpio_clear(gpio_t pin) +{ + _SFR_MEM8(_port_addr(pin)) &= ~(1 << _pin_num(pin)); +} + +void gpio_toggle(gpio_t pin) +{ + if (gpio_read(pin)) { + gpio_clear(pin); + } + else { + gpio_set(pin); + } +} + +void gpio_write(gpio_t pin, int value) +{ + if (value) { + gpio_set(pin); + } + else { + gpio_clear(pin); + } +} + +static inline void irq_handler(uint8_t pin_num) +{ + config[pin_num].cb(config[pin_num].arg); +} + +ISR(INT0_vect, ISR_BLOCK) +{ + irq_handler(0); /**< predefined interrupt pin */ +} + +ISR(INT1_vect, ISR_BLOCK) +{ + irq_handler(1); /**< predefined interrupt pin */ +} + +ISR(INT2_vect, ISR_BLOCK) +{ + irq_handler(2); /**< predefined interrupt pin */ +} + +ISR(INT3_vect, ISR_BLOCK) +{ + irq_handler(3); /**< predefined interrupt pin */ +} + +ISR(INT4_vect, ISR_BLOCK) +{ + irq_handler(4); /**< predefined interrupt pin */ +} + +ISR(INT5_vect, ISR_BLOCK) +{ + irq_handler(5); /**< predefined interrupt pin */ +} + +ISR(INT6_vect, ISR_BLOCK) +{ + irq_handler(6); /**< predefined interrupt pin */ +} + +ISR(INT7_vect, ISR_BLOCK) +{ + irq_handler(7); /**< predefined interrupt pin */ +} -- GitLab