Add gpio event driver
This commit was merged in pull request #10.
	This commit is contained in:
		
							
								
								
									
										3
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							@@ -2,7 +2,8 @@
 | 
			
		||||
    "version": "2.0.0",
 | 
			
		||||
    "options": {
 | 
			
		||||
        "env": {
 | 
			
		||||
            "APPLICATION": "blinky",
 | 
			
		||||
            // "APPLICATION": "blinky",
 | 
			
		||||
            "APPLICATION": "button",
 | 
			
		||||
            // "APPLICATION": "spi",
 | 
			
		||||
            // "APPLICATION": "st7789_lcd",
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,14 @@ class GpioInterface
 | 
			
		||||
    public:
 | 
			
		||||
        enum class direction {IN, OUT};
 | 
			
		||||
 | 
			
		||||
        virtual void set_direction(direction) = 0;
 | 
			
		||||
        virtual void set_direction(direction, bool) = 0;
 | 
			
		||||
        virtual uint32_t get() = 0;
 | 
			
		||||
        virtual void set() = 0;
 | 
			
		||||
        virtual void clear() = 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/nrf52/gpio.h"
 | 
			
		||||
#include "platform/nrf52/gpiote.h"
 | 
			
		||||
#include "platform/nrf52/InterruptHandler.h"
 | 
			
		||||
#include "platform/nrf52/InterruptGuardian.h"
 | 
			
		||||
 | 
			
		||||
@@ -15,6 +16,18 @@
 | 
			
		||||
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_LED_1 = 17,
 | 
			
		||||
    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);
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    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" {
 | 
			
		||||
    #include "nrf52.h"
 | 
			
		||||
    #include "nrf52_bitfields.h"
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
Gpio::Gpio()
 | 
			
		||||
    : pin(0)
 | 
			
		||||
    , blocking(false)
 | 
			
		||||
    , wait_for_event(false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Gpio::Gpio(uint32_t pin)
 | 
			
		||||
    : pin_number(pin)
 | 
			
		||||
    : pin(pin)
 | 
			
		||||
    , blocking(false)
 | 
			
		||||
    , wait_for_event(false)
 | 
			
		||||
{
 | 
			
		||||
    this->set_direction(direction::OUT);
 | 
			
		||||
    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 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.
 | 
			
		||||
        pull = GPIO_PIN_CNF_PULL_Pullup  << GPIO_PIN_CNF_PULL_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 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Gpio::set()
 | 
			
		||||
{
 | 
			
		||||
    GPIO_REGS->OUTSET = 1UL << (this->pin_number);
 | 
			
		||||
    GPIO_REGS->OUTSET = 1UL << (this->pin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Gpio::clear()
 | 
			
		||||
{
 | 
			
		||||
    GPIO_REGS->OUTCLR = 1UL << (this->pin_number);
 | 
			
		||||
    GPIO_REGS->OUTCLR = 1UL << (this->pin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Gpio::toggle()
 | 
			
		||||
{
 | 
			
		||||
    uint32_t state = GPIO_REGS->OUT;
 | 
			
		||||
 | 
			
		||||
    GPIO_REGS->OUTSET = (~state & (1UL << (this->pin_number)));
 | 
			
		||||
    GPIO_REGS->OUTCLR = (state & (1UL << (this->pin_number)));
 | 
			
		||||
}
 | 
			
		||||
    GPIO_REGS->OUTSET = (~state & (1UL << (this->pin)));
 | 
			
		||||
    GPIO_REGS->OUTCLR = (state & (1UL << (this->pin)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Gpio::handle()
 | 
			
		||||
{
 | 
			
		||||
    this->wait_for_event = false;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,22 +3,30 @@
 | 
			
		||||
 | 
			
		||||
#include "gpio_interface.h"
 | 
			
		||||
 | 
			
		||||
#include "platform/nrf52/InterruptHandler.h"
 | 
			
		||||
 | 
			
		||||
namespace pinetime::platform::nrf52 {
 | 
			
		||||
 | 
			
		||||
class Gpio : public pinetime::interfaces::GpioInterface
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        inline Gpio() {}
 | 
			
		||||
        Gpio(uint32_t);
 | 
			
		||||
        void set_pin_number(uint32_t);
 | 
			
		||||
        void set_direction(direction) override;
 | 
			
		||||
        uint32_t get() override;
 | 
			
		||||
        void set() override;
 | 
			
		||||
        void clear() override;
 | 
			
		||||
        void toggle() override;
 | 
			
		||||
public:
 | 
			
		||||
    Gpio();
 | 
			
		||||
    Gpio(uint32_t);
 | 
			
		||||
    void pin_number(uint32_t);
 | 
			
		||||
    uint32_t pin_number() override;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        uint32_t pin_number;
 | 
			
		||||
    void set_direction(direction, bool blocking_read=false) override;
 | 
			
		||||
    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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user