diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 79a5ad79..5cdf75d7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -78,6 +78,9 @@ jobs: - package: embassy-stm32 target: thumbv6m-none-eabi features: stm32l072cz,defmt + - package: embassy-stm32 + target: thumbv7m-none-eabi + features: stm32l151cb-a,defmt - package: examples/stm32f4 target: thumbv7em-none-eabi - package: examples/stm32l4 @@ -86,6 +89,8 @@ jobs: target: thumbv7em-none-eabi - package: examples/stm32l0 target: thumbv6m-none-eabi + - package: examples/stm32l1 + target: thumbv7m-none-eabi - package: examples/stm32wb55 target: thumbv7em-none-eabihf - package: examples/stm32wl55 diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index dec33658..3e91040f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -625,6 +625,93 @@ stm32l083rz = [ "stm32-metapac/stm32l083rz" ] stm32l083v8 = [ "stm32-metapac/stm32l083v8" ] stm32l083vb = [ "stm32-metapac/stm32l083vb" ] stm32l083vz = [ "stm32-metapac/stm32l083vz" ] +stm32l100c6-a = [ "stm32-metapac/stm32l100c6-a" ] +stm32l100c6 = [ "stm32-metapac/stm32l100c6" ] +stm32l100r8-a = [ "stm32-metapac/stm32l100r8-a" ] +stm32l100r8 = [ "stm32-metapac/stm32l100r8" ] +stm32l100rb-a = [ "stm32-metapac/stm32l100rb-a" ] +stm32l100rb = [ "stm32-metapac/stm32l100rb" ] +stm32l100rc = [ "stm32-metapac/stm32l100rc" ] +stm32l151c6-a = [ "stm32-metapac/stm32l151c6-a" ] +stm32l151c6 = [ "stm32-metapac/stm32l151c6" ] +stm32l151c8-a = [ "stm32-metapac/stm32l151c8-a" ] +stm32l151c8 = [ "stm32-metapac/stm32l151c8" ] +stm32l151cb-a = [ "stm32-metapac/stm32l151cb-a" ] +stm32l151cb = [ "stm32-metapac/stm32l151cb" ] +stm32l151cc = [ "stm32-metapac/stm32l151cc" ] +stm32l151qc = [ "stm32-metapac/stm32l151qc" ] +stm32l151qd = [ "stm32-metapac/stm32l151qd" ] +stm32l151qe = [ "stm32-metapac/stm32l151qe" ] +stm32l151r6-a = [ "stm32-metapac/stm32l151r6-a" ] +stm32l151r6 = [ "stm32-metapac/stm32l151r6" ] +stm32l151r8-a = [ "stm32-metapac/stm32l151r8-a" ] +stm32l151r8 = [ "stm32-metapac/stm32l151r8" ] +stm32l151rb-a = [ "stm32-metapac/stm32l151rb-a" ] +stm32l151rb = [ "stm32-metapac/stm32l151rb" ] +stm32l151rc-a = [ "stm32-metapac/stm32l151rc-a" ] +stm32l151rc = [ "stm32-metapac/stm32l151rc" ] +stm32l151rd = [ "stm32-metapac/stm32l151rd" ] +stm32l151re = [ "stm32-metapac/stm32l151re" ] +stm32l151uc = [ "stm32-metapac/stm32l151uc" ] +stm32l151v8-a = [ "stm32-metapac/stm32l151v8-a" ] +stm32l151v8 = [ "stm32-metapac/stm32l151v8" ] +stm32l151vb-a = [ "stm32-metapac/stm32l151vb-a" ] +stm32l151vb = [ "stm32-metapac/stm32l151vb" ] +stm32l151vc-a = [ "stm32-metapac/stm32l151vc-a" ] +stm32l151vc = [ "stm32-metapac/stm32l151vc" ] +stm32l151vd-x = [ "stm32-metapac/stm32l151vd-x" ] +stm32l151vd = [ "stm32-metapac/stm32l151vd" ] +stm32l151ve = [ "stm32-metapac/stm32l151ve" ] +stm32l151zc = [ "stm32-metapac/stm32l151zc" ] +stm32l151zd = [ "stm32-metapac/stm32l151zd" ] +stm32l151ze = [ "stm32-metapac/stm32l151ze" ] +stm32l152c6-a = [ "stm32-metapac/stm32l152c6-a" ] +stm32l152c6 = [ "stm32-metapac/stm32l152c6" ] +stm32l152c8-a = [ "stm32-metapac/stm32l152c8-a" ] +stm32l152c8 = [ "stm32-metapac/stm32l152c8" ] +stm32l152cb-a = [ "stm32-metapac/stm32l152cb-a" ] +stm32l152cb = [ "stm32-metapac/stm32l152cb" ] +stm32l152cc = [ "stm32-metapac/stm32l152cc" ] +stm32l152qc = [ "stm32-metapac/stm32l152qc" ] +stm32l152qd = [ "stm32-metapac/stm32l152qd" ] +stm32l152qe = [ "stm32-metapac/stm32l152qe" ] +stm32l152r6-a = [ "stm32-metapac/stm32l152r6-a" ] +stm32l152r6 = [ "stm32-metapac/stm32l152r6" ] +stm32l152r8-a = [ "stm32-metapac/stm32l152r8-a" ] +stm32l152r8 = [ "stm32-metapac/stm32l152r8" ] +stm32l152rb-a = [ "stm32-metapac/stm32l152rb-a" ] +stm32l152rb = [ "stm32-metapac/stm32l152rb" ] +stm32l152rc-a = [ "stm32-metapac/stm32l152rc-a" ] +stm32l152rc = [ "stm32-metapac/stm32l152rc" ] +stm32l152rd = [ "stm32-metapac/stm32l152rd" ] +stm32l152re = [ "stm32-metapac/stm32l152re" ] +stm32l152uc = [ "stm32-metapac/stm32l152uc" ] +stm32l152v8-a = [ "stm32-metapac/stm32l152v8-a" ] +stm32l152v8 = [ "stm32-metapac/stm32l152v8" ] +stm32l152vb-a = [ "stm32-metapac/stm32l152vb-a" ] +stm32l152vb = [ "stm32-metapac/stm32l152vb" ] +stm32l152vc-a = [ "stm32-metapac/stm32l152vc-a" ] +stm32l152vc = [ "stm32-metapac/stm32l152vc" ] +stm32l152vd-x = [ "stm32-metapac/stm32l152vd-x" ] +stm32l152vd = [ "stm32-metapac/stm32l152vd" ] +stm32l152ve = [ "stm32-metapac/stm32l152ve" ] +stm32l152zc = [ "stm32-metapac/stm32l152zc" ] +stm32l152zd = [ "stm32-metapac/stm32l152zd" ] +stm32l152ze = [ "stm32-metapac/stm32l152ze" ] +stm32l162qc = [ "stm32-metapac/stm32l162qc" ] +stm32l162qd = [ "stm32-metapac/stm32l162qd" ] +stm32l162rc-a = [ "stm32-metapac/stm32l162rc-a" ] +stm32l162rc = [ "stm32-metapac/stm32l162rc" ] +stm32l162rd = [ "stm32-metapac/stm32l162rd" ] +stm32l162re = [ "stm32-metapac/stm32l162re" ] +stm32l162vc-a = [ "stm32-metapac/stm32l162vc-a" ] +stm32l162vc = [ "stm32-metapac/stm32l162vc" ] +stm32l162vd-x = [ "stm32-metapac/stm32l162vd-x" ] +stm32l162vd = [ "stm32-metapac/stm32l162vd" ] +stm32l162ve = [ "stm32-metapac/stm32l162ve" ] +stm32l162zc = [ "stm32-metapac/stm32l162zc" ] +stm32l162zd = [ "stm32-metapac/stm32l162zd" ] +stm32l162ze = [ "stm32-metapac/stm32l162ze" ] stm32l412c8 = [ "stm32-metapac/stm32l412c8" ] stm32l412cb = [ "stm32-metapac/stm32l412cb" ] stm32l412k8 = [ "stm32-metapac/stm32l412k8" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8bb78a6f..32115f9a 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -85,13 +85,28 @@ fn main() { }; ); - let mut chip_and_core = chip_name.split('_'); - let chip = chip_and_core.next().expect("Unexpected stm32xx feature"); - - if let Some(core) = chip_and_core.next() { - println!("cargo:rustc-cfg={}_{}", &chip[..(chip.len() - 2)], core); + let mut s = chip_name.split('_'); + let mut chip_name: String = s.next().unwrap().to_string(); + let core_name = if let Some(c) = s.next() { + if !c.starts_with("CM") { + chip_name.push('_'); + chip_name.push_str(c); + None + } else { + Some(c) + } } else { - println!("cargo:rustc-cfg={}", &chip[..(chip.len() - 2)]); + None + }; + + if let Some(core) = core_name { + println!( + "cargo:rustc-cfg={}_{}", + &chip_name[..chip_name.len() - 2], + core + ); + } else { + println!("cargo:rustc-cfg={}", &chip_name[..chip_name.len() - 2]); } println!("cargo:rerun-if-changed=build.rs"); diff --git a/embassy-stm32/src/rcc/l1/mod.rs b/embassy-stm32/src/rcc/l1/mod.rs new file mode 100644 index 00000000..25b5609c --- /dev/null +++ b/embassy-stm32/src/rcc/l1/mod.rs @@ -0,0 +1,235 @@ +pub use super::types::*; +use crate::pac; +use crate::peripherals::{self, RCC}; +use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::time::Hertz; +use crate::time::U32Ext; +use core::marker::PhantomData; +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; +use pac::rcc::vals::{Hpre, Ppre, Sw}; + +/// Most of clock setup is copied from rcc/l0 + +/// HSI speed +pub const HSI_FREQ: u32 = 16_000_000; + +/// System clock mux source +#[derive(Clone, Copy)] +pub enum ClockSrc { + MSI(MSIRange), + HSE(Hertz), + HSI, +} + +impl Into for APBPrescaler { + fn into(self) -> Ppre { + match self { + APBPrescaler::NotDivided => Ppre::DIV1, + APBPrescaler::Div2 => Ppre::DIV2, + APBPrescaler::Div4 => Ppre::DIV4, + APBPrescaler::Div8 => Ppre::DIV8, + APBPrescaler::Div16 => Ppre::DIV16, + } + } +} + +impl Into for AHBPrescaler { + fn into(self) -> Hpre { + match self { + AHBPrescaler::NotDivided => Hpre::DIV1, + AHBPrescaler::Div2 => Hpre::DIV2, + AHBPrescaler::Div4 => Hpre::DIV4, + AHBPrescaler::Div8 => Hpre::DIV8, + AHBPrescaler::Div16 => Hpre::DIV16, + AHBPrescaler::Div64 => Hpre::DIV64, + AHBPrescaler::Div128 => Hpre::DIV128, + AHBPrescaler::Div256 => Hpre::DIV256, + AHBPrescaler::Div512 => Hpre::DIV512, + } + } +} + +impl Into for MSIRange { + fn into(self) -> u8 { + match self { + MSIRange::Range0 => 0b000, + MSIRange::Range1 => 0b001, + MSIRange::Range2 => 0b010, + MSIRange::Range3 => 0b011, + MSIRange::Range4 => 0b100, + MSIRange::Range5 => 0b101, + MSIRange::Range6 => 0b110, + } + } +} + +/// Clocks configutation +pub struct Config { + mux: ClockSrc, + ahb_pre: AHBPrescaler, + apb1_pre: APBPrescaler, + apb2_pre: APBPrescaler, +} + +impl Default for Config { + #[inline] + fn default() -> Config { + Config { + mux: ClockSrc::MSI(MSIRange::default()), + ahb_pre: AHBPrescaler::NotDivided, + apb1_pre: APBPrescaler::NotDivided, + apb2_pre: APBPrescaler::NotDivided, + } + } +} + +impl Config { + #[inline] + pub fn clock_src(mut self, mux: ClockSrc) -> Self { + self.mux = mux; + self + } + + #[inline] + pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { + self.ahb_pre = pre; + self + } + + #[inline] + pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { + self.apb1_pre = pre; + self + } + + #[inline] + pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { + self.apb2_pre = pre; + self + } +} + +/// RCC peripheral +pub struct Rcc<'d> { + _rb: peripherals::RCC, + phantom: PhantomData<&'d mut peripherals::RCC>, +} + +impl<'d> Rcc<'d> { + pub fn new(rcc: impl Unborrow + 'd) -> Self { + unborrow!(rcc); + Self { + _rb: rcc, + phantom: PhantomData, + } + } + + // Safety: RCC init must have been called + pub fn clocks(&self) -> &'static Clocks { + unsafe { get_freqs() } + } +} + +/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration +pub trait RccExt { + fn freeze(self, config: Config) -> Clocks; +} + +impl RccExt for RCC { + // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by + // marking this function and all `Config` constructors and setters as `#[inline]`. + // This saves ~900 Bytes for the `pwr.rs` example. + #[inline] + fn freeze(self, cfgr: Config) -> Clocks { + let rcc = pac::RCC; + let (sys_clk, sw) = match cfgr.mux { + ClockSrc::MSI(range) => { + // Set MSI range + unsafe { + rcc.icscr().write(|w| w.set_msirange(range.into())); + } + + // Enable MSI + unsafe { + rcc.cr().write(|w| w.set_msion(true)); + while !rcc.cr().read().msirdy() {} + } + + let freq = 32_768 * (1 << (range as u8 + 1)); + (freq, Sw::MSI) + } + ClockSrc::HSI => { + // Enable HSI + unsafe { + rcc.cr().write(|w| w.set_hsion(true)); + while !rcc.cr().read().hsirdy() {} + } + + (HSI_FREQ, Sw::HSI) + } + ClockSrc::HSE(freq) => { + // Enable HSE + unsafe { + rcc.cr().write(|w| w.set_hseon(true)); + while !rcc.cr().read().hserdy() {} + } + + (freq.0, Sw::HSE) + } + }; + + unsafe { + rcc.cfgr().modify(|w| { + w.set_sw(sw.into()); + w.set_hpre(cfgr.ahb_pre.into()); + w.set_ppre1(cfgr.apb1_pre.into()); + w.set_ppre2(cfgr.apb2_pre.into()); + }); + } + + let ahb_freq: u32 = match cfgr.ahb_pre { + AHBPrescaler::NotDivided => sys_clk, + pre => { + let pre: Hpre = pre.into(); + let pre = 1 << (pre.0 as u32 - 7); + sys_clk / pre + } + }; + + let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / pre as u32; + (freq, freq * 2) + } + }; + + let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { + APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + pre => { + let pre: Ppre = pre.into(); + let pre: u8 = 1 << (pre.0 - 3); + let freq = ahb_freq / (1 << (pre as u8 - 3)); + (freq, freq * 2) + } + }; + + Clocks { + sys: sys_clk.hz(), + ahb: ahb_freq.hz(), + apb1: apb1_freq.hz(), + apb2: apb2_freq.hz(), + apb1_tim: apb1_tim_freq.hz(), + apb2_tim: apb2_tim_freq.hz(), + } + } +} + +pub unsafe fn init(config: Config) { + let r = ::steal(); + let clocks = r.freeze(config); + set_freqs(clocks); +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 791b86c0..d6b4bec5 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -27,7 +27,7 @@ pub struct Clocks { #[cfg(rcc_wl5)] pub apb3: Hertz, - #[cfg(any(rcc_l0, rcc_f0, rcc_f0x0, rcc_g0))] + #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f0x0, rcc_g0))] pub ahb: Hertz, #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb, rcc_wl5))] @@ -73,6 +73,9 @@ cfg_if::cfg_if! { } else if #[cfg(rcc_l0)] { mod l0; pub use l0::*; + } else if #[cfg(rcc_l1)] { + mod l1; + pub use l1::*; } else if #[cfg(rcc_l4)] { mod l4; pub use l4::*; diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 554981ce..302b7a2a 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -303,28 +303,8 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T, NoDm let regs = T::regs(); for word in words.iter() { - while unsafe { !regs.sr().read().txe() } { - // spin - } - unsafe { - let dr = regs.dr().ptr() as *mut u8; - ptr::write_volatile(dr, *word); - } - loop { - let sr = unsafe { regs.sr().read() }; - if sr.fre() { - return Err(Error::Framing); - } - if sr.ovr() { - return Err(Error::Overrun); - } - if sr.crcerr() { - return Err(Error::Crc); - } - if !sr.txe() { - // loop waiting for TXE - } - } + write_word(regs, *word)?; + let _: u8 = read_word(regs)?; } Ok(()) @@ -339,33 +319,8 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T, N let regs = T::regs(); for word in words.iter_mut() { - while unsafe { !regs.sr().read().txe() } { - // spin - } - unsafe { - let dr = regs.dr().ptr() as *mut u8; - ptr::write_volatile(dr, *word); - } - - while unsafe { !regs.sr().read().rxne() } { - // spin waiting for inbound to shift in. - } - - unsafe { - let dr = regs.dr().ptr() as *const u8; - *word = ptr::read_volatile(dr); - } - - let sr = unsafe { regs.sr().read() }; - if sr.fre() { - return Err(Error::Framing); - } - if sr.ovr() { - return Err(Error::Overrun); - } - if sr.crcerr() { - return Err(Error::Crc); - } + write_word(regs, *word)?; + *word = read_word(regs)?; } Ok(words) @@ -380,28 +335,8 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T, NoD let regs = T::regs(); for word in words.iter() { - while unsafe { !regs.sr().read().txe() } { - // spin - } - unsafe { - let dr = regs.dr().ptr() as *mut u16; - ptr::write_volatile(dr, *word); - } - loop { - let sr = unsafe { regs.sr().read() }; - if sr.fre() { - return Err(Error::Framing); - } - if sr.ovr() { - return Err(Error::Overrun); - } - if sr.crcerr() { - return Err(Error::Crc); - } - if !sr.txe() { - // loop waiting for TXE - } - } + write_word(regs, *word)?; + let _: u8 = read_word(regs)?; } Ok(()) @@ -416,31 +351,8 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T, let regs = T::regs(); for word in words.iter_mut() { - while unsafe { !regs.sr().read().txe() } { - // spin - } - unsafe { - let dr = regs.dr().ptr() as *mut u16; - ptr::write_volatile(dr, *word); - } - while unsafe { !regs.sr().read().rxne() } { - // spin waiting for inbound to shift in. - } - unsafe { - let dr = regs.dr().ptr() as *const u16; - *word = ptr::read_volatile(dr); - } - - let sr = unsafe { regs.sr().read() }; - if sr.fre() { - return Err(Error::Framing); - } - if sr.ovr() { - return Err(Error::Overrun); - } - if sr.crcerr() { - return Err(Error::Crc); - } + write_word(regs, *word)?; + *word = read_word(regs)?; } Ok(words) @@ -485,3 +397,50 @@ impl<'d, T: Instance, Tx: TxDmaChannel, Rx: RxDmaChannel> traits::FullDupl self.read_write_dma_u8(read, write) } } + +trait Word {} + +impl Word for u8 {} +impl Word for u16 {} + +fn write_word(regs: &'static crate::pac::spi::Spi, word: W) -> Result<(), Error> { + loop { + let sr = unsafe { regs.sr().read() }; + if sr.ovr() { + return Err(Error::Overrun); + } else if sr.fre() { + return Err(Error::Framing); + } else if sr.modf() { + return Err(Error::ModeFault); + } else if sr.crcerr() { + return Err(Error::Crc); + } else if sr.txe() { + unsafe { + let dr = regs.dr().ptr() as *mut W; + ptr::write_volatile(dr, word); + } + return Ok(()); + } + } +} + +/// Read a single word blocking. Assumes word size have already been set. +fn read_word(regs: &'static crate::pac::spi::Spi) -> Result { + loop { + let sr = unsafe { regs.sr().read() }; + if sr.ovr() { + return Err(Error::Overrun); + } else if sr.modf() { + return Err(Error::ModeFault); + } else if sr.fre() { + return Err(Error::Framing); + } else if sr.crcerr() { + return Err(Error::Crc); + } else if sr.rxne() { + unsafe { + let dr = regs.dr().ptr() as *const W; + return Ok(ptr::read_volatile(dr)); + } + } + } +} diff --git a/examples/stm32l1/.cargo/config.toml b/examples/stm32l1/.cargo/config.toml new file mode 100644 index 00000000..e0d2bddf --- /dev/null +++ b/examples/stm32l1/.cargo/config.toml @@ -0,0 +1,18 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip STM32L151CBxxA" + +rustflags = [ + # LLD (shipped with the Rust toolchain) is used as the default linker + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] + +[build] +target = "thumbv7m-none-eabi" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml new file mode 100644 index 00000000..e4dd7186 --- /dev/null +++ b/examples/stm32l1/Cargo.toml @@ -0,0 +1,35 @@ +[package] +authors = ["Dario Nieuwenhuis ", "Ulf Lilleengen "] +edition = "2018" +name = "embassy-stm32l1-examples" +version = "0.1.0" +resolver = "2" + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + +[dependencies] +embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } +embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32l151cb-a", "time-driver-tim2", "memory-x"] } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } +embassy-macros = { path = "../../embassy-macros" } + +defmt = "0.2.3" +defmt-rtt = "0.2.0" + +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +rtt-target = { version = "0.3.1", features = ["cortex-m"] } +heapless = { version = "0.7.5", default-features = false } diff --git a/examples/stm32l1/build.rs b/examples/stm32l1/build.rs new file mode 100644 index 00000000..d534cc3d --- /dev/null +++ b/examples/stm32l1/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/stm32l1/memory.x b/examples/stm32l1/memory.x new file mode 100644 index 00000000..c94d395c --- /dev/null +++ b/examples/stm32l1/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 32K +} diff --git a/examples/stm32l1/src/bin/blinky.rs b/examples/stm32l1/src/bin/blinky.rs new file mode 100644 index 00000000..deabdddb --- /dev/null +++ b/examples/stm32l1/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.PA12, 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/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs new file mode 100644 index 00000000..3cfbe3fc --- /dev/null +++ b/examples/stm32l1/src/bin/spi.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embedded_hal::digital::v2::OutputPin; +use example_common::*; + +use embassy_stm32::dma::NoDma; +use embassy_stm32::spi::{Config, Spi}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Peripherals; +use embedded_hal::blocking::spi::Transfer; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World, folks!"); + + let mut spi = Spi::new( + p.SPI1, + p.PA5, + p.PA7, + p.PA6, + NoDma, + NoDma, + Hertz(1_000_000), + Config::default(), + ); + + let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); + + loop { + let mut buf = [0x0Au8; 4]; + unwrap!(cs.set_low()); + unwrap!(spi.transfer(&mut buf)); + unwrap!(cs.set_high()); + info!("xfer {=[u8]:x}", buf); + } +} diff --git a/examples/stm32l1/src/example_common.rs b/examples/stm32l1/src/example_common.rs new file mode 100644 index 00000000..54d63383 --- /dev/null +++ b/examples/stm32l1/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 + } +} diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index 38dd98d1..b157e3ae 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -1,6 +1,7 @@ [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 STM32L4S5VI" +#runner = "probe-run --chip STM32L475VGT6" +runner = "probe-run --chip STM32L475VG" rustflags = [ # LLD (shipped with the Rust toolchain) is used as the default linker diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d7ad907f..8f347343 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -3,4 +3,4 @@ [toolchain] channel = "nightly-2021-08-18" components = [ "rust-src", "rustfmt" ] -targets = [ "thumbv7em-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "wasm32-unknown-unknown" ] +targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "wasm32-unknown-unknown" ] diff --git a/stm32-data b/stm32-data index 3fb217ad..7f5f8e7c 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 3fb217ad3eebe2d8808b8af4d04ce051c69ecb72 +Subproject commit 7f5f8e7c641d74a0e97e2d84bac61b7c6c267a7e diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index 597d78b0..75eb7d75 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs @@ -2,11 +2,12 @@ use std::{iter::FilterMap, path::Path, slice::Iter}; -const SUPPORTED_FAMILIES: [&str; 8] = [ +const SUPPORTED_FAMILIES: [&str; 9] = [ "stm32f0", "stm32f4", "stm32g0", "stm32l0", + "stm32l1", "stm32l4", "stm32h7", "stm32wb55", diff --git a/stm32-metapac-gen/src/assets/build.rs b/stm32-metapac-gen/src/assets/build.rs index 4110fe48..1c941115 100644 --- a/stm32-metapac-gen/src/assets/build.rs +++ b/stm32-metapac-gen/src/assets/build.rs @@ -9,6 +9,17 @@ fn main() { .unwrap() .to_ascii_lowercase(); + let mut s = chip_name.split('_'); + let mut chip_name: String = s.next().unwrap().to_string(); + if let Some(c) = s.next() { + if !c.starts_with("CM") { + chip_name.push('-'); + } else { + chip_name.push('_'); + } + chip_name.push_str(c); + } + #[cfg(feature = "memory-x")] println!("cargo:rustc-link-search=src/chips/{}/memory_x/", _chip_name); diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 3bfd5297..5c0f1d00 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -218,7 +218,7 @@ pub fn gen(options: Options) { let core_name: Option<&str> = if let Some(c) = s.next() { if !c.starts_with("CM") { println!("Core not detected, adding as variant"); - chip_name.push_str("-"); + chip_name.push('-'); chip_name.push_str(c); None } else { diff --git a/stm32-metapac/build.rs b/stm32-metapac/build.rs index ca964c9e..d840d8fe 100644 --- a/stm32-metapac/build.rs +++ b/stm32-metapac/build.rs @@ -22,6 +22,17 @@ fn main() { chips: vec![chip_name.clone()], }); + let mut s = chip_name.split('_'); + let mut chip_name: String = s.next().unwrap().to_string(); + if let Some(c) = s.next() { + if !c.starts_with("CM") { + chip_name.push('-'); + } else { + chip_name.push('_'); + } + chip_name.push_str(c); + } + println!( "cargo:rustc-link-search={}/src/chips/{}", out_dir.display(),