695 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			695 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
#![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;
 |