Files
jerryboard-two/src/main.rs
T

158 lines
4.4 KiB
Rust
Raw Normal View History

2026-09-07 18:35:36 -05:00
#![no_std]
#![no_main]
mod backlight;
2026-09-07 22:13:21 -05:00
mod display;
mod framebuffer;
2026-09-07 18:35:36 -05:00
mod led;
2026-09-08 22:46:31 -05:00
pub mod board;
2026-09-07 18:35:36 -05:00
2026-09-07 22:13:21 -05:00
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
2026-09-07 23:33:05 -05:00
use embedded_graphics::primitives::{PrimitiveStyle, Triangle};
use embassy_executor::Spawner;
2026-09-07 23:57:58 -05:00
use embassy_time::{Instant, Timer};
2026-09-07 18:35:36 -05:00
use esp_backtrace as _;
use esp_bootloader_esp_idf::esp_app_desc;
2026-09-07 23:33:05 -05:00
use esp_hal::timer::timg::TimerGroup;
2026-09-07 18:35:36 -05:00
use esp_hal::{init, rmt::Rmt, time::Rate, Config};
use esp_println::println;
use smart_leds::hsv::{hsv2rgb, Hsv};
2026-09-07 22:13:21 -05:00
2026-09-07 23:33:05 -05:00
const SAT: u8 = 255;
const VAL: u8 = 255;
2026-09-07 18:35:36 -05:00
esp_app_desc!();
2026-09-07 23:33:05 -05:00
#[embassy_executor::task]
2026-09-08 22:46:31 -05:00
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");
2026-09-07 23:33:05 -05:00
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(
2026-09-07 23:57:58 -05:00
pins: display::LcdPins,
2026-09-08 22:46:31 -05:00
ledc: esp_hal::peripherals::LEDC<'static>,
2026-09-07 23:33:05 -05:00
bl_pin: esp_hal::peripherals::GPIO22<'static>,
) {
2026-09-07 23:57:58 -05:00
let mut parts = display::init_parts(pins);
println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT);
2026-09-08 22:46:31 -05:00
let (_ledc, timer) =
backlight::setup_timer(ledc).expect("Failed to init backlight timer");
2026-09-07 18:35:36 -05:00
let mut backlight =
2026-09-07 23:33:05 -05:00
backlight::LcdBacklight::new(&timer, bl_pin).expect("Failed to init backlight");
2026-09-07 22:13:21 -05:00
backlight.set_level(0.5).unwrap();
2026-09-07 23:33:05 -05:00
println!("backlight set to 0.5");
2026-09-07 22:13:21 -05:00
2026-09-08 22:46:31 -05:00
let mut fb = framebuffer::Framebuffer;
2026-09-07 22:13:21 -05:00
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;
2026-09-07 23:57:58 -05:00
let mut fps_window_start = Instant::now();
let mut fps_frames = 0u32;
2026-09-07 18:35:36 -05:00
loop {
2026-09-07 22:13:21 -05:00
let hue = (frame % 256) as u8;
let lit = hsv2rgb(Hsv {
hue,
sat: SAT,
val: VAL,
});
2026-09-07 23:33:05 -05:00
let accent = Rgb565::new(lit.r/8, lit.g/4, lit.b/8);
2026-09-07 22:13:21 -05:00
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();
2026-09-07 23:57:58 -05:00
display::send_framebuffer(&mut parts.spi, &mut parts.dc, &mut parts.cs, fb.as_bytes())
2026-09-07 23:33:05 -05:00
.await
2026-09-07 22:13:21 -05:00
.unwrap();
if frame % 32 == 0 {
println!(
"frame {frame}: apex=({}, {}), v=({}, {}), hue={hue}",
pts[0].x, pts[0].y, vx, vy
);
2026-09-07 18:35:36 -05:00
}
2026-09-07 23:57:58 -05:00
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();
}
2026-09-07 22:13:21 -05:00
frame = frame.wrapping_add(1);
2026-09-07 23:33:05 -05:00
}
}
#[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);
2026-09-08 22:46:31 -05:00
spawner.spawn(led_task(peripherals.RMT, peripherals.GPIO8).unwrap());
2026-09-07 23:57:58 -05:00
spawner.spawn(display_task(
2026-09-07 23:33:05 -05:00
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,
},
2026-09-08 22:46:31 -05:00
peripherals.LEDC,
2026-09-07 23:33:05 -05:00
peripherals.GPIO22,
).unwrap());
loop {
Timer::after_millis(1000).await;
2026-09-07 18:35:36 -05:00
}
}