diff --git a/ci.sh b/ci.sh index 2259d5b5f..ccd7e2559 100755 --- a/ci.sh +++ b/ci.sh @@ -54,6 +54,7 @@ cargo batch \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ + --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 74903de0b..135f9a918 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -223,6 +223,75 @@ stm32f107rb = [ "stm32-metapac/stm32f107rb" ] stm32f107rc = [ "stm32-metapac/stm32f107rc" ] stm32f107vb = [ "stm32-metapac/stm32f107vb" ] stm32f107vc = [ "stm32-metapac/stm32f107vc" ] +stm32f301c6 = [ "stm32-metapac/stm32f301c6" ] +stm32f301c8 = [ "stm32-metapac/stm32f301c8" ] +stm32f301k6 = [ "stm32-metapac/stm32f301k6" ] +stm32f301k8 = [ "stm32-metapac/stm32f301k8" ] +stm32f301r6 = [ "stm32-metapac/stm32f301r6" ] +stm32f301r8 = [ "stm32-metapac/stm32f301r8" ] +stm32f302c6 = [ "stm32-metapac/stm32f302c6" ] +stm32f302c8 = [ "stm32-metapac/stm32f302c8" ] +stm32f302cb = [ "stm32-metapac/stm32f302cb" ] +stm32f302cc = [ "stm32-metapac/stm32f302cc" ] +stm32f302k6 = [ "stm32-metapac/stm32f302k6" ] +stm32f302k8 = [ "stm32-metapac/stm32f302k8" ] +stm32f302r6 = [ "stm32-metapac/stm32f302r6" ] +stm32f302r8 = [ "stm32-metapac/stm32f302r8" ] +stm32f302rb = [ "stm32-metapac/stm32f302rb" ] +stm32f302rc = [ "stm32-metapac/stm32f302rc" ] +stm32f302rd = [ "stm32-metapac/stm32f302rd" ] +stm32f302re = [ "stm32-metapac/stm32f302re" ] +stm32f302vb = [ "stm32-metapac/stm32f302vb" ] +stm32f302vc = [ "stm32-metapac/stm32f302vc" ] +stm32f302vd = [ "stm32-metapac/stm32f302vd" ] +stm32f302ve = [ "stm32-metapac/stm32f302ve" ] +stm32f302zd = [ "stm32-metapac/stm32f302zd" ] +stm32f302ze = [ "stm32-metapac/stm32f302ze" ] +stm32f303c6 = [ "stm32-metapac/stm32f303c6" ] +stm32f303c8 = [ "stm32-metapac/stm32f303c8" ] +stm32f303cb = [ "stm32-metapac/stm32f303cb" ] +stm32f303cc = [ "stm32-metapac/stm32f303cc" ] +stm32f303k6 = [ "stm32-metapac/stm32f303k6" ] +stm32f303k8 = [ "stm32-metapac/stm32f303k8" ] +stm32f303r6 = [ "stm32-metapac/stm32f303r6" ] +stm32f303r8 = [ "stm32-metapac/stm32f303r8" ] +stm32f303rb = [ "stm32-metapac/stm32f303rb" ] +stm32f303rc = [ "stm32-metapac/stm32f303rc" ] +stm32f303rd = [ "stm32-metapac/stm32f303rd" ] +stm32f303re = [ "stm32-metapac/stm32f303re" ] +stm32f303vb = [ "stm32-metapac/stm32f303vb" ] +stm32f303vc = [ "stm32-metapac/stm32f303vc" ] +stm32f303vd = [ "stm32-metapac/stm32f303vd" ] +stm32f303ve = [ "stm32-metapac/stm32f303ve" ] +stm32f303zd = [ "stm32-metapac/stm32f303zd" ] +stm32f303ze = [ "stm32-metapac/stm32f303ze" ] +stm32f318c8 = [ "stm32-metapac/stm32f318c8" ] +stm32f318k8 = [ "stm32-metapac/stm32f318k8" ] +stm32f328c8 = [ "stm32-metapac/stm32f328c8" ] +stm32f334c4 = [ "stm32-metapac/stm32f334c4" ] +stm32f334c6 = [ "stm32-metapac/stm32f334c6" ] +stm32f334c8 = [ "stm32-metapac/stm32f334c8" ] +stm32f334k4 = [ "stm32-metapac/stm32f334k4" ] +stm32f334k6 = [ "stm32-metapac/stm32f334k6" ] +stm32f334k8 = [ "stm32-metapac/stm32f334k8" ] +stm32f334r6 = [ "stm32-metapac/stm32f334r6" ] +stm32f334r8 = [ "stm32-metapac/stm32f334r8" ] +stm32f358cc = [ "stm32-metapac/stm32f358cc" ] +stm32f358rc = [ "stm32-metapac/stm32f358rc" ] +stm32f358vc = [ "stm32-metapac/stm32f358vc" ] +stm32f373c8 = [ "stm32-metapac/stm32f373c8" ] +stm32f373cb = [ "stm32-metapac/stm32f373cb" ] +stm32f373cc = [ "stm32-metapac/stm32f373cc" ] +stm32f373r8 = [ "stm32-metapac/stm32f373r8" ] +stm32f373rb = [ "stm32-metapac/stm32f373rb" ] +stm32f373rc = [ "stm32-metapac/stm32f373rc" ] +stm32f373v8 = [ "stm32-metapac/stm32f373v8" ] +stm32f373vb = [ "stm32-metapac/stm32f373vb" ] +stm32f373vc = [ "stm32-metapac/stm32f373vc" ] +stm32f378cc = [ "stm32-metapac/stm32f378cc" ] +stm32f378rc = [ "stm32-metapac/stm32f378rc" ] +stm32f378vc = [ "stm32-metapac/stm32f378vc" ] +stm32f398ve = [ "stm32-metapac/stm32f398ve" ] stm32f401cb = [ "stm32-metapac/stm32f401cb" ] stm32f401cc = [ "stm32-metapac/stm32f401cc" ] stm32f401cd = [ "stm32-metapac/stm32f401cd" ] diff --git a/embassy-stm32/src/pwr/f3.rs b/embassy-stm32/src/pwr/f3.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/embassy-stm32/src/pwr/f3.rs @@ -0,0 +1 @@ + diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs index a71ce8f3c..18f462bd2 100644 --- a/embassy-stm32/src/pwr/mod.rs +++ b/embassy-stm32/src/pwr/mod.rs @@ -1,4 +1,5 @@ #[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] +#[cfg_attr(pwr_f3, path = "f3.rs")] #[cfg_attr(pwr_f4, path = "f4.rs")] #[cfg_attr(pwr_f7, path = "f7.rs")] #[cfg_attr(pwr_wl5, path = "wl5.rs")] diff --git a/embassy-stm32/src/rcc/f3/mod.rs b/embassy-stm32/src/rcc/f3/mod.rs new file mode 100644 index 000000000..ab1bd7607 --- /dev/null +++ b/embassy-stm32/src/rcc/f3/mod.rs @@ -0,0 +1,374 @@ +use core::marker::PhantomData; +use embassy::util::Unborrow; + +use crate::pac::{ + flash::vals::Latency, + rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}, + FLASH, RCC, +}; +use crate::peripherals; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +const HSI: u32 = 8_000_000; + +/// RCC peripheral +pub struct Rcc<'d> { + config: Config, + phantom: PhantomData<&'d mut peripherals::RCC>, +} + +/// Clocks configutation +#[non_exhaustive] +#[derive(Default)] +pub struct Config { + /// Frequency of HSE oscillator + /// 4MHz to 32MHz + pub hse: Option, + /// Bypass HSE for an external clock + pub bypass_hse: bool, + /// Frequency of the System Clock + pub sysclk: Option, + /// Frequency of AHB bus + pub hclk: Option, + /// Frequency of APB1 bus + /// - Max frequency 36MHz + pub pclk1: Option, + /// Frequency of APB2 bus + /// - Max frequency with HSE is 72MHz + /// - Max frequency without HSE is 64MHz + pub pclk2: Option, + /// USB clock setup + /// It is valid only when, + /// - HSE is enabled, + /// - The System clock frequency is either 48MHz or 72MHz + /// - APB1 clock has a minimum frequency of 10MHz + pub pll48: bool, +} + +// Information required to setup the PLL clock +struct PllConfig { + pll_src: Pllsrc, + pll_mul: Pllmul, + pll_div: Option, +} + +/// Initialize and Set the clock frequencies +pub unsafe fn init(config: Config) { + let r = ::steal(); + let clocks = Rcc::new(r, config).freeze(); + set_freqs(clocks); +} + +impl<'d> Rcc<'d> { + pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { + Self { + config, + phantom: PhantomData, + } + } + + fn freeze(self) -> Clocks { + // Calculate the real System clock, and PLL configuration if applicable + let (Hertz(sysclk), pll_config) = self.get_sysclk(); + assert!(sysclk <= 72_000_000); + + // Calculate real AHB clock + let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); + let (hpre_bits, hpre_div) = match sysclk / hclk { + 0 => unreachable!(), + 1 => (Hpre::DIV1, 1), + 2 => (Hpre::DIV2, 2), + 3..=5 => (Hpre::DIV4, 4), + 6..=11 => (Hpre::DIV8, 8), + 12..=39 => (Hpre::DIV16, 16), + 40..=95 => (Hpre::DIV64, 64), + 96..=191 => (Hpre::DIV128, 128), + 192..=383 => (Hpre::DIV256, 256), + _ => (Hpre::DIV512, 512), + }; + let hclk = sysclk / hpre_div; + assert!(hclk <= 72_000_000); + + // Calculate real APB1 clock + let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk); + let (ppre1_bits, ppre1) = match hclk / pclk1 { + 0 => unreachable!(), + 1 => (Ppre::DIV1, 1), + 2 => (Ppre::DIV2, 2), + 3..=5 => (Ppre::DIV4, 4), + 6..=11 => (Ppre::DIV8, 8), + _ => (Ppre::DIV16, 16), + }; + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + let pclk1 = hclk / ppre1; + assert!(pclk1 <= 36_000_000); + + // Calculate real APB2 clock + let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk); + let (ppre2_bits, ppre2) = match hclk / pclk2 { + 0 => unreachable!(), + 1 => (Ppre::DIV1, 1), + 2 => (Ppre::DIV2, 2), + 3..=5 => (Ppre::DIV4, 4), + 6..=11 => (Ppre::DIV8, 8), + _ => (Ppre::DIV16, 16), + }; + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + let pclk2 = hclk / ppre2; + assert!(pclk2 <= 72_000_000); + + // Set latency based on HCLK frquency + // NOTE(safety) Atomic write + unsafe { + FLASH.acr().write(|w| { + w.set_latency(if hclk <= 24_000_000 { + Latency::WS0 + } else if hclk <= 48_000_000 { + Latency::WS1 + } else { + Latency::WS2 + }); + }) + } + + // Enable HSE + if self.config.hse.is_some() { + // NOTE(unsafe) We own the peripheral block + unsafe { + RCC.cr().write(|w| { + w.set_hsebyp(if self.config.bypass_hse { + Hsebyp::BYPASSED + } else { + Hsebyp::NOTBYPASSED + }); + // We turn on clock security to switch to HSI when HSE fails + w.set_csson(true); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + } + } + + // Enable PLL + if let Some(ref pll_config) = pll_config { + // NOTE(unsafe) We own the peripheral block + unsafe { + RCC.cfgr().write(|w| { + w.set_pllmul(pll_config.pll_mul); + w.set_pllsrc(pll_config.pll_src); + }); + if let Some(pll_div) = pll_config.pll_div { + RCC.cfgr2().write(|w| w.set_prediv(pll_div)); + } + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + } + } + + if self.config.pll48 { + let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config); + // NOTE(unsafe) We own the peripheral block + unsafe { + RCC.cfgr().write(|w| { + w.set_usbpre(usb_pre); + }); + } + } + + // Set prescalers + unsafe { + // NOTE(unsafe) We own the peripheral block + RCC.cfgr().write(|w| { + w.set_ppre2(ppre2_bits); + w.set_ppre1(ppre1_bits); + w.set_hpre(hpre_bits); + }); + + // Wait for the new prescalers to kick in + // "The clocks are divided with the new prescaler factor from + // 1 to 16 AHB cycles after write" + cortex_m::asm::delay(16); + + // NOTE(unsafe) We own the peripheral block + RCC.cfgr().write(|w| { + w.set_sw(match (pll_config, self.config.hse) { + (Some(_), _) => Sw::PLL, + (None, Some(_)) => Sw::HSE, + (None, None) => Sw::HSI, + }) + }); + } + + Clocks { + sys: Hertz(sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + ahb: Hertz(hclk), + } + } + + #[inline] + fn get_sysclk(&self) -> (Hertz, Option) { + match (self.config.sysclk, self.config.hse) { + (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), + (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), + // If the user selected System clock is different from HSI or HSE + // we will have to setup PLL clock source + (Some(sysclk), _) => { + let (sysclk, pll_config) = self.calc_pll(sysclk); + (sysclk, Some(pll_config)) + } + (None, Some(hse)) => (hse, None), + (None, None) => (Hertz(HSI), None), + } + } + + #[inline] + fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { + // Calculates the Multiplier and the Divisor to arrive at + // the required System clock from PLL source frequency + let get_mul_div = |sysclk, pllsrcclk| { + let common_div = gcd(sysclk, pllsrcclk); + let mut multiplier = sysclk / common_div; + let mut divisor = pllsrcclk / common_div; + // Minimum PLL multiplier is two + if multiplier == 1 { + multiplier *= 2; + divisor *= 2; + } + assert!(multiplier <= 16); + assert!(divisor <= 16); + (multiplier, divisor) + }; + // Based on the source of Pll, we calculate the actual system clock + // frequency, PLL's source identifier, multiplier and divisor + let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse { + Some(Hertz(hse)) => { + let (multiplier, divisor) = get_mul_div(sysclk, hse); + ( + Hertz((hse / divisor) * multiplier), + Pllsrc::HSE_DIV_PREDIV, + into_pll_mul(multiplier), + Some(into_pre_div(divisor)), + ) + } + None => { + cfg_if::cfg_if! { + // For some chips PREDIV is always two, and cannot be changed + if #[cfg(any( + feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd", + feature="stm32f303xe", feature="stm32f398xe" + ))] { + let (multiplier, divisor) = get_mul_div(sysclk, HSI); + ( + Hertz((hse / divisor) * multiplier), + Pllsrc::HSI_DIV_PREDIV, + into_pll_mul(multiplier), + Some(into_pre_div(divisor)), + ) + } else { + let pllsrcclk = HSI / 2; + let multiplier = sysclk / pllsrcclk; + assert!(multiplier <= 16); + ( + Hertz(pllsrcclk * multiplier), + Pllsrc::HSI_DIV2, + into_pll_mul(multiplier), + None, + ) + } + } + } + }; + ( + act_sysclk, + PllConfig { + pll_src, + pll_mul, + pll_div, + }, + ) + } + + #[inline] + fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option) -> Usbpre { + cfg_if::cfg_if! { + // Some chips do not have USB + if #[cfg(any(stm32f301, stm32f318, stm32f334))] { + panic!("USB clock not supported by the chip"); + } else { + let usb_ok = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); + match (usb_ok, sysclk) { + (true, 72_000_000) => Usbpre::DIV1_5, + (true, 48_000_000) => Usbpre::DIV1, + _ => panic!( + "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" + ), + } + } + } + } +} + +// This function assumes cases when multiplier is one and it +// being greater than 16 is made impossible +#[inline] +fn into_pll_mul(multiplier: u32) -> Pllmul { + match multiplier { + 2 => Pllmul::MUL2, + 3 => Pllmul::MUL3, + 4 => Pllmul::MUL4, + 5 => Pllmul::MUL5, + 6 => Pllmul::MUL6, + 7 => Pllmul::MUL7, + 8 => Pllmul::MUL8, + 9 => Pllmul::MUL9, + 10 => Pllmul::MUL10, + 11 => Pllmul::MUL11, + 12 => Pllmul::MUL12, + 13 => Pllmul::MUL13, + 14 => Pllmul::MUL14, + 15 => Pllmul::MUL15, + 16 => Pllmul::MUL16, + _ => unreachable!(), + } +} + +// This function assumes the incoming divisor cannot be greater +// than 16 +#[inline] +fn into_pre_div(divisor: u32) -> Prediv { + match divisor { + 1 => Prediv::DIV1, + 2 => Prediv::DIV2, + 3 => Prediv::DIV3, + 4 => Prediv::DIV4, + 5 => Prediv::DIV5, + 6 => Prediv::DIV6, + 7 => Prediv::DIV7, + 8 => Prediv::DIV8, + 9 => Prediv::DIV9, + 10 => Prediv::DIV10, + 11 => Prediv::DIV11, + 12 => Prediv::DIV12, + 13 => Prediv::DIV13, + 14 => Prediv::DIV14, + 15 => Prediv::DIV15, + 16 => Prediv::DIV16, + _ => unreachable!(), + } +} + +// Determine GCD using Euclidean algorithm +#[inline] +fn gcd(mut a: u32, mut b: u32) -> u32 { + while b != 0 { + let r = a % b; + a = b; + b = r; + } + a +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9883543df..619316df8 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -26,7 +26,7 @@ pub struct Clocks { #[cfg(any(rcc_wl5, rcc_u5))] pub apb3: Hertz, - #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f1, rcc_f0x0, rcc_g0))] + #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f1, rcc_f3, rcc_f0x0, rcc_g0))] pub ahb: Hertz, #[cfg(any(rcc_l4, rcc_f4, rcc_f7, rcc_h7, rcc_g4, rcc_u5, rcc_wb, rcc_wl5))] @@ -81,6 +81,9 @@ cfg_if::cfg_if! { } else if #[cfg(rcc_f1)] { mod f1; pub use f1::*; + } else if #[cfg(rcc_f3)] { + mod f3; + pub use f3::*; } else if #[cfg(rcc_f4)] { mod f4; pub use f4::*; diff --git a/examples/stm32f3/.cargo/config.toml b/examples/stm32f3/.cargo/config.toml new file mode 100644 index 000000000..eb8a8b335 --- /dev/null +++ b/examples/stm32f3/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip STM32F303VCTx" + +[build] +target = "thumbv7em-none-eabihf" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml new file mode 100644 index 000000000..cd9cd3a8f --- /dev/null +++ b/examples/stm32f3/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-stm32f3-examples" +version = "0.1.0" +resolver = "2" + +[dependencies] +embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } +embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f303vc", "unstable-pac", "memory-x", "time-driver-tim2"] } + +defmt = "0.3" +defmt-rtt = "0.3" + +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.7.5", default-features = false } +nb = "1.0.0" diff --git a/examples/stm32f3/build.rs b/examples/stm32f3/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32f3/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32f3/src/bin/blinky.rs b/examples/stm32f3/src/bin/blinky.rs new file mode 100644 index 000000000..321643557 --- /dev/null +++ b/examples/stm32f3/src/bin/blinky.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::Peripherals; +use embedded_hal::digital::v2::OutputPin; +use example_common::*; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut led = Output::new(p.PE12, Level::High, Speed::Low); + + loop { + info!("high"); + unwrap!(led.set_high()); + Timer::after(Duration::from_millis(1000)).await; + + info!("low"); + unwrap!(led.set_low()); + Timer::after(Duration::from_millis(1000)).await; + } +} diff --git a/examples/stm32f3/src/bin/button.rs b/examples/stm32f3/src/bin/button.rs new file mode 100644 index 000000000..c5fab138b --- /dev/null +++ b/examples/stm32f3/src/bin/button.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use cortex_m_rt::entry; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use example_common::*; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PA0, Pull::Down); + let mut led1 = Output::new(p.PE9, Level::High, Speed::Low); + let mut led2 = Output::new(p.PE15, Level::High, Speed::Low); + + loop { + if unwrap!(button.is_high()) { + info!("high"); + unwrap!(led1.set_high()); + unwrap!(led2.set_low()); + } else { + info!("low"); + unwrap!(led1.set_low()); + unwrap!(led2.set_high()); + } + } +} diff --git a/examples/stm32f3/src/bin/button_exti.rs b/examples/stm32f3/src/bin/button_exti.rs new file mode 100644 index 000000000..d45e4365b --- /dev/null +++ b/examples/stm32f3/src/bin/button_exti.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::Peripherals; +use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; +use example_common::*; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let button = Input::new(p.PA0, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI0); + + info!("Press the USER button..."); + + loop { + button.wait_for_rising_edge().await; + info!("Pressed!"); + button.wait_for_falling_edge().await; + info!("Released!"); + } +} diff --git a/examples/stm32f3/src/bin/hello.rs b/examples/stm32f3/src/bin/hello.rs new file mode 100644 index 000000000..9a67419fb --- /dev/null +++ b/examples/stm32f3/src/bin/hello.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_stm32::Peripherals; + +#[path = "../example_common.rs"] +mod example_common; + +fn config() -> Config { + let mut config = Config::default(); + config.rcc.hse = Some(Hertz(8_000_000)); + config.rcc.sysclk = Some(Hertz(16_000_000)); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, _p: Peripherals) -> ! { + loop { + info!("Hello World!"); + Timer::after(Duration::from_secs(1)).await; + } +} diff --git a/examples/stm32f3/src/bin/spi_dma.rs b/examples/stm32f3/src/bin/spi_dma.rs new file mode 100644 index 000000000..a87a36f73 --- /dev/null +++ b/examples/stm32f3/src/bin/spi_dma.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use core::fmt::Write; +use core::str::from_utf8; +use embassy::executor::Spawner; +use embassy_stm32::spi::{Config, Spi}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Peripherals; +use embassy_traits::spi::FullDuplex; +use example_common::*; +use heapless::String; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut spi = Spi::new( + p.SPI1, + p.PB3, + p.PB5, + p.PB4, + p.DMA1_CH3, + p.DMA1_CH2, + Hertz(1_000_000), + Config::default(), + ); + + for n in 0u32.. { + let mut write: String<128> = String::new(); + let mut read = [0; 128]; + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + spi.read_write(&mut read[0..write.len()], write.as_bytes()) + .await + .ok(); + info!("read via spi+dma: {}", from_utf8(&read).unwrap()); + } +} diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs new file mode 100644 index 000000000..99530b5c0 --- /dev/null +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use core::fmt::Write; +use embassy::executor::Spawner; +use embassy_stm32::dma::NoDma; +use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::Peripherals; +use embassy_traits::uart::Write as _; +use example_common::*; +use heapless::String; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let config = Config::default(); + let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + unwrap!(usart.write(s.as_bytes()).await); + info!("wrote DMA"); + } +} diff --git a/examples/stm32f3/src/example_common.rs b/examples/stm32f3/src/example_common.rs new file mode 100644 index 000000000..e14517033 --- /dev/null +++ b/examples/stm32f3/src/example_common.rs @@ -0,0 +1,19 @@ +#![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 + } +} diff --git a/stm32-data b/stm32-data index 5506d2747..f275c3f5e 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 5506d27471c7e3297450127c3279f3dab96c94f8 +Subproject commit f275c3f5ef23339e068f38e1790584277a24623f diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index 50c334852..1ab4865a4 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs @@ -5,6 +5,7 @@ use std::{iter::FilterMap, path::Path, slice::Iter}; const SUPPORTED_FAMILIES: &[&str] = &[ "stm32f0", "stm32f1", + "stm32f3", "stm32f4", "stm32f7", "stm32g0",