Skip to content

Commit

Permalink
stm32h7-nucleo: add button demo task to nucleos (#1693)
Browse files Browse the repository at this point in the history
This commit adds a demo task to the STM32H7 Nucleo boards that provides
an example of how to receive EXTI GPIO notifications in a user task,
replacing the `ping` and `pong` tasks. It toggles an LED when the Nucleo
board's user button is pressed.
  • Loading branch information
hawkw committed Mar 29, 2024
1 parent 740d9a1 commit 3b06f5c
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 34 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 23 additions & 16 deletions app/demo-stm32h7-nucleo/app-h743.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,26 @@ request_reset = ["hiffy"]

[tasks.sys]
name = "drv-stm32xx-sys"
features = ["h743"]
features = ["h743", "exti"]
priority = 1
max-sizes = {flash = 2048, ram = 2048}
uses = ["rcc", "gpios", "system_flash"]
uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"]
start = true
task-slots = ["jefe"]
notifications = ["exti-wildcard-irq"]

[tasks.sys.interrupts]
"exti.exti0" = "exti-wildcard-irq"
"exti.exti1" = "exti-wildcard-irq"
"exti.exti2" = "exti-wildcard-irq"
"exti.exti3" = "exti-wildcard-irq"
"exti.exti4" = "exti-wildcard-irq"
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.button]
port = "C"
pin = 13
owner = {name = "user_button", notification = "button"}

[tasks.i2c_driver]
name = "drv-stm32xx-i2c-server"
Expand Down Expand Up @@ -85,22 +99,15 @@ max-sizes = {flash = 2048, ram = 1024}
start = true
task-slots = ["sys"]
notifications = ["timer"]
config = { blink_at_start = [ "Led::Zero" ] }

[tasks.ping]
name = "task-ping"
features = []
priority = 5
max-sizes = {flash = 8192, ram = 1024}
start = true
task-slots = [{peer = "pong"}]

[tasks.pong]
name = "task-pong"
[tasks.user_button]
name = "task-nucleo-user-button"
priority = 3
max-sizes = {flash = 1024, ram = 1024}
start = true
task-slots = ["user_leds"]
notifications = ["timer"]
task-slots = ["sys", "user_leds"]
notifications = ["button"]
config = { led = 1, rising = false, falling = true }

[tasks.udpecho]
name = "task-udpecho"
Expand Down
23 changes: 7 additions & 16 deletions app/demo-stm32h7-nucleo/app-h753.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ request_reset = ["hiffy"]
name = "drv-stm32xx-sys"
features = ["h753", "exti"]
priority = 1
max-sizes = {flash = 4096, ram = 2048}
uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"]
start = true
task-slots = ["jefe"]
Expand All @@ -45,7 +44,7 @@ notifications = ["exti-wildcard-irq"]
[tasks.sys.config.gpio-irqs.button]
port = "C"
pin = 13
owner = {name = "hiffy", notification = "button"}
owner = {name = "user_button", notification = "button"}

[tasks.i2c_driver]
name = "drv-stm32xx-i2c-server"
Expand Down Expand Up @@ -109,22 +108,15 @@ max-sizes = {flash = 2048, ram = 1024}
start = true
task-slots = ["sys"]
notifications = ["timer"]
config = { blink_at_start = [ "Led::Zero" ] }

[tasks.ping]
name = "task-ping"
features = []
priority = 5
max-sizes = {flash = 8192, ram = 1024}
start = true
task-slots = [{peer = "pong"}]

[tasks.pong]
name = "task-pong"
[tasks.user_button]
name = "task-nucleo-user-button"
priority = 3
max-sizes = {flash = 1024, ram = 1024}
start = true
task-slots = ["user_leds"]
notifications = ["timer"]
task-slots = ["sys", "user_leds"]
notifications = ["button"]
config = { led = 1, rising = false, falling = true }

[tasks.udpecho]
name = "task-udpecho"
Expand Down Expand Up @@ -161,7 +153,6 @@ max-sizes = {flash = 32768, ram = 32768 }
stacksize = 2048
start = true
task-slots = ["sys", "i2c_driver", "hf", "hash_driver"]
notifications = ["button"]

[tasks.hf]
name = "drv-gimlet-hf-server"
Expand Down
4 changes: 2 additions & 2 deletions drv/stm32xx-sys/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
//!
//! * Declare the named notification that we wish to receive (here,
//! `"my-gpio-notification"`) in `task.<taskname>.notifications`
//! * Add a task slot for `sys` in `task.<taskname>.slots`, to allow the
//! * Add a task slot for `sys` in `task.<taskname>.task-slots`, to allow the
//! `sys.gpio_irq_configure` and `sys.gpio_irq_control` IPCs (if the task
//! does not already depend on `sys`)
//!
Expand All @@ -95,7 +95,7 @@
//! notifications = ["my-gpio-notification"]
//!
//! # Add a slot for sys
//! slots = ["sys"]
//! task-slots = ["sys"]
//! ```
//!
//! Next, we must add the following configurations to the `sys` task's
Expand Down
24 changes: 24 additions & 0 deletions task/nucleo-user-button/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "task-nucleo-user-button"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
drv-user-leds-api = { path = "../../drv/user-leds-api" }
drv-stm32xx-sys-api = { path = "../../drv/stm32xx-sys-api", features = ["family-stm32h7"] }

counters = { path = "../../lib/counters" }
ringbuf = { path = "../../lib/ringbuf" }
userlib = { path = "../../sys/userlib" }
task-config = { path = "../../lib/task-config" }

[build-dependencies]
build-util = { path = "../../build/util" }

[[bin]]
name = "task-nucleo-user-button"
test = false
doctest = false
bench = false
9 changes: 9 additions & 0 deletions task/nucleo-user-button/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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 https://mozilla.org/MPL/2.0/.

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
build_util::expose_target_board();
build_util::build_notifications()?;
Ok(())
}
124 changes: 124 additions & 0 deletions task/nucleo-user-button/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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 https://mozilla.org/MPL/2.0/.

//! A demo task showing the use of EXTI (GPIO interrupts) on the
//! STM32H7-NUCLEO-H753ZI2 board.
//!
//! This task listens for interrupts on the user button (PC13) and toggles a LED
//! when the button is pressed, using the `user-leds` IPC interface.

#![no_std]
#![no_main]

use drv_stm32xx_sys_api::{PinSet, Port, Pull};
use ringbuf::ringbuf_entry;
use userlib::*;

#[cfg(not(any(
target_board = "nucleo-h753zi",
target_board = "nucleo-h743zi2"
)))]
compile_error!(
"the `nucleo-user-button` task is only supported on the Nucleo H753ZI and H743ZI2 boards"
);

task_slot!(USER_LEDS, user_leds);
task_slot!(SYS, sys);

task_config::optional_task_config! {
/// The index of the user LED to toggle
led: usize,
/// Whether to enable rising-edge interrupts
rising: bool,
/// Whether to enable falling-edge interrupts
falling: bool,
}

// In real life, we might not actually want to trace all of these events, but
// for demo purposes, it's nice to be able to watch everything that happens in
// Humility.
#[derive(Copy, Clone, Eq, PartialEq, counters::Count)]
enum Trace {
#[count(skip)]
None,

/// We called the `Sys.gpio_irq_configure` IPC with these arguments.
GpioIrqConfigure {
mask: u32,
rising: bool,
falling: bool,
},

/// We called the `Sys.gpio_irq_control` IPC with these arguments.
GpioIrqControl { enable_mask: u32, disable_mask: u32 },

/// We received a notification with these bits set.
Notification(u32),

/// We called the `UserLeds.led_toggle` IPC.
LedToggle { led: usize },
}

ringbuf::counted_ringbuf!(Trace, 16, Trace::None);

#[export_name = "main"]
pub fn main() -> ! {
let user_leds = drv_user_leds_api::UserLeds::from(USER_LEDS.get_task_id());
let sys = drv_stm32xx_sys_api::Sys::from(SYS.get_task_id());

let (led, rising, falling) = if let Some(config) = TASK_CONFIG {
(config.led, config.rising, config.falling)
} else {
(0, false, true)
};

sys.gpio_configure_input(
PinSet {
port: Port::C,
pin_mask: (1 << 13),
},
Pull::None,
);

ringbuf_entry!(Trace::GpioIrqConfigure {
mask: notifications::BUTTON_MASK,
rising,
falling,
});
sys.gpio_irq_configure(notifications::BUTTON_MASK, rising, falling);

loop {
// The first argument to `gpio_irq_control` is the mask of interrupts to
// enable, while the second is the mask to disable. So, enable the
// button notification.
let disable_mask = 0;
ringbuf_entry!(Trace::GpioIrqControl {
enable_mask: notifications::BUTTON_MASK,
disable_mask,
});
sys.gpio_irq_control(disable_mask, notifications::BUTTON_MASK);

// Wait for the user button to be pressed.
//
// We only care about notifications, so we can pass a zero-sized recv
// buffer, and the kernel's task ID.
let recvmsg = sys_recv_closed(
&mut [],
notifications::BUTTON_MASK,
TaskId::KERNEL,
)
// Recv from the kernel never returns an error.
.unwrap_lite();
let notif = recvmsg.operation;
ringbuf_entry!(Trace::Notification(notif));

// If the notification is for the button, toggle the LED.
if notif == notifications::BUTTON_MASK {
ringbuf_entry!(Trace::LedToggle { led });
user_leds.led_toggle(led).unwrap_lite();
}
}
}

include!(concat!(env!("OUT_DIR"), "/notifications.rs"));

0 comments on commit 3b06f5c

Please sign in to comment.