Skip to content

Commit da18712

Browse files
committed
Use ownership to handle sdram memory
1 parent 5ed7599 commit da18712

File tree

5 files changed

+91
-82
lines changed

5 files changed

+91
-82
lines changed

src/bin/async-await.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,17 @@ fn run() -> ! {
103103
init::init_systick(Hz(100), &mut systick, &rcc);
104104
systick.enable_interrupt();
105105

106-
init::init_sdram(&mut rcc, &mut fmc);
107-
let mut lcd = init::init_lcd(&mut ltdc, &mut rcc);
106+
let sdram = init::init_sdram(&mut rcc, &mut fmc);
107+
let (mut lcd, _sdram) = lcd::init(&mut ltdc, &mut rcc, sdram);
108108
pins.display_enable.set(true);
109109
pins.backlight.set(true);
110110

111111
// Initialize the allocator BEFORE you use it
112112
unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }
113113

114114
lcd.set_background_color(Color::from_hex(0x006600));
115-
let layer_1 = lcd.layer_1().unwrap();
116-
let mut layer_2 = lcd.layer_2().unwrap();
115+
let layer_1 = lcd.layer_1.take().unwrap();
116+
let mut layer_2 = lcd.layer_2.take().unwrap();
117117

118118
layer_2.clear();
119119

src/bin/polling.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ fn main() -> ! {
8787
init::init_systick(Hz(100), &mut systick, &rcc);
8888
systick.enable_interrupt();
8989

90-
init::init_sdram(&mut rcc, &mut fmc);
91-
let mut lcd = init::init_lcd(&mut ltdc, &mut rcc);
90+
let sdram = init::init_sdram(&mut rcc, &mut fmc);
91+
let (mut lcd, _sdram) = lcd::init(&mut ltdc, &mut rcc, sdram);
9292
pins.display_enable.set(true);
9393
pins.backlight.set(true);
9494

95-
let mut layer_1 = lcd.layer_1().unwrap();
96-
let mut layer_2 = lcd.layer_2().unwrap();
95+
let mut layer_1 = lcd.layer_1.take().unwrap();
96+
let mut layer_2 = lcd.layer_2.take().unwrap();
9797

9898
layer_1.clear();
9999
layer_2.clear();

src/init/mod.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! Provides various hardware initialization functions.
22
33
use crate::i2c::{self, I2C};
4-
use crate::lcd::{self, Lcd};
54
use crate::system_clock;
6-
use stm32f7::stm32f7x6::{self as device, FLASH, FMC, LTDC, PWR, RCC, SAI2, SYST};
5+
use stm32f7::stm32f7x6::{self as device, FLASH, FMC, PWR, RCC, SAI2, SYST};
76

87
pub use self::pins::init as pins;
98
pub use self::pins::Pins;
@@ -146,10 +145,19 @@ pub fn enable_syscfg(rcc: &mut RCC) {
146145
let _unused = rcc.apb2enr.read();
147146
}
148147

148+
static mut SDRAM_INITIALIZED: bool = false;
149+
149150
/// Initializes the SDRAM, which makes more memory accessible.
150151
///
151152
/// This is a prerequisite for using the LCD.
152-
pub fn init_sdram(rcc: &mut RCC, fmc: &mut FMC) {
153+
pub fn init_sdram(rcc: &mut RCC, fmc: &mut FMC) -> &'static mut [volatile::Volatile<u8>] {
154+
155+
// ensures that we don't do this twice and end up with two `&'static mut` to the same memory
156+
unsafe {
157+
assert!(!SDRAM_INITIALIZED);
158+
SDRAM_INITIALIZED = true;
159+
}
160+
153161
#[allow(dead_code)]
154162
#[derive(Debug, Clone, Copy)]
155163
enum Bank {
@@ -221,7 +229,7 @@ pub fn init_sdram(rcc: &mut RCC, fmc: &mut FMC) {
221229
rcc.ahb3rstr.modify(|_, w| w.fmcrst().reset());
222230
rcc.ahb3rstr.modify(|_, w| w.fmcrst().clear_bit());
223231

224-
// SDRAM contol register
232+
// SDRAM control register
225233
fmc.sdcr1.modify(|_, w| unsafe {
226234
w.nc().bits(8 - 8); // number_of_column_address_bits
227235
w.nr().bits(12 - 11); // number_of_row_address_bits
@@ -272,30 +280,32 @@ pub fn init_sdram(rcc: &mut RCC, fmc: &mut FMC) {
272280
w
273281
});
274282

275-
// test sdram
276-
use core::ptr;
283+
let sdram_start: usize = 0xC000_0000;
284+
let sdram_len: usize = 64 / 8 * 1024 * 1024; // 64 Mbit according to packaging
285+
286+
{
287+
// test sdram
288+
use core::ptr;
277289

278-
let ptr1 = 0xC000_0000 as *mut u32;
279-
let ptr2 = 0xC053_6170 as *mut u32;
280-
let ptr3 = 0xC07F_FFFC as *mut u32;
290+
let ptr1 = sdram_start as *mut u32;
291+
let ptr2 = (sdram_start + 0x0053_6170) as *mut u32;
292+
let ptr3 = (sdram_start + sdram_len - 4) as *mut u32;
281293

294+
unsafe {
295+
ptr::write_volatile(ptr1, 0xcafe_babe);
296+
ptr::write_volatile(ptr2, 0xdead_beaf);
297+
ptr::write_volatile(ptr3, 0x0dea_fbee);
298+
assert_eq!(ptr::read_volatile(ptr1), 0xcafe_babe);
299+
assert_eq!(ptr::read_volatile(ptr2), 0xdead_beaf);
300+
assert_eq!(ptr::read_volatile(ptr3), 0x0dea_fbee);
301+
}
302+
}
303+
// this block's safety is guaranteed by SDRAM_INITIALIZED check at the start of this function
282304
unsafe {
283-
ptr::write_volatile(ptr1, 0xcafe_babe);
284-
ptr::write_volatile(ptr2, 0xdead_beaf);
285-
ptr::write_volatile(ptr3, 0x0dea_fbee);
286-
assert_eq!(ptr::read_volatile(ptr1), 0xcafe_babe);
287-
assert_eq!(ptr::read_volatile(ptr2), 0xdead_beaf);
288-
assert_eq!(ptr::read_volatile(ptr3), 0x0dea_fbee);
305+
core::slice::from_raw_parts_mut(sdram_start as *mut volatile::Volatile<u8>, sdram_len)
289306
}
290307
}
291308

292-
/// Initializes the LCD.
293-
///
294-
/// This function is equivalent to [`lcd::init`](crate::lcd::init::init).
295-
pub fn init_lcd<'a>(ltdc: &'a mut LTDC, rcc: &mut RCC) -> Lcd<'a> {
296-
lcd::init(ltdc, rcc)
297-
}
298-
299309
/// Initializes the I2C3 bus.
300310
///
301311
/// This function is equivalent to [`i2c::init`](crate::i2c::init).

src/lcd/init.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ use stm32f7::stm32f7x6::{LTDC, RCC};
33

44
/// Initializes the LCD controller.
55
///
6-
/// The SDRAM must be initialized before this function is called. See the
7-
/// [`init_sdram`] function for more information.
6+
/// Needs memory for the screen buffers. On stm32f7 this is usually done via SDRAM.
7+
/// The SDRAM is initialized via the [`init_sdram`] function.
88
///
99
/// [`init_sdram`]: crate::init::init_sdram
10-
pub fn init<'a>(ltdc: &'a mut LTDC, rcc: &mut RCC) -> Lcd<'a> {
11-
use crate::lcd::{self, LAYER_1_START, LAYER_2_START};
10+
pub fn init<'a>(
11+
ltdc: &'a mut LTDC,
12+
rcc: &mut RCC,
13+
mem: &'static mut [volatile::Volatile<u8>],
14+
) -> (Lcd<'a>, &'static mut [volatile::Volatile<u8>]) {
15+
use crate::lcd;
1216
const HEIGHT: u16 = lcd::HEIGHT as u16;
1317
const WIDTH: u16 = lcd::WIDTH as u16;
1418
const LAYER_1_OCTETS_PER_PIXEL: u16 = lcd::LAYER_1_OCTETS_PER_PIXEL as u16;
@@ -152,11 +156,14 @@ pub fn init<'a>(ltdc: &'a mut LTDC, rcc: &mut RCC) -> Lcd<'a> {
152156
w
153157
});
154158

159+
let (layer1, mem) = mem.split_at_mut(lcd::LAYER_1_LENGTH);
160+
let (layer2, mem) = mem.split_at_mut(lcd::LAYER_2_LENGTH);
161+
155162
// configure color frame buffer start address
156163
ltdc.l1cfbar
157-
.modify(|_, w| unsafe { w.cfbadd().bits(LAYER_1_START as u32) });
164+
.modify(|_, w| unsafe { w.cfbadd().bits(layer1.as_mut_ptr() as usize as u32) });
158165
ltdc.l2cfbar
159-
.modify(|_, w| unsafe { w.cfbadd().bits(LAYER_2_START as u32) });
166+
.modify(|_, w| unsafe { w.cfbadd().bits(layer2.as_mut_ptr() as usize as u32) });
160167

161168
// configure color frame buffer line length and pitch
162169
ltdc.l1cfblr.modify(|_, w| unsafe {
@@ -180,8 +187,9 @@ pub fn init<'a>(ltdc: &'a mut LTDC, rcc: &mut RCC) -> Lcd<'a> {
180187
ltdc.l1cr.modify(|_, w| w.len().set_bit());
181188
ltdc.l2cr.modify(|_, w| w.len().set_bit().cluten().set_bit());
182189

183-
// reload shadow registers
184-
ltdc.srcr.modify(|_, w| w.imr().set_bit()); // IMMEDIATE_RELOAD
190+
let mut lcd = Lcd::new(ltdc, layer1, layer2);
191+
192+
lcd.reload_shadow_registers(); // IMMEDIATE_RELOAD
185193

186-
Lcd::new(ltdc)
194+
(lcd, mem)
187195
}

src/lcd/mod.rs

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub use self::color::Color;
77
pub use self::init::init;
88
pub use self::stdout::init as init_stdout;
99

10-
use core::{fmt, ptr};
10+
use core::fmt;
1111
use stm32f7::stm32f7x6::LTDC;
1212

1313
#[macro_use]
@@ -29,26 +29,31 @@ pub const LAYER_2_OCTETS_PER_PIXEL: usize = 2;
2929
/// The length of the layer 1 buffer in bytes.
3030
pub const LAYER_2_LENGTH: usize = HEIGHT * WIDTH * LAYER_2_OCTETS_PER_PIXEL;
3131

32-
/// Start address of the SDRAM where the framebuffers live.
33-
pub const SDRAM_START: usize = 0xC000_0000;
34-
/// Start address of the layer 1 framebuffer.
35-
pub const LAYER_1_START: usize = SDRAM_START;
36-
/// Start address of the layer 2 framebuffer.
37-
pub const LAYER_2_START: usize = SDRAM_START + LAYER_1_LENGTH;
38-
3932
/// Represents the LCD and provides methods to access both layers.
4033
pub struct Lcd<'a> {
4134
controller: &'a mut LTDC,
42-
layer_1_in_use: bool,
43-
layer_2_in_use: bool,
35+
36+
/// A layer with RGB + alpha value
37+
///
38+
/// Use `.take()` to get an owned version of this layer.
39+
pub layer_1: Option<Layer<FramebufferArgb8888>>,
40+
41+
/// A layer with alpha + color lookup table index
42+
///
43+
/// Use `.take()` to get an owned version of this layer.
44+
pub layer_2: Option<Layer<FramebufferAl88>>,
4445
}
4546

4647
impl<'a> Lcd<'a> {
47-
fn new(ltdc: &'a mut LTDC) -> Self {
48+
fn new(
49+
ltdc: &'a mut LTDC,
50+
layer_1: &'static mut [volatile::Volatile<u8>],
51+
layer_2: &'static mut [volatile::Volatile<u8>],
52+
) -> Self {
4853
Self {
4954
controller: ltdc,
50-
layer_1_in_use: false,
51-
layer_2_in_use: false,
55+
layer_1: Some(Layer { framebuffer: FramebufferArgb8888::new(layer_1) } ),
56+
layer_2: Some(Layer { framebuffer: FramebufferAl88::new(layer_2) } ),
5257
}
5358
}
5459

@@ -71,26 +76,8 @@ impl<'a> Lcd<'a> {
7176
});
7277
}
7378

74-
/// Returns a reference to layer 1.
75-
pub fn layer_1(&mut self) -> Option<Layer<FramebufferArgb8888>> {
76-
if self.layer_1_in_use {
77-
None
78-
} else {
79-
Some(Layer {
80-
framebuffer: FramebufferArgb8888::new(LAYER_1_START),
81-
})
82-
}
83-
}
84-
85-
/// Returns a reference to layer 2.
86-
pub fn layer_2(&mut self) -> Option<Layer<FramebufferAl88>> {
87-
if self.layer_2_in_use {
88-
None
89-
} else {
90-
Some(Layer {
91-
framebuffer: FramebufferAl88::new(LAYER_2_START),
92-
})
93-
}
79+
fn reload_shadow_registers(&mut self) {
80+
self.controller.srcr.modify(|_, w| w.imr().set_bit()); // IMMEDIATE_RELOAD
9481
}
9582
}
9683

@@ -104,20 +91,23 @@ pub trait Framebuffer {
10491
///
10592
/// It uses 8bits for alpha, red, green, and black respectively, totaling in 32bits per pixel.
10693
pub struct FramebufferArgb8888 {
107-
base_addr: usize,
94+
mem: &'static mut [volatile::Volatile<u8>],
10895
}
10996

11097
impl FramebufferArgb8888 {
111-
const fn new(base_addr: usize) -> Self {
112-
Self { base_addr }
98+
fn new(mem: &'static mut [volatile::Volatile<u8>]) -> Self {
99+
Self { mem }
113100
}
114101
}
115102

116103
impl Framebuffer for FramebufferArgb8888 {
117104
fn set_pixel(&mut self, x: usize, y: usize, color: Color) {
118105
let pixel = y * WIDTH + x;
119-
let pixel_ptr = (self.base_addr + pixel * LAYER_1_OCTETS_PER_PIXEL) as *mut u32;
120-
unsafe { ptr::write_volatile(pixel_ptr, color.to_argb8888()) };
106+
let pixel_idx = pixel * LAYER_1_OCTETS_PER_PIXEL;
107+
self.mem[pixel_idx].write(color.alpha);
108+
self.mem[pixel_idx + 1].write(color.red);
109+
self.mem[pixel_idx + 2].write(color.green);
110+
self.mem[pixel_idx + 3].write(color.blue);
121111
}
122112
}
123113

@@ -126,20 +116,21 @@ impl Framebuffer for FramebufferArgb8888 {
126116
/// There are 8bits for the alpha channel and 8 bits for specifying a color using a
127117
/// lookup table. Thus, each pixel is represented by 16bits.
128118
pub struct FramebufferAl88 {
129-
base_addr: usize,
119+
mem: &'static mut [volatile::Volatile<u8>],
130120
}
131121

132122
impl FramebufferAl88 {
133-
const fn new(base_addr: usize) -> Self {
134-
Self { base_addr }
123+
fn new(mem: &'static mut [volatile::Volatile<u8>]) -> Self {
124+
Self { mem }
135125
}
136126
}
137127

138128
impl Framebuffer for FramebufferAl88 {
139129
fn set_pixel(&mut self, x: usize, y: usize, color: Color) {
140130
let pixel = y * WIDTH + x;
141-
let pixel_ptr = (self.base_addr + pixel * LAYER_2_OCTETS_PER_PIXEL) as *mut u16;
142-
unsafe { ptr::write_volatile(pixel_ptr, u16::from(color.alpha) << 8 | u16::from(color.red)) };
131+
let pixel_idx = pixel * LAYER_2_OCTETS_PER_PIXEL;
132+
self.mem[pixel_idx].write(color.alpha);
133+
self.mem[pixel_idx + 1].write(color.red);
143134
}
144135
}
145136

0 commit comments

Comments
 (0)