-
Notifications
You must be signed in to change notification settings - Fork 134
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 18, 2022
1 parent
27d34e7
commit 599e0ba
Showing
10 changed files
with
511 additions
and
2 deletions.
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,38 @@ | ||
/* | ||
* 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(); | ||
|
||
// Powers on the LED on the low->high transition, and off on high->low. | ||
GpioInput0::setInput(); | ||
IntHandler::connect<GpioInput0>(Gpio::InputTrigger::BothEdges, | ||
[](Gpio::InputTrigger_t triggers) { | ||
Led::set(!!(triggers & Gpio::InputTrigger::RisingEdge)); | ||
}); | ||
|
||
// Toggles LED each time gpio input is at the high level. | ||
GpioInput1::setInput(Gpio::InputType::PullDown); | ||
IntHandler::connect<GpioInput1>(Gpio::InputTrigger::HighLevel, | ||
[](Gpio::InputTrigger_t) { 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,10 @@ | ||
<library> | ||
<extends>modm:rp-pico</extends> | ||
<options> | ||
<option name="modm:build:build.path">../../../build/rp_pico/interrupt</option> | ||
</options> | ||
<modules> | ||
<module>modm:platform:extint</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,98 @@ | ||
/* | ||
* 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/extint/int_handler.hpp> | ||
|
||
namespace modm::platform | ||
{ | ||
|
||
%% if with_bank0 | ||
void | ||
IntHandler::irqBank0Handler() | ||
{ | ||
using PortRegs = Gpio::PortRegs<Gpio::Port::Bank0>; | ||
|
||
static_assert(0b1111u == static_cast<uint32_t>(Gpio::InputTrigger::All)); | ||
|
||
%% if multicore_enabled | ||
auto& proc_irq_ctrl = sio_hw->cpuid ? iobank0_hw->proc1_irq_ctrl : iobank0_hw->proc0_irq_ctrl; | ||
%% else | ||
auto& proc_irq_ctrl = iobank0_hw->proc0_irq_ctrl; | ||
%% endif | ||
|
||
for (size_t group = 0; group < NUM_BANK0_GPIOS / 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 = bank0Handlers[pin]) | ||
{ | ||
handler(static_cast<Gpio::InputTrigger>(triggers)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
%% endif | ||
|
||
%% if with_qspi | ||
void | ||
IntHandler::irqQspiHandler() | ||
{ | ||
using PortRegs = Gpio::PortRegs<Gpio::Port::Qspi>; | ||
|
||
static_assert(NUM_QSPI_GPIOS <= 8); | ||
static_assert(0b1111u == static_cast<uint32_t>(Gpio::InputTrigger::All)); | ||
|
||
%% if multicore_enabled | ||
auto& proc_irq_ctrl = sio_hw->cpuid ? ioqspi_hw->proc1_qspi_ctrl : ioqspi_hw->proc0_qspi_ctrl; | ||
%% else | ||
auto& proc_irq_ctrl = ioqspi_hw->proc0_qspi_ctrl; | ||
%% endif | ||
|
||
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 = qspiHandlers[pin]) | ||
{ | ||
handler(static_cast<Gpio::InputTrigger>(triggers)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
%% endif | ||
|
||
%% for type in types | ||
IntHandler::Handler | ||
IntHandler::{{type}}Handlers[NUM_{{type | upper}}_GPIOS] modm_fastdata; | ||
|
||
%% endfor | ||
|
||
%% for type in types | ||
MODM_ISR(IO_IRQ_{{type | upper}}) | ||
{ | ||
IntHandler::irq{{type | capitalize}}Handler(); | ||
} | ||
|
||
%% endfor | ||
|
||
} // 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,145 @@ | ||
/* | ||
* 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/extint/int_priority.hpp> | ||
#include <modm/platform/gpio/base.hpp> | ||
#include <modm/utils/inplace_function.hpp> | ||
|
||
#include <RP2040.h> | ||
|
||
#if defined __DOXYGEN__ || !defined MODM_EXTINT_HANDLER_STORAGE | ||
/// @ingroup modm_platform_extint | ||
#define MODM_EXTINT_HANDLER_STORAGE sizeof(void*) | ||
#endif | ||
|
||
namespace modm::platform | ||
{ | ||
|
||
%% for type in types | ||
MODM_ISR_DECL(IO_IRQ_{{type | upper}}); | ||
%% endfor | ||
|
||
/** | ||
* Interrupt Handler | ||
* | ||
* @ingroup modm_platform_extint | ||
*/ | ||
class IntHandler | ||
{ | ||
public: | ||
using Handler = modm::inplace_function<void(Gpio::InputTrigger_t), MODM_EXTINT_HANDLER_STORAGE, alignof(void*)>; | ||
|
||
public: | ||
static void | ||
enable(IRQn_Type type, IntPriority priority = IntPriority::Default) | ||
{ | ||
if (!NVIC_GetEnableIRQ(type)) | ||
{ | ||
if (priority != static_cast<IntPriority>(NVIC_GetPriority(type))) | ||
{ | ||
NVIC_SetPriority(type, priority); | ||
} | ||
NVIC_ClearPendingIRQ(type); | ||
NVIC_EnableIRQ(type); | ||
} | ||
} | ||
|
||
static void | ||
disable(IRQn_Type type) | ||
{ | ||
NVIC_DisableIRQ(type); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
connect(Gpio::InputTrigger_t triggers, Handler&& handler) | ||
{ | ||
constexpr const auto type = irqType<Pin::port>(); | ||
static_assert(0 <= type, "Support for this Pin's Port is not enabled!"); | ||
|
||
enable(type); | ||
|
||
disableInterrupts<Pin>(Gpio::InputTrigger::All); | ||
acknowledgeInterrupts<Pin>(Gpio::InputTrigger::All); | ||
|
||
irqHandler<Pin::port>(Pin::pin) = handler; | ||
|
||
enableInterrupts<Pin>(triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
disconnect() | ||
{ | ||
static_assert(0 <= irqType<Pin::port>(), "Support for this Pin's Port is not enabled!"); | ||
|
||
disableInterrupts<Pin>(Gpio::InputTrigger::All); | ||
irqHandler<Pin::port>(Pin::pin) = nullptr; | ||
} | ||
|
||
private: | ||
template<class Pin> | ||
static void | ||
enableInterrupts(Gpio::InputTrigger_t triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::enable_irq(Pin::pin, triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
disableInterrupts(Gpio::InputTrigger_t triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::disable_irq(Pin::pin, triggers); | ||
} | ||
|
||
template<class Pin> | ||
static void | ||
acknowledgeInterrupts(Gpio::InputTrigger_t triggers) | ||
{ | ||
Gpio::PortRegs<Pin::port>::acknowledge_irq(Pin::pin, triggers); | ||
} | ||
|
||
%% for type in types | ||
static void | ||
irq{{type | capitalize}}Handler(); | ||
friend void MODM_ISR_NAME(IO_IRQ_{{type | upper}})(); | ||
|
||
// In the current implementation we do not allow handlers | ||
// for the same line (pin) for more than a single core. | ||
static Handler {{type}}Handlers[NUM_{{type | upper}}_GPIOS]; | ||
|
||
%% endfor | ||
|
||
template <Gpio::Port port> | ||
static constexpr IRQn_Type | ||
irqType() | ||
{ | ||
%% for type in types | ||
if constexpr (port == Gpio::Port::{{type | capitalize}}) { return IO_IRQ_{{type | upper}}_IRQn; } | ||
%% endfor | ||
return static_cast<IRQn_Type>(-99); | ||
} | ||
|
||
template <Gpio::Port port> | ||
static constexpr Handler& | ||
irqHandler(uint8_t pin) | ||
{ | ||
%% for type in types | ||
if constexpr (port == Gpio::Port::{{type | capitalize}}) { return {{type}}Handlers[pin]; } | ||
%% endfor | ||
return *static_cast<Handler*>(nullptr); | ||
} | ||
}; | ||
|
||
} // 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,39 @@ | ||
/* | ||
* 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 <cstdint> | ||
|
||
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_extint | ||
*/ | ||
enum IntPriority : uint8_t | ||
{ | ||
Highest = 0x00, | ||
Default = 0x80, | ||
Lowest = 0xff, | ||
}; | ||
|
||
} // namespace modm::platform |
Oops, something went wrong.