#![no_std] #![no_main] mod backlight; mod display; mod framebuffer; mod led; pub mod board; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyle, Triangle}; use embassy_executor::Spawner; use embassy_time::{Instant, Timer}; use esp_backtrace as _; use esp_bootloader_esp_idf::esp_app_desc; use esp_hal::timer::timg::TimerGroup; use esp_hal::{init, rmt::Rmt, time::Rate, Config}; use esp_println::println; use smart_leds::hsv::{hsv2rgb, Hsv}; const SAT: u8 = 255; const VAL: u8 = 255; esp_app_desc!(); #[embassy_executor::task] async fn led_task( rmt_periph: esp_hal::peripherals::RMT<'static>, led_pin: esp_hal::peripherals::GPIO8<'static>, ) { let rmt = Rmt::new(rmt_periph, Rate::from_mhz(80)).expect("Failed to init RMT"); let mut led = led::RgbLed::new(rmt.channel0, led_pin).expect("Failed to init RGB LED"); let mut frame = 0u32; loop { let hue = (frame % 256) as u8; let lit = hsv2rgb(Hsv { hue, sat: SAT, val: VAL, }); led.set_rgb(lit).unwrap(); Timer::after_millis(30).await; frame = frame.wrapping_add(1); } } #[embassy_executor::task] async fn display_task( pins: display::LcdPins, ledc: esp_hal::peripherals::LEDC<'static>, bl_pin: esp_hal::peripherals::GPIO22<'static>, ) { let mut parts = display::init_parts(pins); println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT); let (_ledc, timer) = backlight::setup_timer(ledc).expect("Failed to init backlight timer"); let mut backlight = backlight::LcdBacklight::new(&timer, bl_pin).expect("Failed to init backlight"); backlight.set_level(0.5).unwrap(); println!("backlight set to 0.5"); let mut fb = framebuffer::Framebuffer; let mut pts = [ Point::new(86, 20), Point::new(61, 50), Point::new(111, 50), ]; let mut vx: i32 = 3; let mut vy: i32 = 2; let mut frame = 0u32; let mut fps_window_start = Instant::now(); let mut fps_frames = 0u32; loop { let hue = (frame % 256) as u8; let lit = hsv2rgb(Hsv { hue, sat: SAT, val: VAL, }); let accent = Rgb565::new(lit.r/8, lit.g/4, lit.b/8); for p in &mut pts { p.x += vx; p.y += vy; } let min_x = pts.iter().map(|p| p.x).min().unwrap(); let max_x = pts.iter().map(|p| p.x).max().unwrap(); let min_y = pts.iter().map(|p| p.y).min().unwrap(); let max_y = pts.iter().map(|p| p.y).max().unwrap(); if min_x <= 0 || max_x >= display::WIDTH as i32 { vx = -vx; } if min_y <= 0 || max_y >= display::HEIGHT as i32 { vy = -vy; } fb.clear(); Triangle::new(pts[0], pts[1], pts[2]) .into_styled(PrimitiveStyle::with_fill(accent)) .draw(&mut fb) .unwrap(); display::send_framebuffer(&mut parts.spi, &mut parts.dc, &mut parts.cs, fb.as_bytes()) .await .unwrap(); if frame % 32 == 0 { println!( "frame {frame}: apex=({}, {}), v=({}, {}), hue={hue}", pts[0].x, pts[0].y, vx, vy ); } fps_frames += 1; if fps_frames >= 60 { let elapsed_ms = fps_window_start.elapsed().as_millis().max(1); let fps = (fps_frames as u64 * 1000) / elapsed_ms; println!("fps: {fps} ({fps_frames} frames in {elapsed_ms} ms)"); fps_frames = 0; fps_window_start = Instant::now(); } frame = frame.wrapping_add(1); } } #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { let peripherals = init(Config::default()); let timg0 = TimerGroup::new(peripherals.TIMG0); esp_rtos::start(timg0.timer0, peripherals.FROM_CPU_INTR0); spawner.spawn(led_task(peripherals.RMT, peripherals.GPIO8).unwrap()); spawner.spawn(display_task( display::LcdPins { spi2: peripherals.SPI2, sck: peripherals.GPIO7, mosi: peripherals.GPIO6, dc: peripherals.GPIO15, cs: peripherals.GPIO14, rst: peripherals.GPIO21, dma_ch: peripherals.DMA_CH0, }, peripherals.LEDC, peripherals.GPIO22, ).unwrap()); loop { Timer::after_millis(1000).await; } }