diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ff30a09a..59549fac 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -112,6 +112,8 @@ jobs: target: wasm32-unknown-unknown - package: examples/stm32f1 target: thumbv7m-none-eabi + - package: examples/stm32f7 + target: thumbv7em-none-eabihf steps: - uses: actions/checkout@v2 with: diff --git a/Cargo.example.toml b/Cargo.example.toml index 0e9d1e32..3fa8a32e 100644 --- a/Cargo.example.toml +++ b/Cargo.example.toml @@ -34,11 +34,17 @@ members = [ #"embassy-stm32", #"stm32-metapac", # uncomment ONLY ONE example crate. + #"examples/stm32f0", + #"examples/stm32f1", #"examples/stm32f4", + #"examples/stm32f7", + #"examples/stm32g0", #"examples/stm32h7", #"examples/stm32l0", + #"examples/stm32l1", #"examples/stm32l4", #"examples/stm32wb55", + #"examples/stm32wl55", # rp2040 #"embassy-rp", diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b2f86337..ecad1975 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -378,6 +378,94 @@ stm32f479vg = [ "stm32-metapac/stm32f479vg" ] stm32f479vi = [ "stm32-metapac/stm32f479vi" ] stm32f479zg = [ "stm32-metapac/stm32f479zg" ] stm32f479zi = [ "stm32-metapac/stm32f479zi" ] +stm32f722ic = [ "stm32-metapac/stm32f722ic" ] +stm32f722ie = [ "stm32-metapac/stm32f722ie" ] +stm32f722rc = [ "stm32-metapac/stm32f722rc" ] +stm32f722re = [ "stm32-metapac/stm32f722re" ] +stm32f722vc = [ "stm32-metapac/stm32f722vc" ] +stm32f722ve = [ "stm32-metapac/stm32f722ve" ] +stm32f722zc = [ "stm32-metapac/stm32f722zc" ] +stm32f722ze = [ "stm32-metapac/stm32f722ze" ] +stm32f723ic = [ "stm32-metapac/stm32f723ic" ] +stm32f723ie = [ "stm32-metapac/stm32f723ie" ] +stm32f723vc = [ "stm32-metapac/stm32f723vc" ] +stm32f723ve = [ "stm32-metapac/stm32f723ve" ] +stm32f723zc = [ "stm32-metapac/stm32f723zc" ] +stm32f723ze = [ "stm32-metapac/stm32f723ze" ] +stm32f730i8 = [ "stm32-metapac/stm32f730i8" ] +stm32f730r8 = [ "stm32-metapac/stm32f730r8" ] +stm32f730v8 = [ "stm32-metapac/stm32f730v8" ] +stm32f730z8 = [ "stm32-metapac/stm32f730z8" ] +stm32f732ie = [ "stm32-metapac/stm32f732ie" ] +stm32f732re = [ "stm32-metapac/stm32f732re" ] +stm32f732ve = [ "stm32-metapac/stm32f732ve" ] +stm32f732ze = [ "stm32-metapac/stm32f732ze" ] +stm32f733ie = [ "stm32-metapac/stm32f733ie" ] +stm32f733ve = [ "stm32-metapac/stm32f733ve" ] +stm32f733ze = [ "stm32-metapac/stm32f733ze" ] +stm32f745ie = [ "stm32-metapac/stm32f745ie" ] +stm32f745ig = [ "stm32-metapac/stm32f745ig" ] +stm32f745ve = [ "stm32-metapac/stm32f745ve" ] +stm32f745vg = [ "stm32-metapac/stm32f745vg" ] +stm32f745ze = [ "stm32-metapac/stm32f745ze" ] +stm32f745zg = [ "stm32-metapac/stm32f745zg" ] +stm32f746be = [ "stm32-metapac/stm32f746be" ] +stm32f746bg = [ "stm32-metapac/stm32f746bg" ] +stm32f746ie = [ "stm32-metapac/stm32f746ie" ] +stm32f746ig = [ "stm32-metapac/stm32f746ig" ] +stm32f746ne = [ "stm32-metapac/stm32f746ne" ] +stm32f746ng = [ "stm32-metapac/stm32f746ng" ] +stm32f746ve = [ "stm32-metapac/stm32f746ve" ] +stm32f746vg = [ "stm32-metapac/stm32f746vg" ] +stm32f746ze = [ "stm32-metapac/stm32f746ze" ] +stm32f746zg = [ "stm32-metapac/stm32f746zg" ] +stm32f750n8 = [ "stm32-metapac/stm32f750n8" ] +stm32f750v8 = [ "stm32-metapac/stm32f750v8" ] +stm32f750z8 = [ "stm32-metapac/stm32f750z8" ] +stm32f756bg = [ "stm32-metapac/stm32f756bg" ] +stm32f756ig = [ "stm32-metapac/stm32f756ig" ] +stm32f756ng = [ "stm32-metapac/stm32f756ng" ] +stm32f756vg = [ "stm32-metapac/stm32f756vg" ] +stm32f756zg = [ "stm32-metapac/stm32f756zg" ] +stm32f765bg = [ "stm32-metapac/stm32f765bg" ] +stm32f765bi = [ "stm32-metapac/stm32f765bi" ] +stm32f765ig = [ "stm32-metapac/stm32f765ig" ] +stm32f765ii = [ "stm32-metapac/stm32f765ii" ] +stm32f765ng = [ "stm32-metapac/stm32f765ng" ] +stm32f765ni = [ "stm32-metapac/stm32f765ni" ] +stm32f765vg = [ "stm32-metapac/stm32f765vg" ] +stm32f765vi = [ "stm32-metapac/stm32f765vi" ] +stm32f765zg = [ "stm32-metapac/stm32f765zg" ] +stm32f765zi = [ "stm32-metapac/stm32f765zi" ] +stm32f767bg = [ "stm32-metapac/stm32f767bg" ] +stm32f767bi = [ "stm32-metapac/stm32f767bi" ] +stm32f767ig = [ "stm32-metapac/stm32f767ig" ] +stm32f767ii = [ "stm32-metapac/stm32f767ii" ] +stm32f767ng = [ "stm32-metapac/stm32f767ng" ] +stm32f767ni = [ "stm32-metapac/stm32f767ni" ] +stm32f767vg = [ "stm32-metapac/stm32f767vg" ] +stm32f767vi = [ "stm32-metapac/stm32f767vi" ] +stm32f767zg = [ "stm32-metapac/stm32f767zg" ] +stm32f767zi = [ "stm32-metapac/stm32f767zi" ] +stm32f768ai = [ "stm32-metapac/stm32f768ai" ] +stm32f769ag = [ "stm32-metapac/stm32f769ag" ] +stm32f769ai = [ "stm32-metapac/stm32f769ai" ] +stm32f769bg = [ "stm32-metapac/stm32f769bg" ] +stm32f769bi = [ "stm32-metapac/stm32f769bi" ] +stm32f769ig = [ "stm32-metapac/stm32f769ig" ] +stm32f769ii = [ "stm32-metapac/stm32f769ii" ] +stm32f769ng = [ "stm32-metapac/stm32f769ng" ] +stm32f769ni = [ "stm32-metapac/stm32f769ni" ] +stm32f777bi = [ "stm32-metapac/stm32f777bi" ] +stm32f777ii = [ "stm32-metapac/stm32f777ii" ] +stm32f777ni = [ "stm32-metapac/stm32f777ni" ] +stm32f777vi = [ "stm32-metapac/stm32f777vi" ] +stm32f777zi = [ "stm32-metapac/stm32f777zi" ] +stm32f778ai = [ "stm32-metapac/stm32f778ai" ] +stm32f779ai = [ "stm32-metapac/stm32f779ai" ] +stm32f779bi = [ "stm32-metapac/stm32f779bi" ] +stm32f779ii = [ "stm32-metapac/stm32f779ii" ] +stm32f779ni = [ "stm32-metapac/stm32f779ni" ] stm32g030c6 = [ "stm32-metapac/stm32g030c6" ] stm32g030c8 = [ "stm32-metapac/stm32g030c8" ] stm32g030f6 = [ "stm32-metapac/stm32g030f6" ] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index f292d020..9c3a30fb 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,6 +1,7 @@ #![macro_use] #[cfg_attr(adc_v3, path = "v3.rs")] +#[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(adc_g0, path = "v3.rs")] mod _version; diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/embassy-stm32/src/adc/v2.rs @@ -0,0 +1 @@ + diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index b73b8839..191fc42a 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -119,7 +119,7 @@ crate::pac::peripherals!( unsafe impl bxcan::MasterInstance for peripherals::CAN1 {} }; (can, CAN3) => { - unsafe impl bxcan::FilterOwner for peripherals::$inst { + unsafe impl bxcan::FilterOwner for peripherals::CAN3 { const NUM_FILTER_BANKS: u8 = 14; } }; diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 0a15563e..a54c4083 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,5 +1,6 @@ #![macro_use] +#[cfg_attr(dac_v1, path = "v1.rs")] #[cfg_attr(dac_v2, path = "v2.rs")] mod _version; use crate::gpio::NoPin; diff --git a/embassy-stm32/src/dac/v1.rs b/embassy-stm32/src/dac/v1.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/embassy-stm32/src/dac/v1.rs @@ -0,0 +1 @@ + diff --git a/embassy-stm32/src/pwr/f7.rs b/embassy-stm32/src/pwr/f7.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/embassy-stm32/src/pwr/f7.rs @@ -0,0 +1 @@ + diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs index 37f7e572..2577eab3 100644 --- a/embassy-stm32/src/pwr/mod.rs +++ b/embassy-stm32/src/pwr/mod.rs @@ -1,5 +1,6 @@ #[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] #[cfg_attr(pwr_f4, path = "f4.rs")] +#[cfg_attr(pwr_f7, path = "f7.rs")] #[cfg_attr(pwr_wl5, path = "wl5.rs")] #[cfg_attr(pwr_g0, path = "g0.rs")] #[cfg_attr(pwr_l1, path = "l1.rs")] diff --git a/embassy-stm32/src/rcc/f7/max.rs b/embassy-stm32/src/rcc/f7/max.rs new file mode 100644 index 00000000..db00fdf3 --- /dev/null +++ b/embassy-stm32/src/rcc/f7/max.rs @@ -0,0 +1,19 @@ +pub(crate) const HSE_OSC_MIN: u32 = 4_000_000; +pub(crate) const HSE_OSC_MAX: u32 = 26_000_000; +pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000; +pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000; + +pub(crate) const HCLK_MAX: u32 = 216_000_000; +pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000; + +pub(crate) const SYSCLK_MIN: u32 = 12_500_000; +pub(crate) const SYSCLK_MAX: u32 = 216_000_000; + +pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN; +pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4; + +pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN; +pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2; + +pub(crate) const PLL_48_CLK: u32 = 48_000_000; +pub(crate) const PLL_48_TOLERANCE: u32 = 120_000; diff --git a/embassy-stm32/src/rcc/f7/mod.rs b/embassy-stm32/src/rcc/f7/mod.rs new file mode 100644 index 00000000..c13e2016 --- /dev/null +++ b/embassy-stm32/src/rcc/f7/mod.rs @@ -0,0 +1,347 @@ +mod max; + +use crate::pac::{FLASH, PWR, RCC}; +use crate::peripherals; +use crate::rcc::{get_freqs, set_freqs, Clocks}; +use crate::time::Hertz; +use core::marker::PhantomData; +use embassy::util::Unborrow; + +const HSI: u32 = 16_000_000; + +#[non_exhaustive] +#[derive(Default)] +pub struct Config { + pub hse: Option, + pub bypass_hse: bool, + pub hclk: Option, + pub sys_ck: Option, + pub pclk1: Option, + pub pclk2: Option, + + pub pll48: bool, +} + +/// RCC peripheral +pub struct Rcc<'d> { + config: Config, + phantom: PhantomData<&'d mut peripherals::RCC>, +} + +impl<'d> Rcc<'d> { + pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { + if let Some(hse) = config.hse { + if config.bypass_hse { + assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); + } else { + assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); + } + } + Self { + config, + phantom: PhantomData, + } + } + + fn freeze(mut self) -> Clocks { + use super::sealed::RccPeripheral; + use crate::pac::pwr::vals::Vos; + use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; + + let base_clock = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); + let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(base_clock); + let sysclk_on_pll = sysclk != base_clock; + + assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); + + let plls = self.setup_pll( + base_clock, + self.config.hse.is_some(), + if sysclk_on_pll { Some(sysclk) } else { None }, + self.config.pll48, + ); + + if self.config.pll48 { + assert!( + // USB specification allows +-0.25% + plls.pll48clk + .map(|freq| (max::PLL_48_CLK as i32 - freq as i32).abs() + <= max::PLL_48_TOLERANCE as i32) + .unwrap_or(false) + ); + } + + let sysclk = if sysclk_on_pll { + unwrap!(plls.pllsysclk) + } else { + sysclk + }; + + // AHB prescaler + let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); + let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / 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), + }; + + // Calculate real AHB clock + let hclk = sysclk / hpre_div; + + assert!(hclk < max::HCLK_MAX); + + let pclk1 = self + .config + .pclk1 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); + + let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + + // Calculate real APB1 clock + let pclk1 = hclk / ppre1; + assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1)); + + let pclk2 = self + .config + .pclk2 + .map(|p| p.0) + .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); + let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { + 0 => unreachable!(), + 1 => (0b000, 1), + 2 => (0b100, 2), + 3..=5 => (0b101, 4), + 6..=11 => (0b110, 8), + _ => (0b111, 16), + }; + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + + // Calculate real APB2 clock + let pclk2 = hclk / ppre2; + assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); + + Self::flash_setup(sysclk); + + if self.config.hse.is_some() { + // NOTE(unsafe) We own the peripheral block + unsafe { + RCC.cr().modify(|w| { + w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); + w.set_hseon(true); + }); + while !RCC.cr().read().hserdy() {} + } + } + + if plls.use_pll { + unsafe { + RCC.cr().modify(|w| w.set_pllon(false)); + + // enable PWR and setup VOSScale + + RCC.apb1enr().modify(|w| w.set_pwren(true)); + + let vos_scale = if sysclk <= 144_000_000 { + 3 + } else if sysclk <= 168_000_000 { + 2 + } else { + 1 + }; + PWR.cr1().modify(|w| { + w.set_vos(match vos_scale { + 3 => Vos::SCALE3, + 2 => Vos::SCALE2, + 1 => Vos::SCALE1, + _ => panic!("Invalid VOS Scale."), + }) + }); + + RCC.cr().modify(|w| w.set_pllon(true)); + + while !RCC.cr().read().pllrdy() {} + + if hclk > max::HCLK_OVERDRIVE_FREQUENCY { + peripherals::PWR::enable(); + + PWR.cr1().modify(|w| w.set_oden(true)); + while !PWR.csr1().read().odrdy() {} + + PWR.cr1().modify(|w| w.set_odswen(true)); + while !PWR.csr1().read().odswrdy() {} + } + + while !RCC.cr().read().pllrdy() {} + } + } + + unsafe { + RCC.cfgr().modify(|w| { + w.set_ppre2(Ppre(ppre2_bits)); + w.set_ppre1(Ppre(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); + + RCC.cfgr().modify(|w| { + w.set_sw(if sysclk_on_pll { + Sw::PLL + } else if self.config.hse.is_some() { + Sw::HSE + } else { + Sw::HSI + }) + }); + } + + Clocks { + sys: Hertz(sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + + ahb1: Hertz(hclk), + ahb2: Hertz(hclk), + ahb3: Hertz(hclk), + } + } + + // Safety: RCC init must have been called + pub fn clocks(&self) -> &'static Clocks { + unsafe { get_freqs() } + } + + fn setup_pll( + &mut self, + pllsrcclk: u32, + use_hse: bool, + pllsysclk: Option, + pll48clk: bool, + ) -> PllResults { + use crate::pac::rcc::vals::{Pllp, Pllsrc}; + + let sysclk = pllsysclk.unwrap_or(pllsrcclk); + if pllsysclk.is_none() && !pll48clk { + // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock + unsafe { + RCC.pllcfgr() + .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); + } + + return PllResults { + use_pll: false, + pllsysclk: None, + pll48clk: None, + }; + } + // Input divisor from PLL source clock, must result to frequency in + // the range from 1 to 2 MHz + let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; + let pllm_max = pllsrcclk / 1_000_000; + + // Sysclk output divisor must be one of 2, 4, 6 or 8 + let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); + + let target_freq = if pll48clk { + 48_000_000 + } else { + sysclk * sysclk_div + }; + + // Find the lowest pllm value that minimize the difference between + // target frequency and the real vco_out frequency. + let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { + let vco_in = pllsrcclk / pllm; + let plln = target_freq / vco_in; + target_freq - vco_in * plln + })); + + let vco_in = pllsrcclk / pllm; + assert!((1_000_000..=2_000_000).contains(&vco_in)); + + // Main scaler, must result in >= 100MHz (>= 192MHz for F401) + // and <= 432MHz, min 50, max 432 + let plln = if pll48clk { + // try the different valid pllq according to the valid + // main scaller values, and take the best + let pllq = unwrap!((4..=9).min_by_key(|pllq| { + let plln = 48_000_000 * pllq / vco_in; + let pll48_diff = 48_000_000 - vco_in * plln / pllq; + let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); + (pll48_diff, sysclk_diff) + })); + 48_000_000 * pllq / vco_in + } else { + sysclk * sysclk_div / vco_in + }; + + let pllp = (sysclk_div / 2) - 1; + + let pllq = (vco_in * plln + 47_999_999) / 48_000_000; + let real_pll48clk = vco_in * plln / pllq; + + unsafe { + RCC.pllcfgr().modify(|w| { + w.set_pllm(pllm as u8); + w.set_plln(plln as u16); + w.set_pllp(Pllp(pllp as u8)); + w.set_pllq(pllq as u8); + w.set_pllsrc(Pllsrc(use_hse as u8)); + }); + } + + let real_pllsysclk = vco_in * plln / sysclk_div; + + PllResults { + use_pll: true, + pllsysclk: Some(real_pllsysclk), + pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, + } + } + + fn flash_setup(sysclk: u32) { + use crate::pac::flash::vals::Latency; + + // Be conservative with voltage ranges + const FLASH_LATENCY_STEP: u32 = 30_000_000; + + critical_section::with(|_| unsafe { + FLASH + .acr() + .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); + }); + } +} + +pub unsafe fn init(config: Config) { + let r = ::steal(); + let clocks = Rcc::new(r, config).freeze(); + set_freqs(clocks); +} + +struct PllResults { + use_pll: bool, + pllsysclk: Option, + pll48clk: Option, +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index ef1d6a85..28def28a 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -30,13 +30,13 @@ pub struct Clocks { #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f1, rcc_f0x0, rcc_g0))] pub ahb: Hertz, - #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb, rcc_wl5))] + #[cfg(any(rcc_l4, rcc_f4, rcc_f7, rcc_h7, rcc_wb, rcc_wl5))] pub ahb1: Hertz, - #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb, rcc_wl5))] + #[cfg(any(rcc_l4, rcc_f4, rcc_f7, rcc_h7, rcc_wb, rcc_wl5))] pub ahb2: Hertz, - #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb, rcc_wl5))] + #[cfg(any(rcc_l4, rcc_f4, rcc_f7, rcc_h7, rcc_wb, rcc_wl5))] pub ahb3: Hertz, #[cfg(any(rcc_h7))] @@ -85,6 +85,9 @@ cfg_if::cfg_if! { } else if #[cfg(rcc_f4)] { mod f4; pub use f4::*; + } else if #[cfg(rcc_f7)] { + mod f7; + pub use f7::*; } else if #[cfg(rcc_wb)] { mod wb; pub use wb::*; diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 9244c22a..087cb4c4 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1,6 +1,6 @@ #![macro_use] -//#[cfg_attr(sdmmc_v1, path = "v1.rs")] +#[cfg_attr(sdmmc_v1, path = "v1.rs")] #[cfg_attr(sdmmc_v2, path = "v2.rs")] mod _version; diff --git a/embassy-stm32/src/sdmmc/v1.rs b/embassy-stm32/src/sdmmc/v1.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/embassy-stm32/src/sdmmc/v1.rs @@ -0,0 +1 @@ + diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml new file mode 100644 index 00000000..632e8154 --- /dev/null +++ b/examples/stm32f7/.cargo/config.toml @@ -0,0 +1,18 @@ +[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 STM32F767ZITx" + +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 = "thumbv7em-none-eabihf" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml new file mode 100644 index 00000000..cda2d777 --- /dev/null +++ b/examples/stm32f7/Cargo.toml @@ -0,0 +1,35 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-stm32f7-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", "stm32f767zi", "unstable-pac", "time-driver-tim2"] } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } + +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 } +nb = "1.0.0" diff --git a/examples/stm32f7/build.rs b/examples/stm32f7/build.rs new file mode 100644 index 00000000..b81f6b6e --- /dev/null +++ b/examples/stm32f7/build.rs @@ -0,0 +1,39 @@ +//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs +use std::env; +use std::fs::File; +use std::io::{self, prelude::*}; +use std::path::PathBuf; + +#[derive(Debug)] +enum Error { + Env(env::VarError), + Io(io::Error), +} + +impl From for Error { + fn from(error: env::VarError) -> Self { + Self::Env(error) + } +} + +impl From for Error { + fn from(error: io::Error) -> Self { + Self::Io(error) + } +} + +fn main() -> Result<(), Error> { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=memory.x"); + + let out_dir = env::var("OUT_DIR")?; + let out_dir = PathBuf::from(out_dir); + + let memory_x = include_bytes!("memory.x").as_ref(); + File::create(out_dir.join("memory.x"))?.write_all(memory_x)?; + + // Tell Cargo where to find the file. + println!("cargo:rustc-link-search={}", out_dir.display()); + + Ok(()) +} diff --git a/examples/stm32f7/memory.x b/examples/stm32f7/memory.x new file mode 100644 index 00000000..899f7a4b --- /dev/null +++ b/examples/stm32f7/memory.x @@ -0,0 +1,12 @@ +/* For STM32F765,767,768,769,777,778,779 devices */ +MEMORY +{ + /* NOTE K = KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 2M + RAM : ORIGIN = 0x20000000, LENGTH = 368K + 16K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); diff --git a/examples/stm32f7/src/bin/blinky.rs b/examples/stm32f7/src/bin/blinky.rs new file mode 100644 index 00000000..c4857195 --- /dev/null +++ b/examples/stm32f7/src/bin/blinky.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::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.PB7, Level::High, Speed::Low); + + loop { + info!("high"); + unwrap!(led.set_high()); + Timer::after(Duration::from_millis(300)).await; + + info!("low"); + unwrap!(led.set_low()); + Timer::after(Duration::from_millis(300)).await; + } +} diff --git a/examples/stm32f7/src/bin/button.rs b/examples/stm32f7/src/bin/button.rs new file mode 100644 index 00000000..95dee7c7 --- /dev/null +++ b/examples/stm32f7/src/bin/button.rs @@ -0,0 +1,34 @@ +#![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.PC13, Pull::Down); + let mut led1 = Output::new(p.PB0, Level::High, Speed::Low); + let _led2 = Output::new(p.PB7, Level::High, Speed::Low); + let mut led3 = Output::new(p.PB14, Level::High, Speed::Low); + + loop { + if unwrap!(button.is_high()) { + info!("high"); + unwrap!(led1.set_high()); + unwrap!(led3.set_low()); + } else { + info!("low"); + unwrap!(led1.set_low()); + unwrap!(led3.set_high()); + } + } +} diff --git a/examples/stm32f7/src/bin/button_exti.rs b/examples/stm32f7/src/bin/button_exti.rs new file mode 100644 index 00000000..2c4318d6 --- /dev/null +++ b/examples/stm32f7/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.PC13, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI13); + + 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/stm32f7/src/bin/hello.rs b/examples/stm32f7/src/bin/hello.rs new file mode 100644 index 00000000..56eb67bf --- /dev/null +++ b/examples/stm32f7/src/bin/hello.rs @@ -0,0 +1,27 @@ +#![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.sys_ck = Some(Hertz(84_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/stm32f7/src/example_common.rs b/examples/stm32f7/src/example_common.rs new file mode 100644 index 00000000..54d63383 --- /dev/null +++ b/examples/stm32f7/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/stm32-data b/stm32-data index bae2d344..4972ce0a 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit bae2d34445f87e7b9a88b683c789c5d0c7560fb6 +Subproject commit 4972ce0a2a4cf2722f334809ada7be4cc6e4b615 diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index 426984cb..381fd1c1 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs @@ -2,10 +2,11 @@ use std::{iter::FilterMap, path::Path, slice::Iter}; -const SUPPORTED_FAMILIES: [&str; 10] = [ +const SUPPORTED_FAMILIES: [&str; 11] = [ "stm32f0", "stm32f1", "stm32f4", + "stm32f7", "stm32g0", "stm32l0", "stm32l1",