/* * 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 * @ingroup drivers_periph_gpio * @{ * * @file * @brief Low-level GPIO driver implementation * * @} */ #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 != NULL; } 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); }