Skip to content

Commit 166c422

Browse files
authored
Merge pull request #789 from tegimeki/add-f469-disco-lcd-test
dsi: add color pattern test for STM32F469I-DISC board
2 parents a7f9d10 + e815b4d commit 166c422

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
9+
- Add `f469disc-lcd-test` with color/BER test pattern LCD output [#789]
910

1011
### Added
1112

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ synopsys-usb-otg = { version = "0.4.0", features = [
3939
sdio-host = { version = "0.9.0", optional = true }
4040
embedded-dma = "0.2.0"
4141
embedded-display-controller = { version = "^0.2.0", optional = true }
42+
otm8009a = "0.1"
4243
bare-metal = { version = "1" }
4344
void = { default-features = false, version = "1.0.2" }
4445
display-interface = { version = "0.5.0", optional = true }
@@ -607,6 +608,10 @@ required-features = [
607608
"fsmc_lcd",
608609
] # stm32f413
609610

611+
[[example]]
612+
name = "f469disco-lcd-test"
613+
required-features = ["stm32f469", "defmt"]
614+
610615
[[example]]
611616
name = "hd44780"
612617
required-features = []

examples/f469disco-lcd-test.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
//! This example initializes the STM32F469I-DISCO LCD and displays a test pattern
2+
//! Run as:
3+
//! cargo run --release --example f469disco-lcd-test --features="stm32f469,defmt"
4+
5+
#![deny(warnings)]
6+
#![no_main]
7+
#![no_std]
8+
9+
extern crate cortex_m;
10+
extern crate cortex_m_rt as rt;
11+
12+
use cortex_m_rt::entry;
13+
14+
use defmt_rtt as _;
15+
use panic_probe as _;
16+
17+
use stm32f4xx_hal as hal;
18+
19+
use crate::hal::{
20+
dsi::{
21+
ColorCoding, DsiChannel, DsiCmdModeTransmissionKind, DsiConfig, DsiHost, DsiInterrupts,
22+
DsiMode, DsiPhyTimers, DsiPllConfig, DsiVideoMode, LaneCount,
23+
},
24+
ltdc::{DisplayConfig, DisplayController, PixelFormat},
25+
pac::{CorePeripherals, Peripherals},
26+
prelude::*,
27+
};
28+
29+
use otm8009a::{Otm8009A, Otm8009AConfig};
30+
31+
pub const WIDTH: usize = 480;
32+
pub const HEIGHT: usize = 800;
33+
34+
pub const DISPLAY_CONFIGURATION: DisplayConfig = DisplayConfig {
35+
active_width: WIDTH as _,
36+
active_height: HEIGHT as _,
37+
h_back_porch: 34,
38+
h_front_porch: 34,
39+
v_back_porch: 15,
40+
v_front_porch: 16,
41+
h_sync: 2,
42+
v_sync: 1,
43+
frame_rate: 60,
44+
h_sync_pol: true,
45+
v_sync_pol: true,
46+
no_data_enable_pol: false,
47+
pixel_clock_pol: true,
48+
};
49+
50+
#[entry]
51+
fn main() -> ! {
52+
let dp = Peripherals::take().unwrap();
53+
let cp = CorePeripherals::take().unwrap();
54+
55+
let rcc = dp.RCC.constrain();
56+
57+
let hse_freq = 8.MHz();
58+
let clocks = rcc
59+
.cfgr
60+
.use_hse(hse_freq)
61+
.pclk2(32.MHz())
62+
.sysclk(180.MHz())
63+
.freeze();
64+
let mut delay = cp.SYST.delay(&clocks);
65+
66+
let gpioh = dp.GPIOH.split();
67+
68+
// Reset display
69+
let mut lcd_reset = gpioh.ph7.into_push_pull_output();
70+
lcd_reset.set_low();
71+
delay.delay_ms(20u32);
72+
lcd_reset.set_high();
73+
delay.delay_ms(10u32);
74+
75+
// Initialize LTDC, needed to provide pixel clock to DSI
76+
defmt::info!("Initializing LTDC");
77+
let ltdc_freq = 27_429.kHz();
78+
let _display = DisplayController::<u32>::new(
79+
dp.LTDC,
80+
dp.DMA2D,
81+
None,
82+
PixelFormat::ARGB8888,
83+
DISPLAY_CONFIGURATION,
84+
Some(hse_freq),
85+
);
86+
87+
// Initialize DSI Host
88+
// VCO = (8MHz HSE / 2 IDF) * 2 * 125 = 1000MHz
89+
// 1000MHz VCO / (2 * 1 ODF * 8) = 62.5MHz
90+
let dsi_pll_config = unsafe {
91+
DsiPllConfig::manual(125, 2, 0 /*div1*/, 4)
92+
};
93+
94+
let dsi_config = DsiConfig {
95+
mode: DsiMode::Video {
96+
mode: DsiVideoMode::Burst,
97+
},
98+
lane_count: LaneCount::DoubleLane,
99+
channel: DsiChannel::Ch0,
100+
hse_freq,
101+
ltdc_freq,
102+
interrupts: DsiInterrupts::None,
103+
color_coding_host: ColorCoding::TwentyFourBits,
104+
color_coding_wrapper: ColorCoding::TwentyFourBits,
105+
lp_size: 4,
106+
vlp_size: 4,
107+
};
108+
109+
defmt::info!("Initializing DSI {:?} {:?}", dsi_config, dsi_pll_config);
110+
let mut dsi_host = DsiHost::init(
111+
dsi_pll_config,
112+
DISPLAY_CONFIGURATION,
113+
dsi_config,
114+
dp.DSI,
115+
&clocks,
116+
)
117+
.unwrap();
118+
119+
dsi_host.configure_phy_timers(DsiPhyTimers {
120+
dataline_hs2lp: 35,
121+
dataline_lp2hs: 35,
122+
clock_hs2lp: 35,
123+
clock_lp2hs: 35,
124+
dataline_max_read_time: 0,
125+
stop_wait_time: 10,
126+
});
127+
128+
dsi_host.set_command_mode_transmission_kind(DsiCmdModeTransmissionKind::AllInLowPower);
129+
dsi_host.start();
130+
dsi_host.enable_bus_turn_around(); // Must be before read attempts
131+
dsi_host.set_command_mode_transmission_kind(DsiCmdModeTransmissionKind::AllInHighSpeed);
132+
dsi_host.force_rx_low_power(true);
133+
dsi_host.enable_color_test(); // Must enable before display initialized
134+
135+
defmt::info!("Initializing OTM8009A");
136+
let otm8009a_config = Otm8009AConfig {
137+
frame_rate: otm8009a::FrameRate::_60Hz,
138+
mode: otm8009a::Mode::Portrait,
139+
color_map: otm8009a::ColorMap::Rgb,
140+
cols: WIDTH as u16,
141+
rows: HEIGHT as u16,
142+
};
143+
let mut otm8009a = Otm8009A::new();
144+
otm8009a
145+
.init(&mut dsi_host, otm8009a_config, &mut delay)
146+
.unwrap();
147+
148+
defmt::info!("Outputting Color/BER test patterns...");
149+
let delay_ms = 5000u32;
150+
loop {
151+
dsi_host.enable_color_test();
152+
delay.delay_ms(delay_ms);
153+
dsi_host.enable_ber_test();
154+
delay.delay_ms(delay_ms);
155+
}
156+
}

src/dsi.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,18 @@ impl DsiHost {
555555
pub fn enable_bus_turn_around(&mut self) {
556556
self.dsi.pcr().modify(|_, w| w.btae().set_bit()); // Enable bus turn around
557557
}
558+
559+
pub fn enable_color_test(&mut self) {
560+
self.dsi
561+
.vmcr()
562+
.modify(|_, w| w.pge().set_bit().pgm().clear_bit());
563+
}
564+
565+
pub fn enable_ber_test(&mut self) {
566+
self.dsi
567+
.vmcr()
568+
.modify(|_, w| w.pge().set_bit().pgm().set_bit());
569+
}
558570
}
559571

560572
impl DsiRefreshHandle {

0 commit comments

Comments
 (0)