From 2f08c7ced56f855f75bb73cb4775c6379958b3f2 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Thu, 15 Jul 2021 13:25:51 -0300 Subject: [PATCH 1/2] stm32: Allow for RccPeripheral without reset field This fix build on F0, since it doesn't have DMARST. This change makes RccPeripheral::reset a no-op on peripherals where a reset field couldn't be found --- embassy-stm32/src/bdma/mod.rs | 2 +- embassy-stm32/src/rcc/mod.rs | 29 +++++++++++++++ stm32-metapac-gen/src/lib.rs | 70 +++++++++++++++++++++++------------ 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index 39e8bec3..f57358f6 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -177,7 +177,7 @@ pub(crate) unsafe fn init() { } pac::peripherals! { (bdma, $peri:ident) => { - crate::peripherals::$peri::enable(); + ::enable(); }; } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index b7b692f1..c02db58f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -121,6 +121,35 @@ crate::pac::peripheral_rcc!( } } + impl RccPeripheral for peripherals::$inst {} + }; + ($inst:ident, $clk:ident, $enable:ident, $perien:ident) => { + impl sealed::RccPeripheral for peripherals::$inst { + fn frequency() -> crate::time::Hertz { + critical_section::with(|_| { + unsafe { + let freqs = get_freqs(); + freqs.$clk + } + }) + } + fn enable() { + critical_section::with(|_| { + unsafe { + crate::pac::RCC.$enable().modify(|w| w.$perien(true)); + } + }) + } + fn disable() { + critical_section::with(|_| { + unsafe { + crate::pac::RCC.$enable().modify(|w| w.$perien(false)); + } + }) + } + fn reset() {} + } + impl RccPeripheral for peripherals::$inst {} }; ); diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 37254f6f..a9ee8800 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -142,18 +142,17 @@ macro_rules! peripheral_count {{ } fn make_dma_channel_counts(out: &mut String, data: &HashMap) { - write!(out, - "#[macro_export] + write!( + out, + "#[macro_export] macro_rules! dma_channels_count {{ - ").unwrap(); + " + ) + .unwrap(); for (name, count) in data { - write!(out, - "({}) => ({});\n", - name, count, - ).unwrap(); + write!(out, "({}) => ({});\n", name, count,).unwrap(); } - write!(out, - " }}\n").unwrap(); + write!(out, " }}\n").unwrap(); } fn make_table(out: &mut String, name: &str, data: &Vec>) { @@ -409,11 +408,25 @@ pub fn gen(options: Options) { if let Some(clock_prefix) = clock_prefix { // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. - let en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); - let rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); + let mut rst = + find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + + if en.is_none() && name.ends_with("1") { + en = find_reg_for_field( + &rcc, + clock_prefix, + &format!("{}EN", &name[..name.len() - 1]), + ); + rst = find_reg_for_field( + &rcc, + clock_prefix, + &format!("{}RST", &name[..name.len() - 1]), + ); + } match (en, rst) { - (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { + (Some((enable_reg, enable_field)), reset_reg_field) => { let clock = if clock_prefix.is_empty() { let re = Regex::new("([A-Z]+\\d*).*").unwrap(); if !re.is_match(enable_reg) { @@ -436,22 +449,33 @@ pub fn gen(options: Options) { }; if !name.starts_with("GPIO") { - peripheral_rcc_table.push(vec![ - name.clone(), - clock, - enable_reg.to_ascii_lowercase(), - reset_reg.to_ascii_lowercase(), - format!("set_{}", enable_field.to_ascii_lowercase()), - format!("set_{}", reset_field.to_ascii_lowercase()), - ]); + let mut row = Vec::with_capacity(6); + row.push(name.clone()); + row.push(clock); + row.push(enable_reg.to_ascii_lowercase()); + + if let Some((reset_reg, reset_field)) = reset_reg_field { + row.push(reset_reg.to_ascii_lowercase()); + row.push(format!( + "set_{}", + enable_field.to_ascii_lowercase() + )); + row.push(format!( + "set_{}", + reset_field.to_ascii_lowercase() + )); + } else { + row.push(format!( + "set_{}", + enable_field.to_ascii_lowercase() + )); + } + peripheral_rcc_table.push(row); } } (None, Some(_)) => { print!("Unable to find enable register for {}", name) } - (Some(_), None) => { - print!("Unable to find reset register for {}", name) - } (None, None) => { print!("Unable to find enable and reset register for {}", name) } From 697f93ad423fb70aa134c8810237622642a301d6 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Thu, 15 Jul 2021 13:50:39 -0300 Subject: [PATCH 2/2] stm32: Add F0 example --- .github/workflows/rust.yml | 2 ++ examples/stm32f0/.cargo/config.toml | 10 +++++++++ examples/stm32f0/Cargo.toml | 29 ++++++++++++++++++++++++ examples/stm32f0/build.rs | 31 ++++++++++++++++++++++++++ examples/stm32f0/memory.x | 6 +++++ examples/stm32f0/src/bin/hello.rs | 23 +++++++++++++++++++ examples/stm32f0/src/example_common.rs | 17 ++++++++++++++ 7 files changed, 118 insertions(+) create mode 100644 examples/stm32f0/.cargo/config.toml create mode 100644 examples/stm32f0/Cargo.toml create mode 100644 examples/stm32f0/build.rs create mode 100644 examples/stm32f0/memory.x create mode 100644 examples/stm32f0/src/bin/hello.rs create mode 100644 examples/stm32f0/src/example_common.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2035c96d..118143da 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -88,6 +88,8 @@ jobs: target: thumbv6m-none-eabi - package: examples/stm32wb55 target: thumbv7em-none-eabihf + - package: examples/stm32f0 + target: thumbv6m-none-eabi steps: - uses: actions/checkout@v2 diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml new file mode 100644 index 00000000..7506fa91 --- /dev/null +++ b/examples/stm32f0/.cargo/config.toml @@ -0,0 +1,10 @@ +[target.thumbv6m-none-eabi] +runner = 'probe-run --chip STM32F030F4Px' +rustflags = [ + # LLD (shipped with the Rust toolchain) is used as the default linker + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", +] + +[build] +target = "thumbv6m-none-eabi" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml new file mode 100644 index 00000000..cc2c3f2b --- /dev/null +++ b/examples/stm32f0/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "embassy-stm32f0-examples" +version = "0.1.0" +authors = ["Thales Fragoso "] +edition = "2018" +resolver = "2" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cortex-m = { version = "0.7.1", features = ["inline-asm"] } +cortex-m-rt = "0.6.13" +defmt = "0.2.0" +defmt-rtt = "0.2.0" +panic-probe = { version = "0.2.0" } +rtt-target = { version = "0.3", features = ["cortex-m"] } +embassy = { path = "../../embassy", features = ["defmt"] } +embassy-stm32 = { path = "../../embassy-stm32", features = ["defmt", "stm32f030f4"] } + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] diff --git a/examples/stm32f0/build.rs b/examples/stm32f0/build.rs new file mode 100644 index 00000000..d534cc3d --- /dev/null +++ b/examples/stm32f0/build.rs @@ -0,0 +1,31 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/examples/stm32f0/memory.x b/examples/stm32f0/memory.x new file mode 100644 index 00000000..3bddaed4 --- /dev/null +++ b/examples/stm32f0/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 16K + /* DTCM */ + RAM : ORIGIN = 0x20000000, LENGTH = 4K +} diff --git a/examples/stm32f0/src/bin/hello.rs b/examples/stm32f0/src/bin/hello.rs new file mode 100644 index 00000000..a78b9892 --- /dev/null +++ b/examples/stm32f0/src/bin/hello.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +use defmt::info; + +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::Peripherals; + +#[path = "../example_common.rs"] +mod example_common; + +#[embassy::main] +async fn main(_spawner: Spawner, _p: Peripherals) -> ! { + loop { + Timer::after(Duration::from_secs(1)).await; + info!("Hello"); + } +} diff --git a/examples/stm32f0/src/example_common.rs b/examples/stm32f0/src/example_common.rs new file mode 100644 index 00000000..54d63383 --- /dev/null +++ b/examples/stm32f0/src/example_common.rs @@ -0,0 +1,17 @@ +#![macro_use] + +use defmt_rtt as _; // global logger +use panic_probe as _; + +pub use defmt::*; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +defmt::timestamp! {"{=u64}", { + static COUNT: AtomicUsize = AtomicUsize::new(0); + // NOTE(no-CAS) `timestamps` runs with interrupts disabled + let n = COUNT.load(Ordering::Relaxed); + COUNT.store(n + 1, Ordering::Relaxed); + n as u64 + } +}