Skip to content

Commit 9e8e1d8

Browse files
author
Henrik Alsér
committed
Add example with interrupt and PPI usage with onboard buttons and led for nRF52840-DK
1 parent f65bb15 commit 9e8e1d8

File tree

5 files changed

+184
-17
lines changed

5 files changed

+184
-17
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ members = [
1616
"examples/ecb-demo",
1717
"examples/ccm-demo",
1818
"examples/ppi-demo",
19+
"examples/gpiote-demo",
1920
]
2021

2122
[profile.dev]

examples/gpiote-demo/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "gpiote-demo"
3+
version = "0.1.0"
4+
authors = ["Henrik Alsér"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
cortex-m = "0.6.2"
11+
cortex-m-rtic = "0.5.3"
12+
rtt-target = {version = "0.2.0", features = ["cortex-m"] }
13+
nrf52840-hal = { version = "0.10", features = ["rt"], path = "../../nrf52840-hal" }
14+
15+
[dependencies.embedded-hal]
16+
version = "0.2.3"
17+
features = ["unproven"]

examples/gpiote-demo/Embed.toml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[probe]
2+
# The index of the probe in the connected probe list.
3+
# probe_index = 0
4+
# The protocol to be used for communicating with the target.
5+
protocol = "Swd"
6+
# The speed in kHz of the data link to the target.
7+
# speed = 1337
8+
9+
[flashing]
10+
# Whether or not the target should be flashed.
11+
enabled = true
12+
# Whether or not the target should be halted after flashing.
13+
halt_afterwards = false
14+
# Whether or not bytes erased but not rewritten with data from the ELF
15+
# should be restored with their contents before erasing.
16+
restore_unwritten_bytes = false
17+
# The path where an SVG of the assembled flash layout should be written to.
18+
# flash_layout_output_path = "out.svg"
19+
20+
[general]
21+
# The chip name of the chip to be debugged.
22+
chip = "nRF52840"
23+
# A list of chip descriptions to be loaded during runtime.
24+
chip_descriptions = []
25+
# The default log level to be used.
26+
log_level = "Warn"
27+
28+
[rtt]
29+
# Whether or not an RTTUI should be opened after flashing.
30+
# This is exclusive and cannot be used with GDB at the moment.
31+
enabled = true
32+
# A list of channel associations to be displayed. If left empty, all channels are displayed.
33+
channels = [
34+
# { up = 0, down = 0, name = "name" }
35+
]
36+
# The duration in ms for which the logger should retry to attach to RTT.
37+
timeout = 3000
38+
# Whether timestamps in the RTTUI are enabled
39+
show_timestamps = true
40+
41+
[gdb]
42+
# Whether or not a GDB server should be opened after flashing.
43+
# This is exclusive and cannot be used with RTT at the moment.
44+
enabled = false
45+
# The connection string in host:port format wher the GDB server will open a socket.
46+
# gdb_connection_string

examples/gpiote-demo/src/main.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use embedded_hal::digital::v2::InputPin;
5+
use {
6+
core::{
7+
panic::PanicInfo,
8+
sync::atomic::{compiler_fence, Ordering},
9+
},
10+
hal::{
11+
gpio::{Input, Level, Pin, PullUp},
12+
gpiote::*,
13+
ppi::{self, ConfigurablePpi, Ppi},
14+
},
15+
nrf52840_hal as hal,
16+
rtic::cyccnt::U32Ext,
17+
rtt_target::{rprintln, rtt_init_print},
18+
};
19+
20+
#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
21+
const APP: () = {
22+
struct Resources {
23+
gpiote: Gpiote,
24+
btn1: Pin<Input<PullUp>>,
25+
btn2: Pin<Input<PullUp>>,
26+
btn3: Pin<Input<PullUp>>,
27+
btn4: Pin<Input<PullUp>>,
28+
}
29+
30+
#[init]
31+
fn init(mut ctx: init::Context) -> init::LateResources {
32+
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
33+
rtt_init_print!();
34+
let p0 = hal::gpio::p0::Parts::new(ctx.device.P0);
35+
let btn1 = p0.p0_11.into_pullup_input().degrade();
36+
let btn2 = p0.p0_12.into_pullup_input().degrade();
37+
let btn3 = p0.p0_24.into_pullup_input().degrade();
38+
let btn4 = p0.p0_25.into_pullup_input().degrade();
39+
let led1 = p0.p0_13.into_push_pull_output(Level::High).degrade();
40+
41+
let gpiote = Gpiote::new(ctx.device.GPIOTE);
42+
43+
// Set btn1 to generate event on channel 0 and enable interrupt
44+
gpiote.channel(0).input_pin(&btn1).hi_to_lo(true);
45+
46+
// Set both btn3 & btn4 to generate port event
47+
gpiote.port().input_pin(&btn3).low();
48+
gpiote.port().input_pin(&btn4).low();
49+
// Enable interrupt for port event
50+
gpiote.port().enable_interrupt();
51+
52+
// PPI usage, channel 2 event triggers "task out" (toggle) on channel 1 (toggles led1)
53+
gpiote.channel(1).output_pin(&led1).task_out_polarity(TaskOutPolarity::Toggle).init_high();
54+
gpiote.channel(2).input_pin(&btn2).hi_to_lo(false);
55+
let ppi_channels = ppi::Parts::new(ctx.device.PPI);
56+
let mut channel0 = ppi_channels.ppi0;
57+
channel0.set_task_endpoint(gpiote.channel(1).task_out());
58+
channel0.set_event_endpoint(gpiote.channel(2).event());
59+
channel0.enable();
60+
61+
// Enable the monotonic timer (CYCCNT)
62+
ctx.core.DCB.enable_trace();
63+
ctx.core.DWT.enable_cycle_counter();
64+
65+
rprintln!("Press a button");
66+
67+
init::LateResources {
68+
gpiote,
69+
btn1,
70+
btn2,
71+
btn3,
72+
btn4,
73+
}
74+
}
75+
76+
#[idle]
77+
fn idle(_: idle::Context) -> ! {
78+
loop {
79+
cortex_m::asm::wfi();
80+
}
81+
}
82+
83+
#[task(binds = GPIOTE, resources = [gpiote], schedule = [debounce])]
84+
fn on_gpiote(ctx: on_gpiote::Context) {
85+
// Reset all events
86+
ctx.resources.gpiote.reset_events();
87+
// Debounce
88+
ctx.schedule.debounce(ctx.start + 3_000_000.cycles()).ok();
89+
}
90+
91+
#[task(resources = [gpiote, btn1, btn2, btn3, btn4])]
92+
fn debounce(ctx: debounce::Context) {
93+
let btn1_pressed = ctx.resources.btn1.is_low().unwrap();
94+
let btn2_pressed = ctx.resources.btn2.is_low().unwrap();
95+
let btn3_pressed = ctx.resources.btn3.is_low().unwrap();
96+
let btn4_pressed = ctx.resources.btn4.is_low().unwrap();
97+
98+
if btn1_pressed {
99+
rprintln!("Button 1 was pressed!");
100+
// Manually run "task out" (toggle) on channel 1 (toggles led1)
101+
ctx.resources.gpiote.channel(1).out();
102+
}
103+
if btn3_pressed { rprintln!("Button 3 was pressed!"); }
104+
if btn4_pressed { rprintln!("Button 4 was pressed!"); }
105+
}
106+
107+
extern "C" {
108+
fn SWI0_EGU0();
109+
}
110+
};
111+
112+
#[inline(never)]
113+
#[panic_handler]
114+
fn panic(info: &PanicInfo) -> ! {
115+
cortex_m::interrupt::disable();
116+
rprintln!("{}", info);
117+
loop {
118+
compiler_fence(Ordering::SeqCst);
119+
}
120+
}

nrf-hal-common/src/gpiote.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -157,35 +157,27 @@ impl<'a, P: GpioteInputPin> GpioteChannelEvent<'_, P> {
157157
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::HiToLo);
158158
if enable_interrupt {
159159
self.enable_interrupt();
160-
} else {
161-
self.disable_interrupt();
162160
}
163161
}
164162

165163
pub fn lo_to_hi(&self, enable_interrupt: bool) {
166164
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::LoToHi);
167165
if enable_interrupt {
168166
self.enable_interrupt();
169-
} else {
170-
self.disable_interrupt();
171167
}
172168
}
173169

174170
pub fn toggle(&self, enable_interrupt: bool) {
175171
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::Toggle);
176172
if enable_interrupt {
177173
self.enable_interrupt();
178-
} else {
179-
self.disable_interrupt();
180174
}
181175
}
182176

183177
pub fn none(&self, enable_interrupt: bool) {
184178
config_channel_event_pin(self.gpiote, self.channel, self.pin, EventPolarity::None);
185179
if enable_interrupt {
186180
self.enable_interrupt();
187-
} else {
188-
self.disable_interrupt();
189181
}
190182
}
191183

@@ -197,15 +189,6 @@ impl<'a, P: GpioteInputPin> GpioteChannelEvent<'_, P> {
197189
.modify(|r, w| w.bits(r.bits() | self.pin.pin() as u32))
198190
}
199191
}
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-
}
209192
}
210193

211194
fn config_channel_event_pin<P: GpioteInputPin>(

0 commit comments

Comments
 (0)