1
1
use micromath:: F32Ext ;
2
2
3
3
use crate :: {
4
- device:: { ltdc :: LAYER , LTDC , RCC } ,
4
+ device:: { LTDC , RCC , DMA2D } ,
5
5
rcc:: HSEClock ,
6
6
} ;
7
7
@@ -35,18 +35,23 @@ pub enum Layer {
35
35
}
36
36
37
37
pub struct DisplayController < T : ' static + SupportedWord > {
38
- // ltdc instance
38
+ /// ltdc instance
39
39
_ltdc : LTDC ,
40
+ /// dma2d instance
41
+ _dma2d : DMA2D ,
42
+ /// Configuration structure
40
43
config : DisplayConfig ,
41
- // Layer 1 buffer
44
+ /// layer 1 buffer
42
45
buffer1 : Option < & ' static mut [ T ] > ,
43
- // Layer 2 buffer
46
+ /// layer 2 buffer
44
47
buffer2 : Option < & ' static mut [ T ] > ,
48
+ /// Pixels format in the layers
49
+ pixel_format : PixelFormat ,
45
50
}
46
51
47
- impl < T : SupportedWord > DisplayController < T > {
52
+ impl < T : ' static + SupportedWord > DisplayController < T > {
48
53
/// 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 > {
50
55
// TODO : change it to something safe ...
51
56
let rcc = unsafe { & ( * RCC :: ptr ( ) ) } ;
52
57
@@ -58,12 +63,18 @@ impl<T: SupportedWord> DisplayController<T> {
58
63
let lcd_clk: u32 =
59
64
( total_width as u32 ) * ( total_height as u32 ) * ( config. frame_rate as u32 ) ;
60
65
61
- // Enable LTDC peripheral's clock
66
+ // Enable LTDC
62
67
rcc. apb2enr . modify ( |_, w| w. ltdcen ( ) . enabled ( ) ) ;
63
68
// Reset LTDC peripheral
64
69
rcc. apb2rstr . modify ( |_, w| w. ltdcrst ( ) . reset ( ) ) ;
65
70
rcc. apb2rstr . modify ( |_, w| w. ltdcrst ( ) . clear_bit ( ) ) ;
66
71
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
+
67
78
// Get base clock and PLLM divisor
68
79
let base_clk: u32 ;
69
80
match & hse {
@@ -169,8 +180,7 @@ impl<T: SupportedWord> DisplayController<T> {
169
180
170
181
// Set blue background color
171
182
ltdc. bccr . write ( |w| unsafe { w. bits ( 0xAAAAAAAA ) } ) ;
172
-
173
- // TODO: configure DMA2D hardware accelerator
183
+
174
184
// TODO: configure interupts
175
185
176
186
// Reload ltdc config immediatly
@@ -180,16 +190,19 @@ impl<T: SupportedWord> DisplayController<T> {
180
190
181
191
// Reload ltdc config immediatly
182
192
ltdc. srcr . modify ( |_, w| w. imr ( ) . set_bit ( ) ) ;
183
-
193
+
184
194
DisplayController {
185
195
_ltdc : ltdc,
196
+ _dma2d : dma2d,
186
197
config,
187
198
buffer1 : None ,
188
199
buffer2 : None ,
200
+ pixel_format
189
201
}
202
+
190
203
}
191
204
192
- /// Configure a layer (layer 1 or layer 2)
205
+ /// Configure the layer
193
206
///
194
207
/// Note : the choice is made (for the sake of simplicity) to make the layer
195
208
/// as big as the screen
@@ -198,37 +211,39 @@ impl<T: SupportedWord> DisplayController<T> {
198
211
pub fn config_layer (
199
212
& mut self ,
200
213
layer : Layer ,
201
- pixel_format : PixelFormat ,
202
214
buffer : & ' static mut [ T ] ,
215
+ pixel_format : PixelFormat
203
216
) {
204
- let config: & DisplayConfig = & self . config ;
205
-
206
- let layer: & LAYER = match layer {
217
+ let _layer = match & layer {
207
218
Layer :: L1 => & self . _ltdc . layer1 ,
208
219
Layer :: L2 => & self . _ltdc . layer2 ,
209
220
} ;
210
221
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
+
211
226
// Horizontal and vertical window (coordinates include porches): where
212
227
// 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 ;
215
230
216
- layer . whpcr . write ( |w| unsafe {
231
+ _layer . whpcr . write ( |w| unsafe {
217
232
w. whstpos ( )
218
233
. bits ( h_win_start + 1 )
219
234
. whsppos ( )
220
- . bits ( h_win_start + config . active_width )
235
+ . bits ( h_win_start + width )
221
236
} ) ;
222
- layer . wvpcr . write ( |w| unsafe {
237
+ _layer . wvpcr . write ( |w| unsafe {
223
238
w. wvstpos ( )
224
239
. bits ( v_win_start + 1 )
225
240
. wvsppos ( )
226
- . bits ( v_win_start + config . active_height )
241
+ . bits ( v_win_start + height )
227
242
} ) ;
228
243
229
244
// 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 {
232
247
PixelFormat :: ARGB8888 => 0b000 ,
233
248
// PixelFormat::RGB888 => 0b001,
234
249
PixelFormat :: RGB565 => 0b010 ,
@@ -237,33 +252,33 @@ impl<T: SupportedWord> DisplayController<T> {
237
252
PixelFormat :: L8 => 0b101 ,
238
253
PixelFormat :: AL44 => 0b110 ,
239
254
PixelFormat :: AL88 => 0b111 ,
240
- _ => unimplemented ! ( ) ,
255
+ // _ => unimplemented!(),
241
256
} )
242
257
} ) ;
243
258
244
259
// 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 ) } ) ;
246
261
247
262
// Set default color to plain (not transparent) red (for debug
248
263
// purposes). The default color is used outside the defined layer window
249
264
// or when a layer is disabled.
250
- layer . dccr . write ( |w| unsafe { w. bits ( 0xFFFF0000 ) } ) ;
265
+ _layer . dccr . write ( |w| unsafe { w. bits ( 0xFFFF0000 ) } ) ;
251
266
252
267
// Blending factor: how the layer is combined with the layer below it
253
268
// (layer 2 with layer 1 or layer 1 with background). Here it is set so
254
269
// that the blending factor does not take the pixel alpha value, just
255
270
// the global value of the layer
256
- layer
271
+ _layer
257
272
. bfcr
258
273
. write ( |w| unsafe { w. bf1 ( ) . bits ( 0b100 ) . bf2 ( ) . bits ( 0b101 ) } ) ;
259
274
260
275
// Color frame buffer start address
261
- layer
276
+ _layer
262
277
. cfbar
263
278
. write ( |w| unsafe { w. cfbadd ( ) . bits ( buffer. as_ptr ( ) as u32 ) } ) ;
264
279
265
280
// 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 {
267
282
PixelFormat :: ARGB8888 => 4 ,
268
283
// PixelFormat::RGB888 => 24, unsupported for now because u24 does not exist
269
284
PixelFormat :: RGB565 => 2 ,
@@ -272,43 +287,53 @@ impl<T: SupportedWord> DisplayController<T> {
272
287
PixelFormat :: L8 => 1 ,
273
288
PixelFormat :: AL44 => 1 ,
274
289
PixelFormat :: AL88 => 2 ,
275
- _ => unimplemented ! ( ) ,
290
+ // _ => unimplemented!(),
276
291
} ;
277
- layer . cfblr . write ( |w| unsafe {
292
+ _layer . cfblr . write ( |w| unsafe {
278
293
w. cfbp ( )
279
- . bits ( config . active_width * byte_per_pixel)
294
+ . bits ( width * byte_per_pixel)
280
295
. cfbll ( )
281
- . bits ( config . active_width * byte_per_pixel + 3 )
296
+ . bits ( width * byte_per_pixel + 3 )
282
297
} ) ;
283
298
284
299
// Frame buffer number of lines
285
- layer
300
+ _layer
286
301
. cfblnr
287
- . write ( |w| unsafe { w. cfblnbr ( ) . bits ( config . active_height ) } ) ;
302
+ . write ( |w| unsafe { w. cfblnbr ( ) . bits ( height ) } ) ;
288
303
289
304
// 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 ( ) ) ;
293
306
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
+ } ) ;
303
324
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
+ }
306
329
}
307
330
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
+ }
312
337
}
313
338
314
339
/// Draw a pixel at position (x,y) on the given layer
@@ -318,14 +343,64 @@ impl<T: SupportedWord> DisplayController<T> {
318
343
}
319
344
320
345
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,
327
348
}
328
349
}
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
+ }
329
404
}
330
405
331
406
/// Available PixelFormats to work with
0 commit comments