fps
This commit is contained in:
+21
-12
@@ -8,7 +8,7 @@ use esp_hal::Async;
|
|||||||
use mipidsi::interface::SpiInterface;
|
use mipidsi::interface::SpiInterface;
|
||||||
use mipidsi::models::ST7789;
|
use mipidsi::models::ST7789;
|
||||||
use mipidsi::options::{ColorInversion, ColorOrder, Orientation, Rotation};
|
use mipidsi::options::{ColorInversion, ColorOrder, Orientation, Rotation};
|
||||||
use mipidsi::{Builder, Display};
|
use mipidsi::Builder;
|
||||||
|
|
||||||
pub const WIDTH: u32 = 172;
|
pub const WIDTH: u32 = 172;
|
||||||
pub const HEIGHT: u32 = 320;
|
pub const HEIGHT: u32 = 320;
|
||||||
@@ -25,13 +25,13 @@ pub type SpiDmaBus = SpiDma<'static, Async>;
|
|||||||
|
|
||||||
/// SPI bus + CS, presented to mipidsi as an `SpiDevice` for init, while keeping
|
/// SPI bus + CS, presented to mipidsi as an `SpiDevice` for init, while keeping
|
||||||
/// the raw pieces recoverable for the async framebuffer path.
|
/// the raw pieces recoverable for the async framebuffer path.
|
||||||
pub struct LcdDevice {
|
struct LcdDevice {
|
||||||
spi: SpiDmaBus,
|
spi: SpiDmaBus,
|
||||||
cs: Output<'static>,
|
cs: Output<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LcdDevice {
|
impl LcdDevice {
|
||||||
pub fn into_inner(self) -> (SpiDmaBus, Output<'static>) {
|
fn into_inner(self) -> (SpiDmaBus, Output<'static>) {
|
||||||
(self.spi, self.cs)
|
(self.spi, self.cs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,11 +60,6 @@ impl SpiDevice for LcdDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Interface<'a> = SpiInterface<'a, LcdDevice, Output<'static>>;
|
|
||||||
|
|
||||||
/// The mipidsi [`Display`] used to initialize the panel.
|
|
||||||
pub type Lcd<'a> = Display<Interface<'a>, ST7789, Output<'static>>;
|
|
||||||
|
|
||||||
/// All the peripheral resources the LCD needs.
|
/// All the peripheral resources the LCD needs.
|
||||||
pub struct LcdPins {
|
pub struct LcdPins {
|
||||||
pub spi2: SPI2<'static>,
|
pub spi2: SPI2<'static>,
|
||||||
@@ -76,7 +71,15 @@ pub struct LcdPins {
|
|||||||
pub dma_ch: DMA_CH0<'static>,
|
pub dma_ch: DMA_CH0<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init<'a>(pins: LcdPins, buffer: &'a mut [u8]) -> Lcd<'a> {
|
/// The raw LCD resources, ready to drive the async framebuffer path.
|
||||||
|
pub struct LcdParts {
|
||||||
|
pub spi: SpiDmaBus,
|
||||||
|
pub cs: Output<'static>,
|
||||||
|
pub dc: Output<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_parts(pins: LcdPins) -> LcdParts {
|
||||||
|
let mut buffer = [0u8; 4096];
|
||||||
let dma_tx_buf = esp_hal::dma_tx_buffer!(DMA_BUF_SIZE).expect("Failed to create DMA TX buffer");
|
let dma_tx_buf = esp_hal::dma_tx_buffer!(DMA_BUF_SIZE).expect("Failed to create DMA TX buffer");
|
||||||
let dma_rx_buf = esp_hal::dma_rx_buffer!(4).expect("Failed to create DMA RX buffer");
|
let dma_rx_buf = esp_hal::dma_rx_buffer!(4).expect("Failed to create DMA RX buffer");
|
||||||
|
|
||||||
@@ -98,14 +101,14 @@ pub fn init<'a>(pins: LcdPins, buffer: &'a mut [u8]) -> Lcd<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let dc_pin = Output::new(pins.dc, Level::Low, OutputConfig::default());
|
let dc_pin = Output::new(pins.dc, Level::Low, OutputConfig::default());
|
||||||
let interface = SpiInterface::new(device, dc_pin, buffer);
|
let interface = SpiInterface::new(device, dc_pin, &mut buffer);
|
||||||
|
|
||||||
let mut rst_pin = Output::new(pins.rst, Level::High, OutputConfig::default());
|
let mut rst_pin = Output::new(pins.rst, Level::High, OutputConfig::default());
|
||||||
rst_pin.set_high();
|
rst_pin.set_high();
|
||||||
|
|
||||||
let mut delay = esp_hal::delay::Delay::new();
|
let mut delay = esp_hal::delay::Delay::new();
|
||||||
|
|
||||||
Builder::new(ST7789, interface)
|
let lcd = Builder::new(ST7789, interface)
|
||||||
.display_size(WIDTH as u16, HEIGHT as u16)
|
.display_size(WIDTH as u16, HEIGHT as u16)
|
||||||
.display_offset(COLUMN_OFFSET, 0)
|
.display_offset(COLUMN_OFFSET, 0)
|
||||||
.orientation(Orientation::new().rotate(Rotation::Deg0))
|
.orientation(Orientation::new().rotate(Rotation::Deg0))
|
||||||
@@ -113,7 +116,13 @@ pub fn init<'a>(pins: LcdPins, buffer: &'a mut [u8]) -> Lcd<'a> {
|
|||||||
.invert_colors(ColorInversion::Inverted)
|
.invert_colors(ColorInversion::Inverted)
|
||||||
.reset_pin(rst_pin)
|
.reset_pin(rst_pin)
|
||||||
.init(&mut delay)
|
.init(&mut delay)
|
||||||
.expect("Failed to init display")
|
.expect("Failed to init display");
|
||||||
|
|
||||||
|
let (interface, _model, _rst) = lcd.release();
|
||||||
|
let (device, dc) = interface.release();
|
||||||
|
let (spi, cs) = device.into_inner();
|
||||||
|
|
||||||
|
LcdParts { spi, cs, dc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stream a full framebuffer to the panel asynchronously (DMA).
|
/// Stream a full framebuffer to the panel asynchronously (DMA).
|
||||||
|
|||||||
+19
-22
@@ -10,10 +10,9 @@ use embedded_graphics::pixelcolor::Rgb565;
|
|||||||
use embedded_graphics::prelude::*;
|
use embedded_graphics::prelude::*;
|
||||||
use embedded_graphics::primitives::{PrimitiveStyle, Triangle};
|
use embedded_graphics::primitives::{PrimitiveStyle, Triangle};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_time::Timer;
|
use embassy_time::{Instant, Timer};
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_bootloader_esp_idf::esp_app_desc;
|
use esp_bootloader_esp_idf::esp_app_desc;
|
||||||
use esp_hal::gpio::Output;
|
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_hal::{init, rmt::Rmt, time::Rate, Config};
|
use esp_hal::{init, rmt::Rmt, time::Rate, Config};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
@@ -42,13 +41,14 @@ async fn led_task(mut led: led::RgbLed) {
|
|||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn display_task(
|
async fn display_task(
|
||||||
mut spi: display::SpiDmaBus,
|
pins: display::LcdPins,
|
||||||
mut dc: Output<'static>,
|
|
||||||
mut cs: Output<'static>,
|
|
||||||
mut fb: framebuffer::Framebuffer,
|
mut fb: framebuffer::Framebuffer,
|
||||||
timer: esp_hal::ledc::timer::Timer<'static, esp_hal::ledc::LowSpeed>,
|
timer: esp_hal::ledc::timer::Timer<'static, esp_hal::ledc::LowSpeed>,
|
||||||
bl_pin: esp_hal::peripherals::GPIO22<'static>,
|
bl_pin: esp_hal::peripherals::GPIO22<'static>,
|
||||||
) {
|
) {
|
||||||
|
let mut parts = display::init_parts(pins);
|
||||||
|
println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT);
|
||||||
|
|
||||||
let mut backlight =
|
let mut backlight =
|
||||||
backlight::LcdBacklight::new(&timer, bl_pin).expect("Failed to init backlight");
|
backlight::LcdBacklight::new(&timer, bl_pin).expect("Failed to init backlight");
|
||||||
backlight.set_level(0.5).unwrap();
|
backlight.set_level(0.5).unwrap();
|
||||||
@@ -62,6 +62,8 @@ async fn display_task(
|
|||||||
let mut vx: i32 = 3;
|
let mut vx: i32 = 3;
|
||||||
let mut vy: i32 = 2;
|
let mut vy: i32 = 2;
|
||||||
let mut frame = 0u32;
|
let mut frame = 0u32;
|
||||||
|
let mut fps_window_start = Instant::now();
|
||||||
|
let mut fps_frames = 0u32;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let hue = (frame % 256) as u8;
|
let hue = (frame % 256) as u8;
|
||||||
@@ -95,7 +97,7 @@ async fn display_task(
|
|||||||
.draw(&mut fb)
|
.draw(&mut fb)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
display::send_framebuffer(&mut spi, &mut dc, &mut cs, fb.as_bytes())
|
display::send_framebuffer(&mut parts.spi, &mut parts.dc, &mut parts.cs, fb.as_bytes())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -106,6 +108,15 @@ async fn display_task(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
frame = frame.wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,8 +135,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let (_ledc, timer) =
|
let (_ledc, timer) =
|
||||||
backlight::setup_timer(peripherals.LEDC).expect("Failed to init backlight timer");
|
backlight::setup_timer(peripherals.LEDC).expect("Failed to init backlight timer");
|
||||||
|
|
||||||
let mut buffer = [0u8; 4096];
|
spawner.spawn(led_task(led).unwrap());
|
||||||
let lcd = display::init(
|
spawner.spawn(display_task(
|
||||||
display::LcdPins {
|
display::LcdPins {
|
||||||
spi2: peripherals.SPI2,
|
spi2: peripherals.SPI2,
|
||||||
sck: peripherals.GPIO7,
|
sck: peripherals.GPIO7,
|
||||||
@@ -135,20 +146,6 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
rst: peripherals.GPIO21,
|
rst: peripherals.GPIO21,
|
||||||
dma_ch: peripherals.DMA_CH0,
|
dma_ch: peripherals.DMA_CH0,
|
||||||
},
|
},
|
||||||
&mut buffer,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (interface, _model, _rst) = lcd.release();
|
|
||||||
let (device, dc) = interface.release();
|
|
||||||
let (spi, cs) = device.into_inner();
|
|
||||||
|
|
||||||
println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT);
|
|
||||||
|
|
||||||
spawner.spawn(led_task(led).unwrap());
|
|
||||||
spawner.spawn(display_task(
|
|
||||||
spi,
|
|
||||||
dc,
|
|
||||||
cs,
|
|
||||||
framebuffer::Framebuffer,
|
framebuffer::Framebuffer,
|
||||||
timer,
|
timer,
|
||||||
peripherals.GPIO22,
|
peripherals.GPIO22,
|
||||||
|
|||||||
Reference in New Issue
Block a user