diff --git a/Cargo.lock b/Cargo.lock index 3bf1cf0cfd..98a76081ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -856,6 +856,18 @@ dependencies = [ "stm32f4", ] +[[package]] +name = "demo-stm32f4-nucleo" +version = "0.1.0" +dependencies = [ + "build-util", + "cfg-if", + "cortex-m", + "cortex-m-rt", + "kern", + "stm32f4", +] + [[package]] name = "demo-stm32g0-nucleo" version = "0.1.0" @@ -2245,6 +2257,7 @@ version = "0.1.0" dependencies = [ "cfg-if", "num-traits", + "stm32f4", "stm32g0", "stm32h7", "userlib", @@ -2306,6 +2319,7 @@ dependencies = [ "idol", "idol-runtime", "num-traits", + "stm32f4", "stm32g0", "stm32h7", "task-jefe-api", @@ -2419,7 +2433,6 @@ dependencies = [ "lpc55-pac", "num-traits", "stm32f3", - "stm32f4", "task-config", "userlib", "zerocopy 0.6.6", @@ -4662,11 +4675,11 @@ dependencies = [ [[package]] name = "stm32f4" -version = "0.13.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3d56009c8f32e4f208dbea17df72484154d1040a8969b75d8c73eb7b18fe8f" +checksum = "fb94729242cd1aebe6dab42a2ca0131985ae93bc3ab2751b680df724bb35528d" dependencies = [ - "bare-metal 0.2.5", + "bare-metal 1.0.0", "cortex-m", "cortex-m-rt", "vcell", diff --git a/Cargo.toml b/Cargo.toml index 1c376057b9..4a01f6474c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } diff --git a/app/demo-stm32f4-discovery/app.toml b/app/demo-stm32f4-discovery/app.toml index 5161437106..bd6c621e00 100644 --- a/app/demo-stm32f4-discovery/app.toml +++ b/app/demo-stm32f4-discovery/app.toml @@ -17,9 +17,19 @@ 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"] @@ -27,10 +37,10 @@ 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] diff --git a/app/demo-stm32f4-nucleo/Cargo.toml b/app/demo-stm32f4-nucleo/Cargo.toml new file mode 100644 index 0000000000..4dd7693a56 --- /dev/null +++ b/app/demo-stm32f4-nucleo/Cargo.toml @@ -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 diff --git a/app/demo-stm32f4-nucleo/README.md b/app/demo-stm32f4-nucleo/README.md new file mode 100644 index 0000000000..984cf2cd23 --- /dev/null +++ b/app/demo-stm32f4-nucleo/README.md @@ -0,0 +1 @@ +# STM32F4 demo application for the NUCLEO-F429ZI board diff --git a/app/demo-stm32f4-nucleo/app.toml b/app/demo-stm32f4-nucleo/app.toml new file mode 100644 index 0000000000..6160af78b6 --- /dev/null +++ b/app/demo-stm32f4-nucleo/app.toml @@ -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 diff --git a/app/demo-stm32f4-nucleo/build.rs b/app/demo-stm32f4-nucleo/build.rs new file mode 100644 index 0000000000..2800895934 --- /dev/null +++ b/app/demo-stm32f4-nucleo/build.rs @@ -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(); +} diff --git a/app/demo-stm32f4-nucleo/src/main.rs b/app/demo-stm32f4-nucleo/src/main.rs new file mode 100644 index 0000000000..4c5502eabf --- /dev/null +++ b/app/demo-stm32f4-nucleo/src/main.rs @@ -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) } +} diff --git a/boards/stm32f429-nucleo.toml b/boards/stm32f429-nucleo.toml new file mode 100644 index 0000000000..56b2669e83 --- /dev/null +++ b/boards/stm32f429-nucleo.toml @@ -0,0 +1,2 @@ +[probe-rs] +chip-name = "STM32F429ZITx" diff --git a/chips/stm32f4/chip.toml b/chips/stm32f4/chip.toml index 2d8a8b403f..519bdcc26e 100644 --- a/chips/stm32f4/chip.toml +++ b/chips/stm32f4/chip.toml @@ -7,10 +7,6 @@ interrupts = { irq = 38 } address = 0x40023800 size = 1024 -[gpioa] +[gpio] address = 0x40020000 -size = 1024 - -[gpiod] -address = 0x40020c00 -size = 1024 +size = 16384 diff --git a/drv/stm32fx-rcc/Cargo.toml b/drv/stm32fx-rcc/Cargo.toml index 2c284c1d7a..af78c85826 100644 --- a/drv/stm32fx-rcc/Cargo.toml +++ b/drv/stm32fx-rcc/Cargo.toml @@ -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. diff --git a/drv/stm32fx-rcc/src/main.rs b/drv/stm32fx-rcc/src/main.rs index 2f04977876..013e1a8e3a 100644 --- a/drv/stm32fx-rcc/src/main.rs +++ b/drv/stm32fx-rcc/src/main.rs @@ -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; diff --git a/drv/stm32fx-usart/Cargo.toml b/drv/stm32fx-usart/Cargo.toml index efddc78234..f397cae19d 100644 --- a/drv/stm32fx-usart/Cargo.toml +++ b/drv/stm32fx-usart/Cargo.toml @@ -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" } diff --git a/drv/stm32fx-usart/src/main.rs b/drv/stm32fx-usart/src/main.rs index d0e8019008..2062f3d73c 100644 --- a/drv/stm32fx-usart/src/main.rs +++ b/drv/stm32fx-usart/src/main.rs @@ -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; diff --git a/drv/stm32xx-gpio-common/Cargo.toml b/drv/stm32xx-gpio-common/Cargo.toml index 4a2ebec37a..4a2690ebf4 100644 --- a/drv/stm32xx-gpio-common/Cargo.toml +++ b/drv/stm32xx-gpio-common/Cargo.toml @@ -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 diff --git a/drv/stm32xx-gpio-common/src/server.rs b/drv/stm32xx-gpio-common/src/server.rs index 517594859f..f1fb5e4a01 100644 --- a/drv/stm32xx-gpio-common/src/server.rs +++ b/drv/stm32xx-gpio-common/src/server.rs @@ -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 distinguishes 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. diff --git a/drv/stm32xx-sys-api/Cargo.toml b/drv/stm32xx-sys-api/Cargo.toml index b7bc0e2655..115e145b6e 100644 --- a/drv/stm32xx-sys-api/Cargo.toml +++ b/drv/stm32xx-sys-api/Cargo.toml @@ -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] diff --git a/drv/stm32xx-sys-api/src/f4.rs b/drv/stm32xx-sys-api/src/f4.rs new file mode 100644 index 0000000000..54ae3326f9 --- /dev/null +++ b/drv/stm32xx-sys-api/src/f4.rs @@ -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), +} diff --git a/drv/stm32xx-sys-api/src/lib.rs b/drv/stm32xx-sys-api/src/lib.rs index 5931eb2301..c3cf3916c0 100644 --- a/drv/stm32xx-sys-api/src/lib.rs +++ b/drv/stm32xx-sys-api/src/lib.rs @@ -13,6 +13,9 @@ cfg_if::cfg_if! { } else if #[cfg(feature = "family-stm32h7")] { mod h7; pub use self::h7::*; + } else if #[cfg(feature = "family-stm32f4")] { + mod f4; + pub use self::f4::*; } else { compile_error!("unsupported SoC family"); } diff --git a/drv/stm32xx-sys/Cargo.toml b/drv/stm32xx-sys/Cargo.toml index 812da6d4d3..27fe0fef97 100644 --- a/drv/stm32xx-sys/Cargo.toml +++ b/drv/stm32xx-sys/Cargo.toml @@ -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"] diff --git a/drv/stm32xx-sys/src/main.rs b/drv/stm32xx-sys/src/main.rs index 8e7849c9fb..8676a6a7dd 100644 --- a/drv/stm32xx-sys/src/main.rs +++ b/drv/stm32xx-sys/src/main.rs @@ -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 { + // TODO map to ResetReason cases + let bits = rcc.csr.read().bits(); + Some(ResetReason::Other(bits)) + } } else { compile_error!("unsupported SoC family"); } diff --git a/drv/stm32xx-uid/Cargo.toml b/drv/stm32xx-uid/Cargo.toml index f17ea684b0..65c81ea12f 100644 --- a/drv/stm32xx-uid/Cargo.toml +++ b/drv/stm32xx-uid/Cargo.toml @@ -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. diff --git a/drv/stm32xx-uid/src/lib.rs b/drv/stm32xx-uid/src/lib.rs index 60a5fd8589..f3ee5679a0 100644 --- a/drv/stm32xx-uid/src/lib.rs +++ b/drv/stm32xx-uid/src/lib.rs @@ -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 diff --git a/drv/user-leds/Cargo.toml b/drv/user-leds/Cargo.toml index 1c59060b37..4050e2cc83 100644 --- a/drv/user-leds/Cargo.toml +++ b/drv/user-leds/Cargo.toml @@ -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"] diff --git a/drv/user-leds/src/main.rs b/drv/user-leds/src/main.rs index 549fac5ea7..20ab0e4945 100644 --- a/drv/user-leds/src/main.rs +++ b/drv/user-leds/src/main.rs @@ -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,19 +215,12 @@ 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(); @@ -235,8 +228,6 @@ fn enable_led_pins() { #[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. +// + +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.