Skip to content

Instantly share code, notes, and snippets.

@randrews
Created July 24, 2025 17:39
Show Gist options
  • Save randrews/3f9346538f1ce9f095b8afc133f9ca43 to your computer and use it in GitHub Desktop.
Save randrews/3f9346538f1ce9f095b8afc133f9ca43 to your computer and use it in GitHub Desktop.
LTDC working and spitting pixels
#![no_std]
#![no_main]
use defmt::info;
use embassy_executor::Spawner;
use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed};
use embassy_stm32::ltdc::{B7Pin, ClkPin, DePin, G7Pin, HsyncPin, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PixelFormat, PolarityActive, PolarityEdge, R7Pin, VsyncPin};
use embassy_stm32::pac::LTDC;
use embassy_stm32::peripherals::LTDC;
use embassy_stm32::rcc;
use embassy_stm32::rcc::Pll;
use embassy_time::Timer;
use {defmt_rtt as _, embassy_stm32 as _, panic_probe as _};
static FBUF: [u16; 320 * 240] = [0xffe0u16; 320 * 240];
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
config.rcc.supply_config = rcc::SupplyConfig::LDO;
config.rcc.voltage_scale = rcc::VoltageScale::Scale0;
config.rcc.pll3 = Some(
Pll {
source: rcc::PllSource::HSI,
prediv: rcc::PllPreDiv::DIV4,
mul: rcc::PllMul::MUL16,
divp: None,
divq: None,
divr: Some(rcc::PllDiv::DIV50),
}
);
let p = embassy_stm32::init(config);
info!("Hello World!");
let mut ltdc = Ltdc::new(p.LTDC);
ltdc.init(&LtdcConfiguration {
active_width: 320,
active_height: 240,
h_back_porch: 20,
h_front_porch: 10,
v_back_porch: 2,
v_front_porch: 4,
h_sync: 10,
v_sync: 2,
h_sync_polarity: PolarityActive::ActiveLow,
v_sync_polarity: PolarityActive::ActiveLow,
data_enable_polarity: PolarityActive::ActiveLow,
pixel_clock_polarity: PolarityEdge::FallingEdge,
});
let num = <embassy_stm32::peripherals::PE14 as ClkPin<LTDC>>::af_num(&p.PE14);
let mut clk = Flex::new(p.PE14);
clk.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PC6 as HsyncPin<LTDC>>::af_num(&p.PC6);
let mut hsync = Flex::new(p.PC6);
hsync.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PA4 as VsyncPin<LTDC>>::af_num(&p.PA4);
let mut vsync = Flex::new(p.PA4);
vsync.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PF10 as DePin<LTDC>>::af_num(&p.PF10);
let mut de = Flex::new(p.PF10);
de.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PC4 as R7Pin<LTDC>>::af_num(&p.PC4);
let mut r7 = Flex::new(p.PC4);
r7.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PB15 as G7Pin<LTDC>>::af_num(&p.PB15);
let mut g7 = Flex::new(p.PB15);
g7.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
let num = <embassy_stm32::peripherals::PD2 as B7Pin<LTDC>>::af_num(&p.PD2);
let mut b7 = Flex::new(p.PD2);
b7.set_as_af_unchecked(num, AfType::output(OutputType::PushPull, Speed::VeryHigh));
ltdc.init_layer(&LtdcLayerConfig {
layer: LtdcLayer::Layer1,
pixel_format: PixelFormat::RGB565,
window_x0: 0,
window_x1: 319,
window_y0: 0,
window_y1: 239,
}, None);
ltdc.enable();
LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(FBUF.as_ptr() as *const _ as u32));
LTDC.srcr().modify(|w| w.set_vbr(embassy_stm32::pac::ltdc::vals::Vbr::RELOAD));
loop {
info!("tick");
Timer::after_secs(1).await;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment