From df0e302bf81e359902ab19ef7d35e2c017c48131 Mon Sep 17 00:00:00 2001 From: Thomas Klaehn Date: Sun, 26 Apr 2020 08:55:44 +0200 Subject: [PATCH] Add gpio event driver --- src/platform/nrf52/gpiote.cc | 77 +++++++++++++++++++++++ src/platform/nrf52/gpiote.h | 44 +++++++++++++ src/platform/nrf52/low_level_interrupt.cc | 10 +++ 3 files changed, 131 insertions(+) create mode 100644 src/platform/nrf52/gpiote.cc create mode 100644 src/platform/nrf52/gpiote.h diff --git a/src/platform/nrf52/gpiote.cc b/src/platform/nrf52/gpiote.cc new file mode 100644 index 0000000..dcc729f --- /dev/null +++ b/src/platform/nrf52/gpiote.cc @@ -0,0 +1,77 @@ +#include + +#include "platform/nrf52/InterruptHandler.h" +#include "platform/nrf52/InterruptGuardian.h" + +#include "platform/nrf52/gpiote.h" + +extern "C" { + #include "nrf52.h" + #include "nrf52_bitfields.h" + + NRF_GPIOTE_Type *const GPIOTE_REGS = reinterpret_cast(NRF_GPIOTE_BASE); +} + +using namespace pinetime::platform::nrf52; + +Gpiote::Gpiote() + : InterruptHandler(InterruptGuardian::Nrf52IrqN::GPIOTE_IRQ) + , num_registered(0) +{ + for(auto it = this->gpiote_channels.begin(); it != this->gpiote_channels.end(); ++it) { + *it = nullptr; + } +} + +void Gpiote::enable() +{ + NVIC_SetPriority(GPIOTE_IRQn, 7); + NVIC_EnableIRQ(GPIOTE_IRQn); +} + +void Gpiote::disable() +{ + NVIC_DisableIRQ(GPIOTE_IRQn); +} + +void Gpiote::register_handler(pinetime::interfaces::GpioInterface *gpio) +{ + if(num_registered == GPIOTE_CHANNELS) { + //FIXME: Error notification + return; + } + + if(num_registered == 0) { + this->enable(); + } else { + //check if gpio already registered + for(auto it = this->gpiote_channels.begin(); it != this->gpiote_channels.end(); ++it) { + if(*it == gpio) { + return; + } + } + } + uint32_t i = 0; + for(auto it = this->gpiote_channels.begin(); it != this->gpiote_channels.end(); ++it) { + if(*it == nullptr) { + *it = gpio; + GPIOTE_REGS->INTENSET = GPIOTE_INTENSET_IN0_Msk; + GPIOTE_REGS->CONFIG[i] = (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) + | ((gpio->pin_number()) << GPIOTE_CONFIG_PSEL_Pos) + | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos); + } + i++; + } +} + +void Gpiote::handle() +{ + for(uint32_t i = 0; i < GPIOTE_CHANNELS; ++i) { + if(GPIOTE_REGS->EVENTS_IN[i] != 0) { + GPIOTE_REGS->EVENTS_IN[i] = 0; + pinetime::interfaces::GpioInterface *h = this->gpiote_channels[i]; + assert(h != nullptr); + h->handle(); + } + } +} diff --git a/src/platform/nrf52/gpiote.h b/src/platform/nrf52/gpiote.h new file mode 100644 index 0000000..6b7408c --- /dev/null +++ b/src/platform/nrf52/gpiote.h @@ -0,0 +1,44 @@ +#ifndef __PLATFORM_NRF52_GPIOTE_H__ +#define __PLATFORM_NRF52_GPIOTE_H__ + +#include + +#include "gpio_interface.h" +#include "platform/nrf52/InterruptHandler.h" + +namespace pinetime::platform::nrf52 +{ +class Gpiote; +} +extern pinetime::platform::nrf52::Gpiote gpiote; + +namespace pinetime::platform::nrf52 +{ + +class Gpiote + : public pinetime::platform::nrf52::InterruptHandler +{ +public: + Gpiote(); + + static inline Gpiote & instance() { return gpiote; } + + void enable() override; + void disable() override; + + void register_handler(pinetime::interfaces::GpioInterface *); + +private: + void handle() override; + + enum { + GPIOTE_CHANNELS = 8, + }; + + std::array gpiote_channels; + uint32_t num_registered; +}; + +} + +#endif diff --git a/src/platform/nrf52/low_level_interrupt.cc b/src/platform/nrf52/low_level_interrupt.cc index 35807ab..c185c90 100644 --- a/src/platform/nrf52/low_level_interrupt.cc +++ b/src/platform/nrf52/low_level_interrupt.cc @@ -54,3 +54,13 @@ void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) h->handle(); } + +void GPIOTE_IRQHandler(void) +{ + uint32_t irq_nr = InterruptGuardian::Nrf52IrqN::GPIOTE_IRQ; + InterruptHandler *h = InterruptGuardian::instance.nrf52_vector[irq_nr]; + + assert(h != nullptr); + + h->handle(); +}