Skip to content

Commit 599e0ba

Browse files
author
cocasema
committed
[rp2040] Implement IRQ handlers for GPIO and QSPI
Based on discussion #847
1 parent 27d34e7 commit 599e0ba

File tree

10 files changed

+511
-2
lines changed

10 files changed

+511
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
276276
<td align="center">✅</td>
277277
<td align="center">○</td>
278278
<td align="center">○</td>
279-
<td align="center"></td>
279+
<td align="center"></td>
280280
<td align="center">✅</td>
281281
<td align="center">✅</td>
282282
<td align="center">✅</td>

examples/rp_pico/interrupt/main.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2022, Nikolay Semenov
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include <modm/board.hpp>
13+
14+
int
15+
main()
16+
{
17+
Board::initialize();
18+
19+
using Led = Board::LedGreen;
20+
Led::setOutput();
21+
Led::set();
22+
23+
// Powers on the LED on the low->high transition, and off on high->low.
24+
GpioInput0::setInput();
25+
IntHandler::connect<GpioInput0>(Gpio::InputTrigger::BothEdges,
26+
[](Gpio::InputTrigger_t triggers) {
27+
Led::set(!!(triggers & Gpio::InputTrigger::RisingEdge));
28+
});
29+
30+
// Toggles LED each time gpio input is at the high level.
31+
GpioInput1::setInput(Gpio::InputType::PullDown);
32+
IntHandler::connect<GpioInput1>(Gpio::InputTrigger::HighLevel,
33+
[](Gpio::InputTrigger_t) { Led::toggle(); });
34+
35+
while (true) {}
36+
37+
return 0;
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<library>
2+
<extends>modm:rp-pico</extends>
3+
<options>
4+
<option name="modm:build:build.path">../../../build/rp_pico/interrupt</option>
5+
</options>
6+
<modules>
7+
<module>modm:platform:extint</module>
8+
<module>modm:build:scons</module>
9+
</modules>
10+
</library>
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) 2022, Nikolay Semenov
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include <modm/platform/extint/int_handler.hpp>
13+
14+
namespace modm::platform
15+
{
16+
17+
%% if with_bank0
18+
void
19+
IntHandler::irqBank0Handler()
20+
{
21+
using PortRegs = Gpio::PortRegs<Gpio::Port::Bank0>;
22+
23+
static_assert(0b1111u == static_cast<uint32_t>(Gpio::InputTrigger::All));
24+
25+
%% if multicore_enabled
26+
auto& proc_irq_ctrl = sio_hw->cpuid ? iobank0_hw->proc1_irq_ctrl : iobank0_hw->proc0_irq_ctrl;
27+
%% else
28+
auto& proc_irq_ctrl = iobank0_hw->proc0_irq_ctrl;
29+
%% endif
30+
31+
for (size_t group = 0; group < NUM_BANK0_GPIOS / 8; ++group)
32+
{
33+
if (uint32_t int_status = proc_irq_ctrl.ints[group])
34+
{
35+
for (uint8_t pin = group * 8; int_status; ++pin, int_status >>= 4)
36+
{
37+
if (uint32_t triggers = int_status & 0b1111u)
38+
{
39+
PortRegs::acknowledge_irq(pin, static_cast<Gpio::InputTrigger>(triggers));
40+
if (auto& handler = bank0Handlers[pin])
41+
{
42+
handler(static_cast<Gpio::InputTrigger>(triggers));
43+
}
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
%% endif
51+
52+
%% if with_qspi
53+
void
54+
IntHandler::irqQspiHandler()
55+
{
56+
using PortRegs = Gpio::PortRegs<Gpio::Port::Qspi>;
57+
58+
static_assert(NUM_QSPI_GPIOS <= 8);
59+
static_assert(0b1111u == static_cast<uint32_t>(Gpio::InputTrigger::All));
60+
61+
%% if multicore_enabled
62+
auto& proc_irq_ctrl = sio_hw->cpuid ? ioqspi_hw->proc1_qspi_ctrl : ioqspi_hw->proc0_qspi_ctrl;
63+
%% else
64+
auto& proc_irq_ctrl = ioqspi_hw->proc0_qspi_ctrl;
65+
%% endif
66+
67+
uint32_t int_status = proc_irq_ctrl.ints;
68+
69+
for (uint8_t pin = 0; int_status; ++pin, int_status >>= 4)
70+
{
71+
if (uint32_t triggers = int_status & 0b1111u)
72+
{
73+
PortRegs::acknowledge_irq(pin, static_cast<Gpio::InputTrigger>(triggers));
74+
if (auto& handler = qspiHandlers[pin])
75+
{
76+
handler(static_cast<Gpio::InputTrigger>(triggers));
77+
}
78+
}
79+
}
80+
}
81+
82+
%% endif
83+
84+
%% for type in types
85+
IntHandler::Handler
86+
IntHandler::{{type}}Handlers[NUM_{{type | upper}}_GPIOS] modm_fastdata;
87+
88+
%% endfor
89+
90+
%% for type in types
91+
MODM_ISR(IO_IRQ_{{type | upper}})
92+
{
93+
IntHandler::irq{{type | capitalize}}Handler();
94+
}
95+
96+
%% endfor
97+
98+
} // namespace modm::platform
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (c) 2022, Nikolay Semenov
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#pragma once
13+
14+
#include <modm/architecture/interface/interrupt.hpp>
15+
#include <modm/platform/extint/int_priority.hpp>
16+
#include <modm/platform/gpio/base.hpp>
17+
#include <modm/utils/inplace_function.hpp>
18+
19+
#include <RP2040.h>
20+
21+
#if defined __DOXYGEN__ || !defined MODM_EXTINT_HANDLER_STORAGE
22+
/// @ingroup modm_platform_extint
23+
#define MODM_EXTINT_HANDLER_STORAGE sizeof(void*)
24+
#endif
25+
26+
namespace modm::platform
27+
{
28+
29+
%% for type in types
30+
MODM_ISR_DECL(IO_IRQ_{{type | upper}});
31+
%% endfor
32+
33+
/**
34+
* Interrupt Handler
35+
*
36+
* @ingroup modm_platform_extint
37+
*/
38+
class IntHandler
39+
{
40+
public:
41+
using Handler = modm::inplace_function<void(Gpio::InputTrigger_t), MODM_EXTINT_HANDLER_STORAGE, alignof(void*)>;
42+
43+
public:
44+
static void
45+
enable(IRQn_Type type, IntPriority priority = IntPriority::Default)
46+
{
47+
if (!NVIC_GetEnableIRQ(type))
48+
{
49+
if (priority != static_cast<IntPriority>(NVIC_GetPriority(type)))
50+
{
51+
NVIC_SetPriority(type, priority);
52+
}
53+
NVIC_ClearPendingIRQ(type);
54+
NVIC_EnableIRQ(type);
55+
}
56+
}
57+
58+
static void
59+
disable(IRQn_Type type)
60+
{
61+
NVIC_DisableIRQ(type);
62+
}
63+
64+
template<class Pin>
65+
static void
66+
connect(Gpio::InputTrigger_t triggers, Handler&& handler)
67+
{
68+
constexpr const auto type = irqType<Pin::port>();
69+
static_assert(0 <= type, "Support for this Pin's Port is not enabled!");
70+
71+
enable(type);
72+
73+
disableInterrupts<Pin>(Gpio::InputTrigger::All);
74+
acknowledgeInterrupts<Pin>(Gpio::InputTrigger::All);
75+
76+
irqHandler<Pin::port>(Pin::pin) = handler;
77+
78+
enableInterrupts<Pin>(triggers);
79+
}
80+
81+
template<class Pin>
82+
static void
83+
disconnect()
84+
{
85+
static_assert(0 <= irqType<Pin::port>(), "Support for this Pin's Port is not enabled!");
86+
87+
disableInterrupts<Pin>(Gpio::InputTrigger::All);
88+
irqHandler<Pin::port>(Pin::pin) = nullptr;
89+
}
90+
91+
private:
92+
template<class Pin>
93+
static void
94+
enableInterrupts(Gpio::InputTrigger_t triggers)
95+
{
96+
Gpio::PortRegs<Pin::port>::enable_irq(Pin::pin, triggers);
97+
}
98+
99+
template<class Pin>
100+
static void
101+
disableInterrupts(Gpio::InputTrigger_t triggers)
102+
{
103+
Gpio::PortRegs<Pin::port>::disable_irq(Pin::pin, triggers);
104+
}
105+
106+
template<class Pin>
107+
static void
108+
acknowledgeInterrupts(Gpio::InputTrigger_t triggers)
109+
{
110+
Gpio::PortRegs<Pin::port>::acknowledge_irq(Pin::pin, triggers);
111+
}
112+
113+
%% for type in types
114+
static void
115+
irq{{type | capitalize}}Handler();
116+
friend void MODM_ISR_NAME(IO_IRQ_{{type | upper}})();
117+
118+
// In the current implementation we do not allow handlers
119+
// for the same line (pin) for more than a single core.
120+
static Handler {{type}}Handlers[NUM_{{type | upper}}_GPIOS];
121+
122+
%% endfor
123+
124+
template <Gpio::Port port>
125+
static constexpr IRQn_Type
126+
irqType()
127+
{
128+
%% for type in types
129+
if constexpr (port == Gpio::Port::{{type | capitalize}}) { return IO_IRQ_{{type | upper}}_IRQn; }
130+
%% endfor
131+
return static_cast<IRQn_Type>(-99);
132+
}
133+
134+
template <Gpio::Port port>
135+
static constexpr Handler&
136+
irqHandler(uint8_t pin)
137+
{
138+
%% for type in types
139+
if constexpr (port == Gpio::Port::{{type | capitalize}}) { return {{type}}Handlers[pin]; }
140+
%% endfor
141+
return *static_cast<Handler*>(nullptr);
142+
}
143+
};
144+
145+
} // namespace modm::platform
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2022, Nikolay Semenov
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#pragma once
13+
14+
#include <cstdint>
15+
16+
namespace modm::platform
17+
{
18+
19+
/**
20+
* Priority level of 0-192 in steps of 64 for each interrupt.
21+
* A higher level corresponds to a lower priority,
22+
* so level 0 is the highest programmable interrupt priority.
23+
* ...
24+
* The processor implements only bits[7:6] of each field, bits [5:0] read as zero and ignore writes.
25+
* This means writing 255 to a priority register saves value 192 to the register.
26+
*
27+
* https://developer.arm.com/documentation/dui0662/b/Cortex-M0--Peripherals/Nested-Vectored-Interrupt-Controller
28+
* https://developer.arm.com/documentation/dui0662/b/Cortex-M0--Peripherals/Nested-Vectored-Interrupt-Controller/Interrupt-Priority-Registers
29+
*
30+
* @ingroup modm_platform_extint
31+
*/
32+
enum IntPriority : uint8_t
33+
{
34+
Highest = 0x00,
35+
Default = 0x80,
36+
Lowest = 0xff,
37+
};
38+
39+
} // namespace modm::platform

0 commit comments

Comments
 (0)