Skip to content

Commit 897b576

Browse files
Merge pull request #167 from kalkyl/gpiote
Add Gpiote module (open for feedback)
2 parents cd41c2c + 3a13b11 commit 897b576

File tree

6 files changed

+631
-0
lines changed

6 files changed

+631
-0
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: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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+
btn3: Pin<Input<PullUp>>,
26+
btn4: Pin<Input<PullUp>>,
27+
}
28+
29+
#[init]
30+
fn init(mut ctx: init::Context) -> init::LateResources {
31+
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
32+
rtt_init_print!();
33+
let p0 = hal::gpio::p0::Parts::new(ctx.device.P0);
34+
let btn1 = p0.p0_11.into_pullup_input().degrade();
35+
let btn2 = p0.p0_12.into_pullup_input().degrade();
36+
let btn3 = p0.p0_24.into_pullup_input().degrade();
37+
let btn4 = p0.p0_25.into_pullup_input().degrade();
38+
let led1 = p0.p0_13.into_push_pull_output(Level::High).degrade();
39+
40+
let gpiote = Gpiote::new(ctx.device.GPIOTE);
41+
42+
// Set btn1 to generate event on channel 0 and enable interrupt
43+
gpiote
44+
.channel0()
45+
.input_pin(&btn1)
46+
.hi_to_lo()
47+
.enable_interrupt();
48+
49+
// Set both btn3 & btn4 to generate port event
50+
gpiote.port().input_pin(&btn3).low();
51+
gpiote.port().input_pin(&btn4).low();
52+
// Enable interrupt for port event
53+
gpiote.port().enable_interrupt();
54+
55+
// PPI usage, channel 2 event triggers "task out" operation (toggle) on channel 1 (toggles led1)
56+
gpiote
57+
.channel1()
58+
.output_pin(led1)
59+
.task_out_polarity(TaskOutPolarity::Toggle)
60+
.init_high();
61+
gpiote.channel2().input_pin(&btn2).hi_to_lo();
62+
let ppi_channels = ppi::Parts::new(ctx.device.PPI);
63+
let mut ppi0 = ppi_channels.ppi0;
64+
ppi0.set_task_endpoint(gpiote.channel1().task_out());
65+
ppi0.set_event_endpoint(gpiote.channel2().event());
66+
ppi0.enable();
67+
68+
// Enable the monotonic timer (CYCCNT)
69+
ctx.core.DCB.enable_trace();
70+
ctx.core.DWT.enable_cycle_counter();
71+
72+
rprintln!("Press a button");
73+
74+
init::LateResources {
75+
gpiote,
76+
btn1,
77+
btn3,
78+
btn4,
79+
}
80+
}
81+
82+
#[idle]
83+
fn idle(_: idle::Context) -> ! {
84+
loop {
85+
cortex_m::asm::wfi();
86+
}
87+
}
88+
89+
#[task(binds = GPIOTE, resources = [gpiote], schedule = [debounce])]
90+
fn on_gpiote(ctx: on_gpiote::Context) {
91+
if ctx.resources.gpiote.channel0().is_event_triggered() {
92+
rprintln!("Interrupt from channel 0 event");
93+
}
94+
if ctx.resources.gpiote.port().is_event_triggered() {
95+
rprintln!("Interrupt from port event");
96+
}
97+
// Reset all events
98+
ctx.resources.gpiote.reset_events();
99+
// Debounce
100+
ctx.schedule.debounce(ctx.start + 3_000_000.cycles()).ok();
101+
}
102+
103+
#[task(resources = [gpiote, btn1, btn3, btn4])]
104+
fn debounce(ctx: debounce::Context) {
105+
let btn1_pressed = ctx.resources.btn1.is_low().unwrap();
106+
let btn3_pressed = ctx.resources.btn3.is_low().unwrap();
107+
let btn4_pressed = ctx.resources.btn4.is_low().unwrap();
108+
109+
if btn1_pressed {
110+
rprintln!("Button 1 was pressed!");
111+
// Manually run "task out" operation (toggle) on channel 1 (toggles led1)
112+
ctx.resources.gpiote.channel1().out();
113+
}
114+
if btn3_pressed {
115+
rprintln!("Button 3 was pressed!");
116+
// Manually run "task clear" on channel 1 (led1 on)
117+
ctx.resources.gpiote.channel1().clear();
118+
}
119+
if btn4_pressed {
120+
rprintln!("Button 4 was pressed!");
121+
// Manually run "task set" on channel 1 (led1 off)
122+
ctx.resources.gpiote.channel1().set();
123+
}
124+
}
125+
126+
extern "C" {
127+
fn SWI0_EGU0();
128+
}
129+
};
130+
131+
#[inline(never)]
132+
#[panic_handler]
133+
fn panic(info: &PanicInfo) -> ! {
134+
cortex_m::interrupt::disable();
135+
rprintln!("{}", info);
136+
loop {
137+
compiler_fence(Ordering::SeqCst);
138+
}
139+
}

0 commit comments

Comments
 (0)