From d37d714314093747c9042faefcc3a22e2bfee59d Mon Sep 17 00:00:00 2001 From: Matous Hybl Date: Tue, 8 Feb 2022 14:32:18 +0100 Subject: [PATCH] stm32: Add support for FMC --- embassy-stm32/Cargo.toml | 1 + embassy-stm32/src/fmc/mod.rs | 145 ++++++ embassy-stm32/src/fmc/pins.rs | 672 +++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + examples/stm32h7/Cargo.toml | 3 +- examples/stm32h7/src/bin/fmc.rs | 204 ++++++++ examples/stm32h7/src/example_common.rs | 1 + 7 files changed, 1027 insertions(+), 1 deletion(-) create mode 100644 embassy-stm32/src/fmc/mod.rs create mode 100644 embassy-stm32/src/fmc/pins.rs create mode 100644 examples/stm32h7/src/bin/fmc.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1aa665fb6..edee4e3a5 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -30,6 +30,7 @@ stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt" vcell = { version = "0.1.3", optional = true } bxcan = "0.6.2" nb = "1.0.0" +stm32-fmc = "0.2.4" seq-macro = "0.2.2" cfg-if = "1.0.0" diff --git a/embassy-stm32/src/fmc/mod.rs b/embassy-stm32/src/fmc/mod.rs new file mode 100644 index 000000000..afdb45af9 --- /dev/null +++ b/embassy-stm32/src/fmc/mod.rs @@ -0,0 +1,145 @@ +mod pins; + +use core::marker::PhantomData; + +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; + +use pins::*; + +pub struct Fmc<'d, T: Instance> { + peri: PhantomData<&'d mut T>, +} + +unsafe impl<'d, T> Send for Fmc<'d, T> where T: Instance {} + +unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T> +where + T: Instance, +{ + const REGISTERS: *const () = crate::pac::FMC.0 as *const _; + + fn enable(&mut self) { + ::enable(); + ::reset(); + } + + fn memory_controller_enable(&mut self) { + // The FMCEN bit of the FMC_BCR2..4 registers is don’t + // care. It is only enabled through the FMC_BCR1 register. + unsafe { T::regs().bcr1().modify(|r| r.set_fmcen(true)) }; + } + + fn source_clock_hz(&self) -> u32 { + ::frequency().0 + } +} +macro_rules! config_pins { + ($($pin:ident),*) => { + $( + $pin.configure(); + )* +}; +} + +macro_rules! fmc_sdram_constructor { + ($name:ident: ( + addr: [$(($addr_pin_name:ident: $addr_signal:ident)),*], + ba: [$(($ba_pin_name:ident: $ba_signal:ident)),*], + d: [$(($d_pin_name:ident: $d_signal:ident)),*], + nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], + ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] + )) => { + pub fn $name( + _instance: impl Unborrow + 'd, + $($addr_pin_name: impl Unborrow + 'd),*, + $($ba_pin_name: impl Unborrow + 'd),*, + $($d_pin_name: impl Unborrow + 'd),*, + $($nbl_pin_name: impl Unborrow + 'd),*, + $($ctrl_pin_name: impl Unborrow + 'd),*, + chip: CHIP + ) -> stm32_fmc::Sdram, CHIP> { + unborrow!( + $($addr_pin_name),*, + $($ba_pin_name),*, + $($d_pin_name),*, + $($nbl_pin_name),*, + $($ctrl_pin_name),* + ); + + config_pins!( + $($addr_pin_name),*, + $($ba_pin_name),*, + $($d_pin_name),*, + $($nbl_pin_name),*, + $($ctrl_pin_name),* + ); + + let fmc = Self { peri: PhantomData }; + stm32_fmc::Sdram::new( + fmc, + ( + $($addr_pin_name),*, + $($ba_pin_name),*, + $($d_pin_name),*, + $($nbl_pin_name),*, + $($ctrl_pin_name),*, + ), + chip, + ) + } + }; +} + +impl<'d, T: Instance> Fmc<'d, T> { + fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank1: ( + addr: [ + (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin) + ], + ba: [(ba0: BA0Pin), (ba1: BA1Pin)], + d: [ + (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin), + (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin), + (d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin), + (d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin) + ], + nbl: [ + (nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin) + ], + ctrl: [ + (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) + ] + )); + + fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank2: ( + addr: [ + (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin) + ], + ba: [(ba0: BA0Pin), (ba1: BA1Pin)], + d: [ + (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin), + (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin), + (d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin), + (d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin) + ], + nbl: [ + (nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin) + ], + ctrl: [ + (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) + ] + )); +} + +pub trait Instance: sealed::Instance + 'static {} + +crate::pac::peripherals!( + (fmc, $inst:ident) => { + impl crate::fmc::sealed::Instance for crate::peripherals::$inst { + fn regs() -> stm32_metapac::fmc::Fmc { + crate::pac::$inst + } + } + impl crate::fmc::Instance for crate::peripherals::$inst {} + }; +); diff --git a/embassy-stm32/src/fmc/pins.rs b/embassy-stm32/src/fmc/pins.rs new file mode 100644 index 000000000..c42c2792f --- /dev/null +++ b/embassy-stm32/src/fmc/pins.rs @@ -0,0 +1,672 @@ +pub(crate) mod sealed { + pub trait Instance: crate::rcc::sealed::RccPeripheral { + fn regs() -> crate::pac::fmc::Fmc; + } + + macro_rules! declare_pin { + ($name:ident) => { + pub trait $name { + fn configure(&mut self); + } + }; + } + + declare_pin!(SDNWEPin); + declare_pin!(SDNCASPin); + declare_pin!(SDNRASPin); + + declare_pin!(SDNE0Pin); + declare_pin!(SDNE1Pin); + + declare_pin!(SDCKE0Pin); + declare_pin!(SDCKE1Pin); + + declare_pin!(SDCLKPin); + + declare_pin!(NBL0Pin); + declare_pin!(NBL1Pin); + declare_pin!(NBL2Pin); + declare_pin!(NBL3Pin); + + declare_pin!(INTPin); + declare_pin!(NLPin); + declare_pin!(NWaitPin); + + declare_pin!(NE1Pin); + declare_pin!(NE2Pin); + declare_pin!(NE3Pin); + declare_pin!(NE4Pin); + + declare_pin!(NCEPin); + declare_pin!(NOEPin); + declare_pin!(NWEPin); + declare_pin!(ClkPin); + + declare_pin!(BA0Pin); + declare_pin!(BA1Pin); + + declare_pin!(D0Pin); + declare_pin!(D1Pin); + declare_pin!(D2Pin); + declare_pin!(D3Pin); + declare_pin!(D4Pin); + declare_pin!(D5Pin); + declare_pin!(D6Pin); + declare_pin!(D7Pin); + declare_pin!(D8Pin); + declare_pin!(D9Pin); + declare_pin!(D10Pin); + declare_pin!(D11Pin); + declare_pin!(D12Pin); + declare_pin!(D13Pin); + declare_pin!(D14Pin); + declare_pin!(D15Pin); + declare_pin!(D16Pin); + declare_pin!(D17Pin); + declare_pin!(D18Pin); + declare_pin!(D19Pin); + declare_pin!(D20Pin); + declare_pin!(D21Pin); + declare_pin!(D22Pin); + declare_pin!(D23Pin); + declare_pin!(D24Pin); + declare_pin!(D25Pin); + declare_pin!(D26Pin); + declare_pin!(D27Pin); + declare_pin!(D28Pin); + declare_pin!(D29Pin); + declare_pin!(D30Pin); + declare_pin!(D31Pin); + + declare_pin!(DA0Pin); + declare_pin!(DA1Pin); + declare_pin!(DA2Pin); + declare_pin!(DA3Pin); + declare_pin!(DA4Pin); + declare_pin!(DA5Pin); + declare_pin!(DA6Pin); + declare_pin!(DA7Pin); + declare_pin!(DA8Pin); + declare_pin!(DA9Pin); + declare_pin!(DA10Pin); + declare_pin!(DA11Pin); + declare_pin!(DA12Pin); + declare_pin!(DA13Pin); + declare_pin!(DA14Pin); + declare_pin!(DA15Pin); + + declare_pin!(A0Pin); + declare_pin!(A1Pin); + declare_pin!(A2Pin); + declare_pin!(A3Pin); + declare_pin!(A4Pin); + declare_pin!(A5Pin); + declare_pin!(A6Pin); + declare_pin!(A7Pin); + declare_pin!(A8Pin); + declare_pin!(A9Pin); + declare_pin!(A10Pin); + declare_pin!(A11Pin); + declare_pin!(A12Pin); + declare_pin!(A13Pin); + declare_pin!(A14Pin); + declare_pin!(A15Pin); + declare_pin!(A16Pin); + declare_pin!(A17Pin); + declare_pin!(A18Pin); + declare_pin!(A19Pin); + declare_pin!(A20Pin); + declare_pin!(A21Pin); + declare_pin!(A22Pin); + declare_pin!(A23Pin); + declare_pin!(A24Pin); + declare_pin!(A25Pin); +} + +macro_rules! declare_pin { + ($name:ident, $fmc_pin:ident) => { + pub trait $name: sealed::$name + stm32_fmc::$fmc_pin + 'static {} + }; +} + +declare_pin!(SDNWEPin, SDNWE); +declare_pin!(SDNCASPin, SDNCAS); +declare_pin!(SDNRASPin, SDNRAS); + +declare_pin!(SDNE0Pin, SDNE0); +declare_pin!(SDNE1Pin, SDNE1); + +declare_pin!(SDCKE0Pin, SDCKE0); +declare_pin!(SDCKE1Pin, SDCKE1); + +declare_pin!(SDCLKPin, SDCLK); + +declare_pin!(NBL0Pin, NBL0); +declare_pin!(NBL1Pin, NBL1); +declare_pin!(NBL2Pin, NBL2); +declare_pin!(NBL3Pin, NBL3); + +declare_pin!(INTPin, INT); +declare_pin!(NLPin, NL); +declare_pin!(NWaitPin, NWAIT); + +declare_pin!(NE1Pin, NE1); +declare_pin!(NE2Pin, NE2); +declare_pin!(NE3Pin, NE3); +declare_pin!(NE4Pin, NE4); + +declare_pin!(NCEPin, NCE); +declare_pin!(NOEPin, NOE); +declare_pin!(NWEPin, NWE); +declare_pin!(ClkPin, CLK); + +declare_pin!(BA0Pin, BA0); +declare_pin!(BA1Pin, BA1); + +declare_pin!(D0Pin, D0); +declare_pin!(D1Pin, D1); +declare_pin!(D2Pin, D2); +declare_pin!(D3Pin, D3); +declare_pin!(D4Pin, D4); +declare_pin!(D5Pin, D5); +declare_pin!(D6Pin, D6); +declare_pin!(D7Pin, D7); +declare_pin!(D8Pin, D8); +declare_pin!(D9Pin, D9); +declare_pin!(D10Pin, D10); +declare_pin!(D11Pin, D11); +declare_pin!(D12Pin, D12); +declare_pin!(D13Pin, D13); +declare_pin!(D14Pin, D14); +declare_pin!(D15Pin, D15); +declare_pin!(D16Pin, D16); +declare_pin!(D17Pin, D17); +declare_pin!(D18Pin, D18); +declare_pin!(D19Pin, D19); +declare_pin!(D20Pin, D20); +declare_pin!(D21Pin, D21); +declare_pin!(D22Pin, D22); +declare_pin!(D23Pin, D23); +declare_pin!(D24Pin, D24); +declare_pin!(D25Pin, D25); +declare_pin!(D26Pin, D26); +declare_pin!(D27Pin, D27); +declare_pin!(D28Pin, D28); +declare_pin!(D29Pin, D29); +declare_pin!(D30Pin, D30); +declare_pin!(D31Pin, D31); + +declare_pin!(DA0Pin, DA0); +declare_pin!(DA1Pin, DA1); +declare_pin!(DA2Pin, DA2); +declare_pin!(DA3Pin, DA3); +declare_pin!(DA4Pin, DA4); +declare_pin!(DA5Pin, DA5); +declare_pin!(DA6Pin, DA6); +declare_pin!(DA7Pin, DA7); +declare_pin!(DA8Pin, DA8); +declare_pin!(DA9Pin, DA9); +declare_pin!(DA10Pin, DA10); +declare_pin!(DA11Pin, DA11); +declare_pin!(DA12Pin, DA12); +declare_pin!(DA13Pin, DA13); +declare_pin!(DA14Pin, DA14); +declare_pin!(DA15Pin, DA15); + +declare_pin!(A0Pin, A0); +declare_pin!(A1Pin, A1); +declare_pin!(A2Pin, A2); +declare_pin!(A3Pin, A3); +declare_pin!(A4Pin, A4); +declare_pin!(A5Pin, A5); +declare_pin!(A6Pin, A6); +declare_pin!(A7Pin, A7); +declare_pin!(A8Pin, A8); +declare_pin!(A9Pin, A9); +declare_pin!(A10Pin, A10); +declare_pin!(A11Pin, A11); +declare_pin!(A12Pin, A12); +declare_pin!(A13Pin, A13); +declare_pin!(A14Pin, A14); +declare_pin!(A15Pin, A15); +declare_pin!(A16Pin, A16); +declare_pin!(A17Pin, A17); +declare_pin!(A18Pin, A18); +declare_pin!(A19Pin, A19); +declare_pin!(A20Pin, A20); +declare_pin!(A21Pin, A21); +declare_pin!(A22Pin, A22); +declare_pin!(A23Pin, A23); +declare_pin!(A24Pin, A24); +declare_pin!(A25Pin, A25); + +macro_rules! impl_pin { + ($pin:ident, $signal:ident, $fmc_name:ident, $af:expr) => { + impl sealed::$signal for crate::peripherals::$pin { + fn configure(&mut self) { + use crate::gpio::sealed::{AFType::OutputPushPull, Pin as SealedPin}; + use crate::gpio::Pin; + use crate::gpio::Speed; + use crate::pac::gpio::vals::Pupdr; + + critical_section::with(|_| unsafe { + self.set_as_af($af, OutputPushPull); + self.set_speed(Speed::VeryHigh); + + self.block() + .pupdr() + .modify(|w| w.set_pupdr(self.pin() as usize, Pupdr::PULLUP)); + }) + } + } + + impl stm32_fmc::$fmc_name for crate::peripherals::$pin {} + + impl $signal for crate::peripherals::$pin {} + }; +} + +crate::pac::peripheral_pins!( + ($inst:ident, fmc, FMC, $pin:ident, A0, $af:expr) => { + impl_pin!($pin, A0Pin, A0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A1, $af:expr) => { + impl_pin!($pin, A1Pin, A1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A2, $af:expr) => { + impl_pin!($pin, A2Pin, A2, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A3, $af:expr) => { + impl_pin!($pin, A3Pin, A3, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A4, $af:expr) => { + impl_pin!($pin, A4Pin, A4, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A5, $af:expr) => { + impl_pin!($pin, A5Pin, A5, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A6, $af:expr) => { + impl_pin!($pin, A6Pin, A6, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A7, $af:expr) => { + impl_pin!($pin, A7Pin, A7, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A8, $af:expr) => { + impl_pin!($pin, A8Pin, A8, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A9, $af:expr) => { + impl_pin!($pin, A9Pin, A9, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A10, $af:expr) => { + impl_pin!($pin, A10Pin, A10, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A11, $af:expr) => { + impl_pin!($pin, A11Pin, A11, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A12, $af:expr) => { + impl_pin!($pin, A12Pin, A12, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A13, $af:expr) => { + impl_pin!($pin, A13Pin, A13, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A14, $af:expr) => { + impl_pin!($pin, A14Pin, A14, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A15, $af:expr) => { + impl_pin!($pin, A15Pin, A15, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A16, $af:expr) => { + impl_pin!($pin, A16Pin, A16, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A17, $af:expr) => { + impl_pin!($pin, A17Pin, A17, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A18, $af:expr) => { + impl_pin!($pin, A18Pin, A18, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A19, $af:expr) => { + impl_pin!($pin, A19Pin, A19, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A20, $af:expr) => { + impl_pin!($pin, A20Pin, A20, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A21, $af:expr) => { + impl_pin!($pin, A21Pin, A21, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A22, $af:expr) => { + impl_pin!($pin, A22Pin, A22, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A23, $af:expr) => { + impl_pin!($pin, A23Pin, A23, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A24, $af:expr) => { + impl_pin!($pin, A24Pin, A24, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, A25, $af:expr) => { + impl_pin!($pin, A25Pin, A25, $af); + }; +); + +crate::pac::peripheral_pins!( + ($inst:ident, fmc, FMC, $pin:ident, D0, $af:expr) => { + impl_pin!($pin, D0Pin, D0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D1, $af:expr) => { + impl_pin!($pin, D1Pin, D1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D2, $af:expr) => { + impl_pin!($pin, D2Pin, D2, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D3, $af:expr) => { + impl_pin!($pin, D3Pin, D3, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D4, $af:expr) => { + impl_pin!($pin, D4Pin, D4, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D5, $af:expr) => { + impl_pin!($pin, D5Pin, D5, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D6, $af:expr) => { + impl_pin!($pin, D6Pin, D6, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D7, $af:expr) => { + impl_pin!($pin, D7Pin, D7, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D8, $af:expr) => { + impl_pin!($pin, D8Pin, D8, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D9, $af:expr) => { + impl_pin!($pin, D9Pin, D9, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D10, $af:expr) => { + impl_pin!($pin, D10Pin, D10, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D11, $af:expr) => { + impl_pin!($pin, D11Pin, D11, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D12, $af:expr) => { + impl_pin!($pin, D12Pin, D12, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D13, $af:expr) => { + impl_pin!($pin, D13Pin, D13, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D14, $af:expr) => { + impl_pin!($pin, D14Pin, D14, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D15, $af:expr) => { + impl_pin!($pin, D15Pin, D15, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D16, $af:expr) => { + impl_pin!($pin, D16Pin, D16, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D17, $af:expr) => { + impl_pin!($pin, D17Pin, D17, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D18, $af:expr) => { + impl_pin!($pin, D18Pin, D18, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D19, $af:expr) => { + impl_pin!($pin, D19Pin, D19, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D20, $af:expr) => { + impl_pin!($pin, D20Pin, D20, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D21, $af:expr) => { + impl_pin!($pin, D21Pin, D21, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D22, $af:expr) => { + impl_pin!($pin, D22Pin, D22, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D23, $af:expr) => { + impl_pin!($pin, D23Pin, D23, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D24, $af:expr) => { + impl_pin!($pin, D24Pin, D24, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D25, $af:expr) => { + impl_pin!($pin, D25Pin, D25, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D26, $af:expr) => { + impl_pin!($pin, D26Pin, D26, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D27, $af:expr) => { + impl_pin!($pin, D27Pin, D27, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D28, $af:expr) => { + impl_pin!($pin, D28Pin, D28, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D29, $af:expr) => { + impl_pin!($pin, D29Pin, D29, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D30, $af:expr) => { + impl_pin!($pin, D30Pin, D30, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, D31, $af:expr) => { + impl_pin!($pin, D31Pin, D31, $af); + }; +); + +crate::pac::peripheral_pins!( + ($inst:ident, fmc, FMC, $pin:ident, DA0, $af:expr) => { + impl_pin!($pin, DA0Pin, DA0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA1, $af:expr) => { + impl_pin!($pin, DA1Pin, DA1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA2, $af:expr) => { + impl_pin!($pin, DA2Pin, DA2, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA3, $af:expr) => { + impl_pin!($pin, DA3Pin, DA3, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA4, $af:expr) => { + impl_pin!($pin, DA4Pin, DA4, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA5, $af:expr) => { + impl_pin!($pin, DA5Pin, DA5, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA6, $af:expr) => { + impl_pin!($pin, DA6Pin, DA6, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA7, $af:expr) => { + impl_pin!($pin, DA7Pin, DA7, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA8, $af:expr) => { + impl_pin!($pin, DA8Pin, DA8, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA9, $af:expr) => { + impl_pin!($pin, DA9Pin, DA9, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA10, $af:expr) => { + impl_pin!($pin, DA10Pin, DA10, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA11, $af:expr) => { + impl_pin!($pin, DA11Pin, DA11, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA12, $af:expr) => { + impl_pin!($pin, DA12Pin, DA12, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA13, $af:expr) => { + impl_pin!($pin, DA13Pin, DA13, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA14, $af:expr) => { + impl_pin!($pin, DA14Pin, DA14, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, DA15, $af:expr) => { + impl_pin!($pin, DA15Pin, DA15, $af); + }; + +); + +crate::pac::peripheral_pins!( + ($inst:ident, fmc, FMC, $pin:ident, SDNWE, $af:expr) => { + impl_pin!($pin, SDNWEPin, SDNWE, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDNCAS, $af:expr) => { + impl_pin!($pin, SDNCASPin, SDNCAS, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDNRAS, $af:expr) => { + impl_pin!($pin, SDNRASPin, SDNRAS, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDNE0, $af:expr) => { + impl_pin!($pin, SDNE0Pin, SDNE0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDNE1, $af:expr) => { + impl_pin!($pin, SDNE1Pin, SDNE1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDCKE0, $af:expr) => { + impl_pin!($pin, SDCKE0Pin, SDCKE0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDCKE1, $af:expr) => { + impl_pin!($pin, SDCKE1Pin, SDCKE1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, SDCLK, $af:expr) => { + impl_pin!($pin, SDCLKPin, SDCLK, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NBL0, $af:expr) => { + impl_pin!($pin, NBL0Pin, NBL0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NBL1, $af:expr) => { + impl_pin!($pin, NBL1Pin, NBL1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NBL2, $af:expr) => { + impl_pin!($pin, NBL2Pin, NBL2, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NBL3, $af:expr) => { + impl_pin!($pin, NBL3Pin, NBL3, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, INT, $af:expr) => { + impl_pin!($pin, INTPin, INT, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NL, $af:expr) => { + impl_pin!($pin, NLPin, NL, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NWAIT, $af:expr) => { + impl_pin!($pin, NWaitPin, NWAIT, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NE1, $af:expr) => { + impl_pin!($pin, NE1Pin, NE1, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NE2, $af:expr) => { + impl_pin!($pin, NE2Pin, NE2, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NE3, $af:expr) => { + impl_pin!($pin, NE3Pin, NE3, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NE4, $af:expr) => { + impl_pin!($pin, NE4Pin, NE4, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NCE, $af:expr) => { + impl_pin!($pin, NCEPin, NCE, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NOE, $af:expr) => { + impl_pin!($pin, NOEPin, NOE, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, NWE, $af:expr) => { + impl_pin!($pin, NWEPin, NWE, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, Clk, $af:expr) => { + impl_pin!($pin, ClkPin, CLK, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, BA0, $af:expr) => { + impl_pin!($pin, BA0Pin, BA0, $af); + }; + + ($inst:ident, fmc, FMC, $pin:ident, BA1, $af:expr) => { + impl_pin!($pin, BA1Pin, BA1, $af); + }; +); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index dfc027733..75a4d22d8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -36,6 +36,8 @@ pub mod dcmi; pub mod eth; #[cfg(feature = "exti")] pub mod exti; +#[cfg(fmc)] +pub mod fmc; #[cfg(i2c)] pub mod i2c; diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 463dd83d5..59d99bbcb 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743zi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } embassy-hal-common = { path = "../../embassy-hal-common", default-features = false, features = ["defmt"] } @@ -26,6 +26,7 @@ heapless = { version = "0.7.5", default-features = false } rand_core = "0.6.3" critical-section = "0.2.5" micromath = "2.0.0" +stm32-fmc = "0.2.4" [dependencies.smoltcp] version = "0.8.0" diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs new file mode 100644 index 000000000..b9ac1318e --- /dev/null +++ b/examples/stm32h7/src/bin/fmc.rs @@ -0,0 +1,204 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Spawner; +use embassy::time::{Delay, Duration, Timer}; +use embassy_stm32::fmc::Fmc; +use embassy_stm32::Peripherals; +use example_common::*; + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut core_peri = cortex_m::Peripherals::take().unwrap(); + + // taken from stm32h7xx-hal + core_peri.SCB.enable_icache(); + // See Errata Sheet 2.2.1 + // core_peri.SCB.enable_dcache(&mut core_peri.CPUID); + core_peri.DWT.enable_cycle_counter(); + // ---------------------------------------------------------- + // Configure MPU for external SDRAM + // MPU config for SDRAM write-through + let sdram_size = 32 * 1024 * 1024; + + { + let mpu = core_peri.MPU; + let scb = &mut core_peri.SCB; + let size = sdram_size; + // Refer to ARM®v7-M Architecture Reference Manual ARM DDI 0403 + // Version E.b Section B3.5 + const MEMFAULTENA: u32 = 1 << 16; + + unsafe { + /* Make sure outstanding transfers are done */ + cortex_m::asm::dmb(); + + scb.shcsr.modify(|r| r & !MEMFAULTENA); + + /* Disable the MPU and clear the control register*/ + mpu.ctrl.write(0); + } + + const REGION_NUMBER0: u32 = 0x00; + const REGION_BASE_ADDRESS: u32 = 0xD000_0000; + + const REGION_FULL_ACCESS: u32 = 0x03; + const REGION_CACHEABLE: u32 = 0x01; + const REGION_WRITE_BACK: u32 = 0x01; + const REGION_ENABLE: u32 = 0x01; + + crate::assert_eq!( + size & (size - 1), + 0, + "SDRAM memory region size must be a power of 2" + ); + crate::assert_eq!( + size & 0x1F, + 0, + "SDRAM memory region size must be 32 bytes or more" + ); + fn log2minus1(sz: u32) -> u32 { + for i in 5..=31 { + if sz == (1 << i) { + return i - 1; + } + } + crate::panic!("Unknown SDRAM memory region size!"); + } + + //info!("SDRAM Memory Size 0x{:x}", log2minus1(size as u32)); + + // Configure region 0 + // + // Cacheable, outer and inner write-back, no write allocate. So + // reads are cached, but writes always write all the way to SDRAM + unsafe { + mpu.rnr.write(REGION_NUMBER0); + mpu.rbar.write(REGION_BASE_ADDRESS); + mpu.rasr.write( + (REGION_FULL_ACCESS << 24) + | (REGION_CACHEABLE << 17) + | (REGION_WRITE_BACK << 16) + | (log2minus1(size as u32) << 1) + | REGION_ENABLE, + ); + } + + const MPU_ENABLE: u32 = 0x01; + const MPU_DEFAULT_MMAP_FOR_PRIVILEGED: u32 = 0x04; + + // Enable + unsafe { + mpu.ctrl + .modify(|r| r | MPU_DEFAULT_MMAP_FOR_PRIVILEGED | MPU_ENABLE); + + scb.shcsr.modify(|r| r | MEMFAULTENA); + + // Ensure MPU settings take effect + cortex_m::asm::dsb(); + cortex_m::asm::isb(); + } + } + + let mut sdram = Fmc::sdram_a12bits_d32bits_4banks_bank2( + p.FMC, + // A0-A11 + p.PF0, + p.PF1, + p.PF2, + p.PF3, + p.PF4, + p.PF5, + p.PF12, + p.PF13, + p.PF14, + p.PF15, + p.PG0, + p.PG1, + // BA0-BA1 + p.PG4, + p.PG5, + // D0-D31 + p.PD14, + p.PD15, + p.PD0, + p.PD1, + p.PE7, + p.PE8, + p.PE9, + p.PE10, + p.PE11, + p.PE12, + p.PE13, + p.PE14, + p.PE15, + p.PD8, + p.PD9, + p.PD10, + p.PH8, + p.PH9, + p.PH10, + p.PH11, + p.PH12, + p.PH13, + p.PH14, + p.PH15, + p.PI0, + p.PI1, + p.PI2, + p.PI3, + p.PI6, + p.PI7, + p.PI9, + p.PI10, + // NBL0 - NBL3 + p.PE0, + p.PE1, + p.PI4, + p.PI5, + p.PH7, // SDCKE1 + p.PG8, // SDCLK + p.PG15, // SDNCAS + p.PH6, // SDNE1 (!CS) + p.PF11, // SDRAS + p.PC0, // SDNWE, change to p.PH5 for EVAL boards + stm32_fmc::devices::is42s32800g_6::Is42s32800g {}, + ); + + let mut delay = Delay; + + let ram_slice = unsafe { + // Initialise controller and SDRAM + let ram_ptr: *mut u32 = sdram.init(&mut delay) as *mut _; + + // Convert raw pointer to slice + core::slice::from_raw_parts_mut(ram_ptr, sdram_size / core::mem::size_of::()) + }; + + // // ---------------------------------------------------------- + // // Use memory in SDRAM + info!("RAM contents before writing: {:x}", ram_slice[..10]); + + ram_slice[0] = 1; + ram_slice[1] = 2; + ram_slice[2] = 3; + ram_slice[3] = 4; + + info!("RAM contents after writing: {:x}", ram_slice[..10]); + + crate::assert_eq!(ram_slice[0], 1); + crate::assert_eq!(ram_slice[1], 2); + crate::assert_eq!(ram_slice[2], 3); + crate::assert_eq!(ram_slice[3], 4); + + info!("Assertions succeeded."); + + loop { + Timer::after(Duration::from_millis(1000)).await; + } +} diff --git a/examples/stm32h7/src/example_common.rs b/examples/stm32h7/src/example_common.rs index 524bee6d9..b8acc2790 100644 --- a/examples/stm32h7/src/example_common.rs +++ b/examples/stm32h7/src/example_common.rs @@ -22,6 +22,7 @@ defmt::timestamp! {"{=u64}", { pub fn config() -> Config { let mut config = Config::default(); config.rcc.sys_ck = Some(400.mhz().into()); + config.rcc.hclk = Some(200.mhz().into()); config.rcc.pll1.q_ck = Some(100.mhz().into()); config }