Skip to content
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8c19c18
move FMC driver into module directory
northernpaws Jan 25, 2026
2e13f9a
create initial SDRAM driver
northernpaws Jan 25, 2026
18ce017
SDRAM doc comments and `cargo fmt`
northernpaws Jan 25, 2026
4a77edf
add guard so SDRAM support is only enabled for `fmc_v1x3`, `fmc_v2x1`…
northernpaws Jan 25, 2026
8c44f7c
add handling for `fmc_v4` SDRAM register differences
northernpaws Jan 25, 2026
5ba8520
remove unused fields
northernpaws Jan 25, 2026
82b2b23
allow dead code for now for sdram bank handles
northernpaws Jan 25, 2026
834db2d
start porting NAND FMC driver
northernpaws Jan 29, 2026
46bdf43
replace `unwrap()`s with `Result`
northernpaws Jan 29, 2026
6df42f4
add SDRAM and NAND device definitions
northernpaws Jan 29, 2026
f32d0e8
make NAND interface compatible with `fmc_v1x3`
northernpaws Jan 29, 2026
958f215
`cargo fmt`
northernpaws Jan 29, 2026
6dd763b
fix NAND pointer to resolve correctly on non-`fmc_v1x3` peripherals
northernpaws Jan 29, 2026
36a8439
add missing NAND bank predicate
northernpaws Jan 29, 2026
a6168de
add missing qualifier for FMC bank pointer
northernpaws Jan 29, 2026
1a8b701
add missing doc comments and `cargo fmt`
northernpaws Jan 30, 2026
da1318c
remove leftover predicates from non-v1.3 FMC types
northernpaws Jan 30, 2026
c5b1d76
add module documentation
northernpaws Jan 30, 2026
a50528e
use new `Sdram` type in constructors, remove remaining outdated`stm32…
northernpaws Jan 30, 2026
ac489a2
rename `fmc.rs` example to reflect it's sole sdram functionality
northernpaws Jan 30, 2026
6ae4660
add dual SDRAM bank initializers
northernpaws Jan 30, 2026
6919a11
add comment to SDRAM constructor implementations
northernpaws Jan 30, 2026
bf0c866
start implementing NOR/PSRAM/SRAM driver
northernpaws Jan 30, 2026
62a431d
add `fmc_v1x3` predicates to SRAM driver
northernpaws Jan 30, 2026
8cbf8bf
add SRAM `fmc_v2x1` predicate for `cburstrw` register
northernpaws Jan 30, 2026
80f2c2f
rename `sram` module to `nor_sram` to reflect dual usage
northernpaws Jan 31, 2026
fc49f68
add `ili9341` as sample SRAM driver device
northernpaws Jan 31, 2026
57b5f3d
add `nor_sram` constructors to set pin alternate functions correctly
northernpaws Jan 31, 2026
0378dcb
fix `fmc_sram_init` comment
northernpaws Jan 31, 2026
63e0e6d
`cargo fmt`
northernpaws Jan 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
"rust-analyzer.cargo.features": [
// Comment out these features when working on the examples. Most example crates do not have any cargo features.
"stm32f107rb",
"time-driver-any",
"unstable-pac",
"exti",
"rt",
// "stm32h7s3l8",
// "time-driver-any",
// "unstable-pac",
// "exti",
// "rt",
],
"rust-analyzer.linkedProjects": [
"embassy-stm32/Cargo.toml",
// "embassy-stm32/Cargo.toml",
// To work on the examples, comment the line above and all of the cargo.features lines,
// then uncomment ONE line below to select the chip you want to work on.
// This makes rust-analyzer work on the example crate and all its dependencies.
Expand All @@ -54,8 +54,9 @@
// "examples/stm32f7/Cargo.toml",
// "examples/stm32g0/Cargo.toml",
// "examples/stm32g4/Cargo.toml",
// "examples/stm32h5/Cargo.toml",
"examples/stm32h5/Cargo.toml",
// "examples/stm32h7/Cargo.toml",
// "examples/stm32h7rs/Cargo.toml",
// "examples/stm32l0/Cargo.toml",
// "examples/stm32l1/Cargo.toml",
// "examples/stm32l4/Cargo.toml",
Expand Down
128 changes: 113 additions & 15 deletions embassy-stm32/src/fmc.rs → embassy-stm32/src/fmc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
use core::marker::PhantomData;

use embassy_hal_internal::PeripheralType;

use crate::gpio::{AfType, OutputType, Pull, Speed};
use crate::{Peri, rcc};

// Shadow the metapac values to make them more convenient to access.
pub use crate::pac::fmc::vals;

// Implements the SDRAM functionality.
//
// SDRAM registers are not supported by FSMC peripherals, only FMC.
#[cfg(any(fmc_v1x3, fmc_v2x1, fmc_v3x1, fmc_v4))]
pub mod sdram;

#[cfg(any(fmc_v1x3, fmc_v2x1, fmc_v3x1, fmc_v4))]
pub mod nand;

#[cfg(fmc_v1x3)]
pub mod v1;
#[cfg(fmc_v1x3)]
pub use v1::*;

#[cfg(not(fmc_v1x3))]
pub mod others;
#[cfg(not(fmc_v1x3))]
pub use others::*;

/// FMC driver
pub struct Fmc<'d, T: Instance> {
peri: PhantomData<&'d mut T>,
#[allow(unused)]
peri: Peri<'d, T>,

// Specifies the bank mapping in used by the FMC.
#[cfg(not(fmc_v1x3))]
mapping: FmcBankMapping,
}

unsafe impl<'d, T> Send for Fmc<'d, T> where T: Instance {}
Expand All @@ -17,15 +42,67 @@ impl<'d, T> Fmc<'d, T>
where
T: Instance,
{
/// Create a raw FMC instance.
/// Create an FMC instance.
pub fn new(peri: Peri<'d, T>) -> Self {
Self {
peri,
#[cfg(not(fmc_v1x3))]
mapping: FmcBankMapping::Default,
}
}

/// Returns the bank mapping in use by the FMC.
///
/// **Note:** This is currently used to provide access to some basic FMC functions
/// for manual configuration for memory types that stm32-fmc does not support.
pub fn new_raw(_instance: Peri<'d, T>) -> Self {
Self { peri: PhantomData }
/// This can be used to derrive the correct mapped
/// memory addresses of the various banks.
#[cfg(not(fmc_v1x3))]
pub fn mapping(&self) -> FmcBankMapping {
self.mapping
}

/// Returns the pointer to the specified SDRAM bank.
#[cfg(not(fmc_v1x3))]
pub fn sdram_ptr(&self, bank: FmcSdramBank) -> *mut u32 {
(match self.mapping {
FmcBankMapping::Default => match bank {
// Note Bank 1 is mapped to 0x7000_0000 and 0xC000_0000.
FmcSdramBank::Bank1 => FmcBank::Bank5.ptr(), // 0xC000_0000
FmcSdramBank::Bank2 => FmcBank::Bank6.ptr(), // 0xD000_0000
},
FmcBankMapping::NorSdramSwapped => match bank {
FmcSdramBank::Bank1 => FmcBank::Bank1.ptr(), // 0x6000_0000
FmcSdramBank::Bank2 => FmcBank::Bank6.ptr(), // 0xD000_0000
},
FmcBankMapping::Sdram2Swapped => match bank {
FmcSdramBank::Bank1 => FmcBank::Bank5.ptr(), // 0xC000_0000
// Note Bank 1 is mapped to 0x7000_0000 and 0xD000_0000.
FmcSdramBank::Bank2 => FmcBank::Bank6.ptr(), // 0xD000_0000
},
} as *mut u32)
}

/// Returns the pointer to the specified SDRAM bank.
#[cfg(fmc_v1x3)]
pub fn sdram_ptr(&self, bank: FmcSdramBank) -> *mut u32 {
match bank {
// Note Bank 1 is mapped to 0x7000_0000 and 0xC000_0000.
FmcSdramBank::Bank1 => FmcBank::Bank5.ptr(), // 0xC000_0000
FmcSdramBank::Bank2 => FmcBank::Bank6.ptr(), // 0xD000_0000
}
}

/// Returns a pointer to the address for the specified NAND bank.
#[cfg(fmc_v1x3)]
pub fn nand_ptr(&self, bank: FmcNandBank) -> *mut u32 {
match bank {
FmcNandBank::Bank1 => FmcBank::Bank2.ptr(),
FmcNandBank::Bank2 => FmcBank::Bank3.ptr(),
}
}

/// Enable the FMC peripheral and reset it.
///
/// This should be called before configuring any of the FMC memory device controllers.
pub fn enable(&mut self) {
rcc::enable_and_reset::<T>();
}
Expand All @@ -36,9 +113,24 @@ where
// fsmc v1, v2 and v3 does not have the fmcen bit
// This is a "not" because it is expected that all future versions have this bit
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4, fmc_n6)))]
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
T::regs().bcr1().modify(|r| r.set_fmcen(true));
#[cfg(any(fmc_v4, fmc_n6))]
T::regs().nor_psram().bcr1().modify(|r| r.set_fmcen(true));
}

/// Disable the memory controller on applicable chips.
///
/// This is typically called when changes need to be made
/// to the FMC clock registers, which requires the FMC
/// to be disabled.
pub fn memory_controller_disable(&mut self) {
// fmc v1 and v2 does not have the fmcen bit
// fsmc v1, v2 and v3 does not have the fmcen bit
// This is a "not" because it is expected that all future versions have this bit
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4, fmc_n6)))]
T::regs().bcr1().modify(|r| r.set_fmcen(false));
#[cfg(any(fmc_v4, fmc_n6))]
T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
T::regs().nor_psram().bcr1().modify(|r| r.set_fmcen(false));
}

/// Get the kernel clock currently in use for this FMC instance.
Expand All @@ -62,9 +154,9 @@ where
// fsmc v1, v2 and v3 does not have the fmcen bit
// This is a "not" because it is expected that all future versions have this bit
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4, fmc_n6)))]
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
T::regs().bcr1().modify(|r| r.set_fmcen(true));
#[cfg(any(fmc_v4, fmc_n6))]
T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
T::regs().nor_psram().bcr1().modify(|r| r.set_fmcen(true));
}

fn source_clock_hz(&self) -> u32 {
Expand All @@ -91,7 +183,7 @@ macro_rules! fmc_sdram_constructor {
)) => {
/// Create a new FMC instance.
pub fn $name<CHIP: stm32_fmc::SdramChip>(
_instance: Peri<'d, T>,
instance: Peri<'d, T>,
$($addr_pin_name: Peri<'d, impl $addr_signal<T>>),*,
$($ba_pin_name: Peri<'d, impl $ba_signal<T>>),*,
$($d_pin_name: Peri<'d, impl $d_signal<T>>),*,
Expand All @@ -110,7 +202,7 @@ macro_rules! fmc_sdram_constructor {
);
});

let fmc = Self { peri: PhantomData };
let fmc = Fmc::new(instance);
stm32_fmc::Sdram::new_unchecked(
fmc,
$bank,
Expand Down Expand Up @@ -274,8 +366,10 @@ impl<'d, T: Instance> Fmc<'d, T> {
));
}

trait SealedInstance: crate::rcc::RccPeripheral {
pub(crate) trait SealedInstance: crate::rcc::RccPeripheral {
const REGS: crate::pac::fmc::Fmc;

fn regs() -> crate::pac::fmc::Fmc;
}

/// FMC instance trait.
Expand All @@ -286,6 +380,10 @@ foreach_peripheral!(
(fmc, $inst:ident) => {
impl crate::fmc::SealedInstance for crate::peripherals::$inst {
const REGS: crate::pac::fmc::Fmc = crate::pac::$inst;

fn regs() -> crate::pac::fmc::Fmc {
crate::pac::$inst
}
}
impl crate::fmc::Instance for crate::peripherals::$inst {}
};
Expand Down
5 changes: 5 additions & 0 deletions embassy-stm32/src/fmc/nand/devices/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//! This module contains [`NandChip`] implementations
//! with timing definitions for common NAND devices.

mod s34ml08g3;
pub use s34ml08g3::*;
34 changes: 34 additions & 0 deletions embassy-stm32/src/fmc/nand/devices/s34ml08g3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// SkyHigh S34ML08G3 SLC NAND Flash
#[allow(unused)]

/// SkyHigh S34ML08G3 SLC NAND Flash with 4kB pages
pub mod s34ml08g3_4kb {
use crate::fmc::nand::{NandChip, NandConfiguration, NandTiming, NandDataWidth};

/// S32ML08G3
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct S34ml08g3 {}

impl NandChip for S34ml08g3 {
/// Timing Parameters
const TIMING: NandTiming = NandTiming {
nce_setup_time: 15, // tCS = 15ns min
data_setup_time: 7, // tDS = 7ns min
ale_hold_time: 5, // tALH = 5ns min
cle_hold_time: 5, // tCLH = 5ns min
ale_to_nre_delay: 10, // tAR = 10ns min
cle_to_nre_delay: 10, // tCLR = 10ns min
nre_pulse_width_ns: 10, // tRP = 10ns min
nwe_pulse_width_ns: 10, // tWP = 10ns min
read_cycle_time_ns: 20, // tRC = 20ns min
write_cycle_time_ns: 20, // tWC = 20ns min
nwe_high_to_busy_ns: 100, // tWB = 100ns max
};

/// Nand controller configuration
const CONFIG: NandConfiguration = NandConfiguration {
data_width: NandDataWidth::Bits8, // 8-bit
column_bits: 12, // 4096 byte pages
};
}
}
Loading