Skip to content

Commit

Permalink
fmc-sdram example
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Jun 14, 2024
1 parent 492e750 commit 2ed6c8c
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -755,3 +755,7 @@ required-features = ["otg-fs", "usb_fs"] # stm32f401
[[example]]
name = "ws2812-spi"
required-features = []

[[example]]
name = "fmc-sdram"
required-features = ["stm32f469", "stm32-fmc"]
135 changes: 135 additions & 0 deletions examples/fmc-sdram.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! This example shows how to use the FMC controller on the STM32F7 to communicate with an
//! off-chip SDRAM memory device. The `stm32-fmc` crate does the majority of the work, and
//! after initialization the SDRAM is memory mapped to the STM32F7 address space.
//!
//! This example was tested on the STM32F746G Discovery Board. The board has an IS42S32400F-6BL
//! SDRAM chip, with only 16 of the 32 data wires connected to the microcontroller. This device
//! is not explictly supported in the `stm32-fmc` crate at time of writing, but the IS42S16400J
//! has very similar parameters and is used as a placeholder for now. Because of this, only half
//! of the available memory space is available (128 Mb = 16 MB, so 8 MB available).
//!
//! To use the example, launch a GDB server and then `cargo run`. After several seconds, the
//! message "Success!" should be printed in the GDB server terminal (via semihosting).

#![deny(warnings)]
#![no_main]
#![no_std]

extern crate panic_semihosting;

use core::{mem, slice};
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
use stm32_fmc::devices::is42s16400j_7;
use stm32f4xx_hal::{
fmc::FmcExt,
gpio::{alt::fmc as alt, Speed},
pac,
prelude::*,
};

/// Configure pins for the FMC controller
macro_rules! fmc_pins {
($($alt:ident: $pin:expr,)*) => {
(
$(
alt::$alt::from($pin.into_alternate()
.speed(Speed::VeryHigh)
.internal_pull_up(true)
)
),*
)
};
}

#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();

// Get the delay provider.
let clocks = dp.RCC.constrain().cfgr.sysclk(216.MHz()).freeze();
let mut delay = cp.SYST.delay(&clocks);

// IO
let gpioc = dp.GPIOC.split();
let gpiod = dp.GPIOD.split();
let gpioe = dp.GPIOE.split();
let gpiof = dp.GPIOF.split();
let gpiog = dp.GPIOG.split();
let gpioh = dp.GPIOH.split();

// Initialise SDRAM
let fmc_io = fmc_pins! {
A0: gpiof.pf0,
A1: gpiof.pf1,
A2: gpiof.pf2,
A3: gpiof.pf3,
A4: gpiof.pf4,
A5: gpiof.pf5,
A6: gpiof.pf12,
A7: gpiof.pf13,
A8: gpiof.pf14,
A9: gpiof.pf15,
A10: gpiog.pg0,
A11: gpiog.pg1,
Ba0: gpiog.pg4,
Ba1: gpiog.pg5,
D0: gpiod.pd14,
D1: gpiod.pd15,
D2: gpiod.pd0,
D3: gpiod.pd1,
D4: gpioe.pe7,
D5: gpioe.pe8,
D6: gpioe.pe9,
D7: gpioe.pe10,
D8: gpioe.pe11,
D9: gpioe.pe12,
D10: gpioe.pe13,
D11: gpioe.pe14,
D12: gpioe.pe15,
D13: gpiod.pd8,
D14: gpiod.pd9,
D15: gpiod.pd10,
Nbl0: gpioe.pe0,
Nbl1: gpioe.pe1,
Sdcke0: gpioc.pc3,
Sdclk: gpiog.pg8,
Sdncas: gpiog.pg15,
Sdne0: gpioh.ph3,
Sdnras: gpiof.pf11,
Sdnwe: gpioh.ph5,
};

// New SDRAM
let mut sdram = dp.FMC.sdram(fmc_io, is42s16400j_7::Is42s16400j {}, &clocks);

// Initialise controller and SDRAM
let len_bytes = (16 * 1024 * 1024) / 2;
let len_words = len_bytes / mem::size_of::<u32>();
let ram = unsafe {
let ram_ptr: *mut u32 = sdram.init(&mut delay);
slice::from_raw_parts_mut(ram_ptr, len_words)
};

// Access all the words in SDRAM (takes several seconds)
for addr in 0..len_words {
let val: u32 = addr as u32;

// Write
ram[addr] = val;

// Read
let res: u32 = ram[addr];
if res != val {
panic!(
"Error: Expected {} while reading address {:X} but got {}.",
val, addr, res
);
}
}

hprintln!("Success!");

loop {}
}
18 changes: 11 additions & 7 deletions src/fmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@
use stm32_fmc::FmcPeripheral;
use stm32_fmc::{AddressPinSet, PinsSdram, Sdram, SdramChip, SdramPinSet, SdramTargetBank};

use crate::pac;
use crate::rcc::{BusClock, Clocks, Enable, Reset};
use fugit::HertzU32 as Hertz;

use crate::gpio::alt::fmc as alt;

#[cfg(feature = "fmc")]
use crate::pac::FMC as FMC_PER;
#[cfg(feature = "fsmc")]
use crate::pac::FSMC as FMC_PER;

/// Storage type for Flexible Memory Controller and its clocks
pub struct FMC {
pub fmc: pac::FMC,
pub fmc: FMC_PER,
hclk: Hertz,
}

Expand Down Expand Up @@ -51,26 +55,26 @@ pub trait FmcExt: Sized {
}
}

impl FmcExt for pac::FMC {
impl FmcExt for FMC_PER {
/// New FMC instance
fn fmc(self, clocks: &Clocks) -> FMC {
FMC {
fmc: self,
hclk: pac::FMC::clock(clocks),
hclk: FMC_PER::clock(clocks),
}
}
}

unsafe impl FmcPeripheral for FMC {
const REGISTERS: *const () = pac::FMC::ptr() as *const ();
const REGISTERS: *const () = FMC_PER::ptr() as *const ();

fn enable(&mut self) {
// TODO : change it to something safe ...
unsafe {
// Enable FMC
pac::FMC::enable_unchecked();
FMC_PER::enable_unchecked();
// Reset FMC
pac::FMC::reset_unchecked();
FMC_PER::reset_unchecked();
}
}

Expand Down
5 changes: 2 additions & 3 deletions tools/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ def main():

crate_info = cargo_meta["packages"][0]

features = ["{},usb_fs,can,i2s,fsmc_lcd,rtic1,defmt".format(x)
features = ["{},usb_fs,can,i2s,fsmc_lcd,rtic1,defmt,stm32-fmc".format(x)
for x in crate_info["features"].keys()
if x.startswith("stm32f4")]

if 'size_check' in sys.argv:
cargo_cmd = ['cargo', 'build', '--release']
else:
cargo_cmd = ['cargo', 'check']

if '--examples' in sys.argv:
cargo_cmd += ['--examples']

Expand All @@ -47,4 +47,3 @@ def main():

if __name__ == "__main__":
main()

0 comments on commit 2ed6c8c

Please sign in to comment.