From 37281c8c5e21aa1bf7a90dddeb79487059cbb20f Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Fri, 31 Mar 2017 09:41:27 +0100 Subject: [PATCH] cpu: pic32_common: Implement simple GPIO driver Signed-off-by: Francois Berder --- .../include/periph_cpu_common.h | 48 ++++ cpu/mips_pic32_common/periph/gpio.c | 212 ++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 cpu/mips_pic32_common/include/periph_cpu_common.h create mode 100644 cpu/mips_pic32_common/periph/gpio.c diff --git a/cpu/mips_pic32_common/include/periph_cpu_common.h b/cpu/mips_pic32_common/include/periph_cpu_common.h new file mode 100644 index 0000000000..2f838c8aec --- /dev/null +++ b/cpu/mips_pic32_common/include/periph_cpu_common.h @@ -0,0 +1,48 @@ +/* + * Copyright(C) 2017, Imagination Technologies Limited and/or its + * affiliated group companies. + * + * 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_mips_pic32_common + * @{ + * + * @file + * @brief CPU specific definitions for internal peripheral handling + * + * @author Francois Berder + */ + +#ifndef PERIPH_CPU_COMMON_H +#define PERIPH_CPU_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define GPIO_PIN(x,y) ((x << 4) | (y & 0xf)) + +/** + * @brief Available ports on the PIC32 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 */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CPU_COMMON_H */ +/** @} */ diff --git a/cpu/mips_pic32_common/periph/gpio.c b/cpu/mips_pic32_common/periph/gpio.c new file mode 100644 index 0000000000..210b83179f --- /dev/null +++ b/cpu/mips_pic32_common/periph/gpio.c @@ -0,0 +1,212 @@ +/* + * Copyright(C) 2017 Imagination Technologies Limited and/or its + * affiliated group companies. + * + * 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. + * + */ + +#include +#include +#include "periph/gpio.h" +#include "board.h" + +#define GPIO_PIN_NO(PIN) (1 << ((PIN) & 0xf)) +#define GPIO_PORT(PIN) ((PIN) >> 4) + +#define LATx(P) (base_address[P].gpio[0x10/0x4]) +#define LATxCLR(P) (base_address[P].gpio[0x14/0x4]) +#define LATxSET(P) (base_address[P].gpio[0x18/0x4]) +#define LATxINV(P) (base_address[P].gpio[0x1C/0x4]) +#define PORTx(P) (base_address[P].gpio[0x0]) +#define CNPUxCLR(P) (base_address[P].gpio[0x34/0x4]) +#define CNPUxSET(P) (base_address[P].gpio[0x38/0x4]) +#define CNPDxCLR(P) (base_address[P].gpio[0x44/0x4]) +#define CNPDxSET(P) (base_address[P].gpio[0x48/0x4]) +#define ODCxCLR(P) (base_address[P].gpio[0x24/0x4]) +#define ODCxSET(P) (base_address[P].gpio[0x28/0x4]) +#define ANSELxCLR(P) (base_address[P].ansel[0x04/0x4]) +#define TRISxCLR(P) (base_address[P].tris[0x04/0x4]) +#define TRISxSET(P) (base_address[P].tris[0x08/0x4]) + +typedef struct PIC32_GPIO_tag { + volatile uint32_t* gpio; + volatile uint32_t* ansel; + volatile uint32_t* tris; +} PIC32_GPIO_T; + +static PIC32_GPIO_T base_address[] = { +#ifdef _PORTA_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTA_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELA, + .tris = (volatile uint32_t*)&TRISA + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTB_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTB_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELB, + .tris = (volatile uint32_t*)&TRISB + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTC_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTC_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELC, + .tris = (volatile uint32_t*)&TRISC + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTD_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTD_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELD, + .tris = (volatile uint32_t*)&TRISD + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTE_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTE_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELE, + .tris = (volatile uint32_t*)&TRISE + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTF_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTF_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELF, + .tris = (volatile uint32_t*)&TRISF + }, +#else + {0 , 0, 0}, +#endif +#ifdef _PORTG_BASE_ADDRESS + { + .gpio = (volatile uint32_t*)_PORTG_BASE_ADDRESS, + .ansel = (volatile uint32_t*)&ANSELG, + .tris = (volatile uint32_t*)&TRISG + }, +#else + {0 , 0, 0}, +#endif +}; + +static inline int check_valid_port(uint8_t port) +{ + return port < (sizeof(base_address)/sizeof(base_address[0])) + && base_address[port].gpio != 0; +} + +int gpio_init(gpio_t pin, gpio_mode_t mode) +{ + uint8_t port = GPIO_PORT(pin); + uint32_t pin_no = GPIO_PIN_NO(pin); + uint8_t output = 0, pu = 0, pd = 0, od = 0; + + assert(check_valid_port(port)); + + switch (mode) { + case GPIO_IN: + break; + case GPIO_IN_PD: + pd = 1; + break; + case GPIO_IN_PU: + pu = 1; + break; + + case GPIO_OD_PU: + pu = 1; + case GPIO_OD: + od = 1; + case GPIO_OUT: + output = 1; + break; + } + + ANSELxCLR(port) = pin_no; /* Configure GPIO as digital */ + + if (pu) + CNPUxSET(port) = pin_no; + else + CNPUxCLR(port) = pin_no; + + if (pd) + CNPDxSET(port) = pin_no; + else + CNPDxCLR(port) = pin_no; + + if (od) + ODCxSET(port) = pin_no; + else + ODCxCLR(port) = pin_no; + + if (output) + TRISxCLR(port) = pin_no; + else + TRISxSET(port) = pin_no; + + return 0; +} + +int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, + gpio_cb_t cb, void *arg) +{ + (void)pin; + (void)mode; + (void)flank; + (void)cb; + (void)arg; + + /* TODO: Not implemented yet */ + + return -1; +} + +int gpio_read(gpio_t pin) +{ + assert(check_valid_port(GPIO_PORT(pin))); + + return PORTx(GPIO_PORT(pin)) & GPIO_PIN_NO(pin); +} + +void gpio_set(gpio_t pin) +{ + assert(check_valid_port(GPIO_PORT(pin))); + + LATxSET(GPIO_PORT(pin)) = GPIO_PIN_NO(pin); +} + +void gpio_clear(gpio_t pin) +{ + assert(check_valid_port(GPIO_PORT(pin))); + + LATxCLR(GPIO_PORT(pin)) = GPIO_PIN_NO(pin); +} + +void gpio_toggle(gpio_t pin) +{ + assert(check_valid_port(GPIO_PORT(pin))); + + LATxINV(GPIO_PORT(pin)) = GPIO_PIN_NO(pin); +} + +void gpio_write(gpio_t pin, int value) +{ + if (value) + gpio_set(pin); + else + gpio_clear(pin); +}