Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the NUCLEO-STM32F429ZI board. #1917

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ spin = { version = "0.9.4", default-features = false, features = ["mutex", "spin
ssmarshal = { version = "1.0.0", default-features = false }
static_assertions = { version = "1", default-features = false }
stm32f3 = { version = "0.13.0", default-features = false }
stm32f4 = { version = "0.13.0", default-features = false }
stm32f4 = { version = "0.15.1", default-features = false }
stm32h7 = { version = "0.14", default-features = false }
stm32g0 = { version = "0.15.1", default-features = false }
strsim = { version = "0.10.0", default-features = false }
19 changes: 14 additions & 5 deletions app/demo-stm32f4-discovery/app.toml
Original file line number Diff line number Diff line change
@@ -17,20 +17,30 @@ start = true
stacksize = 1536
notifications = ["fault", "timer"]

[tasks.sys]
name = "drv-stm32xx-sys"
priority = 1
max-sizes = {flash = 2048, ram = 256}
uses = ["rcc", "gpio"]
start = true
features = ["f407", "no-ipc-counters"]
stacksize = 256
task-slots = ["jefe"]

[tasks.rcc_driver]
name = "drv-stm32fx-rcc"
features = ["f4"]
features = ["f407"]
priority = 1
max-sizes = {flash = 8192, ram = 1024}
uses = ["rcc"]
start = true

[tasks.usart_driver]
name = "drv-stm32fx-usart"
features = ["stm32f4"]
features = ["f407"]
priority = 2
max-sizes = {flash = 8192, ram = 1024}
uses = ["usart2", "gpioa"]
uses = ["usart2", "gpio"]
start = true
notifications = ["usart-irq"]
interrupts = {"usart2.irq" = "usart-irq"}
@@ -41,9 +51,8 @@ name = "drv-user-leds"
features = ["stm32f4"]
priority = 2
max-sizes = {flash = 8192, ram = 1024}
uses = ["gpiod"]
start = true
task-slots = ["rcc_driver"]
task-slots = ["rcc_driver", "sys"]
notifications = ["timer"]

[tasks.ping]
30 changes: 30 additions & 0 deletions app/demo-stm32f4-nucleo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
edition = "2021"
readme = "README.md"
name = "demo-stm32f4-nucleo"
version = "0.1.0"

[features]
f429 = ["stm32f4/stm32f429", "kern/nano"]
dump = ["kern/dump"]

[dependencies]
cortex-m = { workspace = true }
cortex-m-rt = { workspace = true }
cfg-if = { workspace = true }
stm32f4 = { workspace = true, features = ["stm32f429", "rt"] }

kern = { path = "../../sys/kern" }

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

# this lets you use `cargo fix`!
[[bin]]
name = "demo-stm32f4-nucleo"
test = false
doctest = false
bench = false

[lints]
workspace = true
1 change: 1 addition & 0 deletions app/demo-stm32f4-nucleo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# STM32F4 demo application for the NUCLEO-F429ZI board
86 changes: 86 additions & 0 deletions app/demo-stm32f4-nucleo/app.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name = "demo-stm32f4-nucleo"
target = "thumbv7em-none-eabihf"
board = "stm32f429-nucleo"
chip = "../../chips/stm32f4"
stacksize = 896

[kernel]
name = "demo-stm32f4-nucleo"
requires = {flash = 20000, ram = 3072}

[tasks.jefe]
name = "task-jefe"
priority = 0
max-sizes = {flash = 8192, ram = 2048}
start = true
stacksize = 1536
notifications = ["fault", "timer"]

[tasks.sys]
name = "drv-stm32xx-sys"
priority = 1
max-sizes = {flash = 2048, ram = 256}
uses = ["rcc", "gpio"]
start = true
features = ["f429", "no-ipc-counters"]
stacksize = 256
task-slots = ["jefe"]

[tasks.rcc_driver]
name = "drv-stm32fx-rcc"
features = ["f429"]
priority = 1
max-sizes = {flash = 8192, ram = 1024}
uses = ["rcc"]
start = true

[tasks.usart_driver]
name = "drv-stm32fx-usart"
features = ["f429"]
priority = 2
max-sizes = {flash = 8192, ram = 1024}
uses = ["usart2", "gpio"]
start = true
notifications = ["usart-irq"]
interrupts = {"usart2.irq" = "usart-irq"}
task-slots = ["rcc_driver"]

[tasks.user_leds]
name = "drv-user-leds"
features = ["stm32f4"]
priority = 2
max-sizes = {flash = 8192, ram = 1024}
start = true
task-slots = ["rcc_driver", "sys"]
notifications = ["timer"]

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

[tasks.pong]
name = "task-pong"
priority = 3
max-sizes = {flash = 8192, ram = 1024}
start = true
task-slots = ["user_leds"]
notifications = ["timer"]

[tasks.hiffy]
name = "task-hiffy"
priority = 3
max-sizes = {flash = 16384, ram = 16384 }
stacksize = 2048
start = true

[tasks.idle]
name = "task-idle"
priority = 5
max-sizes = {flash = 128, ram = 256}
stacksize = 256
start = true
7 changes: 7 additions & 0 deletions app/demo-stm32f4-nucleo/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// 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() {
build_util::expose_target_board();
}
19 changes: 19 additions & 0 deletions app/demo-stm32f4-nucleo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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/.

#![no_std]
#![no_main]

// We have to do this if we don't otherwise use it to ensure its vector table
// gets linked in.
extern crate stm32f4;

use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
const CYCLES_PER_MS: u32 = 16_000;

unsafe { kern::startup::start_kernel(CYCLES_PER_MS) }
}
2 changes: 2 additions & 0 deletions boards/stm32f429-nucleo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[probe-rs]
chip-name = "STM32F429ZITx"
8 changes: 2 additions & 6 deletions chips/stm32f4/chip.toml
Original file line number Diff line number Diff line change
@@ -7,10 +7,6 @@ interrupts = { irq = 38 }
address = 0x40023800
size = 1024

[gpioa]
[gpio]
address = 0x40020000
size = 1024

[gpiod]
address = 0x40020c00
size = 1024
size = 16384
3 changes: 2 additions & 1 deletion drv/stm32fx-rcc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -13,7 +13,8 @@ userlib = { path = "../../sys/userlib", features = ["panic-messages"] }

[features]
f3 = ["stm32f3/stm32f303"]
f4 = ["stm32f4/stm32f407"]
f407 = ["stm32f4/stm32f407"]
f429 = ["stm32f4/stm32f429"]

# This section is here to discourage RLS/rust-analyzer from doing test builds,
# since test builds don't work for cross compilation.
5 changes: 4 additions & 1 deletion drv/stm32fx-rcc/src/main.rs
Original file line number Diff line number Diff line change
@@ -53,9 +53,12 @@
#[cfg(feature = "stm32f3")]
use stm32f3::stm32f303 as device;

#[cfg(feature = "stm32f4")]
#[cfg(feature = "f407")]
use stm32f4::stm32f407 as device;

#[cfg(feature = "f429")]
use stm32f4::stm32f429 as device;

use userlib::*;
use zerocopy::AsBytes;

6 changes: 5 additions & 1 deletion drv/stm32fx-usart/Cargo.toml
Original file line number Diff line number Diff line change
@@ -6,11 +6,15 @@ edition = "2021"
[dependencies]
num-traits = { workspace = true }
stm32f3 = { workspace = true, optional = true, features = ["stm32f303"] }
stm32f4 = { workspace = true, optional = true, features = ["stm32f407"] }
stm32f4 = { workspace = true, optional = true }
zerocopy = { workspace = true }

userlib = { path = "../../sys/userlib", features = ["panic-messages"] }

[features]
f407 = [ "stm32f4/stm32f407" ]
f429 = [ "stm32f4/stm32f429" ]

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

13 changes: 8 additions & 5 deletions drv/stm32fx-usart/src/main.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,10 @@
#![no_std]
#![no_main]

#[cfg(feature = "stm32f4")]
#[cfg(feature = "f429")]
use stm32f4::stm32f429 as device;

#[cfg(feature = "f407")]
use stm32f4::stm32f407 as device;

#[cfg(feature = "stm32f3")]
@@ -74,7 +77,7 @@ fn main() -> ! {
.write(|w| w.brr().bits((CLOCK_HZ / BAUDRATE) as u16));
}

#[cfg(feature = "stm32f4")]
#[cfg(any(feature = "f407", feature = "f429"))]
{
const CLOCK_HZ: u32 = 16_000_000;
const CYCLES_PER_BIT: u32 = (CLOCK_HZ + (BAUDRATE / 2)) / BAUDRATE;
@@ -126,7 +129,7 @@ fn main() -> ! {

#[cfg(feature = "stm32f3")]
let txe = usart.isr.read().txe().bit();
#[cfg(feature = "stm32f4")]
#[cfg(any(feature = "f407", feature = "f429"))]
let txe = usart.sr.read().txe().bit();
if txe {
// TX register empty. Do we need to send something?
@@ -208,7 +211,7 @@ fn turn_on_gpioa() {

#[cfg(feature = "stm32f3")]
let pnum = 17; // see bits in AHBENR
#[cfg(feature = "stm32f4")]
#[cfg(any(feature = "f407", feature = "f429"))]
let pnum = 0; // see bits in AHB1ENR

let (code, _) = userlib::sys_send(
@@ -250,7 +253,7 @@ fn step_transmit(
// Stuff byte into transmitter.
#[cfg(feature = "stm32f3")]
usart.tdr.write(|w| w.tdr().bits(u16::from(byte)));
#[cfg(feature = "stm32f4")]
#[cfg(any(feature = "f407", feature = "f429"))]
usart.dr.write(|w| w.dr().bits(u16::from(byte)));

txs.pos += 1;
18 changes: 18 additions & 0 deletions drv/stm32xx-gpio-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ cfg-if = { workspace = true }
num-traits = { workspace = true }
stm32g0 = { workspace = true, optional = true }
stm32h7 = { workspace = true, optional = true }
stm32f4 = { workspace = true, optional = true }
zerocopy = { workspace = true }

userlib = { path = "../../sys/userlib" }
@@ -57,12 +58,29 @@ family-stm32h7 = [
model-stm32h743 = ["family-stm32h7"]
model-stm32h753 = ["family-stm32h7"]

family-stm32f4 = [
"stm32f4",
"has-gpioa-type",
"has-gpiob-type",
"has-gpiok-type",
"has-port-gpioe",
"has-port-gpiof",
"has-port-gpiog",
"has-port-gpioh",
"has-port-gpioi",
"has-port-gpioj",
"has-port-gpiok",
]
model-stm32f407 = ["family-stm32f4"]
model-stm32f429 = ["family-stm32f4"]

# The has-gpioX-type features indicates that the PAC for the chosen model calls
# at least some of the GPIO ports `gpioX`. Note that this has nothing to do
# with the actual identity of the port; GPIOX is probably called `gpioX` but
# GPIOZ might be too.
has-gpioa-type = []
has-gpiob-type = []
has-gpiok-type = []

# The has-port-gpioX features indicate that the model or family includes the
# given GPIO port in the memory map. Numbering here starts at E because it is a
15 changes: 15 additions & 0 deletions drv/stm32xx-gpio-common/src/server.rs
Original file line number Diff line number Diff line change
@@ -38,6 +38,17 @@ cfg_if::cfg_if! {
compile_error!("unsupported or missing SoC model feature");
}
}
} else if #[cfg(feature = "family-stm32f4")] {
use stm32f4 as pac;
cfg_if::cfg_if! {
if #[cfg(feature = "model-stm32f407")] {
use pac::stm32f407 as device;
} else if #[cfg(feature = "model-stm32f429")] {
use pac::stm32f429 as device;
} else {
compile_error!("unsupported or missing SoC model feature");
}
}
} else {
compile_error!("unsupported or missing SoC family feature");
}
@@ -259,6 +270,10 @@ impl_gpio_periph!(gpioa);
#[cfg(feature = "has-gpiob-type")]
impl_gpio_periph!(gpiob);

// At least F4 distinguish gpiok from other ports.
#[cfg(feature = "has-gpiok-type")]
impl_gpio_periph!(gpiok);

// Add add'l types here as PAC crates invent more - L4 in particular
// distinguishes gpioc, so if we support that family, gpioc would go here.

4 changes: 4 additions & 0 deletions drv/stm32xx-sys-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -30,6 +30,10 @@ g031 = ["family-stm32g0", "drv-stm32xx-gpio-common/model-stm32g031"]
g070 = ["family-stm32g0", "drv-stm32xx-gpio-common/model-stm32g070"]
g0b1 = ["family-stm32g0", "drv-stm32xx-gpio-common/model-stm32g0b1"]

family-stm32f4 = ["drv-stm32xx-gpio-common/family-stm32f4"]
f407 = ["family-stm32f4", "drv-stm32xx-gpio-common/model-stm32f407"]
f429 = ["family-stm32f4", "drv-stm32xx-gpio-common/model-stm32f429"]

# This section is here to discourage RLS/rust-analyzer from doing test builds,
# since test builds don't work for cross compilation.
[lib]
51 changes: 51 additions & 0 deletions drv/stm32xx-sys-api/src/f4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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/.

//! STM32F4 specifics
use crate::periph;
use userlib::FromPrimitive;

/// Peripherals appear in "groups." All peripherals in a group are controlled
/// from the same subset of registers in the RCC.
///
/// The reference manual lacks a term for this, so we made this one up. It would
/// be tempting to refer to these as "buses," but in practice there are almost
/// always more groups than there are buses, particularly on M0.
///
/// This is `pub` mostly for use inside driver-servers.
#[derive(Copy, Clone, Debug, FromPrimitive)]
#[repr(u8)]
pub enum Group {
Ahb1,
Ahb2,
Ahb3,
Apb1,
Apb2,
}

/// Peripheral numbering.
///
/// Peripheral bit numbers per the STM32F4 documentation.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(u32)]
pub enum Peripheral {
GpioA = periph(Group::Ahb1, 0),
GpioB = periph(Group::Ahb1, 1),
GpioC = periph(Group::Ahb1, 2),
GpioD = periph(Group::Ahb1, 3),
GpioE = periph(Group::Ahb1, 4),
GpioF = periph(Group::Ahb1, 5),
GpioG = periph(Group::Ahb1, 6),
GpioH = periph(Group::Ahb1, 7),
GpioI = periph(Group::Ahb1, 8),
GpioJ = periph(Group::Ahb1, 9),
GpioK = periph(Group::Ahb1, 10),
Crc = periph(Group::Ahb1, 12),
Dma1 = periph(Group::Ahb1, 21),
Dma2 = periph(Group::Ahb1, 22),
Dma2d = periph(Group::Ahb1, 23),
EthMac = periph(Group::Ahb1, 25),
UsbOtgHs = periph(Group::Ahb1, 29),
}
5 changes: 4 additions & 1 deletion drv/stm32xx-sys-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,10 @@ cfg_if::cfg_if! {
pub use self::g0::*;
} else if #[cfg(feature = "family-stm32h7")] {
mod h7;
pub use self::h7::*;
pub use self::f4::*;
} else if #[cfg(feature = "family-stm32f4")] {
mod f4;
pub use self::f4::*;
} else {
compile_error!("unsupported SoC family");
}
5 changes: 5 additions & 0 deletions drv/stm32xx-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ idol-runtime = { workspace = true }
num-traits = { workspace = true }
stm32g0 = { workspace = true, optional = true }
stm32h7 = { workspace = true, optional = true }
stm32f4 = { workspace = true, optional = true }
zerocopy = { workspace = true }

[build-dependencies]
@@ -36,6 +37,10 @@ g031 = ["family-stm32g0", "stm32g0/stm32g031", "drv-stm32xx-sys-api/g031", "drv-
g070 = ["family-stm32g0", "stm32g0/stm32g070", "drv-stm32xx-sys-api/g070", "drv-stm32xx-gpio-common/model-stm32g070"]
g0b1 = ["family-stm32g0", "stm32g0/stm32g0b1", "drv-stm32xx-sys-api/g0b1", "drv-stm32xx-gpio-common/model-stm32g0b1"]

family-stm32f4 = ["stm32f4", "drv-stm32xx-uid/family-stm32f4"]
f407 = ["family-stm32f4", "stm32f4/stm32f407", "drv-stm32xx-sys-api/f407", "drv-stm32xx-gpio-common/model-stm32f407"]
f429 = ["family-stm32f4", "stm32f4/stm32f429", "drv-stm32xx-sys-api/f429", "drv-stm32xx-gpio-common/model-stm32f429"]

no-ipc-counters = ["idol/no-counters"]
no-panic = ["userlib/no-panic"]

90 changes: 90 additions & 0 deletions drv/stm32xx-sys/src/main.rs
Original file line number Diff line number Diff line change
@@ -315,6 +315,14 @@ cfg_if! {
use stm32h7::stm32h743 as device;
#[cfg(feature = "h753")]
use stm32h7::stm32h753 as device;
} else if #[cfg(feature = "family-stm32f4")] {
use stm32f4 as pac;

#[cfg(feature = "f407")]
use stm32f4::stm32f407 as device;

#[cfg(feature = "f429")]
use stm32f4::stm32f429 as device;
} else {
compile_error!("unsupported SoC family");
}
@@ -504,6 +512,23 @@ fn main() -> ! {
.gpioken()
.set_bit()
});
} else if #[cfg(feature = "family-stm32f4")] {
rcc.ahb1enr.write(|w| {
w.gpioaen().set_bit();
w.gpioben().set_bit();
w.gpiocen().set_bit();
w.gpioden().set_bit();
w.gpioeen().set_bit();
w.gpiofen().set_bit();
w.gpiogen().set_bit();
w.gpiohen().set_bit();
w.gpioien().set_bit();
#[cfg(feature = "f429")]
w.gpiojen().set_bit();
#[cfg(feature = "f429")]
w.gpioken().set_bit();
w
});
}
}

@@ -1220,6 +1245,71 @@ cfg_if! {

Some(reason)
}
} else if #[cfg(feature = "family-stm32f4")] {
fn enable_clock(
rcc: &device::rcc::RegisterBlock,
group: Group,
bit: u8,
) {
match group {
Group::Ahb1 => unsafe { rcc.ahb1enr.set_bit(bit) },
Group::Ahb2 => unsafe { rcc.ahb2enr.set_bit(bit) },
Group::Ahb3 => unsafe { rcc.ahb3enr.set_bit(bit) },
Group::Apb1 => unsafe { rcc.apb1enr.set_bit(bit) },
Group::Apb2 => unsafe { rcc.apb2enr.set_bit(bit) },
}
}

fn disable_clock(
rcc: &device::rcc::RegisterBlock,
group: Group,
bit: u8,
) {
match group {
Group::Ahb1 => unsafe { rcc.ahb1enr.clear_bit(bit) },
Group::Ahb2 => unsafe { rcc.ahb2enr.clear_bit(bit) },
Group::Ahb3 => unsafe { rcc.ahb3enr.clear_bit(bit) },
Group::Apb1 => unsafe { rcc.apb1enr.clear_bit(bit) },
Group::Apb2 => unsafe { rcc.apb2enr.clear_bit(bit) },
}
}

fn enter_reset(
rcc: &device::rcc::RegisterBlock,
group: Group,
bit: u8,
) {
match group {
Group::Ahb1 => unsafe { rcc.ahb1rstr.set_bit(bit) },
Group::Ahb2 => unsafe { rcc.ahb2rstr.set_bit(bit) },
Group::Ahb3 => unsafe { rcc.ahb3rstr.set_bit(bit) },
Group::Apb1 => unsafe { rcc.apb1rstr.set_bit(bit) },
Group::Apb2 => unsafe { rcc.apb2rstr.set_bit(bit) },
}
}

fn leave_reset(
rcc: &device::rcc::RegisterBlock,
group: Group,
bit: u8,
) {
match group {
Group::Ahb1 => unsafe { rcc.ahb1rstr.clear_bit(bit) },
Group::Ahb2 => unsafe { rcc.ahb2rstr.clear_bit(bit) },
Group::Ahb3 => unsafe { rcc.ahb3rstr.clear_bit(bit) },
Group::Apb1 => unsafe { rcc.apb1rstr.clear_bit(bit) },
Group::Apb2 => unsafe { rcc.apb2rstr.clear_bit(bit) },
}
}

#[cfg(not(feature = "test"))]
fn try_read_reset_reason(
rcc: &device::rcc::RegisterBlock,
) -> Option<ResetReason> {
// TODO map to ResetReason cases
let bits = rcc.csr.read().bits();
Some(ResetReason::Other(bits))
}
} else {
compile_error!("unsupported SoC family");
}
1 change: 1 addition & 0 deletions drv/stm32xx-uid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ cfg-if = { workspace = true }
[features]
family-stm32g0 = []
family-stm32h7 = []
family-stm32f4 = []

# This section is here to discourage RLS/rust-analyzer from doing test builds,
# since test builds don't work for cross compilation.
2 changes: 2 additions & 0 deletions drv/stm32xx-uid/src/lib.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ cfg_if::cfg_if! {
const UID_ADDR: u32 = 0x1FFF_7590;
} else if #[cfg(feature = "family-stm32h7")] {
const UID_ADDR: u32 = 0x1FF1_E800;
} else if #[cfg(feature = "family-stm32f4")] {
const UID_ADDR: u32 = 0x1FFF_7A10;
} else {
compile_error!("unsupported SoC family");
const UID_ADDR: u32 = 0; // Prevents a second error below
2 changes: 1 addition & 1 deletion drv/user-leds/Cargo.toml
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@ idol-runtime.workspace = true
lpc55-pac = { workspace = true, optional = true }
num-traits.workspace = true
stm32f3 = { workspace = true, optional = true, features = ["stm32f303"] }
stm32f4 = { workspace = true, optional = true, features = ["stm32f407"] }
zerocopy.workspace = true

drv-lpc55-gpio-api = { path = "../lpc55-gpio-api", optional = true }
@@ -26,6 +25,7 @@ idol.workspace = true
[features]
stm32g0 = ["drv-stm32xx-sys-api/family-stm32g0"]
stm32h7 = ["drv-stm32xx-sys-api/family-stm32h7"]
stm32f4 = ["drv-stm32xx-sys-api/family-stm32f4"]
lpc55 = ["lpc55-pac", "drv-lpc55-gpio-api"]
panic-messages = ["userlib/panic-messages"]
no-ipc-counters = ["idol/no-counters"]
148 changes: 102 additions & 46 deletions drv/user-leds/src/main.rs
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ cfg_if::cfg_if! {
}
}
// Target boards with 3 leds
else if #[cfg(any(target_board = "nucleo-h753zi", target_board = "nucleo-h743zi2"))] {
else if #[cfg(any(target_board = "nucleo-h753zi", target_board = "nucleo-h743zi2", target_board = "stm32f429-nucleo"))] {
#[derive(enum_map::Enum, Copy, Clone, FromPrimitive)]
enum Led {
Zero = 0,
@@ -202,7 +202,7 @@ fn main() -> ! {
// intermediary.

cfg_if::cfg_if! {
if #[cfg(any(feature = "stm32f4", feature = "stm32f3"))] {
if #[cfg(any(feature = "stm32f3"))] {
task_slot!(RCC, rcc_driver);
}
}
@@ -215,28 +215,19 @@ macro_rules! gpio {
unsafe { &*stm32f3::stm32f303::GPIOE::ptr() }
};
}
#[cfg(feature = "stm32f4")]
macro_rules! gpio {
() => {
unsafe { &*stm32f4::stm32f407::GPIOD::ptr() }
};
}

#[cfg(any(feature = "stm32f3", feature = "stm32f4"))]
#[cfg(any(feature = "stm32f3"))]
fn enable_led_pins() {
use zerocopy::AsBytes;

// This assumes an STM32F4DISCOVERY board, where the LEDs are on D12 and
// D13 OR an STM32F3DISCOVERY board, where the LEDs are on E8 and E9.
// This assumes a STM32F3DISCOVERY board, where the LEDs are on E8 and E9.

// Contact the RCC driver to get power turned on for GPIOD/E.
let rcc_driver = RCC.get_task_id();
const ENABLE_CLOCK: u16 = 1;

#[cfg(feature = "stm32f3")]
let gpio_pnum: u32 = 21; // see bits in AHBENR
#[cfg(feature = "stm32f4")]
let gpio_pnum: u32 = 3; // see bits in AHB1ENR

let (code, _) = userlib::sys_send(
rcc_driver,
@@ -247,17 +238,15 @@ fn enable_led_pins() {
);
assert_eq!(code, 0);

// Now, directly manipulate GPIOD/E.
// Now, directly manipulate GPIOB/E.
// TODO: this should go through a gpio driver probably.
let gpio_moder = &gpio!().moder;

#[cfg(feature = "stm32f3")]
gpio_moder.modify(|_, w| w.moder8().output().moder9().output());
#[cfg(feature = "stm32f4")]
gpio_moder.modify(|_, w| w.moder12().output().moder13().output());
}

#[cfg(any(feature = "stm32f3", feature = "stm32f4"))]
#[cfg(any(feature = "stm32f3"))]
fn led_on(led: Led) {
let gpio = gpio!();

@@ -266,15 +255,10 @@ fn led_on(led: Led) {
Led::Zero => gpio.bsrr.write(|w| w.bs8().set_bit()),
#[cfg(feature = "stm32f3")]
Led::One => gpio.bsrr.write(|w| w.bs9().set_bit()),

#[cfg(feature = "stm32f4")]
Led::Zero => gpio.bsrr.write(|w| w.bs12().set_bit()),
#[cfg(feature = "stm32f4")]
Led::One => gpio.bsrr.write(|w| w.bs13().set_bit()),
}
}

#[cfg(any(feature = "stm32f3", feature = "stm32f4"))]
#[cfg(any(feature = "stm32f3"))]
fn led_off(led: Led) {
let gpio = gpio!();

@@ -283,15 +267,10 @@ fn led_off(led: Led) {
Led::Zero => gpio.bsrr.write(|w| w.br8().set_bit()),
#[cfg(feature = "stm32f3")]
Led::One => gpio.bsrr.write(|w| w.br9().set_bit()),

#[cfg(feature = "stm32f4")]
Led::Zero => gpio.bsrr.write(|w| w.br12().set_bit()),
#[cfg(feature = "stm32f4")]
Led::One => gpio.bsrr.write(|w| w.br13().set_bit()),
}
}

#[cfg(any(feature = "stm32f3", feature = "stm32f4"))]
#[cfg(any(feature = "stm32f3"))]
fn led_toggle(led: Led) {
let gpio = gpio!();

@@ -312,23 +291,6 @@ fn led_toggle(led: Led) {
gpio.bsrr.write(|w| w.bs9().set_bit())
}
}

#[cfg(feature = "stm32f4")]
Led::Zero => {
if gpio.odr.read().odr12().bit() {
gpio.bsrr.write(|w| w.br12().set_bit())
} else {
gpio.bsrr.write(|w| w.bs12().set_bit())
}
}
#[cfg(feature = "stm32f4")]
Led::One => {
if gpio.odr.read().odr13().bit() {
gpio.bsrr.write(|w| w.br13().set_bit())
} else {
gpio.bsrr.write(|w| w.bs13().set_bit())
}
}
}
}

@@ -575,6 +537,100 @@ fn led_toggle(led: Led) {
sys.gpio_toggle(pinset.port, pinset.pin_mask).unwrap_lite();
}

///////////////////////////////////////////////////////////////////////////////
// The STM32F4 specific bits.
Comment on lines +540 to +541
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take it or leave it: I wonder if we might want to move the board-specific bits into submodules with #[cfg(feature = <board feature>] on them, instead of sticking a cfg attribute on each function and constant? We could do the same for the existing F3 stuff. The code might read a little nicer that way. But, it's up to you.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a good follow-up PR. I just wanted to share what I'd done to make it run on the board I had.

//

cfg_if::cfg_if! {
if #[cfg(feature = "stm32f4")] {
task_slot!(SYS, sys);

const LEDS: &[(drv_stm32xx_sys_api::PinSet, bool)] =
{
cfg_if::cfg_if! {
if #[cfg(target_board = "stm32f429-nucleo")] {
&[
(drv_stm32xx_sys_api::Port::B.pin(0), true),
(drv_stm32xx_sys_api::Port::B.pin(7), true),
(drv_stm32xx_sys_api::Port::B.pin(14), true)
]
} else if #[cfg(target_board = "stm32f4-discovery")] {
&[
(drv_stm32xx_sys_api::Port::D.pin(12), true),
(drv_stm32xx_sys_api::Port::D.pin(13), true),
]
} else {
compile_error!("Unknown STM32F4 board")
}
}
};
}
}

#[cfg(feature = "stm32f4")]
fn enable_led_pins() {
use drv_stm32xx_sys_api::*;

let sys = SYS.get_task_id();
let sys = Sys::from(sys);

for &(pinset, active_low) in LEDS {
// Make sure LEDs are initially off.
sys.gpio_set_to(pinset, active_low);
// Make them outputs.
sys.gpio_configure_output(
pinset,
OutputType::PushPull,
Speed::High,
Pull::None,
);
}
}

#[cfg(feature = "stm32f4")]
fn led_info(led: Led) -> (drv_stm32xx_sys_api::PinSet, bool) {
match led {
Led::Zero => LEDS[0],
Led::One => LEDS[1],
#[cfg(target_board = "stm32f429-nucleo")]
Led::Two => LEDS[2],
}
}

#[cfg(feature = "stm32f4")]
fn led_on(led: Led) {
use drv_stm32xx_sys_api::*;

let sys = SYS.get_task_id();
let sys = Sys::from(sys);

let (pinset, active_low) = led_info(led);
sys.gpio_set_to(pinset, !active_low);
}

#[cfg(feature = "stm32f4")]
fn led_off(led: Led) {
use drv_stm32xx_sys_api::*;

let sys = SYS.get_task_id();
let sys = Sys::from(sys);

let (pinset, active_low) = led_info(led);

sys.gpio_set_to(pinset, active_low);
}

#[cfg(feature = "stm32f4")]
fn led_toggle(led: Led) {
use drv_stm32xx_sys_api::*;

let sys = SYS.get_task_id();
let sys = Sys::from(sys);

let pinset = led_info(led).0;
sys.gpio_toggle(pinset.port, pinset.pin_mask).unwrap_lite();
}

///////////////////////////////////////////////////////////////////////////////
// The LPC55 specific bits.