Add gpio event driver
This commit is contained in:
parent
85e960e612
commit
aa7e9fb3a4
3
.vscode/tasks.json
vendored
3
.vscode/tasks.json
vendored
@ -2,7 +2,8 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"options": {
|
"options": {
|
||||||
"env": {
|
"env": {
|
||||||
"APPLICATION": "blinky",
|
// "APPLICATION": "blinky",
|
||||||
|
"APPLICATION": "button",
|
||||||
// "APPLICATION": "spi",
|
// "APPLICATION": "spi",
|
||||||
// "APPLICATION": "st7789_lcd",
|
// "APPLICATION": "st7789_lcd",
|
||||||
},
|
},
|
||||||
|
@ -10,11 +10,14 @@ class GpioInterface
|
|||||||
public:
|
public:
|
||||||
enum class direction {IN, OUT};
|
enum class direction {IN, OUT};
|
||||||
|
|
||||||
virtual void set_direction(direction) = 0;
|
virtual void set_direction(direction, bool) = 0;
|
||||||
virtual uint32_t get() = 0;
|
virtual uint32_t get() = 0;
|
||||||
virtual void set() = 0;
|
virtual void set() = 0;
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
virtual void toggle() = 0;
|
virtual void toggle() = 0;
|
||||||
|
|
||||||
|
virtual void handle() = 0;
|
||||||
|
virtual uint32_t pin_number() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "platform/cm4/SystemTick.h"
|
#include "platform/cm4/SystemTick.h"
|
||||||
|
|
||||||
#include "platform/nrf52/gpio.h"
|
#include "platform/nrf52/gpio.h"
|
||||||
|
#include "platform/nrf52/gpiote.h"
|
||||||
#include "platform/nrf52/InterruptHandler.h"
|
#include "platform/nrf52/InterruptHandler.h"
|
||||||
#include "platform/nrf52/InterruptGuardian.h"
|
#include "platform/nrf52/InterruptGuardian.h"
|
||||||
|
|
||||||
@ -15,6 +16,18 @@
|
|||||||
using namespace pinetime::platform;
|
using namespace pinetime::platform;
|
||||||
using namespace pinetime::virtual_timer;
|
using namespace pinetime::virtual_timer;
|
||||||
|
|
||||||
|
// IRQs
|
||||||
|
nrf52::InterruptGuardian nrf52::InterruptGuardian::instance;
|
||||||
|
cm4::InterruptGuardian cm4::InterruptGuardian::instance;
|
||||||
|
|
||||||
|
// GPIO events
|
||||||
|
nrf52::Gpiote gpiote;
|
||||||
|
|
||||||
|
// Timer
|
||||||
|
cm4::SystemTick system_tick;
|
||||||
|
VirtualTimerDistributor virtual_timer_distributor(system_tick.instance());
|
||||||
|
pinetime::Delay delay;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PIN_NUMBER_LED_1 = 17,
|
PIN_NUMBER_LED_1 = 17,
|
||||||
PIN_NUMBER_LED_2 = 18,
|
PIN_NUMBER_LED_2 = 18,
|
||||||
@ -29,15 +42,6 @@ nrf52::Gpio led_3(PIN_NUMBER_LED_3);
|
|||||||
nrf52::Gpio led_4(PIN_NUMBER_LED_4);
|
nrf52::Gpio led_4(PIN_NUMBER_LED_4);
|
||||||
std::array<nrf52::Gpio *, 4> leds = {&led_1, &led_2, &led_3, &led_4};
|
std::array<nrf52::Gpio *, 4> leds = {&led_1, &led_2, &led_3, &led_4};
|
||||||
|
|
||||||
// IRQs
|
|
||||||
nrf52::InterruptGuardian nrf52::InterruptGuardian::instance;
|
|
||||||
cm4::InterruptGuardian cm4::InterruptGuardian::instance;
|
|
||||||
|
|
||||||
// Timer
|
|
||||||
cm4::SystemTick system_tick;
|
|
||||||
VirtualTimerDistributor virtual_timer_distributor(system_tick.instance());
|
|
||||||
pinetime::Delay delay;
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
cm4::InterruptGuardian::enable_interrupts();
|
cm4::InterruptGuardian::enable_interrupts();
|
||||||
|
72
src/application/button/main.cc
Normal file
72
src/application/button/main.cc
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "virtual_timer/VirtualTimerDistributor.h"
|
||||||
|
|
||||||
|
#include "platform/cm4/InterruptHandler.h"
|
||||||
|
#include "platform/cm4/InterruptGuardian.h"
|
||||||
|
#include "platform/cm4/SystemTick.h"
|
||||||
|
|
||||||
|
#include "platform/nrf52/gpio.h"
|
||||||
|
#include "platform/nrf52/gpiote.h"
|
||||||
|
#include "platform/nrf52/InterruptHandler.h"
|
||||||
|
#include "platform/nrf52/InterruptGuardian.h"
|
||||||
|
|
||||||
|
#include "gpio_interface.h"
|
||||||
|
#include "delay.h"
|
||||||
|
|
||||||
|
using namespace pinetime::platform;
|
||||||
|
using namespace pinetime::virtual_timer;
|
||||||
|
|
||||||
|
// IRQs
|
||||||
|
nrf52::InterruptGuardian nrf52::InterruptGuardian::instance;
|
||||||
|
cm4::InterruptGuardian cm4::InterruptGuardian::instance;
|
||||||
|
|
||||||
|
// GPIO events
|
||||||
|
nrf52::Gpiote gpiote;
|
||||||
|
|
||||||
|
// Timer
|
||||||
|
cm4::SystemTick system_tick;
|
||||||
|
VirtualTimerDistributor virtual_timer_distributor(system_tick.instance());
|
||||||
|
pinetime::Delay delay;
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PIN_NUMBER_BUTTON_1 = 13,
|
||||||
|
PIN_NUMBER_BUTTON_2 = 14,
|
||||||
|
PIN_NUMBER_BUTTON_3 = 15,
|
||||||
|
PIN_NUMBER_BUTTON_4 = 16,
|
||||||
|
PIN_NUMBER_LED_1 = 17,
|
||||||
|
PIN_NUMBER_LED_2 = 18,
|
||||||
|
PIN_NUMBER_LED_3 = 19,
|
||||||
|
PIN_NUMBER_LED_4 = 20
|
||||||
|
};
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
nrf52::Gpio led_1(PIN_NUMBER_LED_1);
|
||||||
|
nrf52::Gpio led_2(PIN_NUMBER_LED_2);
|
||||||
|
nrf52::Gpio led_3(PIN_NUMBER_LED_3);
|
||||||
|
nrf52::Gpio led_4(PIN_NUMBER_LED_4);
|
||||||
|
std::array<nrf52::Gpio *, 4> leds = {&led_1, &led_2, &led_3, &led_4};
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
nrf52::Gpio button_1(PIN_NUMBER_BUTTON_1);
|
||||||
|
nrf52::Gpio button_2(PIN_NUMBER_BUTTON_2);
|
||||||
|
nrf52::Gpio button_3(PIN_NUMBER_BUTTON_3);
|
||||||
|
nrf52::Gpio button_4(PIN_NUMBER_BUTTON_4);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
button_1.set_direction(pinetime::interfaces::GpioInterface::direction::IN, true);
|
||||||
|
cm4::InterruptGuardian::enable_interrupts();
|
||||||
|
while(true) {
|
||||||
|
for(auto it = leds.begin(); it != leds.end(); ++it) {
|
||||||
|
uint32_t b1 = button_1.get();
|
||||||
|
if(b1) {
|
||||||
|
nrf52::Gpio * led = *it;
|
||||||
|
led->toggle();
|
||||||
|
}
|
||||||
|
// delay.ms(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,22 +1,33 @@
|
|||||||
#include "platform/nrf52/gpio.h"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "nrf52.h"
|
#include "nrf52.h"
|
||||||
#include "nrf52_bitfields.h"
|
#include "nrf52_bitfields.h"
|
||||||
|
|
||||||
NRF_GPIO_Type *const GPIO_REGS = reinterpret_cast<NRF_GPIO_Type *>(NRF_P0_BASE);
|
NRF_GPIO_Type *const GPIO_REGS = reinterpret_cast<NRF_GPIO_Type *>(NRF_P0_BASE);
|
||||||
|
NRF_GPIOTE_Type *const GPIOTE_REGS = reinterpret_cast<NRF_GPIOTE_Type *>(NRF_GPIOTE_BASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "platform/nrf52/gpiote.h"
|
||||||
|
#include "platform/nrf52/gpio.h"
|
||||||
|
|
||||||
using namespace pinetime::platform::nrf52;
|
using namespace pinetime::platform::nrf52;
|
||||||
|
|
||||||
|
Gpio::Gpio()
|
||||||
|
: pin(0)
|
||||||
|
, blocking(false)
|
||||||
|
, wait_for_event(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Gpio::Gpio(uint32_t pin)
|
Gpio::Gpio(uint32_t pin)
|
||||||
: pin_number(pin)
|
: pin(pin)
|
||||||
|
, blocking(false)
|
||||||
|
, wait_for_event(false)
|
||||||
{
|
{
|
||||||
this->set_direction(direction::OUT);
|
this->set_direction(direction::OUT);
|
||||||
this->clear();
|
this->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::set_direction(direction dir)
|
void Gpio::set_direction(direction dir, bool blocking_read)
|
||||||
{
|
{
|
||||||
uint32_t direct = GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos;
|
uint32_t direct = GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos;
|
||||||
uint32_t input = GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos;
|
uint32_t input = GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos;
|
||||||
@ -33,36 +44,60 @@ void Gpio::set_direction(direction dir)
|
|||||||
// GPIO_PIN_CNF_PULL_Pullup, ///< Pin pull-up resistor enabled.
|
// GPIO_PIN_CNF_PULL_Pullup, ///< Pin pull-up resistor enabled.
|
||||||
pull = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos;
|
pull = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos;
|
||||||
drive = GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos;
|
drive = GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos;
|
||||||
sense = GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos;
|
sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
|
||||||
|
|
||||||
|
gpiote.instance().register_handler(Gpiote::GpioteChannel::CHANNEL_0, *this);
|
||||||
|
|
||||||
|
this->blocking = blocking_read;
|
||||||
|
|
||||||
|
gpiote.instance().enable();
|
||||||
}
|
}
|
||||||
GPIO_REGS->PIN_CNF[pin_number] = direct | input | pull | drive | sense;
|
GPIO_REGS->PIN_CNF[pin] = direct | input | pull | drive | sense;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::set_pin_number(uint32_t pin)
|
void Gpio::pin_number(uint32_t pin)
|
||||||
{
|
{
|
||||||
this->pin_number = pin;
|
this->pin = pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Gpio::pin_number()
|
||||||
|
{
|
||||||
|
return this->pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Gpio::get()
|
uint32_t Gpio::get()
|
||||||
{
|
{
|
||||||
uint32_t res = (GPIO_REGS->IN >> pin_number) & 1UL;
|
if(this->blocking) {
|
||||||
|
this->wait_for_event = true;
|
||||||
|
while(this->wait_for_event == true) {
|
||||||
|
// FIXME: Low Power
|
||||||
|
asm volatile("nop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t res = (GPIO_REGS->IN >> pin) & 1UL;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::set()
|
void Gpio::set()
|
||||||
{
|
{
|
||||||
GPIO_REGS->OUTSET = 1UL << (this->pin_number);
|
GPIO_REGS->OUTSET = 1UL << (this->pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::clear()
|
void Gpio::clear()
|
||||||
{
|
{
|
||||||
GPIO_REGS->OUTCLR = 1UL << (this->pin_number);
|
GPIO_REGS->OUTCLR = 1UL << (this->pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gpio::toggle()
|
void Gpio::toggle()
|
||||||
{
|
{
|
||||||
uint32_t state = GPIO_REGS->OUT;
|
uint32_t state = GPIO_REGS->OUT;
|
||||||
|
|
||||||
GPIO_REGS->OUTSET = (~state & (1UL << (this->pin_number)));
|
GPIO_REGS->OUTSET = (~state & (1UL << (this->pin)));
|
||||||
GPIO_REGS->OUTCLR = (state & (1UL << (this->pin_number)));
|
GPIO_REGS->OUTCLR = (state & (1UL << (this->pin)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gpio::handle()
|
||||||
|
{
|
||||||
|
this->wait_for_event = false;
|
||||||
}
|
}
|
@ -3,22 +3,30 @@
|
|||||||
|
|
||||||
#include "gpio_interface.h"
|
#include "gpio_interface.h"
|
||||||
|
|
||||||
|
#include "platform/nrf52/InterruptHandler.h"
|
||||||
|
|
||||||
namespace pinetime::platform::nrf52 {
|
namespace pinetime::platform::nrf52 {
|
||||||
|
|
||||||
class Gpio : public pinetime::interfaces::GpioInterface
|
class Gpio : public pinetime::interfaces::GpioInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline Gpio() {}
|
Gpio();
|
||||||
Gpio(uint32_t);
|
Gpio(uint32_t);
|
||||||
void set_pin_number(uint32_t);
|
void pin_number(uint32_t);
|
||||||
void set_direction(direction) override;
|
uint32_t pin_number() override;
|
||||||
uint32_t get() override;
|
|
||||||
void set() override;
|
|
||||||
void clear() override;
|
|
||||||
void toggle() override;
|
|
||||||
|
|
||||||
private:
|
void set_direction(direction, bool blocking_read=false) override;
|
||||||
uint32_t pin_number;
|
uint32_t get() override;
|
||||||
|
void set() override;
|
||||||
|
void clear() override;
|
||||||
|
void toggle() override;
|
||||||
|
|
||||||
|
void handle() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t pin;
|
||||||
|
bool blocking;
|
||||||
|
volatile bool wait_for_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
56
src/platform/nrf52/gpiote.cc
Normal file
56
src/platform/nrf52/gpiote.cc
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#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_Type *>(NRF_GPIOTE_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace pinetime::platform::nrf52;
|
||||||
|
|
||||||
|
Gpiote::Gpiote()
|
||||||
|
: InterruptHandler(InterruptGuardian::Nrf52IrqN::GPIOTE_IRQ)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gpiote::enable()
|
||||||
|
{
|
||||||
|
NVIC_SetPriority(GPIOTE_IRQn, 7);
|
||||||
|
NVIC_EnableIRQ(GPIOTE_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gpiote::disable()
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ(GPIOTE_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gpiote::register_handler(GpioteChannel channel, pinetime::interfaces::GpioInterface & gpio)
|
||||||
|
{
|
||||||
|
unsigned int idx = static_cast<unsigned int>(channel);
|
||||||
|
this->gpiote_channels[idx] = &gpio;
|
||||||
|
|
||||||
|
GPIOTE_REGS->INTENSET = GPIOTE_INTENSET_IN0_Msk;
|
||||||
|
GPIOTE_REGS->CONFIG[idx] = (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
|
||||||
|
| ((gpio.pin_number()) << GPIOTE_CONFIG_PSEL_Pos)
|
||||||
|
| (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
src/platform/nrf52/gpiote.h
Normal file
55
src/platform/nrf52/gpiote.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __PLATFORM_NRF52_GPIOTE_H__
|
||||||
|
#define __PLATFORM_NRF52_GPIOTE_H__
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
enum class GpioteChannel {
|
||||||
|
CHANNEL_0 = 0,
|
||||||
|
CHANNEL_1,
|
||||||
|
CHANNEL_2,
|
||||||
|
CHANNEL_3,
|
||||||
|
CHANNEL_4,
|
||||||
|
CHANNEL_5,
|
||||||
|
CHANNEL_6,
|
||||||
|
CHANNEL_7,
|
||||||
|
};
|
||||||
|
|
||||||
|
void register_handler(GpioteChannel, pinetime::interfaces::GpioInterface &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle() override;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GPIOTE_CHANNELS = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<pinetime::interfaces::GpioInterface *, GPIOTE_CHANNELS> gpiote_channels;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -54,3 +54,13 @@ void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
|
|||||||
|
|
||||||
h->handle();
|
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();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user