Skip to content

Commit a5fea4a

Browse files
author
Henrik Alsér
committed
Add GPIOTE module
1 parent 04f23f6 commit a5fea4a

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed

nrf-hal-common/src/gpiote.rs

Lines changed: 385 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
#[cfg(feature = "51")]
2+
use crate::target::{gpio, GPIO as P0};
3+
4+
#[cfg(not(feature = "51"))]
5+
use crate::target::{p0 as gpio, P0};
6+
7+
#[cfg(any(feature = "52833", feature = "52840"))]
8+
use crate::target::P1;
9+
10+
use {
11+
crate::gpio::{
12+
Floating, Input, Level, OpenDrain, Output, Pin, Port, PullDown, PullUp, PushPull,
13+
},
14+
crate::target::gpiote::{_EVENTS_IN, _EVENTS_PORT, _TASKS_OUT},
15+
crate::target::{generic::Reg, GPIOTE},
16+
};
17+
18+
#[cfg(not(feature = "51"))]
19+
use crate::target::gpiote::{_TASKS_CLR, _TASKS_SET};
20+
21+
#[cfg(not(feature = "51"))]
22+
const NUM_CHANNELS: usize = 8;
23+
#[cfg(feature = "51")]
24+
const NUM_CHANNELS: usize = 4;
25+
26+
pub struct Gpiote {
27+
gpiote: GPIOTE,
28+
}
29+
30+
impl Gpiote {
31+
pub fn new(gpiote: GPIOTE) -> Self {
32+
Self { gpiote }
33+
}
34+
35+
pub fn channel(&self, channel: usize) -> GpioteChannel {
36+
GpioteChannel {
37+
gpiote: &self.gpiote,
38+
channel,
39+
}
40+
}
41+
42+
pub fn port(&self) -> GpiotePort {
43+
GpiotePort {
44+
gpiote: &self.gpiote,
45+
}
46+
}
47+
48+
pub fn reset_events(&self) {
49+
// Mark all events as handled
50+
(0..NUM_CHANNELS).for_each(|ch| self.gpiote.events_in[ch].write(|w| w));
51+
self.gpiote.events_port.write(|w| w);
52+
}
53+
54+
pub fn free(self) -> GPIOTE {
55+
self.gpiote
56+
}
57+
}
58+
59+
pub struct GpioteChannel<'a> {
60+
gpiote: &'a GPIOTE,
61+
channel: usize,
62+
}
63+
64+
impl<'a> GpioteChannel<'_> {
65+
pub fn input_pin<P: GpioteInputPin>(&'a self, pin: &'a P) -> GpioteChannelEvent<'a, P> {
66+
GpioteChannelEvent {
67+
gpiote: &self.gpiote,
68+
pin: pin,
69+
channel: self.channel,
70+
}
71+
}
72+
73+
pub fn output_pin<P: GpioteOutputPin>(&'a self, pin: &'a P) -> GpioteTask<'a, P> {
74+
GpioteTask {
75+
gpiote: &self.gpiote,
76+
pin: pin,
77+
channel: self.channel,
78+
task_out_polarity: TaskOutPolarity::Toggle,
79+
}
80+
}
81+
82+
pub fn reset_events(&self) {
83+
self.gpiote.events_in[self.channel].write(|w| w);
84+
}
85+
86+
pub fn out(&self) {
87+
self.gpiote.tasks_out[self.channel].write(|w| unsafe { w.bits(1) });
88+
}
89+
90+
#[cfg(not(feature = "51"))]
91+
pub fn set(&self) {
92+
self.gpiote.tasks_set[self.channel].write(|w| unsafe { w.bits(1) });
93+
}
94+
95+
#[cfg(not(feature = "51"))]
96+
pub fn clear(&self) {
97+
self.gpiote.tasks_clr[self.channel].write(|w| unsafe { w.bits(1) });
98+
}
99+
100+
pub fn event(&self) -> &Reg<u32, _EVENTS_IN> {
101+
// Return reference to event for PPI
102+
&self.gpiote.events_in[self.channel]
103+
}
104+
105+
pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> {
106+
// Return reference to task_out for PPI
107+
&self.gpiote.tasks_out[self.channel]
108+
}
109+
110+
#[cfg(not(feature = "51"))]
111+
pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> {
112+
// Return reference to task_clr for PPI
113+
&self.gpiote.tasks_clr[self.channel]
114+
}
115+
116+
#[cfg(not(feature = "51"))]
117+
pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> {
118+
// Return reference to task_set for PPI
119+
&self.gpiote.tasks_set[self.channel]
120+
}
121+
}
122+
123+
pub struct GpiotePort<'a> {
124+
gpiote: &'a GPIOTE,
125+
}
126+
127+
impl<'a> GpiotePort<'_> {
128+
pub fn input_pin<P: GpioteInputPin>(&'a self, pin: &'a P) -> GpiotePortEvent<'a, P> {
129+
GpiotePortEvent { pin }
130+
}
131+
pub fn enable_interrupt(&self) {
132+
// Enable port interrupt
133+
self.gpiote.intenset.write(|w| w.port().set());
134+
}
135+
pub fn disable_interrupt(&self) {
136+
// Disable port interrupt
137+
self.gpiote.intenclr.write(|w| w.port().set_bit());
138+
}
139+
pub fn reset_events(&self) {
140+
// Mark port events as handled
141+
self.gpiote.events_port.write(|w| w);
142+
}
143+
pub fn event(&self) -> &Reg<u32, _EVENTS_PORT> {
144+
// Return reference to event for PPI
145+
&self.gpiote.events_port
146+
}
147+
}
148+
149+
pub struct GpioteChannelEvent<'a, P: GpioteInputPin> {
150+
gpiote: &'a GPIOTE,
151+
pin: &'a P,
152+
channel: usize,
153+
}
154+
155+
impl<'a, P: GpioteInputPin> GpioteChannelEvent<'_, P> {
156+
pub fn hi_to_lo(&self, enable_interrupt: bool) {
157+
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::HiToLo);
158+
if enable_interrupt {
159+
self.enable_interrupt();
160+
} else {
161+
self.disable_interrupt();
162+
}
163+
}
164+
165+
pub fn lo_to_hi(&self, enable_interrupt: bool) {
166+
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::LoToHi);
167+
if enable_interrupt {
168+
self.enable_interrupt();
169+
} else {
170+
self.disable_interrupt();
171+
}
172+
}
173+
174+
pub fn toggle(&self, enable_interrupt: bool) {
175+
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::Toggle);
176+
if enable_interrupt {
177+
self.enable_interrupt();
178+
} else {
179+
self.disable_interrupt();
180+
}
181+
}
182+
183+
pub fn none(&self, enable_interrupt: bool) {
184+
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::None);
185+
if enable_interrupt {
186+
self.enable_interrupt();
187+
} else {
188+
self.disable_interrupt();
189+
}
190+
}
191+
192+
pub fn enable_interrupt(&self) {
193+
// Enable interrupt for pin
194+
unsafe {
195+
self.gpiote
196+
.intenset
197+
.modify(|r, w| w.bits(r.bits() | self.pin.pin() as u32))
198+
}
199+
}
200+
201+
pub fn disable_interrupt(&self) {
202+
// Disable interrupt for pin
203+
unsafe {
204+
self.gpiote
205+
.intenclr
206+
.modify(|r, w| w.bits(r.bits() | self.pin.pin() as u32))
207+
}
208+
}
209+
}
210+
211+
fn config_channel_event_pin<P: GpioteInputPin>(
212+
gpiote: &GPIOTE,
213+
channel: usize,
214+
pin: &P,
215+
trigger_mode: EventPolarity,
216+
) {
217+
// Config pin as event-triggering input for specified edge transition trigger mode
218+
gpiote.config[channel].write(|w| {
219+
match trigger_mode {
220+
EventPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
221+
EventPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
222+
EventPolarity::None => w.mode().event().polarity().none(),
223+
EventPolarity::Toggle => w.mode().event().polarity().toggle(),
224+
};
225+
unsafe { w.psel().bits(pin.pin()) }
226+
});
227+
}
228+
229+
pub struct GpiotePortEvent<'a, P: GpioteInputPin> {
230+
pin: &'a P,
231+
}
232+
233+
impl<'a, P: GpioteInputPin> GpiotePortEvent<'_, P> {
234+
pub fn low(&self) {
235+
config_port_event_pin(self.pin, PortEventSense::Low);
236+
}
237+
pub fn high(&self) {
238+
config_port_event_pin(self.pin, PortEventSense::High);
239+
}
240+
pub fn disabled(&self) {
241+
config_port_event_pin(self.pin, PortEventSense::Disabled);
242+
}
243+
}
244+
245+
fn config_port_event_pin<P: GpioteInputPin>(pin: &P, sense: PortEventSense) {
246+
// Set pin sense to specified mode to trigger port events
247+
unsafe {
248+
&(*{
249+
match pin.port() {
250+
Port::Port0 => P0::ptr(),
251+
#[cfg(any(feature = "52833", feature = "52840"))]
252+
Port::Port1 => P1::ptr(),
253+
}
254+
})
255+
.pin_cnf[pin.pin() as usize]
256+
}
257+
.modify(|_r, w| match sense {
258+
PortEventSense::Disabled => w.sense().disabled(),
259+
PortEventSense::High => w.sense().high(),
260+
PortEventSense::Low => w.sense().low(),
261+
});
262+
}
263+
264+
pub struct GpioteTask<'a, P: GpioteOutputPin> {
265+
gpiote: &'a GPIOTE,
266+
pin: &'a P,
267+
channel: usize,
268+
task_out_polarity: TaskOutPolarity,
269+
}
270+
271+
impl<'a, P: GpioteOutputPin> GpioteTask<'_, P> {
272+
pub fn init_high(&self) {
273+
config_channel_task_pin(
274+
self.gpiote,
275+
self.channel,
276+
self.pin,
277+
&self.task_out_polarity,
278+
Level::High,
279+
);
280+
}
281+
282+
pub fn init_low(&self) {
283+
config_channel_task_pin(
284+
self.gpiote,
285+
self.channel,
286+
self.pin,
287+
&self.task_out_polarity,
288+
Level::Low,
289+
);
290+
}
291+
292+
pub fn task_out_polarity(&mut self, polarity: TaskOutPolarity) -> &mut Self {
293+
self.task_out_polarity = polarity;
294+
self
295+
}
296+
}
297+
298+
fn config_channel_task_pin<P: GpioteOutputPin>(
299+
gpiote: &GPIOTE,
300+
channel: usize,
301+
pin: &P,
302+
task_out_polarity: &TaskOutPolarity,
303+
init_out: Level,
304+
) {
305+
// Config pin as task output with specified initial state and task out polarity
306+
gpiote.config[channel].write(|w| {
307+
match init_out {
308+
Level::High => w.mode().task().outinit().high(),
309+
Level::Low => w.mode().task().outinit().low(),
310+
};
311+
match task_out_polarity {
312+
TaskOutPolarity::Set => w.polarity().lo_to_hi(),
313+
TaskOutPolarity::Clear => w.polarity().hi_to_lo(),
314+
TaskOutPolarity::Toggle => w.polarity().toggle(),
315+
};
316+
unsafe { w.psel().bits(pin.pin()) }
317+
});
318+
}
319+
320+
pub enum TaskOutPolarity {
321+
Set,
322+
Clear,
323+
Toggle,
324+
}
325+
326+
pub enum EventPolarity {
327+
None,
328+
HiToLo,
329+
LoToHi,
330+
Toggle,
331+
}
332+
333+
pub enum PortEventSense {
334+
Disabled,
335+
High,
336+
Low,
337+
}
338+
339+
pub trait GpioteInputPin {
340+
fn pin(&self) -> u8;
341+
fn port(&self) -> Port;
342+
}
343+
344+
impl GpioteInputPin for Pin<Input<PullUp>> {
345+
fn pin(&self) -> u8 {
346+
self.pin()
347+
}
348+
fn port(&self) -> Port {
349+
self.port()
350+
}
351+
}
352+
353+
impl GpioteInputPin for Pin<Input<PullDown>> {
354+
fn pin(&self) -> u8 {
355+
self.pin()
356+
}
357+
fn port(&self) -> Port {
358+
self.port()
359+
}
360+
}
361+
362+
impl GpioteInputPin for Pin<Input<Floating>> {
363+
fn pin(&self) -> u8 {
364+
self.pin()
365+
}
366+
fn port(&self) -> Port {
367+
self.port()
368+
}
369+
}
370+
371+
pub trait GpioteOutputPin {
372+
fn pin(&self) -> u8;
373+
}
374+
375+
impl GpioteOutputPin for Pin<Output<OpenDrain>> {
376+
fn pin(&self) -> u8 {
377+
self.pin()
378+
}
379+
}
380+
381+
impl GpioteOutputPin for Pin<Output<PushPull>> {
382+
fn pin(&self) -> u8 {
383+
self.pin()
384+
}
385+
}

nrf-hal-common/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub mod delay;
3131
pub mod ecb;
3232
pub mod gpio;
3333
#[cfg(not(feature = "9160"))]
34+
pub mod gpiote;
35+
#[cfg(not(feature = "9160"))]
3436
pub mod ppi;
3537
#[cfg(not(feature = "9160"))]
3638
pub mod rng;

0 commit comments

Comments
 (0)