-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[rp2040] Implement IRQ handlers for GPIO and QSPI
Based on discussion #847
- Loading branch information
cocasema
committed
Apr 16, 2022
1 parent
98a2483
commit 24c4f4f
Showing
11 changed files
with
528 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright (c) 2022, Nikolay Semenov | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include <modm/board.hpp> | ||
|
||
int | ||
main() | ||
{ | ||
Board::initialize(); | ||
|
||
using Led = Board::LedGreen; | ||
Led::setOutput(); | ||
Led::set(); | ||
|
||
GpioIntHandler::enable(); | ||
|
||
// Powers on the LED on the low->high transition, and off on high->low. | ||
GpioInput0::setInput(); | ||
GpioIntHandler::connect<GpioInput0>(Gpio::InputTrigger::BothEdges, | ||
[](Gpio::InputTrigger triggers) { | ||
Led::set(!!(triggers & Gpio::InputTrigger::RisingEdge)); | ||
}); | ||
|
||
// Toggles LED each time gpio input is at the high level. | ||
GpioInput1::setInput(Gpio::InputType::PullDown); | ||
GpioIntHandler::connect<GpioInput1>(Gpio::InputTrigger::HighLevel, | ||
[](Gpio::InputTrigger) { Led::toggle(); }); | ||
|
||
while (true) {} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<library> | ||
<extends>modm:rp-pico</extends> | ||
<options> | ||
<option name="modm:build:build.path">../../../build/rp_pico/interrupt</option> | ||
</options> | ||
<modules> | ||
<module>modm:platform:gpio</module> | ||
<module>modm:platform:irq</module> | ||
<module>modm:build:scons</module> | ||
</modules> | ||
</library> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright (c) 2022, Nikolay Semenov | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#pragma once | ||
|
||
#include <RP2040.h> | ||
|
||
namespace modm::platform | ||
{ | ||
|
||
/** | ||
* Priority level of 0-192 in steps of 64 for each interrupt. | ||
* A higher level corresponds to a lower priority, | ||
* so level 0 is the highest programmable interrupt priority. | ||
* ... | ||
* The processor implements only bits[7:6] of each field, bits [5:0] read as zero and ignore writes. | ||
* This means writing 255 to a priority register saves value 192 to the register. | ||
* | ||
* https://developer.arm.com/documentation/dui0662/b/Cortex-M0--Peripherals/Nested-Vectored-Interrupt-Controller | ||
* https://developer.arm.com/documentation/dui0662/b/Cortex-M0--Peripherals/Nested-Vectored-Interrupt-Controller/Interrupt-Priority-Registers | ||
* | ||
* @ingroup modm_platform_irq | ||
*/ | ||
enum IntPriority : uint8_t | ||
{ | ||
Highest = 0x00, | ||
Default = 0x80, | ||
Lowest = 0xff, | ||
}; | ||
|
||
/** | ||
* Interrupt Controller | ||
* | ||
* @ingroup modm_platform_irq | ||
*/ | ||
class IntController | ||
{ | ||
public: | ||
static void | ||
enable(IRQn_Type type) | ||
{ | ||
NVIC_ClearPendingIRQ(type); | ||
NVIC_EnableIRQ(type); | ||
} | ||
|
||
static void | ||
disable(IRQn_Type type) | ||
{ | ||
NVIC_DisableIRQ(type); | ||
} | ||
|
||
static void | ||
setPriority(IRQn_Type type, IntPriority priority) | ||
{ | ||
NVIC_SetPriority(type, priority); | ||
} | ||
|
||
static IntPriority | ||
getPriority(IRQn_Type type) | ||
{ | ||
return static_cast<IntPriority>(NVIC_GetPriority(type)); | ||
} | ||
}; | ||
|
||
} // namespace modm::platform |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* Copyright (c) 2022, Nikolay Semenov | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include <modm/platform/irq/int_handler.hpp> | ||
|
||
namespace modm::platform | ||
{ | ||
|
||
%% if with_gpio | ||
template<> | ||
void | ||
IntHandler<IO_IRQ_BANK0_IRQn, NUM_BANK0_GPIOS>::irqHandler() | ||
{ | ||
using PortRegs = Gpio::PortRegs<gpioPort()>; | ||
|
||
static_assert(0b1111u == static_cast<uint32_t>(Gpio::InputTrigger::All)); | ||
|
||
// TODO: check if multicore enabled | ||
auto& proc_irq_ctrl = sio_hw->cpuid ? iobank0_hw->proc1_irq_ctrl : iobank0_hw->proc0_irq_ctrl; | ||
|
||
for (size_t group = 0; group < Lines / 8; ++group) | ||
{ | ||
if (uint32_t int_status = proc_irq_ctrl.ints[group]) | ||
{ | ||
for (uint8_t pin = group * 8; int_status; ++pin, int_status >>= 4) | ||
{ | ||
if (uint32_t triggers = int_status & 0b1111u) | ||
{ | ||
PortRegs::acknowledge_irq(pin, static_cast<Gpio::InputTrigger>(triggers)); | ||
if (auto& handler = handlers[pin]) | ||
{ | ||
handler(static_cast<Gpio::InputTrigger>(triggers)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
%%endif | ||
|
||
%% if with_qspi | ||
template<> | ||
void | ||
IntHandler<IO_IRQ_QSPI_IRQn, NUM_QSPI_GPIOS>::irqHandler() | ||
{ | ||
using PortRegs = Gpio::PortRegs<gpioPort()>; | ||
|
||
static_assert(Lines <= 8); | ||
|
||
// TODO: check if multicore enabled | ||
auto& proc_irq_ctrl = sio_hw->cpuid ? ioqspi_hw->proc1_qspi_ctrl : ioqspi_hw->proc0_qspi_ctrl; | ||
|
||
uint32_t int_status = proc_irq_ctrl.ints; | ||
|
||
for (uint8_t pin = 0; int_status; ++pin, int_status >>= 4) | ||
{ | ||
if (uint32_t triggers = int_status & 0b1111u) | ||
{ | ||
PortRegs::acknowledge_irq(pin, static_cast<Gpio::InputTrigger>(triggers)); | ||
if (auto& handler = handlers[pin]) | ||
{ | ||
handler(static_cast<Gpio::InputTrigger>(triggers)); | ||
} | ||
} | ||
} | ||
} | ||
%%endif | ||
|
||
template<IRQn_Type Type, size_t Lines> | ||
IntHandler<Type, Lines>::Handler IntHandler<Type, Lines>::handlers[IntHandler::Lines] modm_fastdata; | ||
|
||
%% if with_gpio | ||
MODM_ISR(IO_IRQ_BANK0) | ||
{ | ||
IntHandler<IO_IRQ_BANK0_IRQn, NUM_BANK0_GPIOS>::irqHandler(); | ||
} | ||
%%endif | ||
|
||
%% if with_qspi | ||
MODM_ISR(IO_IRQ_QSPI) | ||
{ | ||
IntHandler<IO_IRQ_QSPI_IRQn, NUM_QSPI_GPIOS>::irqHandler(); | ||
} | ||
%%endif | ||
|
||
} // namespace modm::platform |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* Copyright (c) 2022, Nikolay Semenov | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#pragma once | ||
|
||
#include <modm/architecture/interface/interrupt.hpp> | ||
#include <modm/platform/gpio/base.hpp> | ||
#include <modm/platform/irq/int_controller.hpp> | ||
#include <modm/utils/inplace_function.hpp> | ||
|
||
namespace modm::platform | ||
{ | ||
%% if with_gpio | ||
MODM_ISR_DECL(IO_IRQ_BANK0); | ||
%%endif | ||
%% if with_qspi | ||
MODM_ISR_DECL(IO_IRQ_QSPI); | ||
%%endif | ||
|
||
/** | ||
* Interrupt Handler | ||
* | ||
* @ingroup modm_platform_irq | ||
*/ | ||
template<IRQn_Type Type, size_t NLines> | ||
class IntHandler | ||
{ | ||
public: | ||
static constexpr size_t Lines = NLines; | ||
using Handler = | ||
modm::inplace_function<void(Gpio::InputTrigger), {{handler_storage}}, alignof(void*)>; | ||
|
||
public: | ||
static void | ||
enable(IntPriority priority = IntPriority::Default) | ||
{ | ||
if (priority != IntController::getPriority(Type)) | ||
{ | ||
IntController::setPriority(Type, priority); | ||
} | ||
IntController::enable(Type); | ||
} | ||
|
||
static void | ||
disable() | ||
{ | ||
IntController::disable(Type); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
connect(Gpio::InputTrigger triggers, Handler&& handler) | ||
{ | ||
static_assert(Pin::port == gpioPort()); | ||
|
||
disableInterrupts<Pin>(Gpio::InputTrigger::All); | ||
acknowledgeInterrupts<Pin>(Gpio::InputTrigger::All); | ||
|
||
handlers[Pin::pin] = handler; | ||
|
||
enableInterrupts<Pin>(triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
disconnect() | ||
{ | ||
static_assert(Pin::port == gpioPort()); | ||
|
||
disableInterrupts<Pin>(Gpio::InputTrigger::All); | ||
handlers[Pin::pin] = nullptr; | ||
} | ||
|
||
private: | ||
template<class Pin> | ||
static void | ||
enableInterrupts(Gpio::InputTrigger triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::enable_irq(Pin::pin, triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
disableInterrupts(Gpio::InputTrigger triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::disable_irq(Pin::pin, triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
acknowledgeInterrupts(Gpio::InputTrigger triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::acknowledge_irq(Pin::pin, triggers); | ||
} | ||
|
||
static void | ||
irqHandler(); | ||
friend void MODM_ISR_NAME(IO_IRQ_BANK0)(); | ||
friend void MODM_ISR_NAME(IO_IRQ_QSPI)(); | ||
|
||
// In the current implementation we do not allow handlers | ||
// for the same line (pin) for more than a single core. | ||
static Handler handlers[Lines]; | ||
|
||
static constexpr Gpio::Port | ||
gpioPort() | ||
{ | ||
%% if with_gpio | ||
if constexpr (Type == IO_IRQ_BANK0_IRQn) { return Gpio::Port::Bank0; } | ||
%%endif | ||
%% if with_qspi | ||
if constexpr (Type == IO_IRQ_QSPI_IRQn) { return Gpio::Port::Qspi; } | ||
%%endif | ||
return static_cast<Gpio::Port>(-1); | ||
} | ||
}; | ||
|
||
%% if with_gpio | ||
using GpioIntHandler = IntHandler<IO_IRQ_BANK0_IRQn, NUM_BANK0_GPIOS>; | ||
%%endif | ||
%% if with_qspi | ||
using QspiIntHandler = IntHandler<IO_IRQ_QSPI_IRQn, NUM_QSPI_GPIOS>; | ||
%%endif | ||
|
||
} // namespace modm::platform |
Oops, something went wrong.