Skip to content

Commit 1174d6a

Browse files
grodinomvertescher
authored andcommitted
Added basic hardware acceleration for rectangles
1 parent 0ca17a2 commit 1174d6a

File tree

1 file changed

+134
-59
lines changed

1 file changed

+134
-59
lines changed

src/ltdc.rs

Lines changed: 134 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use micromath::F32Ext;
22

33
use crate::{
4-
device::{ltdc::LAYER, LTDC, RCC},
4+
device::{LTDC, RCC, DMA2D},
55
rcc::HSEClock,
66
};
77

@@ -35,18 +35,23 @@ pub enum Layer {
3535
}
3636

3737
pub struct DisplayController<T: 'static + SupportedWord> {
38-
// ltdc instance
38+
/// ltdc instance
3939
_ltdc: LTDC,
40+
/// dma2d instance
41+
_dma2d: DMA2D,
42+
/// Configuration structure
4043
config: DisplayConfig,
41-
// Layer 1 buffer
44+
/// layer 1 buffer
4245
buffer1: Option<&'static mut [T]>,
43-
// Layer 2 buffer
46+
/// layer 2 buffer
4447
buffer2: Option<&'static mut [T]>,
48+
/// Pixels format in the layers
49+
pixel_format: PixelFormat,
4550
}
4651

47-
impl<T: SupportedWord> DisplayController<T> {
52+
impl<T: 'static + SupportedWord> DisplayController<T> {
4853
/// Create and configure the DisplayController
49-
pub fn new(ltdc: LTDC, config: DisplayConfig, hse: Option<&HSEClock>) -> DisplayController<T> {
54+
pub fn new(ltdc: LTDC, dma2d: DMA2D, pixel_format: PixelFormat, config: DisplayConfig, hse: Option<&HSEClock>) -> DisplayController<T> {
5055
// TODO : change it to something safe ...
5156
let rcc = unsafe { &(*RCC::ptr()) };
5257

@@ -58,12 +63,18 @@ impl<T: SupportedWord> DisplayController<T> {
5863
let lcd_clk: u32 =
5964
(total_width as u32) * (total_height as u32) * (config.frame_rate as u32);
6065

61-
// Enable LTDC peripheral's clock
66+
// Enable LTDC
6267
rcc.apb2enr.modify(|_, w| w.ltdcen().enabled());
6368
// Reset LTDC peripheral
6469
rcc.apb2rstr.modify(|_, w| w.ltdcrst().reset());
6570
rcc.apb2rstr.modify(|_, w| w.ltdcrst().clear_bit());
6671

72+
// Enable DMA2D
73+
rcc.ahb1enr.modify(|_, w| w.dma2den().enabled());
74+
// Reset DMA2D
75+
rcc.ahb1rstr.modify(|_, w| w.dma2drst().reset());
76+
rcc.ahb1rstr.modify(|_, w| w.dma2drst().clear_bit());
77+
6778
// Get base clock and PLLM divisor
6879
let base_clk: u32;
6980
match &hse {
@@ -169,8 +180,7 @@ impl<T: SupportedWord> DisplayController<T> {
169180

170181
// Set blue background color
171182
ltdc.bccr.write(|w| unsafe { w.bits(0xAAAAAAAA) });
172-
173-
// TODO: configure DMA2D hardware accelerator
183+
174184
// TODO: configure interupts
175185

176186
// Reload ltdc config immediatly
@@ -180,16 +190,19 @@ impl<T: SupportedWord> DisplayController<T> {
180190

181191
// Reload ltdc config immediatly
182192
ltdc.srcr.modify(|_, w| w.imr().set_bit());
183-
193+
184194
DisplayController {
185195
_ltdc: ltdc,
196+
_dma2d: dma2d,
186197
config,
187198
buffer1: None,
188199
buffer2: None,
200+
pixel_format
189201
}
202+
190203
}
191204

192-
/// Configure a layer (layer 1 or layer 2)
205+
/// Configure the layer
193206
///
194207
/// Note : the choice is made (for the sake of simplicity) to make the layer
195208
/// as big as the screen
@@ -198,37 +211,39 @@ impl<T: SupportedWord> DisplayController<T> {
198211
pub fn config_layer(
199212
&mut self,
200213
layer: Layer,
201-
pixel_format: PixelFormat,
202214
buffer: &'static mut [T],
215+
pixel_format: PixelFormat
203216
) {
204-
let config: &DisplayConfig = &self.config;
205-
206-
let layer: &LAYER = match layer {
217+
let _layer = match &layer {
207218
Layer::L1 => &self._ltdc.layer1,
208219
Layer::L2 => &self._ltdc.layer2,
209220
};
210221

222+
let height = self.config.active_height;
223+
let width = self.config.active_width;
224+
assert!(buffer.len() == height as usize * width as usize);
225+
211226
// Horizontal and vertical window (coordinates include porches): where
212227
// in the time frame the layer values should be sent
213-
let h_win_start = config.h_sync + config.h_back_porch - 1;
214-
let v_win_start = config.v_sync + config.v_back_porch - 1;
228+
let h_win_start = self.config.h_sync + self.config.h_back_porch - 1;
229+
let v_win_start = self.config.v_sync + self.config.v_back_porch - 1;
215230

216-
layer.whpcr.write(|w| unsafe {
231+
_layer.whpcr.write(|w| unsafe {
217232
w.whstpos()
218233
.bits(h_win_start + 1)
219234
.whsppos()
220-
.bits(h_win_start + config.active_width)
235+
.bits(h_win_start + width)
221236
});
222-
layer.wvpcr.write(|w| unsafe {
237+
_layer.wvpcr.write(|w| unsafe {
223238
w.wvstpos()
224239
.bits(v_win_start + 1)
225240
.wvsppos()
226-
.bits(v_win_start + config.active_height)
241+
.bits(v_win_start + height)
227242
});
228243

229244
// Set pixel format
230-
layer.pfcr.write(|w| unsafe {
231-
w.pf().bits(match pixel_format {
245+
_layer.pfcr.write(|w| unsafe {
246+
w.pf().bits(match &pixel_format {
232247
PixelFormat::ARGB8888 => 0b000,
233248
// PixelFormat::RGB888 => 0b001,
234249
PixelFormat::RGB565 => 0b010,
@@ -237,33 +252,33 @@ impl<T: SupportedWord> DisplayController<T> {
237252
PixelFormat::L8 => 0b101,
238253
PixelFormat::AL44 => 0b110,
239254
PixelFormat::AL88 => 0b111,
240-
_ => unimplemented!(),
255+
// _ => unimplemented!(),
241256
})
242257
});
243258

244259
// Set global alpha value to 1 (255/255). Used for layer blending.
245-
layer.cacr.write(|w| unsafe { w.consta().bits(0xFF) });
260+
_layer.cacr.write(|w| unsafe { w.consta().bits(0xFF) });
246261

247262
// Set default color to plain (not transparent) red (for debug
248263
// purposes). The default color is used outside the defined layer window
249264
// or when a layer is disabled.
250-
layer.dccr.write(|w| unsafe { w.bits(0xFFFF0000) });
265+
_layer.dccr.write(|w| unsafe { w.bits(0xFFFF0000) });
251266

252267
// Blending factor: how the layer is combined with the layer below it
253268
// (layer 2 with layer 1 or layer 1 with background). Here it is set so
254269
// that the blending factor does not take the pixel alpha value, just
255270
// the global value of the layer
256-
layer
271+
_layer
257272
.bfcr
258273
.write(|w| unsafe { w.bf1().bits(0b100).bf2().bits(0b101) });
259274

260275
// Color frame buffer start address
261-
layer
276+
_layer
262277
.cfbar
263278
.write(|w| unsafe { w.cfbadd().bits(buffer.as_ptr() as u32) });
264279

265280
// Color frame buffer line length (active*byte per pixel + 3), and pitch
266-
let byte_per_pixel: u16 = match pixel_format {
281+
let byte_per_pixel: u16 = match &pixel_format {
267282
PixelFormat::ARGB8888 => 4,
268283
// PixelFormat::RGB888 => 24, unsupported for now because u24 does not exist
269284
PixelFormat::RGB565 => 2,
@@ -272,43 +287,53 @@ impl<T: SupportedWord> DisplayController<T> {
272287
PixelFormat::L8 => 1,
273288
PixelFormat::AL44 => 1,
274289
PixelFormat::AL88 => 2,
275-
_ => unimplemented!(),
290+
// _ => unimplemented!(),
276291
};
277-
layer.cfblr.write(|w| unsafe {
292+
_layer.cfblr.write(|w| unsafe {
278293
w.cfbp()
279-
.bits(config.active_width * byte_per_pixel)
294+
.bits(width * byte_per_pixel)
280295
.cfbll()
281-
.bits(config.active_width * byte_per_pixel + 3)
296+
.bits(width * byte_per_pixel + 3)
282297
});
283298

284299
// Frame buffer number of lines
285-
layer
300+
_layer
286301
.cfblnr
287-
.write(|w| unsafe { w.cfblnbr().bits(config.active_height) });
302+
.write(|w| unsafe { w.cfblnbr().bits(height) });
288303

289304
// No Color Lookup table (CLUT)
290-
layer.cr.modify(|_, w| w.cluten().clear_bit());
291-
292-
self.buffer1 = Some(buffer);
305+
_layer.cr.modify(|_, w| w.cluten().clear_bit());
293306

294-
self.reload();
295-
}
296-
297-
/// Enable a layer (layer 1 or layer 2)
298-
pub fn enable_layer(&mut self, layer: Layer) {
299-
let layer: &LAYER = match layer {
300-
Layer::L1 => &self._ltdc.layer1,
301-
Layer::L2 => &self._ltdc.layer2,
302-
};
307+
// Config DMA2D hardware acceleration : pixel format, no CLUT
308+
self._dma2d.fgpfccr.write(|w| unsafe {
309+
w.bits(match &pixel_format {
310+
PixelFormat::ARGB8888 => 0b000,
311+
// PixelFormat::RGB888 => 0b0001, unsupported for now because u24 does not exist
312+
PixelFormat::RGB565 => 0b0010,
313+
PixelFormat::ARGB1555 => 0b0011,
314+
PixelFormat::ARGB4444 => 0b0100,
315+
PixelFormat::L8 => 0b0101,
316+
PixelFormat::AL44 => 0b0110,
317+
PixelFormat::AL88 => 0b0111,
318+
// PixelFormat::L4 => 0b1000, unsupported for now
319+
// PixelFormat::A8 => 0b1001,
320+
// PixelFormat::A4 => 0b1010
321+
// _ => unimplemented!(),
322+
})
323+
});
303324

304-
// Layer enable
305-
layer.cr.modify(|_, w| w.len().set_bit());
325+
match &layer {
326+
Layer::L1 => self.buffer1 = Some(buffer),
327+
Layer::L2 => self.buffer2 = Some(buffer)
328+
}
306329
}
307330

308-
/// Reload display controller immediatly
309-
pub fn reload(&self) {
310-
// Reload ltdc config immediatly
311-
self._ltdc.srcr.modify(|_, w| w.imr().set_bit());
331+
/// Enable the layer
332+
pub fn enable_layer(&self, layer: Layer) {
333+
match layer {
334+
Layer::L1 => self._ltdc.layer1.cr.modify(|_, w| w.len().set_bit()),
335+
Layer::L2 => self._ltdc.layer2.cr.modify(|_, w| w.len().set_bit()),
336+
}
312337
}
313338

314339
/// Draw a pixel at position (x,y) on the given layer
@@ -318,14 +343,64 @@ impl<T: SupportedWord> DisplayController<T> {
318343
}
319344

320345
match layer {
321-
Layer::L1 => {
322-
self.buffer1.as_mut().unwrap()[x + self.config.active_width as usize * y] = color
323-
}
324-
Layer::L2 => {
325-
self.buffer2.as_mut().unwrap()[x + self.config.active_width as usize * y] = color
326-
}
346+
Layer::L1 => self.buffer1.as_mut().unwrap()[x + self.config.active_width as usize * y] = color,
347+
Layer::L2 => self.buffer2.as_mut().unwrap()[x + self.config.active_width as usize * y] = color,
327348
}
328349
}
350+
351+
/// Draw hardware accelerated rectangle
352+
/// TODO: use safer DMA transfers
353+
pub unsafe fn draw_rectangle(
354+
&mut self,
355+
layer: Layer,
356+
top_left: (usize, usize),
357+
bottom_right: (usize, usize),
358+
color: u32,
359+
) {
360+
// Output color format
361+
self._dma2d.opfccr.write(|w| w.cm().bits(
362+
match &self.pixel_format {
363+
PixelFormat::ARGB8888 => 0b000,
364+
// PixelFormat::RGB888 => 0b001, unsupported for now
365+
PixelFormat::RGB565 => 0b010,
366+
PixelFormat::ARGB1555 => 0b011,
367+
PixelFormat::ARGB4444 => 0b100,
368+
_ => unreachable!(),
369+
}
370+
));
371+
372+
// Output color
373+
self._dma2d.ocolr.write_with_zero(|w| w.bits(color));
374+
375+
// Destination memory address
376+
let offset: isize = (top_left.0 + self.config.active_width as usize * top_left.1) as isize;
377+
self._dma2d.omar.write_with_zero(|w| w.bits(
378+
match &layer {
379+
Layer::L1 => self.buffer1.as_ref().unwrap().as_ptr().offset(offset) as u32,
380+
Layer::L2 => self.buffer2.as_ref().unwrap().as_ptr().offset(offset) as u32,
381+
}
382+
));
383+
384+
// Pixels per line and number of lines
385+
self._dma2d.nlr.write(|w|
386+
w.pl()
387+
.bits((bottom_right.0 - top_left.0) as u16)
388+
.nl()
389+
.bits((bottom_right.1 - top_left.1) as u16)
390+
);
391+
392+
// Line offset
393+
self._dma2d.oor.write(|w| w.lo().bits(top_left.0 as u16));
394+
395+
// Start transfert: register to memory mode
396+
self._dma2d.cr.modify(|_, w| w.mode().bits(0b11).start().set_bit());
397+
}
398+
399+
/// Reload display controller immediatly
400+
pub fn reload(&self) {
401+
// Reload ltdc config immediatly
402+
self._ltdc.srcr.modify(|_, w| w.imr().set_bit());
403+
}
329404
}
330405

331406
/// Available PixelFormats to work with

0 commit comments

Comments
 (0)