Skip to content

Commit 7a1f902

Browse files
committed
stm32-fmc
1 parent 2e8f1ba commit 7a1f902

File tree

9 files changed

+373
-6
lines changed

9 files changed

+373
-6
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
rust:
4242
- stable
4343
features:
44-
- usb_fs,sdio-host,can,i2s,fsmc_lcd,rtic1
44+
- usb_fs,sdio-host,can,i2s,fsmc_lcd,rtic1,stm32-fmc
4545
include:
4646
- rust: nightly
4747
mcu: stm32f479

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1414
- `i2c_scanner` example [#758]
1515
- Enable `sdio` for stm32f446
1616
- port LTDC implementation and example from stm32f7xx-hal [#731]
17+
- port `stm32-fmc` support and example from stm32f7xx-hal [#759]
1718
- IrDA mode for USARTs
1819
- initial `SAI` support [#248]
1920
- initial `embedded-io` support [#725]
@@ -38,6 +39,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3839
[#772]: https://github.com/stm32-rs/stm32f4xx-hal/pull/772
3940
[#773]: https://github.com/stm32-rs/stm32f4xx-hal/pull/773
4041
[#783]: https://github.com/stm32-rs/stm32f4xx-hal/pull/783
42+
[#759]: https://github.com/stm32-rs/stm32f4xx-hal/pull/759
4143

4244
## [v0.21.0] - 2024-05-30
4345

Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ embedded-hal-async = { version = "1.0", optional = true }
5757
rtic = { version = "2.0.1", features = ["thumbv7-backend"], optional = true }
5858
atomic-polyfill = { version = "1.0.3", optional = true }
5959

60+
stm32-fmc = { version = "0.3.0", optional = true }
61+
6062
enumflags2 = "0.7.8"
6163
embedded-storage = "0.3"
6264
document-features = "0.2"
@@ -760,3 +762,7 @@ required-features = ["otg-fs", "usb_fs"] # stm32f401
760762
[[example]]
761763
name = "ws2812-spi"
762764
required-features = []
765+
766+
[[example]]
767+
name = "fmc-sdram"
768+
required-features = ["stm32f469", "stm32-fmc"]

examples/fmc-sdram.rs

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//! This example shows how to use the FMC controller on the STM32F7 to communicate with an
2+
//! off-chip SDRAM memory device. The `stm32-fmc` crate does the majority of the work, and
3+
//! after initialization the SDRAM is memory mapped to the STM32F7 address space.
4+
//!
5+
//! This example was tested on the STM32F746G Discovery Board. The board has an IS42S32400F-6BL
6+
//! SDRAM chip, with only 16 of the 32 data wires connected to the microcontroller. This device
7+
//! is not explictly supported in the `stm32-fmc` crate at time of writing, but the IS42S16400J
8+
//! has very similar parameters and is used as a placeholder for now. Because of this, only half
9+
//! of the available memory space is available (128 Mb = 16 MB, so 8 MB available).
10+
//!
11+
//! To use the example, launch a GDB server and then `cargo run`. After several seconds, the
12+
//! message "Success!" should be printed in the GDB server terminal (via semihosting).
13+
14+
#![deny(warnings)]
15+
#![no_main]
16+
#![no_std]
17+
18+
extern crate panic_semihosting;
19+
20+
use core::{mem, slice};
21+
use cortex_m_rt::entry;
22+
use cortex_m_semihosting::hprintln;
23+
use stm32_fmc::devices::is42s16400j_7;
24+
use stm32f4xx_hal::{
25+
fmc::FmcExt,
26+
gpio::{alt::fmc as alt, Speed},
27+
pac,
28+
prelude::*,
29+
};
30+
31+
/// Configure pins for the FMC controller
32+
macro_rules! fmc_pins {
33+
($($alt:ident: $pin:expr,)*) => {
34+
(
35+
$(
36+
alt::$alt::from($pin.into_alternate()
37+
.speed(Speed::VeryHigh)
38+
.internal_pull_up(true)
39+
)
40+
),*
41+
)
42+
};
43+
}
44+
45+
#[entry]
46+
fn main() -> ! {
47+
let cp = cortex_m::Peripherals::take().unwrap();
48+
let dp = pac::Peripherals::take().unwrap();
49+
50+
// Get the delay provider.
51+
let clocks = dp.RCC.constrain().cfgr.sysclk(216.MHz()).freeze();
52+
let mut delay = cp.SYST.delay(&clocks);
53+
54+
// IO
55+
let gpioc = dp.GPIOC.split();
56+
let gpiod = dp.GPIOD.split();
57+
let gpioe = dp.GPIOE.split();
58+
let gpiof = dp.GPIOF.split();
59+
let gpiog = dp.GPIOG.split();
60+
let gpioh = dp.GPIOH.split();
61+
62+
// Initialise SDRAM
63+
let fmc_io = fmc_pins! {
64+
A0: gpiof.pf0,
65+
A1: gpiof.pf1,
66+
A2: gpiof.pf2,
67+
A3: gpiof.pf3,
68+
A4: gpiof.pf4,
69+
A5: gpiof.pf5,
70+
A6: gpiof.pf12,
71+
A7: gpiof.pf13,
72+
A8: gpiof.pf14,
73+
A9: gpiof.pf15,
74+
A10: gpiog.pg0,
75+
A11: gpiog.pg1,
76+
Ba0: gpiog.pg4,
77+
Ba1: gpiog.pg5,
78+
D0: gpiod.pd14,
79+
D1: gpiod.pd15,
80+
D2: gpiod.pd0,
81+
D3: gpiod.pd1,
82+
D4: gpioe.pe7,
83+
D5: gpioe.pe8,
84+
D6: gpioe.pe9,
85+
D7: gpioe.pe10,
86+
D8: gpioe.pe11,
87+
D9: gpioe.pe12,
88+
D10: gpioe.pe13,
89+
D11: gpioe.pe14,
90+
D12: gpioe.pe15,
91+
D13: gpiod.pd8,
92+
D14: gpiod.pd9,
93+
D15: gpiod.pd10,
94+
Nbl0: gpioe.pe0,
95+
Nbl1: gpioe.pe1,
96+
Sdcke0: gpioc.pc3,
97+
Sdclk: gpiog.pg8,
98+
Sdncas: gpiog.pg15,
99+
Sdne0: gpioh.ph3,
100+
Sdnras: gpiof.pf11,
101+
Sdnwe: gpioh.ph5,
102+
};
103+
104+
// New SDRAM
105+
let mut sdram = dp.FMC.sdram(fmc_io, is42s16400j_7::Is42s16400j {}, &clocks);
106+
107+
// Initialise controller and SDRAM
108+
let len_bytes = (16 * 1024 * 1024) / 2;
109+
let len_words = len_bytes / mem::size_of::<u32>();
110+
let ram = unsafe {
111+
let ram_ptr: *mut u32 = sdram.init(&mut delay);
112+
slice::from_raw_parts_mut(ram_ptr, len_words)
113+
};
114+
115+
// Access all the words in SDRAM (takes several seconds)
116+
for addr in 0..len_words {
117+
let val: u32 = addr as u32;
118+
119+
// Write
120+
ram[addr] = val;
121+
122+
// Read
123+
let res: u32 = ram[addr];
124+
if res != val {
125+
panic!(
126+
"Error: Expected {} while reading address {:X} but got {}.",
127+
val, addr, res
128+
);
129+
}
130+
}
131+
132+
hprintln!("Success!");
133+
134+
loop {}
135+
}

src/fmc.rs

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
//! HAL for Flexible memory controller (FMC)
2+
//!
3+
//! See the stm32-fmc [usage guide](https://github.com/stm32-rs/stm32-fmc#usage)
4+
5+
// From stm32_fmc
6+
7+
use stm32_fmc::FmcPeripheral;
8+
use stm32_fmc::{AddressPinSet, PinsSdram, Sdram, SdramChip, SdramPinSet, SdramTargetBank};
9+
10+
use crate::rcc::{BusClock, Clocks, Enable, Reset};
11+
use fugit::HertzU32 as Hertz;
12+
13+
use crate::gpio::alt::fmc as alt;
14+
15+
#[cfg(feature = "fmc")]
16+
use crate::pac::FMC as FMC_PER;
17+
#[cfg(feature = "fsmc")]
18+
use crate::pac::FSMC as FMC_PER;
19+
20+
/// Storage type for Flexible Memory Controller and its clocks
21+
pub struct FMC {
22+
pub fmc: FMC_PER,
23+
hclk: Hertz,
24+
}
25+
26+
/// Extension trait for FMC controller
27+
pub trait FmcExt: Sized {
28+
fn fmc(self, clocks: &Clocks) -> FMC;
29+
30+
/// A new SDRAM memory via the Flexible Memory Controller
31+
fn sdram<
32+
BANK: SdramPinSet,
33+
ADDR: AddressPinSet,
34+
PINS: PinsSdram<BANK, ADDR>,
35+
CHIP: SdramChip,
36+
>(
37+
self,
38+
pins: PINS,
39+
chip: CHIP,
40+
clocks: &Clocks,
41+
) -> Sdram<FMC, CHIP> {
42+
let fmc = self.fmc(clocks);
43+
Sdram::new(fmc, pins, chip)
44+
}
45+
46+
/// A new SDRAM memory via the Flexible Memory Controller
47+
fn sdram_unchecked<CHIP: SdramChip, BANK: Into<SdramTargetBank>>(
48+
self,
49+
bank: BANK,
50+
chip: CHIP,
51+
clocks: &Clocks,
52+
) -> Sdram<FMC, CHIP> {
53+
let fmc = self.fmc(clocks);
54+
Sdram::new_unchecked(fmc, bank, chip)
55+
}
56+
}
57+
58+
impl FmcExt for FMC_PER {
59+
/// New FMC instance
60+
fn fmc(self, clocks: &Clocks) -> FMC {
61+
FMC {
62+
fmc: self,
63+
hclk: FMC_PER::clock(clocks),
64+
}
65+
}
66+
}
67+
68+
unsafe impl FmcPeripheral for FMC {
69+
const REGISTERS: *const () = FMC_PER::ptr() as *const ();
70+
71+
fn enable(&mut self) {
72+
// TODO : change it to something safe ...
73+
unsafe {
74+
// Enable FMC
75+
FMC_PER::enable_unchecked();
76+
// Reset FMC
77+
FMC_PER::reset_unchecked();
78+
}
79+
}
80+
81+
fn source_clock_hz(&self) -> u32 {
82+
// FMC block is clocked by HCLK
83+
self.hclk.raw()
84+
}
85+
}
86+
87+
macro_rules! pins {
88+
($($F:ident: $P:ident;)+) => {
89+
$(
90+
impl stm32_fmc::$F for alt::$P {}
91+
)+
92+
}
93+
}
94+
95+
pins! {
96+
A0: A0;
97+
A1: A1;
98+
A2: A2;
99+
A3: A3;
100+
A4: A4;
101+
A5: A5;
102+
A6: A6;
103+
A7: A7;
104+
A8: A8;
105+
A9: A9;
106+
A10: A10;
107+
A11: A11;
108+
A12: A12;
109+
A13: A13;
110+
A14: A14;
111+
A15: A15;
112+
A16: A16;
113+
A17: A17;
114+
A18: A18;
115+
A19: A19;
116+
A20: A20;
117+
A21: A21;
118+
A22: A22;
119+
A23: A23;
120+
A24: A24;
121+
CLK: Clk;
122+
D0: D0;
123+
D1: D1;
124+
D2: D2;
125+
D3: D3;
126+
D4: D4;
127+
D5: D5;
128+
D6: D6;
129+
D7: D7;
130+
D8: D8;
131+
D9: D9;
132+
D10: D10;
133+
D11: D11;
134+
D12: D12;
135+
D13: D13;
136+
D14: D14;
137+
D15: D15;
138+
DA0: Da0;
139+
DA1: Da1;
140+
DA2: Da2;
141+
DA3: Da3;
142+
DA4: Da4;
143+
DA5: Da5;
144+
DA6: Da6;
145+
DA7: Da7;
146+
DA8: Da8;
147+
DA9: Da9;
148+
DA10: Da10;
149+
DA11: Da11;
150+
DA12: Da12;
151+
DA13: Da13;
152+
DA14: Da14;
153+
DA15: Da15;
154+
NBL0: Nbl0;
155+
NBL1: Nbl1;
156+
NE1: Ne1;
157+
NE2: Ne2;
158+
NE3: Ne3;
159+
NE4: Ne4;
160+
NL: Nl;
161+
NOE: Noe;
162+
NWAIT: Nwait;
163+
NWE: Nwe;
164+
}
165+
166+
#[cfg(any(feature = "gpio-f427", feature = "gpio-f446", feature = "gpio-f469"))]
167+
pins! {
168+
BA0: Ba0;
169+
BA1: Ba1;
170+
SDCKE0: Sdcke0;
171+
SDCKE1: Sdcke1;
172+
SDCLK: Sdclk;
173+
SDNCAS: Sdncas;
174+
SDNE0: Sdne0;
175+
SDNE1: Sdne1;
176+
SDNRAS: Sdnras;
177+
SDNWE: Sdnwe;
178+
}
179+
180+
#[cfg(any(feature = "gpio-f427", feature = "gpio-f469"))]
181+
pins! {
182+
D16: D16;
183+
D17: D17;
184+
D18: D18;
185+
D19: D19;
186+
D20: D20;
187+
D21: D21;
188+
D22: D22;
189+
D23: D23;
190+
D24: D24;
191+
D25: D25;
192+
D26: D26;
193+
D27: D27;
194+
D28: D28;
195+
D29: D29;
196+
D30: D30;
197+
D31: D31;
198+
NBL2: Nbl2;
199+
NBL3: Nbl3;
200+
}
201+
202+
#[cfg(feature = "gpio-f469")]
203+
pins! {
204+
INT: Int;
205+
}
206+
207+
#[cfg(any(
208+
feature = "gpio-f417",
209+
feature = "gpio-f427",
210+
feature = "gpio-f446",
211+
feature = "gpio-f469"
212+
))]
213+
pins! {
214+
NCE: Nce3;
215+
}
216+
#[cfg(any(feature = "gpio-f417", feature = "gpio-f427"))]
217+
pins! {
218+
NCE: Nce2;
219+
}

0 commit comments

Comments
 (0)