mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-24 15:52:34 +00:00
Add dsi example
This commit is contained in:
parent
bb82a1bd60
commit
4e42eaef7c
1
ci.sh
1
ci.sh
@ -187,6 +187,7 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \
|
||||
--- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \
|
||||
--- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
|
||||
--- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f469 \
|
||||
--- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \
|
||||
--- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
|
||||
--- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
|
||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Change stm32f429zi to your chip name, if necessary.
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
|
||||
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||
|
9
examples/stm32f469/.cargo/config.toml
Normal file
9
examples/stm32f469/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip STM32F469NIHx"
|
||||
|
||||
[build]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
22
examples/stm32f469/Cargo.toml
Normal file
22
examples/stm32f469/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-stm32f469-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Specific examples only for stm32f469
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7.0"
|
||||
embedded-hal = "1.0.0"
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
5
examples/stm32f469/build.rs
Normal file
5
examples/stm32f469/build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
694
examples/stm32f469/src/bin/dsi_bsp.rs
Normal file
694
examples/stm32f469/src/bin/dsi_bsp.rs
Normal file
@ -0,0 +1,694 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType};
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_stm32::ltdc::Ltdc;
|
||||
use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1};
|
||||
use embassy_stm32::pac::ltdc::vals::{Bf1, Bf2, Depol, Hspol, Imr, Pcpol, Pf, Vspol};
|
||||
use embassy_stm32::pac::{DSIHOST, LTDC};
|
||||
use embassy_stm32::rcc::{
|
||||
AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk,
|
||||
};
|
||||
use embassy_stm32::time::mhz;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
enum _Orientation {
|
||||
Landscape,
|
||||
Portrait,
|
||||
}
|
||||
|
||||
const _LCD_ORIENTATION: _Orientation = _Orientation::Landscape;
|
||||
const LCD_X_SIZE: u16 = 800;
|
||||
const LCD_Y_SIZE: u16 = 480;
|
||||
|
||||
static FERRIS_IMAGE: &[u8; 1536000] = include_bytes!("ferris.bin");
|
||||
|
||||
// This example allows to display an image on the STM32F469NI-DISCO boards
|
||||
// with the Revision C, that is at least the boards marked DK32F469I$AU1.
|
||||
// These boards have the NT35510 display driver. This example does not work
|
||||
// for the older revisions with OTM8009A, though there are lots of C-examples
|
||||
// available online where the correct config for the OTM8009A could be gotten from.
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut config = embassy_stm32::Config::default();
|
||||
config.rcc.sys = Sysclk::PLL1_P;
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV1;
|
||||
config.rcc.apb1_pre = APBPrescaler::DIV4;
|
||||
config.rcc.apb2_pre = APBPrescaler::DIV2;
|
||||
|
||||
// HSE is on and ready
|
||||
config.rcc.hse = Some(Hse {
|
||||
freq: mhz(8),
|
||||
mode: HseMode::Oscillator,
|
||||
});
|
||||
config.rcc.pll_src = PllSource::HSE;
|
||||
|
||||
config.rcc.pll = Some(Pll {
|
||||
prediv: PllPreDiv::DIV8, // PLLM
|
||||
mul: PllMul::MUL360, // PLLN
|
||||
divp: Some(PllPDiv::DIV2),
|
||||
divq: Some(PllQDiv::DIV7), // was DIV4, but STM BSP example uses 7
|
||||
divr: Some(PllRDiv::DIV6),
|
||||
});
|
||||
|
||||
// This seems to be working, the values in the RCC.PLLSAICFGR are correct according to the debugger. Also on and ready according to CR
|
||||
config.rcc.pllsai = Some(Pll {
|
||||
prediv: PllPreDiv::DIV8, // Actually ignored
|
||||
mul: PllMul::MUL384, // PLLN
|
||||
divp: None, // PLLP
|
||||
divq: None, // PLLQ
|
||||
divr: Some(PllRDiv::DIV7), // PLLR (Sai actually has special clockdiv register)
|
||||
});
|
||||
|
||||
let p = embassy_stm32::init(config);
|
||||
info!("Starting...");
|
||||
|
||||
let mut led = Output::new(p.PG6, Level::High, Speed::Low);
|
||||
|
||||
// According to UM for the discovery kit, PH7 is an active-low reset for the LCD and touchsensor
|
||||
let mut reset = Output::new(p.PH7, Level::Low, Speed::High);
|
||||
|
||||
// CubeMX example waits 20 ms before de-asserting reset
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(20));
|
||||
|
||||
// Disable the reset signal and wait 140ms as in the Linux driver (CubeMX waits only 20)
|
||||
reset.set_high();
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(140));
|
||||
|
||||
let mut ltdc = Ltdc::new(p.LTDC);
|
||||
let mut dsi = DsiHost::new(p.DSIHOST, p.PJ2);
|
||||
let version = dsi.get_version();
|
||||
defmt::warn!("en: {:x}", version);
|
||||
|
||||
// Disable the DSI wrapper
|
||||
dsi.disable_wrapper_dsi();
|
||||
|
||||
// Disable the DSI host
|
||||
dsi.disable();
|
||||
|
||||
// D-PHY clock and digital disable
|
||||
DSIHOST.pctlr().modify(|w| {
|
||||
w.set_cke(false);
|
||||
w.set_den(false)
|
||||
});
|
||||
|
||||
// Turn off the DSI PLL
|
||||
DSIHOST.wrpcr().modify(|w| w.set_pllen(false));
|
||||
|
||||
// Disable the regulator
|
||||
DSIHOST.wrpcr().write(|w| w.set_regen(false));
|
||||
|
||||
// Enable regulator
|
||||
info!("DSIHOST: enabling regulator");
|
||||
DSIHOST.wrpcr().write(|w| w.set_regen(true));
|
||||
|
||||
for _ in 1..1000 {
|
||||
// The regulator status (ready or not) can be monitored with the RRS flag in the DSI_WISR register.
|
||||
// Once it is set, we stop waiting.
|
||||
if DSIHOST.wisr().read().rrs() {
|
||||
info!("DSIHOST Regulator ready");
|
||||
break;
|
||||
}
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(1));
|
||||
}
|
||||
|
||||
if !DSIHOST.wisr().read().rrs() {
|
||||
defmt::panic!("DSIHOST: enabling regulator FAILED");
|
||||
}
|
||||
|
||||
// Set up PLL and enable it
|
||||
DSIHOST.wrpcr().modify(|w| {
|
||||
w.set_pllen(true);
|
||||
w.set_ndiv(125); // PLL loop division factor set to 125
|
||||
w.set_idf(2); // PLL input divided by 2
|
||||
w.set_odf(0); // PLL output divided by 1
|
||||
});
|
||||
|
||||
/* 500 MHz / 8 = 62.5 MHz = 62500 kHz */
|
||||
const LANE_BYTE_CLK_K_HZ: u16 = 62500; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L224C21-L224C26
|
||||
|
||||
const _LCD_CLOCK: u16 = 27429; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L183
|
||||
|
||||
/* TX_ESCAPE_CKDIV = f(LaneByteClk)/15.62 = 4 */
|
||||
const TX_ESCAPE_CKDIV: u8 = (LANE_BYTE_CLK_K_HZ / 15620) as u8; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L230
|
||||
|
||||
for _ in 1..1000 {
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(1));
|
||||
// The PLL status (lock or unlock) can be monitored with the PLLLS flag in the DSI_WISR register.
|
||||
// Once it is set, we stop waiting.
|
||||
if DSIHOST.wisr().read().pllls() {
|
||||
info!("DSIHOST PLL locked");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !DSIHOST.wisr().read().pllls() {
|
||||
defmt::panic!("DSIHOST: enabling PLL FAILED");
|
||||
}
|
||||
|
||||
// Set the PHY parameters
|
||||
|
||||
// D-PHY clock and digital enable
|
||||
DSIHOST.pctlr().write(|w| {
|
||||
w.set_cke(true);
|
||||
w.set_den(true);
|
||||
});
|
||||
|
||||
// Set Clock lane to high-speed mode and disable automatic clock lane control
|
||||
DSIHOST.clcr().modify(|w| {
|
||||
w.set_dpcc(true);
|
||||
w.set_acr(false);
|
||||
});
|
||||
|
||||
// Set number of active data lanes to two (lanes 0 and 1)
|
||||
DSIHOST.pconfr().modify(|w| w.set_nl(1));
|
||||
|
||||
// Set the DSI clock parameters
|
||||
|
||||
// Set the TX escape clock division factor to 4
|
||||
DSIHOST.ccr().modify(|w| w.set_txeckdiv(TX_ESCAPE_CKDIV));
|
||||
|
||||
// Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4)
|
||||
// The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 )
|
||||
// Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF)
|
||||
// Set the bit period in high-speed mode
|
||||
DSIHOST.wpcr0().modify(|w| w.set_uix4(8)); // 8 is set in the BSP example (confirmed with Debugger)
|
||||
|
||||
// Disable all error interrupts and reset the Error Mask
|
||||
DSIHOST.ier0().write_value(Ier0(0));
|
||||
DSIHOST.ier1().write_value(Ier1(0));
|
||||
|
||||
// Enable this to fix read timeout
|
||||
DSIHOST.pcr().modify(|w| w.set_btae(true));
|
||||
|
||||
const DSI_PIXEL_FORMAT_RGB888: u8 = 0x05;
|
||||
const _DSI_PIXEL_FORMAT_ARGB888: u8 = 0x00;
|
||||
|
||||
const HACT: u16 = LCD_X_SIZE;
|
||||
const VACT: u16 = LCD_Y_SIZE;
|
||||
|
||||
const VSA: u16 = 120;
|
||||
const VBP: u16 = 150;
|
||||
const VFP: u16 = 150;
|
||||
const HSA: u16 = 2;
|
||||
const HBP: u16 = 34;
|
||||
const HFP: u16 = 34;
|
||||
|
||||
const VIRTUAL_CHANNEL_ID: u8 = 0;
|
||||
|
||||
const COLOR_CODING: u8 = DSI_PIXEL_FORMAT_RGB888;
|
||||
const VS_POLARITY: bool = false; // DSI_VSYNC_ACTIVE_HIGH == 0
|
||||
const HS_POLARITY: bool = false; // DSI_HSYNC_ACTIVE_HIGH == 0
|
||||
const DE_POLARITY: bool = false; // DSI_DATA_ENABLE_ACTIVE_HIGH == 0
|
||||
const MODE: u8 = 2; // DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
|
||||
const NULL_PACKET_SIZE: u16 = 0xFFF;
|
||||
const NUMBER_OF_CHUNKS: u16 = 0;
|
||||
const PACKET_SIZE: u16 = HACT; /* Value depending on display orientation choice portrait/landscape */
|
||||
const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16;
|
||||
const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16;
|
||||
const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */
|
||||
// FIXME: Make depend on orientation
|
||||
const VERTICAL_SYNC_ACTIVE: u16 = VSA;
|
||||
const VERTICAL_BACK_PORCH: u16 = VBP;
|
||||
const VERTICAL_FRONT_PORCH: u16 = VFP;
|
||||
const VERTICAL_ACTIVE: u16 = VACT;
|
||||
const LP_COMMAND_ENABLE: bool = true; /* Enable sending commands in mode LP (Low Power) */
|
||||
|
||||
/* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */
|
||||
/* Only useful when sending LP packets is allowed while streaming is active in video mode */
|
||||
const LP_LARGEST_PACKET_SIZE: u8 = 16;
|
||||
|
||||
/* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
|
||||
/* Only useful when sending LP packets is allowed while streaming is active in video mode */
|
||||
const LPVACT_LARGEST_PACKET_SIZE: u8 = 0;
|
||||
|
||||
const LPHORIZONTAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HFP period */
|
||||
const LPHORIZONTAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HBP period */
|
||||
const LPVERTICAL_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VACT period */
|
||||
const LPVERTICAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VFP period */
|
||||
const LPVERTICAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VBP period */
|
||||
const LPVERTICAL_SYNC_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VSync = VSA period */
|
||||
const FRAME_BTAACKNOWLEDGE_ENABLE: bool = false; /* Frame bus-turn-around acknowledge enable => false according to debugger */
|
||||
|
||||
/* Select video mode by resetting CMDM and DSIM bits */
|
||||
DSIHOST.mcr().modify(|w| w.set_cmdm(false));
|
||||
DSIHOST.wcfgr().modify(|w| w.set_dsim(false));
|
||||
|
||||
/* Configure the video mode transmission type */
|
||||
DSIHOST.vmcr().modify(|w| w.set_vmt(MODE));
|
||||
|
||||
/* Configure the video packet size */
|
||||
DSIHOST.vpcr().modify(|w| w.set_vpsize(PACKET_SIZE));
|
||||
|
||||
/* Set the chunks number to be transmitted through the DSI link */
|
||||
DSIHOST.vccr().modify(|w| w.set_numc(NUMBER_OF_CHUNKS));
|
||||
|
||||
/* Set the size of the null packet */
|
||||
DSIHOST.vnpcr().modify(|w| w.set_npsize(NULL_PACKET_SIZE));
|
||||
|
||||
/* Select the virtual channel for the LTDC interface traffic */
|
||||
DSIHOST.lvcidr().modify(|w| w.set_vcid(VIRTUAL_CHANNEL_ID));
|
||||
|
||||
/* Configure the polarity of control signals */
|
||||
DSIHOST.lpcr().modify(|w| {
|
||||
w.set_dep(DE_POLARITY);
|
||||
w.set_hsp(HS_POLARITY);
|
||||
w.set_vsp(VS_POLARITY);
|
||||
});
|
||||
|
||||
/* Select the color coding for the host */
|
||||
DSIHOST.lcolcr().modify(|w| w.set_colc(COLOR_CODING));
|
||||
|
||||
/* Select the color coding for the wrapper */
|
||||
DSIHOST.wcfgr().modify(|w| w.set_colmux(COLOR_CODING));
|
||||
|
||||
/* Set the Horizontal Synchronization Active (HSA) in lane byte clock cycles */
|
||||
DSIHOST.vhsacr().modify(|w| w.set_hsa(HORIZONTAL_SYNC_ACTIVE));
|
||||
|
||||
/* Set the Horizontal Back Porch (HBP) in lane byte clock cycles */
|
||||
DSIHOST.vhbpcr().modify(|w| w.set_hbp(HORIZONTAL_BACK_PORCH));
|
||||
|
||||
/* Set the total line time (HLINE=HSA+HBP+HACT+HFP) in lane byte clock cycles */
|
||||
DSIHOST.vlcr().modify(|w| w.set_hline(HORIZONTAL_LINE));
|
||||
|
||||
/* Set the Vertical Synchronization Active (VSA) */
|
||||
DSIHOST.vvsacr().modify(|w| w.set_vsa(VERTICAL_SYNC_ACTIVE));
|
||||
|
||||
/* Set the Vertical Back Porch (VBP)*/
|
||||
DSIHOST.vvbpcr().modify(|w| w.set_vbp(VERTICAL_BACK_PORCH));
|
||||
|
||||
/* Set the Vertical Front Porch (VFP)*/
|
||||
DSIHOST.vvfpcr().modify(|w| w.set_vfp(VERTICAL_FRONT_PORCH));
|
||||
|
||||
/* Set the Vertical Active period*/
|
||||
DSIHOST.vvacr().modify(|w| w.set_va(VERTICAL_ACTIVE));
|
||||
|
||||
/* Configure the command transmission mode */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lpce(LP_COMMAND_ENABLE));
|
||||
|
||||
/* Low power largest packet size */
|
||||
DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
|
||||
|
||||
/* Low power VACT largest packet size */
|
||||
DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE));
|
||||
DSIHOST.lpmcr().modify(|w| w.set_vlpsize(LPVACT_LARGEST_PACKET_SIZE));
|
||||
|
||||
/* Enable LP transition in HFP period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lphfpe(LPHORIZONTAL_FRONT_PORCH_ENABLE));
|
||||
|
||||
/* Enable LP transition in HBP period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lphbpe(LPHORIZONTAL_BACK_PORCH_ENABLE));
|
||||
|
||||
/* Enable LP transition in VACT period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lpvae(LPVERTICAL_ACTIVE_ENABLE));
|
||||
|
||||
/* Enable LP transition in VFP period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lpvfpe(LPVERTICAL_FRONT_PORCH_ENABLE));
|
||||
|
||||
/* Enable LP transition in VBP period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lpvbpe(LPVERTICAL_BACK_PORCH_ENABLE));
|
||||
|
||||
/* Enable LP transition in vertical sync period */
|
||||
DSIHOST.vmcr().modify(|w| w.set_lpvsae(LPVERTICAL_SYNC_ACTIVE_ENABLE));
|
||||
|
||||
/* Enable the request for an acknowledge response at the end of a frame */
|
||||
DSIHOST.vmcr().modify(|w| w.set_fbtaae(FRAME_BTAACKNOWLEDGE_ENABLE));
|
||||
|
||||
/* Configure DSI PHY HS2LP and LP2HS timings */
|
||||
const CLOCK_LANE_HS2_LPTIME: u16 = 35;
|
||||
const CLOCK_LANE_LP2_HSTIME: u16 = 35;
|
||||
const DATA_LANE_HS2_LPTIME: u8 = 35;
|
||||
const DATA_LANE_LP2_HSTIME: u8 = 35;
|
||||
const DATA_LANE_MAX_READ_TIME: u16 = 0;
|
||||
const STOP_WAIT_TIME: u8 = 10;
|
||||
|
||||
const MAX_TIME: u16 = if CLOCK_LANE_HS2_LPTIME > CLOCK_LANE_LP2_HSTIME {
|
||||
CLOCK_LANE_HS2_LPTIME
|
||||
} else {
|
||||
CLOCK_LANE_LP2_HSTIME
|
||||
};
|
||||
|
||||
/* Clock lane timer configuration */
|
||||
|
||||
/* In Automatic Clock Lane control mode, the DSI Host can turn off the clock lane between two
|
||||
High-Speed transmission.
|
||||
To do so, the DSI Host calculates the time required for the clock lane to change from HighSpeed
|
||||
to Low-Power and from Low-Power to High-Speed.
|
||||
This timings are configured by the HS2LP_TIME and LP2HS_TIME in the DSI Host Clock Lane Timer Configuration
|
||||
Register (DSI_CLTCR).
|
||||
But the DSI Host is not calculating LP2HS_TIME + HS2LP_TIME but 2 x HS2LP_TIME.
|
||||
|
||||
Workaround : Configure HS2LP_TIME and LP2HS_TIME with the same value being the max of HS2LP_TIME or LP2HS_TIME.
|
||||
*/
|
||||
|
||||
DSIHOST.cltcr().modify(|w| {
|
||||
w.set_hs2lp_time(MAX_TIME);
|
||||
w.set_lp2hs_time(MAX_TIME)
|
||||
});
|
||||
|
||||
// Data lane timer configuration
|
||||
DSIHOST.dltcr().modify(|w| {
|
||||
w.set_hs2lp_time(DATA_LANE_HS2_LPTIME);
|
||||
w.set_lp2hs_time(DATA_LANE_LP2_HSTIME);
|
||||
w.set_mrd_time(DATA_LANE_MAX_READ_TIME);
|
||||
});
|
||||
|
||||
// Configure the wait period to request HS transmission after a stop state
|
||||
DSIHOST.pconfr().modify(|w| w.set_sw_time(STOP_WAIT_TIME));
|
||||
|
||||
const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0
|
||||
|
||||
const LTDC_DE_POLARITY: Depol = if !DE_POLARITY {
|
||||
Depol::ACTIVELOW
|
||||
} else {
|
||||
Depol::ACTIVEHIGH
|
||||
};
|
||||
const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY {
|
||||
Vspol::ACTIVEHIGH
|
||||
} else {
|
||||
Vspol::ACTIVELOW
|
||||
};
|
||||
|
||||
const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY {
|
||||
Hspol::ACTIVEHIGH
|
||||
} else {
|
||||
Hspol::ACTIVELOW
|
||||
};
|
||||
|
||||
/* Timing Configuration */
|
||||
const HORIZONTAL_SYNC: u16 = HSA - 1;
|
||||
const VERTICAL_SYNC: u16 = VERTICAL_SYNC_ACTIVE - 1;
|
||||
const ACCUMULATED_HBP: u16 = HSA + HBP - 1;
|
||||
const ACCUMULATED_VBP: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH - 1;
|
||||
const ACCUMULATED_ACTIVE_W: u16 = LCD_X_SIZE + HSA + HBP - 1;
|
||||
const ACCUMULATED_ACTIVE_H: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE - 1;
|
||||
const TOTAL_WIDTH: u16 = LCD_X_SIZE + HSA + HBP + HFP - 1;
|
||||
const TOTAL_HEIGHT: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE + VERTICAL_FRONT_PORCH - 1;
|
||||
|
||||
// DISABLE LTDC before making changes
|
||||
ltdc.disable();
|
||||
|
||||
// Configure the HS, VS, DE and PC polarity
|
||||
LTDC.gcr().modify(|w| {
|
||||
w.set_hspol(LTDC_HS_POLARITY);
|
||||
w.set_vspol(LTDC_VS_POLARITY);
|
||||
w.set_depol(LTDC_DE_POLARITY);
|
||||
w.set_pcpol(Pcpol::RISINGEDGE);
|
||||
});
|
||||
|
||||
// Set Synchronization size
|
||||
LTDC.sscr().modify(|w| {
|
||||
w.set_hsw(HORIZONTAL_SYNC);
|
||||
w.set_vsh(VERTICAL_SYNC)
|
||||
});
|
||||
|
||||
// Set Accumulated Back porch
|
||||
LTDC.bpcr().modify(|w| {
|
||||
w.set_ahbp(ACCUMULATED_HBP);
|
||||
w.set_avbp(ACCUMULATED_VBP);
|
||||
});
|
||||
|
||||
// Set Accumulated Active Width
|
||||
LTDC.awcr().modify(|w| {
|
||||
w.set_aah(ACCUMULATED_ACTIVE_H);
|
||||
w.set_aaw(ACCUMULATED_ACTIVE_W);
|
||||
});
|
||||
|
||||
// Set Total Width
|
||||
LTDC.twcr().modify(|w| {
|
||||
w.set_totalh(TOTAL_HEIGHT);
|
||||
w.set_totalw(TOTAL_WIDTH);
|
||||
});
|
||||
|
||||
// Set the background color value
|
||||
LTDC.bccr().modify(|w| {
|
||||
w.set_bcred(0);
|
||||
w.set_bcgreen(0);
|
||||
w.set_bcblue(0)
|
||||
});
|
||||
|
||||
// Enable the Transfer Error and FIFO underrun interrupts
|
||||
LTDC.ier().modify(|w| {
|
||||
w.set_terrie(true);
|
||||
w.set_fuie(true);
|
||||
});
|
||||
|
||||
// ENABLE LTDC after making changes
|
||||
ltdc.enable();
|
||||
|
||||
dsi.enable();
|
||||
dsi.enable_wrapper_dsi();
|
||||
|
||||
// First, delay 120 ms (reason unknown, STM32 Cube Example does it)
|
||||
blocking_delay_ms(120);
|
||||
|
||||
// 1 to 26
|
||||
dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_1[0], &NT35510_WRITES_1[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_2[0], &NT35510_WRITES_2[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_3[0], &NT35510_WRITES_3[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_4[0], &NT35510_WRITES_4[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_5[0], &NT35510_WRITES_5[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_6[0], &NT35510_WRITES_6[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_7[0], &NT35510_WRITES_7[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_8[0], &NT35510_WRITES_8[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_9[0], &NT35510_WRITES_9[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_10[0], &NT35510_WRITES_10[1..]).unwrap();
|
||||
// 11 missing
|
||||
dsi.write_cmd(0, NT35510_WRITES_12[0], &NT35510_WRITES_12[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_13[0], &NT35510_WRITES_13[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_14[0], &NT35510_WRITES_14[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_15[0], &NT35510_WRITES_15[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_16[0], &NT35510_WRITES_16[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_17[0], &NT35510_WRITES_17[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_18[0], &NT35510_WRITES_18[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_19[0], &NT35510_WRITES_19[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_20[0], &NT35510_WRITES_20[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_21[0], &NT35510_WRITES_21[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_22[0], &NT35510_WRITES_22[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_23[0], &NT35510_WRITES_23[1..]).unwrap();
|
||||
dsi.write_cmd(0, NT35510_WRITES_24[0], &NT35510_WRITES_24[1..]).unwrap();
|
||||
|
||||
// Tear on
|
||||
dsi.write_cmd(0, NT35510_WRITES_26[0], &NT35510_WRITES_26[1..]).unwrap();
|
||||
|
||||
// Set Pixel color format to RGB888
|
||||
dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
|
||||
|
||||
// Add a delay, otherwise MADCTL not taken
|
||||
blocking_delay_ms(200);
|
||||
|
||||
// Configure orientation as landscape
|
||||
dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..])
|
||||
.unwrap();
|
||||
dsi.write_cmd(0, NT35510_CASET_LANDSCAPE[0], &NT35510_CASET_LANDSCAPE[1..])
|
||||
.unwrap();
|
||||
dsi.write_cmd(0, NT35510_RASET_LANDSCAPE[0], &NT35510_RASET_LANDSCAPE[1..])
|
||||
.unwrap();
|
||||
|
||||
// Sleep out
|
||||
dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap();
|
||||
|
||||
// Wait for sleep out exit
|
||||
blocking_delay_ms(120);
|
||||
|
||||
// Configure COLOR_CODING
|
||||
dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
|
||||
|
||||
/* CABC : Content Adaptive Backlight Control section start >> */
|
||||
/* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */
|
||||
dsi.write_cmd(0, NT35510_WRITES_31[0], &NT35510_WRITES_31[1..]).unwrap();
|
||||
/* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */
|
||||
dsi.write_cmd(0, NT35510_WRITES_32[0], &NT35510_WRITES_32[1..]).unwrap();
|
||||
/* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */
|
||||
dsi.write_cmd(0, NT35510_WRITES_33[0], &NT35510_WRITES_33[1..]).unwrap();
|
||||
/* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */
|
||||
dsi.write_cmd(0, NT35510_WRITES_34[0], &NT35510_WRITES_34[1..]).unwrap();
|
||||
/* CABC : Content Adaptive Backlight Control section end << */
|
||||
/* Display on */
|
||||
dsi.write_cmd(0, NT35510_WRITES_30[0], &NT35510_WRITES_30[1..]).unwrap();
|
||||
|
||||
/* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */
|
||||
/* DSI host from LTDC incoming pixels in video mode */
|
||||
dsi.write_cmd(0, NT35510_WRITES_35[0], &NT35510_WRITES_35[1..]).unwrap();
|
||||
|
||||
/* Initialize the LCD pixel width and pixel height */
|
||||
const WINDOW_X0: u16 = 0;
|
||||
const WINDOW_X1: u16 = LCD_X_SIZE; // 480 for ferris
|
||||
const WINDOW_Y0: u16 = 0;
|
||||
const WINDOW_Y1: u16 = LCD_Y_SIZE; // 800 for ferris
|
||||
const PIXEL_FORMAT: Pf = Pf::ARGB8888;
|
||||
//const FBStartAdress: u16 = FB_Address;
|
||||
const ALPHA: u8 = 255;
|
||||
const ALPHA0: u8 = 0;
|
||||
const BACKCOLOR_BLUE: u8 = 0;
|
||||
const BACKCOLOR_GREEN: u8 = 0;
|
||||
const BACKCOLOR_RED: u8 = 0;
|
||||
const IMAGE_WIDTH: u16 = LCD_X_SIZE; // 480 for ferris
|
||||
const IMAGE_HEIGHT: u16 = LCD_Y_SIZE; // 800 for ferris
|
||||
|
||||
const PIXEL_SIZE: u8 = match PIXEL_FORMAT {
|
||||
Pf::ARGB8888 => 4,
|
||||
Pf::RGB888 => 3,
|
||||
Pf::ARGB4444 | Pf::RGB565 | Pf::ARGB1555 | Pf::AL88 => 2,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
// Configure the horizontal start and stop position
|
||||
LTDC.layer(0).whpcr().write(|w| {
|
||||
w.set_whstpos(LTDC.bpcr().read().ahbp() + 1 + WINDOW_X0);
|
||||
w.set_whsppos(LTDC.bpcr().read().ahbp() + WINDOW_X1);
|
||||
});
|
||||
|
||||
// Configures the vertical start and stop position
|
||||
LTDC.layer(0).wvpcr().write(|w| {
|
||||
w.set_wvstpos(LTDC.bpcr().read().avbp() + 1 + WINDOW_Y0);
|
||||
w.set_wvsppos(LTDC.bpcr().read().avbp() + WINDOW_Y1);
|
||||
});
|
||||
|
||||
// Specify the pixel format
|
||||
LTDC.layer(0).pfcr().write(|w| w.set_pf(PIXEL_FORMAT));
|
||||
|
||||
// Configures the default color values as zero
|
||||
LTDC.layer(0).dccr().modify(|w| {
|
||||
w.set_dcblue(BACKCOLOR_BLUE);
|
||||
w.set_dcgreen(BACKCOLOR_GREEN);
|
||||
w.set_dcred(BACKCOLOR_RED);
|
||||
w.set_dcalpha(ALPHA0);
|
||||
});
|
||||
|
||||
// Specifies the constant ALPHA value
|
||||
LTDC.layer(0).cacr().write(|w| w.set_consta(ALPHA));
|
||||
|
||||
// Specifies the blending factors
|
||||
LTDC.layer(0).bfcr().write(|w| {
|
||||
w.set_bf1(Bf1::CONSTANT);
|
||||
w.set_bf2(Bf2::CONSTANT);
|
||||
});
|
||||
|
||||
// Configure the color frame buffer start address
|
||||
let fb_start_address: u32 = &FERRIS_IMAGE[0] as *const _ as u32;
|
||||
info!("Setting Framebuffer Start Address: {:010x}", fb_start_address);
|
||||
LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(fb_start_address));
|
||||
|
||||
// Configures the color frame buffer pitch in byte
|
||||
LTDC.layer(0).cfblr().write(|w| {
|
||||
w.set_cfbp(IMAGE_WIDTH * PIXEL_SIZE as u16);
|
||||
w.set_cfbll(((WINDOW_X1 - WINDOW_X0) * PIXEL_SIZE as u16) + 3);
|
||||
});
|
||||
|
||||
// Configures the frame buffer line number
|
||||
LTDC.layer(0).cfblnr().write(|w| w.set_cfblnbr(IMAGE_HEIGHT));
|
||||
|
||||
// Enable LTDC_Layer by setting LEN bit
|
||||
LTDC.layer(0).cr().modify(|w| w.set_len(true));
|
||||
|
||||
//LTDC->SRCR = LTDC_SRCR_IMR;
|
||||
LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD));
|
||||
|
||||
blocking_delay_ms(5000);
|
||||
|
||||
const READ_SIZE: u16 = 1;
|
||||
let mut data = [1u8; READ_SIZE as usize];
|
||||
dsi.read(0, PacketType::DcsShortPktRead(0xDA), READ_SIZE, &mut data)
|
||||
.unwrap();
|
||||
info!("Display ID1: {:#04x}", data);
|
||||
|
||||
dsi.read(0, PacketType::DcsShortPktRead(0xDB), READ_SIZE, &mut data)
|
||||
.unwrap();
|
||||
info!("Display ID2: {:#04x}", data);
|
||||
|
||||
dsi.read(0, PacketType::DcsShortPktRead(0xDC), READ_SIZE, &mut data)
|
||||
.unwrap();
|
||||
info!("Display ID3: {:#04x}", data);
|
||||
|
||||
blocking_delay_ms(500);
|
||||
|
||||
info!("Config done, start blinking LED");
|
||||
loop {
|
||||
led.set_high();
|
||||
Timer::after_millis(1000).await;
|
||||
|
||||
// Increase screen brightness
|
||||
dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0xFF]).unwrap();
|
||||
|
||||
led.set_low();
|
||||
Timer::after_millis(1000).await;
|
||||
|
||||
// Reduce screen brightness
|
||||
dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0x50]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
const NT35510_WRITES_0: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01]; // LV2: Page 1 enable
|
||||
const NT35510_WRITES_1: &[u8] = &[0xB0, 0x03, 0x03, 0x03]; // AVDD: 5.2V
|
||||
const NT35510_WRITES_2: &[u8] = &[0xB6, 0x46, 0x46, 0x46]; // AVDD: Ratio
|
||||
const NT35510_WRITES_3: &[u8] = &[0xB1, 0x03, 0x03, 0x03]; // AVEE: -5.2V
|
||||
const NT35510_WRITES_4: &[u8] = &[0xB7, 0x36, 0x36, 0x36]; // AVEE: Ratio
|
||||
const NT35510_WRITES_5: &[u8] = &[0xB2, 0x00, 0x00, 0x02]; // VCL: -2.5V
|
||||
const NT35510_WRITES_6: &[u8] = &[0xB8, 0x26, 0x26, 0x26]; // VCL: Ratio
|
||||
const NT35510_WRITES_7: &[u8] = &[0xBF, 0x01]; // VGH: 15V (Free Pump)
|
||||
const NT35510_WRITES_8: &[u8] = &[0xB3, 0x09, 0x09, 0x09];
|
||||
const NT35510_WRITES_9: &[u8] = &[0xB9, 0x36, 0x36, 0x36]; // VGH: Ratio
|
||||
const NT35510_WRITES_10: &[u8] = &[0xB5, 0x08, 0x08, 0x08]; // VGL_REG: -10V
|
||||
const NT35510_WRITES_12: &[u8] = &[0xBA, 0x26, 0x26, 0x26]; // VGLX: Ratio
|
||||
const NT35510_WRITES_13: &[u8] = &[0xBC, 0x00, 0x80, 0x00]; // VGMP/VGSP: 4.5V/0V
|
||||
const NT35510_WRITES_14: &[u8] = &[0xBD, 0x00, 0x80, 0x00]; // VGMN/VGSN:-4.5V/0V
|
||||
const NT35510_WRITES_15: &[u8] = &[0xBE, 0x00, 0x50]; // VCOM: -1.325V
|
||||
const NT35510_WRITES_16: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00]; // LV2: Page 0 enable
|
||||
const NT35510_WRITES_17: &[u8] = &[0xB1, 0xFC, 0x00]; // Display control
|
||||
const NT35510_WRITES_18: &[u8] = &[0xB6, 0x03]; // Src hold time
|
||||
const NT35510_WRITES_19: &[u8] = &[0xB5, 0x51];
|
||||
const NT35510_WRITES_20: &[u8] = &[0x00, 0x00, 0xB7]; // Gate EQ control
|
||||
const NT35510_WRITES_21: &[u8] = &[0xB8, 0x01, 0x02, 0x02, 0x02]; // Src EQ control(Mode2)
|
||||
const NT35510_WRITES_22: &[u8] = &[0xBC, 0x00, 0x00, 0x00]; // Inv. mode(2-dot)
|
||||
const NT35510_WRITES_23: &[u8] = &[0xCC, 0x03, 0x00, 0x00];
|
||||
const NT35510_WRITES_24: &[u8] = &[0xBA, 0x01];
|
||||
|
||||
const _NT35510_MADCTL_PORTRAIT: &[u8] = &[NT35510_CMD_MADCTL, 0x00];
|
||||
const _NT35510_CASET_PORTRAIT: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x01, 0xDF];
|
||||
const _NT35510_RASET_PORTRAIT: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x03, 0x1F];
|
||||
const NT35510_MADCTL_LANDSCAPE: &[u8] = &[NT35510_CMD_MADCTL, 0x60];
|
||||
const NT35510_CASET_LANDSCAPE: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x03, 0x1F];
|
||||
const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0xDF];
|
||||
|
||||
const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on
|
||||
const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out
|
||||
// 28,29 missing
|
||||
const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on
|
||||
|
||||
const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F];
|
||||
const NT35510_WRITES_32: &[u8] = &[NT35510_CMD_WRCTRLD, 0x2C];
|
||||
const NT35510_WRITES_33: &[u8] = &[NT35510_CMD_WRCABC, 0x02];
|
||||
const NT35510_WRITES_34: &[u8] = &[NT35510_CMD_WRCABCMB, 0xFF];
|
||||
const NT35510_WRITES_35: &[u8] = &[NT35510_CMD_RAMWR, 0x00];
|
||||
|
||||
//const NT35510_WRITES_36: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB565]; // FIXME: Example sets it to 888 but rest of the code seems to configure DSI for 565
|
||||
const NT35510_WRITES_37: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB888];
|
||||
|
||||
// More of these: https://elixir.bootlin.com/linux/latest/source/include/video/mipi_display.h#L83
|
||||
const _NT35510_CMD_TEEON_GET_DISPLAY_ID: u8 = 0x04;
|
||||
|
||||
const NT35510_CMD_TEEON: u8 = 0x35;
|
||||
const NT35510_CMD_MADCTL: u8 = 0x36;
|
||||
|
||||
const NT35510_CMD_SLPOUT: u8 = 0x11;
|
||||
const NT35510_CMD_DISPON: u8 = 0x29;
|
||||
const NT35510_CMD_CASET: u8 = 0x2A;
|
||||
const NT35510_CMD_RASET: u8 = 0x2B;
|
||||
const NT35510_CMD_RAMWR: u8 = 0x2C; /* Memory write */
|
||||
const NT35510_CMD_COLMOD: u8 = 0x3A;
|
||||
|
||||
const NT35510_CMD_WRDISBV: u8 = 0x51; /* Write display brightness */
|
||||
const _NT35510_CMD_RDDISBV: u8 = 0x52; /* Read display brightness */
|
||||
const NT35510_CMD_WRCTRLD: u8 = 0x53; /* Write CTRL display */
|
||||
const _NT35510_CMD_RDCTRLD: u8 = 0x54; /* Read CTRL display value */
|
||||
const NT35510_CMD_WRCABC: u8 = 0x55; /* Write content adaptative brightness control */
|
||||
const NT35510_CMD_WRCABCMB: u8 = 0x5E; /* Write CABC minimum brightness */
|
||||
|
||||
const _NT35510_COLMOD_RGB565: u8 = 0x55;
|
||||
const NT35510_COLMOD_RGB888: u8 = 0x77;
|
70
examples/stm32f469/src/bin/ferris.bin
Normal file
70
examples/stm32f469/src/bin/ferris.bin
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user