Skip to content

Commit bcd601e

Browse files
authored
Merge pull request #731 from stm32-rs/ltdc
port ltdc from f7xx-hal
2 parents da63ec4 + 84e51e7 commit bcd601e

File tree

7 files changed

+808
-2
lines changed

7 files changed

+808
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12-
- `i2c_scanner` example
12+
- `i2c_scanner` example [#758]
13+
- port LTDC implementation and example from stm32f7xx-hal [#731]
1314

1415
### Changed
1516

1617
- Use `stm32f4-staging` until `stm32f4` is released [#706]
1718

1819
[#706]: https://github.com/stm32-rs/stm32f4xx-hal/pull/706
20+
[#731]: https://github.com/stm32-rs/stm32f4xx-hal/pull/731
21+
[#758]: https://github.com/stm32-rs/stm32f4xx-hal/pull/758
1922

2023
## [v0.21.0] - 2024-05-30
2124

Cargo.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ embedded-storage = "0.3"
6161
vcell = "0.1.3"
6262
document-features = "0.2"
6363

64+
micromath = { version = "2.1.0", optional = true }
65+
6466
[dependencies.stm32f4]
6567
package = "stm32f4-staging"
6668
version = "0.16.0"
@@ -320,6 +322,7 @@ gpio-f427 = [
320322
"can2",
321323
"dac",
322324
"dcmi",
325+
"dma2d",
323326
"eth",
324327
"i2c3",
325328
"ltdc",
@@ -406,6 +409,7 @@ gpio-f469 = [
406409
"can1",
407410
"can2",
408411
"dac",
412+
"dma2d",
409413
"dcmi",
410414
"dsihost",
411415
"eth",
@@ -494,6 +498,7 @@ dac = []
494498
dcmi = []
495499
dfsdm1 = ["dfsdm"]
496500
dfsdm2 = ["dfsdm"]
501+
dma2d = []
497502
dsihost = []
498503
eth = []
499504
fmc = []
@@ -508,7 +513,7 @@ gpioj = []
508513
gpiok = []
509514
i2c3 = []
510515
lptim1 = []
511-
ltdc = []
516+
ltdc = ["dep:micromath"]
512517
quadspi = []
513518
otg-fs = []
514519
otg-hs = []
@@ -725,6 +730,10 @@ required-features = ["tim2"] # stm32f411
725730
name = "stopwatch-with-ssd1306-and-interrupts-and-dma-i2c"
726731
required-features = ["tim2", "stm32f411"] # stm32f411
727732

733+
[[example]]
734+
name = "ltdc-screen"
735+
required-features = ["stm32f429"]
736+
728737
[[example]]
729738
name = "timer-periph"
730739
required-features = []

examples/ltdc-screen/main.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
// Required
5+
extern crate panic_semihosting;
6+
7+
use cortex_m_rt::entry;
8+
use embedded_graphics::{
9+
mono_font::{ascii::FONT_6X9, MonoTextStyle},
10+
pixelcolor::{Rgb565, RgbColor},
11+
prelude::*,
12+
primitives::{Circle, PrimitiveStyle, Rectangle},
13+
text::Text,
14+
};
15+
16+
use stm32f4xx_hal::{
17+
ltdc::{BluePins, GreenPins, Layer, LtdcPins, PixelFormat, RedPins},
18+
pac,
19+
prelude::*,
20+
rcc::Rcc,
21+
};
22+
23+
mod screen;
24+
25+
// DIMENSIONS
26+
const WIDTH: u16 = 480;
27+
const HEIGHT: u16 = 272;
28+
29+
// Graphics framebuffer
30+
const FB_GRAPHICS_SIZE: usize = (WIDTH as usize) * (HEIGHT as usize);
31+
static mut FB_LAYER1: [u16; FB_GRAPHICS_SIZE] = [0; FB_GRAPHICS_SIZE];
32+
33+
#[entry]
34+
fn main() -> ! {
35+
let perif = pac::Peripherals::take().unwrap();
36+
let _cp = cortex_m::Peripherals::take().unwrap();
37+
38+
let rcc_hal: Rcc = perif.RCC.constrain();
39+
40+
// Set up pins
41+
let _gpioa = perif.GPIOA.split();
42+
let _gpiob = perif.GPIOB.split();
43+
let gpioe = perif.GPIOE.split();
44+
let gpiog = perif.GPIOG.split();
45+
let gpioh = perif.GPIOH.split();
46+
let gpioi = perif.GPIOI.split();
47+
let gpioj = perif.GPIOJ.split();
48+
let gpiok = perif.GPIOK.split();
49+
50+
let pins = LtdcPins::new(
51+
RedPins::new(
52+
gpioi.pi15, gpioj.pj0, gpioj.pj1, gpioj.pj2, gpioj.pj3, gpioj.pj4, gpioj.pj5, gpioj.pj6,
53+
),
54+
GreenPins::new(
55+
gpioj.pj7, gpioj.pj8, gpioj.pj9, gpioj.pj10, gpioj.pj11, gpiok.pk0, gpiok.pk1,
56+
gpiok.pk2,
57+
),
58+
BluePins::new(
59+
gpioe.pe4, gpioj.pj13, gpioj.pj14, gpioj.pj15, gpiog.pg12, gpiok.pk4, gpiok.pk5,
60+
gpiok.pk6,
61+
),
62+
gpioi.pi10,
63+
gpioi.pi9,
64+
gpiok.pk7,
65+
gpioi.pi14,
66+
);
67+
68+
// HSE osc out in High Z
69+
gpioh.ph1.into_floating_input();
70+
let _clocks = rcc_hal
71+
.cfgr
72+
.use_hse(25.MHz())
73+
.bypass_hse_oscillator()
74+
.sysclk(216.MHz())
75+
.hclk(216.MHz())
76+
.freeze();
77+
78+
// LCD enable: set it low first to avoid LCD bleed while setting up timings
79+
let mut disp_on = gpioi.pi12.into_push_pull_output();
80+
disp_on.set_low();
81+
82+
// LCD backlight enable
83+
let mut backlight = gpiok.pk3.into_push_pull_output();
84+
backlight.set_high();
85+
86+
let mut display = screen::Stm32F7DiscoDisplay::new(perif.LTDC, perif.DMA2D, pins);
87+
display
88+
.controller
89+
.config_layer(Layer::L1, unsafe { &mut FB_LAYER1 }, PixelFormat::RGB565);
90+
91+
display.controller.enable_layer(Layer::L1);
92+
display.controller.reload();
93+
94+
let display = &mut display;
95+
96+
// LCD enable: activate LCD !
97+
disp_on.set_high();
98+
99+
Rectangle::new(Point::new(0, 0), Size::new(479, 271))
100+
.into_styled(PrimitiveStyle::with_fill(Rgb565::new(0, 0b11110, 0b11011)))
101+
.draw(display)
102+
.ok();
103+
104+
let c1 = Circle::new(Point::new(20, 20), 2 * 8)
105+
.into_styled(PrimitiveStyle::with_fill(Rgb565::new(0, 63, 0)));
106+
107+
let c2 = Circle::new(Point::new(25, 20), 2 * 8)
108+
.into_styled(PrimitiveStyle::with_fill(Rgb565::new(31, 0, 0)));
109+
110+
let t = Text::new(
111+
"Hello Rust!",
112+
Point::new(100, 100),
113+
MonoTextStyle::new(&FONT_6X9, RgbColor::WHITE),
114+
);
115+
116+
c1.draw(display).ok();
117+
c2.draw(display).ok();
118+
t.draw(display).ok();
119+
120+
for i in 0..300 {
121+
Circle::new(Point::new(20 + i, 20), 2 * 8)
122+
.into_styled(PrimitiveStyle::with_fill(RgbColor::GREEN))
123+
.draw(display)
124+
.ok();
125+
}
126+
127+
#[allow(clippy::empty_loop)]
128+
loop {}
129+
}

examples/ltdc-screen/screen.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use embedded_graphics::{
2+
pixelcolor::{Rgb565, RgbColor},
3+
prelude::{DrawTarget, OriginDimensions, Pixel, Size},
4+
};
5+
6+
use stm32f4xx_hal::{
7+
ltdc::{DisplayConfig, DisplayController, Layer, LtdcPins, PixelFormat, SupportedWord},
8+
pac::{DMA2D, LTDC},
9+
prelude::*,
10+
};
11+
12+
/// STM32F7-DISCO board display
13+
pub const DISCO_SCREEN_CONFIG: DisplayConfig = DisplayConfig {
14+
active_width: 480,
15+
active_height: 272,
16+
h_back_porch: 13,
17+
h_front_porch: 30,
18+
h_sync: 41,
19+
v_back_porch: 2,
20+
v_front_porch: 2,
21+
v_sync: 10,
22+
frame_rate: 60,
23+
h_sync_pol: false,
24+
v_sync_pol: false,
25+
no_data_enable_pol: false,
26+
pixel_clock_pol: false,
27+
};
28+
29+
pub struct Stm32F7DiscoDisplay<T: 'static + SupportedWord> {
30+
pub controller: DisplayController<T>,
31+
}
32+
33+
impl<T: 'static + SupportedWord> Stm32F7DiscoDisplay<T> {
34+
pub fn new(ltdc: LTDC, dma2d: DMA2D, pins: LtdcPins) -> Stm32F7DiscoDisplay<T> {
35+
let controller = DisplayController::new(
36+
ltdc,
37+
dma2d,
38+
pins,
39+
PixelFormat::RGB565,
40+
DISCO_SCREEN_CONFIG,
41+
Some(25.MHz()),
42+
);
43+
44+
Stm32F7DiscoDisplay { controller }
45+
}
46+
}
47+
48+
impl DrawTarget for Stm32F7DiscoDisplay<u16> {
49+
type Color = Rgb565;
50+
type Error = core::convert::Infallible;
51+
52+
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
53+
where
54+
I: IntoIterator<Item = Pixel<Self::Color>>,
55+
{
56+
for Pixel(coord, color) in pixels.into_iter() {
57+
// Check if the pixel coordinates are out of bounds (negative or greater than
58+
// (480,272)). `DrawTarget` implementation are required to discard any out of bounds
59+
// pixels without returning an error or causing a panic.
60+
if let (x @ 0..=479, y @ 0..=271) = coord.into() {
61+
let value: u16 = (color.b() as u16 & 0x1F)
62+
| ((color.g() as u16 & 0x3F) << 5)
63+
| ((color.r() as u16 & 0x1F) << 11);
64+
65+
self.controller
66+
.draw_pixel(Layer::L1, x as usize, y as usize, value);
67+
}
68+
}
69+
70+
Ok(())
71+
}
72+
}
73+
74+
impl OriginDimensions for Stm32F7DiscoDisplay<u16> {
75+
fn size(&self) -> Size {
76+
Size::new(480, 272)
77+
}
78+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ pub mod dwt;
109109
pub mod flash;
110110
#[cfg(all(feature = "fsmc_lcd", any(feature = "fmc", feature = "fsmc")))]
111111
pub mod fsmc_lcd;
112+
#[cfg(all(feature = "dma2d", feature = "ltdc"))]
113+
pub mod ltdc;
112114
pub mod prelude;
113115
pub mod qei;
114116
#[cfg(feature = "quadspi")]

0 commit comments

Comments
 (0)