Repository: incubator-mynewt-core Updated Branches: refs/heads/master 5ae5f3df5 -> debf64f45
hw: mcu: pic32mz2048efg100: Implement hal_gpio driver Signed-off-by: Francois Berder <fber...@outlook.fr> Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/32427b41 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/32427b41 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/32427b41 Branch: refs/heads/master Commit: 32427b4128abf57836b98a73800a14c48ea22793 Parents: 5ae5f3d Author: Francois Berder <fber...@outlook.fr> Authored: Sun May 7 19:08:53 2017 +0200 Committer: Francois Berder <fber...@outlook.fr> Committed: Sun May 7 20:07:28 2017 +0200 ---------------------------------------------------------------------- .../pic32mz2048efg100/include/mcu/mcu.h | 16 + .../microchip/pic32mz2048efg100/src/hal_gpio.c | 485 +++++++++++++++++++ 2 files changed, 501 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/32427b41/hw/mcu/microchip/pic32mz2048efg100/include/mcu/mcu.h ---------------------------------------------------------------------- diff --git a/hw/mcu/microchip/pic32mz2048efg100/include/mcu/mcu.h b/hw/mcu/microchip/pic32mz2048efg100/include/mcu/mcu.h index 2be36a9..186bfee 100644 --- a/hw/mcu/microchip/pic32mz2048efg100/include/mcu/mcu.h +++ b/hw/mcu/microchip/pic32mz2048efg100/include/mcu/mcu.h @@ -22,4 +22,20 @@ #include "p32mz2048efg100.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define MCU_GPIO_PORTA(pin) ((0 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTB(pin) ((1 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTC(pin) ((2 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTD(pin) ((3 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTE(pin) ((4 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTF(pin) ((5 * 16) + (pin & 0xF)) +#define MCU_GPIO_PORTG(pin) ((6 * 16) + (pin & 0xF)) + +#ifdef __cplusplus +} +#endif + #endif /* __MCU_MCU_H_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/32427b41/hw/mcu/microchip/pic32mz2048efg100/src/hal_gpio.c ---------------------------------------------------------------------- diff --git a/hw/mcu/microchip/pic32mz2048efg100/src/hal_gpio.c b/hw/mcu/microchip/pic32mz2048efg100/src/hal_gpio.c new file mode 100644 index 0000000..1c98a7a --- /dev/null +++ b/hw/mcu/microchip/pic32mz2048efg100/src/hal_gpio.c @@ -0,0 +1,485 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/os.h> +#include <hal/hal_gpio.h> +#include <mcu/mips_hal.h> +#include <mcu/p32mz2048efg100.h> + +#define GPIO_INDEX(pin) ((pin) & 0x0F) +#define GPIO_PORT(pin) (((pin) >> 4) & 0x0F) +#define GPIO_MASK(pin) (1 << GPIO_INDEX(pin)) + +#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 CNCONxSET(P) (base_address[P].gpio[0x58 / 0x4]) +#define CNENxCLR(P) (base_address[P].gpio[0x64 / 0x4]) +#define CNENxSET(P) (base_address[P].gpio[0x68 / 0x4]) +#define CNNExCLR(P) (base_address[P].gpio[0x84 / 0x4]) +#define CNNExSET(P) (base_address[P].gpio[0x88 / 0x4]) +#define CNFx(P) (base_address[P].gpio[0x90 / 0x4]) +#define CNFxCLR(P) (base_address[P].gpio[0x94 / 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]) + +struct hal_gpio_irq_t { + int pin; + hal_gpio_irq_trig_t trig; + hal_gpio_irq_handler_t handler; + void *arg; +}; + +#define HAL_GPIO_MAX_IRQ (8) +static struct hal_gpio_irq_t hal_gpio_irqs[HAL_GPIO_MAX_IRQ]; + +struct pic32_gpio_t { + volatile uint32_t * gpio; + volatile uint32_t * ansel; + volatile uint32_t * tris; +}; + +static struct pic32_gpio_t base_address[] = { + { + .gpio = (volatile uint32_t *)_PORTA_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELA, + .tris = (volatile uint32_t *)&TRISA + }, + { + .gpio = (volatile uint32_t *)_PORTB_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELB, + .tris = (volatile uint32_t *)&TRISB + }, + { + .gpio = (volatile uint32_t *)_PORTC_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELC, + .tris = (volatile uint32_t *)&TRISC + }, + { + .gpio = (volatile uint32_t *)_PORTD_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELD, + .tris = (volatile uint32_t *)&TRISD + }, + { + .gpio = (volatile uint32_t *)_PORTE_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELE, + .tris = (volatile uint32_t *)&TRISE + }, + { + .gpio = (volatile uint32_t *)_PORTF_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELF, + .tris = (volatile uint32_t *)&TRISF + }, + { + .gpio = (volatile uint32_t *)_PORTG_BASE_ADDRESS, + .ansel = (volatile uint32_t *)&ANSELG, + .tris = (volatile uint32_t *)&TRISG + } +}; + +static uint8_t +hal_gpio_find_pin(int pin) +{ + uint8_t index = 0; + + while (index < HAL_GPIO_MAX_IRQ) { + if (hal_gpio_irqs[index].pin == pin) { + break; + } + + ++index; + } + + return index; +} + +static uint8_t +hal_gpio_find_empty_slot(void) +{ + uint8_t index = 0; + + while (index < HAL_GPIO_MAX_IRQ) { + if (hal_gpio_irqs[index].handler == NULL) { + break; + } + + ++index; + } + + return index; +} + +static void +hal_gpio_handle_isr(uint32_t port) +{ + uint8_t index = 0; + static unsigned int i = 0; + for (index = 0; index < HAL_GPIO_MAX_IRQ; ++index) { + uint32_t mask, val; + + if (hal_gpio_irqs[index].handler == NULL) { + continue; + } + if (GPIO_PORT(hal_gpio_irqs[index].pin) != port) { + continue; + } + + mask = GPIO_MASK(hal_gpio_irqs[index].pin); + if (CNFx(port) & mask != mask) { + continue; + } + + val = PORTx(port) & mask; + if ((val && (hal_gpio_irqs[index].trig & HAL_GPIO_TRIG_RISING)) || + (!val && (hal_gpio_irqs[index].trig & HAL_GPIO_TRIG_FALLING))) { + hal_gpio_irqs[index].handler(hal_gpio_irqs[index].arg); + } + CNFxCLR(port) = mask; + } +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_A_VECTOR))) +hal_gpio_porta_isr(void) +{ + hal_gpio_handle_isr(0); + IFS3CLR = _IFS3_CNAIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_B_VECTOR))) +hal_gpio_portb_isr(void) +{ + hal_gpio_handle_isr(1); + IFS3CLR = _IFS3_CNBIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_C_VECTOR))) +hal_gpio_portc_isr(void) +{ + hal_gpio_handle_isr(2); + IFS3CLR = _IFS3_CNCIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_D_VECTOR))) +hal_gpio_portd_isr(void) +{ + hal_gpio_handle_isr(3); + IFS3CLR = _IFS3_CNDIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_E_VECTOR))) +hal_gpio_porte_isr(void) +{ + hal_gpio_handle_isr(4); + IFS3CLR = _IFS3_CNEIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_F_VECTOR))) +hal_gpio_portf_isr(void) +{ + hal_gpio_handle_isr(5); + IFS3CLR = _IFS3_CNFIF_MASK; +} + +void +__attribute__((interrupt(IPL1AUTO), vector(_CHANGE_NOTICE_G_VECTOR))) +hal_gpio_portg_isr(void) +{ + hal_gpio_handle_isr(6); + IFS3CLR = _IFS3_CNGIF_MASK; +} + +int +hal_gpio_init_in(int pin, hal_gpio_pull_t pull) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + /* Configure pin as digital */ + ANSELxCLR(port) = mask; + + ODCxCLR(port) = mask; + + switch (pull) { + case HAL_GPIO_PULL_NONE: + CNPUxCLR(port) = mask; + CNPDxCLR(port) = mask; + break; + + case HAL_GPIO_PULL_DOWN: + CNPUxCLR(port) = mask; + CNPDxSET(port) = mask; + break; + + case HAL_GPIO_PULL_UP: + CNPUxSET(port) = mask; + CNPDxCLR(port) = mask; + break; + + default: + return -1; + } + + /* Configure pin direction as input */ + TRISxSET(port) = mask; + + return 0; +} + +int +hal_gpio_init_out(int pin, int val) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + /* Configure pin as digital */ + ANSELxCLR(port) = mask; + + /* Disable pull-up, pull-down and open drain */ + CNPUxCLR(port) = mask; + CNPDxCLR(port) = mask; + ODCxCLR(port) = mask; + + if (val) { + LATxSET(port) = mask; + } else { + LATxCLR(port) = mask; + } + + /* Configure pin direction as output */ + TRISxCLR(port) = mask; + + return 0; +} + +void +hal_gpio_write(int pin, int val) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + if (val) { + LATxSET(port) = mask; + } else { + LATxCLR(port) = mask; + } +} + +int +hal_gpio_read(int pin) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + return !!(PORTx(port) & mask); +} + +int +hal_gpio_toggle(int pin) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + LATxINV(port) = mask; + + /* + * One instruction cycle is required between a write and a read + * operation on the same port. + */ + asm volatile ("nop"); + + return !!(PORTx(port) & mask); +} + +int +hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg, + hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + uint32_t ctx; + int ret; + uint8_t index; + + /* HAL_GPIO_TRIG_LOW and HAL_GPIO_TRIG_HIGH are not supported */ + if (trig == HAL_GPIO_TRIG_LOW || + trig == HAL_GPIO_TRIG_HIGH || + trig == HAL_GPIO_TRIG_NONE) { + return -1; + } + + /* Remove any existing irq handler attached to the pin */ + hal_gpio_irq_release(pin); + hal_gpio_irq_disable(pin); + + index = hal_gpio_find_empty_slot(); + if (index == HAL_GPIO_MAX_IRQ) { + return -1; + } + + ret = hal_gpio_init_in(pin, pull); + if (ret < 0) { + return ret; + } + + __HAL_DISABLE_INTERRUPTS(ctx); + hal_gpio_irqs[index].arg = arg; + hal_gpio_irqs[index].pin = pin; + hal_gpio_irqs[index].trig = trig; + hal_gpio_irqs[index].handler = handler; + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} + +void +hal_gpio_irq_release(int pin) +{ + uint32_t ctx; + uint8_t index = hal_gpio_find_pin(pin); + if (index == HAL_GPIO_MAX_IRQ) { + return; + } + + __HAL_DISABLE_INTERRUPTS(ctx); + hal_gpio_irqs[index].handler = NULL; + __HAL_ENABLE_INTERRUPTS(ctx); +} + +void +hal_gpio_irq_enable(int pin) +{ + volatile uint32_t dummy; + uint32_t port, mask, ctx; + + uint8_t index = hal_gpio_find_pin(pin); + if (index == HAL_GPIO_MAX_IRQ) + return; + + port = GPIO_PORT(pin); + mask = GPIO_MASK(pin); + + __HAL_DISABLE_INTERRUPTS(ctx); + + /* Enable Change Notice module for the port */ + CNCONxSET(port) = _CNCONA_ON_MASK | _CNCONA_EDGEDETECT_MASK; + + switch (hal_gpio_irqs[index].trig) { + case HAL_GPIO_TRIG_RISING: + CNENxSET(port) = mask; + break; + case HAL_GPIO_TRIG_FALLING: + CNNExSET(port) = mask; + break; + case HAL_GPIO_TRIG_BOTH: + CNENxSET(port) = mask; + CNNExSET(port) = mask; + break; + default: + break; + } + + /* Set interrupt priority */ + switch (port) { + case 0: + IPC29CLR = (_IPC29_CNAIP_MASK | _IPC29_CNAIS_MASK); + IPC29 |= 1 << _IPC29_CNAIP_POSITION; + break; + case 1: + IPC29CLR = (_IPC29_CNBIP_MASK | _IPC29_CNBIS_MASK); + IPC29 |= 1 << _IPC29_CNBIP_POSITION; + break; + case 2: + IPC30CLR = (_IPC30_CNCIP_MASK | _IPC30_CNCIS_MASK); + IPC30 |= 1 << _IPC30_CNCIP_POSITION; + break; + case 3: + IPC30CLR = (_IPC30_CNDIP_MASK | _IPC30_CNDIS_MASK); + IPC30 |= 1 << _IPC30_CNDIP_POSITION; + break; + case 4: + IPC30CLR = (_IPC30_CNEIP_MASK | _IPC30_CNEIS_MASK); + IPC30 |= 1 << _IPC30_CNEIP_POSITION; + break; + case 5: + IPC30CLR = (_IPC30_CNFIP_MASK | _IPC30_CNFIS_MASK); + IPC30 |= 1 << _IPC30_CNFIP_POSITION; + break; + case 6: + IPC31CLR = (_IPC31_CNGIP_MASK | _IPC31_CNGIS_MASK); + IPC31 |= 1 << _IPC31_CNGIP_POSITION; + break; + } + + /* Clear interrupt flag and enable Change Notice interrupt */ + switch (port) { + case 0: + IFS3CLR = _IFS3_CNAIF_MASK; + IEC3SET = _IEC3_CNAIE_MASK; + break; + case 1: + IFS3CLR = _IFS3_CNBIF_MASK; + IEC3SET = _IEC3_CNBIE_MASK; + break; + case 2: + IFS3CLR = _IFS3_CNCIF_MASK; + IEC3SET = _IEC3_CNCIE_MASK; + break; + case 3: + IFS3CLR = _IFS3_CNDIF_MASK; + IEC3SET = _IEC3_CNDIE_MASK; + break; + case 4: + IFS3CLR = _IFS3_CNEIF_MASK; + IEC3SET = _IEC3_CNEIE_MASK; + break; + case 5: + IFS3CLR = _IFS3_CNFIF_MASK; + IEC3SET = _IEC3_CNFIE_MASK; + break; + case 6: + IFS3CLR = _IFS3_CNGIF_MASK; + IEC3SET = _IEC3_CNGIE_MASK; + break; + } + + __HAL_ENABLE_INTERRUPTS(ctx); +} + +void +hal_gpio_irq_disable(int pin) +{ + uint32_t port = GPIO_PORT(pin); + uint32_t mask = GPIO_MASK(pin); + + CNENxCLR(port) = mask; + CNNExCLR(port) = mask; +} \ No newline at end of file