|
| 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