From e628c47e4b4d1b478119bd2ebc3fd68199ef2826 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Thu, 18 Sep 2025 19:20:20 -0600 Subject: [PATCH] remove screen tearing --- abi/src/lib.rs | 2 +- abi_sys/src/lib.rs | 18 +++++++++++++++--- kernel/src/abi.rs | 14 ++++++++++++-- kernel/src/display.rs | 21 ++++++++++----------- kernel/src/elf.rs | 1 + kernel/src/main.rs | 1 - kernel/src/ui.rs | 16 ++++++++++------ user-apps/calculator/src/main.rs | 5 ++++- 8 files changed, 53 insertions(+), 25 deletions(-) diff --git a/abi/src/lib.rs b/abi/src/lib.rs index db012a0..f4c8b4c 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] use abi_sys::draw_iter; -pub use abi_sys::{get_key, print, sleep}; +pub use abi_sys::{get_key, lock_display, print, sleep}; pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers}; use talc::*; diff --git a/abi_sys/src/lib.rs b/abi_sys/src/lib.rs index e503c5b..43317da 100644 --- a/abi_sys/src/lib.rs +++ b/abi_sys/src/lib.rs @@ -21,12 +21,13 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable:: pub enum CallAbiTable { Print = 0, Sleep = 1, - DrawIter = 2, - GetKey = 3, + LockDisplay = 2, + DrawIter = 3, + GetKey = 4, } impl CallAbiTable { - pub const COUNT: usize = 4; + pub const COUNT: usize = 5; } pub type PrintAbi = extern "Rust" fn(msg: &str); @@ -51,6 +52,17 @@ pub fn sleep(ms: u64) { } } +pub type LockDisplay = extern "Rust" fn(lock: bool); + +#[allow(unused)] +pub fn lock_display(lock: bool) { + unsafe { + let ptr = CALL_ABI_TABLE[CallAbiTable::LockDisplay as usize]; + let f: LockDisplay = core::mem::transmute(ptr); + f(lock); + } +} + pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel]); #[allow(unused)] diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index 0b59d51..fb17722 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -1,13 +1,19 @@ -use abi_sys::{DrawIterAbi, GetKeyAbi, PrintAbi, SleepAbi}; +use core::sync::atomic::Ordering; + +use abi_sys::{DrawIterAbi, GetKeyAbi, LockDisplay, PrintAbi, SleepAbi}; use embassy_rp::clocks::clk_sys_freq; use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565}; use shared::keyboard::KeyEvent; -use crate::{KEY_CACHE, display::FRAMEBUFFER}; +use crate::{ + KEY_CACHE, + display::{FB_PAUSED, FRAMEBUFFER}, +}; // ensure the abi and the kernel fn signatures are the same const _: PrintAbi = print; const _: SleepAbi = sleep; +const _: LockDisplay = lock_display; const _: DrawIterAbi = draw_iter; const _: GetKeyAbi = get_key; @@ -24,6 +30,10 @@ pub extern "Rust" fn sleep(ms: u64) { } } +pub extern "Rust" fn lock_display(lock: bool) { + FB_PAUSED.store(lock, Ordering::Relaxed); +} + // TODO: maybe return result pub extern "Rust" fn draw_iter(pixels: &[Pixel]) { unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() } diff --git a/kernel/src/display.rs b/kernel/src/display.rs index 1c7e369..a1e0000 100644 --- a/kernel/src/display.rs +++ b/kernel/src/display.rs @@ -1,3 +1,5 @@ +use core::sync::atomic::{AtomicBool, Ordering}; + use crate::framebuffer::AtomicFrameBuffer; use embassy_rp::{ Peri, @@ -24,6 +26,7 @@ pub const SCREEN_WIDTH: usize = 320; pub const SCREEN_HEIGHT: usize = 320; pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer::new(); +pub static FB_PAUSED: AtomicBool = AtomicBool::new(false); pub async fn init_display( spi: Spi<'static, SPI1, Async>, @@ -48,20 +51,16 @@ pub async fn init_display( display } -pub fn clear_fb() { - unsafe { - FRAMEBUFFER.clear(Rgb565::WHITE).unwrap(); - } -} - #[embassy_executor::task] pub async fn display_handler(mut display: DISPLAY) { loop { - unsafe { - FRAMEBUFFER - .partial_draw_batched(&mut display) - .await - .unwrap() + if !FB_PAUSED.load(Ordering::Acquire) { + unsafe { + FRAMEBUFFER + .partial_draw_batched(&mut display) + .await + .unwrap() + } } Timer::after_millis(32).await; // 30 fps diff --git a/kernel/src/elf.rs b/kernel/src/elf.rs index 0c9bd04..608595b 100644 --- a/kernel/src/elf.rs +++ b/kernel/src/elf.rs @@ -54,6 +54,7 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Result { let entries: &[(CallAbiTable, usize)] = &[ (CallAbiTable::Print, abi::print as usize), (CallAbiTable::Sleep, abi::sleep as usize), + (CallAbiTable::LockDisplay, abi::lock_display as usize), (CallAbiTable::DrawIter, abi::draw_iter as usize), (CallAbiTable::GetKey, abi::get_key as usize), ]; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index f9f160c..2de46c4 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -29,7 +29,6 @@ use crate::{ ui::{SELECTIONS, clear_selection, ui_handler}, }; use abi_sys::EntryFn; -use alloc::string::String; use embedded_graphics::{ pixelcolor::Rgb565, prelude::{DrawTarget, RgbColor}, diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index a7372e1..c7efd85 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -1,15 +1,16 @@ use crate::{ - BINARY_CH, display::FRAMEBUFFER, elf::load_binary, peripherals::keyboard, storage::FileName, + BINARY_CH, + display::{FB_PAUSED, FRAMEBUFFER}, + elf::load_binary, + peripherals::keyboard, + storage::FileName, }; use alloc::{str::FromStr, string::String, vec::Vec}; +use core::sync::atomic::Ordering; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex}; -use embassy_time::Timer; use embedded_graphics::{ Drawable, - mono_font::{ - MonoTextStyle, - ascii::{FONT_9X15, FONT_10X20}, - }, + mono_font::{MonoTextStyle, ascii::FONT_10X20}, pixelcolor::Rgb565, prelude::{Dimensions, Point, Primitive, RgbColor, Size}, primitives::{PrimitiveStyle, Rectangle}, @@ -81,6 +82,8 @@ async fn draw_selection() { const NO_BINS: &str = "No Programs found on SD Card. Ensure programs end with '.bin', and are located in the root directory"; let no_bins = String::from_str(NO_BINS).unwrap(); + FB_PAUSED.store(true, Ordering::Release); // ensure all elements show up at once + if file_names.is_empty() { TextBox::new( &no_bins, @@ -124,6 +127,7 @@ async fn draw_selection() { } guard.changed = false; + FB_PAUSED.store(false, Ordering::Release); // ensure all elements show up at once } #[derive(Clone)] diff --git a/user-apps/calculator/src/main.rs b/user-apps/calculator/src/main.rs index f66f5e3..dfe45c0 100644 --- a/user-apps/calculator/src/main.rs +++ b/user-apps/calculator/src/main.rs @@ -2,7 +2,7 @@ #![no_main] extern crate alloc; -use abi::{KeyCode, display::Display, get_key, print}; +use abi::{KeyCode, display::Display, get_key, lock_display, print}; use alloc::{format, string::String, vec, vec::Vec}; use core::panic::PanicInfo; use embedded_graphics::{ @@ -57,6 +57,8 @@ pub fn main() { loop { if dirty { + lock_display(true); + let style = PrimitiveStyle::with_fill(Rgb565::BLACK); if let Some(area) = last_area { Rectangle::new(area.0.top_left, area.0.size) @@ -100,6 +102,7 @@ pub fn main() { eq_layout.draw(&mut display).unwrap(); dirty = false; + lock_display(false); } if let Some(event) = get_key() {