Skip to content

Commit d0a7ba5

Browse files
Merge #116
116: Add FMC controller via stm32-fmc crate r=richardeoin a=richardeoin The [stm32-fmc](https://github.com/stm32-rs/stm32-fmc) crate is still a work in progress. Todo: - [ ] Add example Co-authored-by: Richard Meadows <[email protected]>
2 parents df75390 + d3c8223 commit d0a7ba5

File tree

7 files changed

+504
-2
lines changed

7 files changed

+504
-2
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- stm32h753v
2121
- stm32h747cm7
2222
env: # Peripheral Feature flags
23-
FLAGS: rt,quadspi,sdmmc
23+
FLAGS: rt,quadspi,sdmmc,fmc
2424

2525
steps:
2626
- uses: actions/checkout@v2

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- log-semihost
2020
- log-rtt
2121
env: # Peripheral Feature flags
22-
FLAGS: rt,quadspi,sdmmc
22+
FLAGS: rt,quadspi,sdmmc,fmc
2323

2424
steps:
2525
- uses: actions/checkout@v2

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ cast = { version = "0.2.3", default-features = false }
3131
nb = "0.1.2"
3232
paste = "0.1.18"
3333
sdio-host = { version = "0.4", optional = true }
34+
stm32-fmc = { version = "0.2", optional = true }
3435

3536
[dependencies.bare-metal]
3637
version = "0.2.5"
@@ -71,6 +72,7 @@ dsi = []
7172
cm4 = []
7273
cm7 = []
7374
quadspi = []
75+
fmc = ["stm32-fmc"]
7476
sdmmc = ["sdio-host"]
7577
ethernet = ["smoltcp"]
7678
phy_ksz8081r = []
@@ -112,6 +114,10 @@ required-features = ["rt"]
112114
name = "vos0"
113115
required-features = ["revision_v"]
114116

117+
[[example]]
118+
name = "fmc"
119+
required-features = ["fmc"]
120+
115121
[[example]]
116122
name = "qspi"
117123
required-features = ["quadspi"]

examples/fmc.rs

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
//! FMC Example
2+
#![no_main]
3+
#![no_std]
4+
5+
use core::mem;
6+
use core::slice;
7+
8+
use rtic::app;
9+
10+
extern crate cortex_m;
11+
extern crate panic_itm;
12+
extern crate rtic;
13+
14+
use stm32h7xx_hal::gpio::Speed;
15+
use stm32h7xx_hal::{prelude::*, stm32};
16+
17+
use stm32_fmc::devices::is42s32800g_6;
18+
19+
/// Configure MPU for external SDRAM
20+
fn mpu_sdram_init(mpu: stm32::MPU, scb: &mut stm32::SCB, size: usize) {
21+
/// Refer to ARM®v7-M Architecture Reference Manual ARM DDI 0403
22+
/// Version E.b Section B3.5
23+
const MEMFAULTENA: u32 = 1 << 16;
24+
25+
unsafe {
26+
/* Make sure outstanding transfers are done */
27+
cortex_m::asm::dmb();
28+
29+
scb.shcsr.modify(|r| r & !MEMFAULTENA);
30+
31+
/* Disable the MPU and clear the control register*/
32+
mpu.ctrl.write(0);
33+
}
34+
35+
const REGION_NUMBER0: u32 = 0x00;
36+
const REGION_BASE_ADDRESS: u32 = 0xD000_0000;
37+
38+
const REGION_FULL_ACCESS: u32 = 0x03;
39+
const REGION_CACHEABLE: u32 = 0x01;
40+
const REGION_WRITE_BACK: u32 = 0x01;
41+
const REGION_ENABLE: u32 = 0x01;
42+
43+
assert_eq!(
44+
size & (size - 1),
45+
0,
46+
"SDRAM memory region size must be a power of 2"
47+
);
48+
assert_eq!(
49+
size & 0x1F,
50+
0,
51+
"SDRAM memory region size must be 32 bytes or more"
52+
);
53+
fn log2minus1(sz: u32) -> u32 {
54+
for i in 5..=31 {
55+
if sz == (1 << i) {
56+
return i - 1;
57+
}
58+
}
59+
panic!("Unknown SDRAM memory region size!");
60+
}
61+
62+
//info!("SDRAM Memory Size 0x{:x}", log2minus1(size as u32));
63+
64+
// Configure region 0
65+
//
66+
// Cacheable, outer and inner write-back, no write allocate. So
67+
// reads are cached, but writes always write all the way to SDRAM
68+
unsafe {
69+
mpu.rnr.write(REGION_NUMBER0);
70+
mpu.rbar.write(REGION_BASE_ADDRESS);
71+
mpu.rasr.write(
72+
(REGION_FULL_ACCESS << 24)
73+
| (REGION_CACHEABLE << 17)
74+
| (REGION_WRITE_BACK << 16)
75+
| (log2minus1(size as u32) << 1)
76+
| REGION_ENABLE,
77+
);
78+
}
79+
80+
const MPU_ENABLE: u32 = 0x01;
81+
const MPU_DEFAULT_MMAP_FOR_PRIVILEGED: u32 = 0x04;
82+
83+
// Enable
84+
unsafe {
85+
mpu.ctrl
86+
.modify(|r| r | MPU_DEFAULT_MMAP_FOR_PRIVILEGED | MPU_ENABLE);
87+
88+
scb.shcsr.modify(|r| r | MEMFAULTENA);
89+
90+
// Ensure MPU settings take effect
91+
cortex_m::asm::dsb();
92+
cortex_m::asm::isb();
93+
}
94+
}
95+
96+
/// Configre a pin for the FMC controller
97+
macro_rules! fmc_pins {
98+
($($pin:expr),*) => {
99+
(
100+
$(
101+
$pin.into_push_pull_output()
102+
.set_speed(Speed::VeryHigh)
103+
.into_alternate_af12()
104+
.internal_pull_up(true)
105+
),*
106+
)
107+
};
108+
}
109+
110+
#[app(device = stm32h7xx_hal::stm32, peripherals = true)]
111+
const APP: () = {
112+
// the program entry point
113+
#[init]
114+
fn init(mut ctx: init::Context) {
115+
let dp = ctx.device;
116+
117+
// Initialise power...
118+
let pwr = dp.PWR.constrain();
119+
let vos = pwr.freeze();
120+
121+
// Initialise clocks...
122+
let rcc = dp.RCC.constrain();
123+
let ccdr = rcc
124+
.sys_ck(200.mhz())
125+
.hclk(200.mhz()) // FMC clock from HCLK by default
126+
.freeze(vos, &dp.SYSCFG);
127+
128+
// Get the delay provider.
129+
let mut delay = ctx.core.SYST.delay(ccdr.clocks);
130+
131+
// Initialise system...
132+
ctx.core.SCB.invalidate_icache();
133+
ctx.core.SCB.enable_icache();
134+
// See Errata Sheet 2.2.1
135+
//ctx.core.SCB.enable_dcache(&mut ctx.core.CPUID);
136+
ctx.core.DWT.enable_cycle_counter();
137+
138+
// Initialise IO...
139+
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
140+
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
141+
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
142+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
143+
let gpioh = dp.GPIOH.split(ccdr.peripheral.GPIOH);
144+
let gpioi = dp.GPIOI.split(ccdr.peripheral.GPIOI);
145+
146+
// ----------------------------------------------------------
147+
// MPU config for SDRAM write-through
148+
let sdram_size = 32 * 1024 * 1024;
149+
mpu_sdram_init(ctx.core.MPU, &mut ctx.core.SCB, sdram_size);
150+
151+
// ----------------------------------------------------------
152+
// SDRAM
153+
// Initialise SDRAM...
154+
let fmc_io = fmc_pins! {
155+
// A0-A11
156+
gpiof.pf0, gpiof.pf1, gpiof.pf2, gpiof.pf3,
157+
gpiof.pf4, gpiof.pf5, gpiof.pf12, gpiof.pf13,
158+
gpiof.pf14, gpiof.pf15, gpiog.pg0, gpiog.pg1,
159+
// BA0-BA1
160+
gpiog.pg4, gpiog.pg5,
161+
// D0-D31
162+
gpiod.pd14, gpiod.pd15, gpiod.pd0, gpiod.pd1,
163+
gpioe.pe7, gpioe.pe8, gpioe.pe9, gpioe.pe10,
164+
gpioe.pe11, gpioe.pe12, gpioe.pe13, gpioe.pe14,
165+
gpioe.pe15, gpiod.pd8, gpiod.pd9, gpiod.pd10,
166+
gpioh.ph8, gpioh.ph9, gpioh.ph10, gpioh.ph11,
167+
gpioh.ph12, gpioh.ph13, gpioh.ph14, gpioh.ph15,
168+
gpioi.pi0, gpioi.pi1, gpioi.pi2, gpioi.pi3,
169+
gpioi.pi6, gpioi.pi7, gpioi.pi9, gpioi.pi10,
170+
// NBL0 - NBL3
171+
gpioe.pe0, gpioe.pe1, gpioi.pi4, gpioi.pi5,
172+
gpioh.ph7, // SDCKE1
173+
gpiog.pg8, // SDCLK
174+
gpiog.pg15, // SDNCAS
175+
gpioh.ph6, // SDNE1 (!CS)
176+
gpiof.pf11, // SDRAS
177+
gpioh.ph5 // SDNWE
178+
};
179+
180+
let mut sdram = dp.FMC.sdram(
181+
fmc_io,
182+
is42s32800g_6::Is42s32800g {},
183+
ccdr.peripheral.FMC,
184+
&ccdr.clocks,
185+
);
186+
187+
let ram_slice = unsafe {
188+
// Initialise controller and SDRAM
189+
let ram_ptr: *mut u32 = sdram.init(&mut delay);
190+
191+
// Get 16-bit words
192+
let ram_ptr = ram_ptr as *mut u16;
193+
194+
// Convert raw pointer to slice
195+
let ram_slice = slice::from_raw_parts_mut(ram_ptr, sdram_size);
196+
197+
// Return a 4-word slice
198+
let size = mem::size_of::<u16>() * 4usize;
199+
let mut chunks = ram_slice.chunks_exact_mut(size);
200+
chunks.next().unwrap()
201+
};
202+
203+
// ----------------------------------------------------------
204+
// Use memory in SDRAM
205+
206+
ram_slice[0] = 1u16;
207+
ram_slice[1] = 2;
208+
ram_slice[2] = 3;
209+
ram_slice[3] = 4;
210+
211+
assert_eq!(ram_slice[0], 1);
212+
213+
loop {}
214+
}
215+
};

0 commit comments

Comments
 (0)