mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
remove screen tearing
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use abi_sys::draw_iter;
|
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};
|
pub use shared::keyboard::{KeyCode, KeyEvent, KeyState, Modifiers};
|
||||||
use talc::*;
|
use talc::*;
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,13 @@ pub static mut CALL_ABI_TABLE: [usize; CallAbiTable::COUNT] = [0; CallAbiTable::
|
|||||||
pub enum CallAbiTable {
|
pub enum CallAbiTable {
|
||||||
Print = 0,
|
Print = 0,
|
||||||
Sleep = 1,
|
Sleep = 1,
|
||||||
DrawIter = 2,
|
LockDisplay = 2,
|
||||||
GetKey = 3,
|
DrawIter = 3,
|
||||||
|
GetKey = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallAbiTable {
|
impl CallAbiTable {
|
||||||
pub const COUNT: usize = 4;
|
pub const COUNT: usize = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PrintAbi = extern "Rust" fn(msg: &str);
|
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<Rgb565>]);
|
pub type DrawIterAbi = extern "Rust" fn(pixels: &[Pixel<Rgb565>]);
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|||||||
@@ -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 embassy_rp::clocks::clk_sys_freq;
|
||||||
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
|
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
|
||||||
use shared::keyboard::KeyEvent;
|
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
|
// ensure the abi and the kernel fn signatures are the same
|
||||||
const _: PrintAbi = print;
|
const _: PrintAbi = print;
|
||||||
const _: SleepAbi = sleep;
|
const _: SleepAbi = sleep;
|
||||||
|
const _: LockDisplay = lock_display;
|
||||||
const _: DrawIterAbi = draw_iter;
|
const _: DrawIterAbi = draw_iter;
|
||||||
const _: GetKeyAbi = get_key;
|
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
|
// TODO: maybe return result
|
||||||
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
pub extern "Rust" fn draw_iter(pixels: &[Pixel<Rgb565>]) {
|
||||||
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
|
unsafe { FRAMEBUFFER.draw_iter(pixels.iter().copied()).unwrap() }
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::framebuffer::AtomicFrameBuffer;
|
use crate::framebuffer::AtomicFrameBuffer;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
Peri,
|
Peri,
|
||||||
@@ -24,6 +26,7 @@ pub const SCREEN_WIDTH: usize = 320;
|
|||||||
pub const SCREEN_HEIGHT: usize = 320;
|
pub const SCREEN_HEIGHT: usize = 320;
|
||||||
|
|
||||||
pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer::new();
|
pub static mut FRAMEBUFFER: AtomicFrameBuffer = AtomicFrameBuffer::new();
|
||||||
|
pub static FB_PAUSED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
pub async fn init_display(
|
pub async fn init_display(
|
||||||
spi: Spi<'static, SPI1, Async>,
|
spi: Spi<'static, SPI1, Async>,
|
||||||
@@ -48,21 +51,17 @@ pub async fn init_display(
|
|||||||
display
|
display
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_fb() {
|
|
||||||
unsafe {
|
|
||||||
FRAMEBUFFER.clear(Rgb565::WHITE).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn display_handler(mut display: DISPLAY) {
|
pub async fn display_handler(mut display: DISPLAY) {
|
||||||
loop {
|
loop {
|
||||||
|
if !FB_PAUSED.load(Ordering::Acquire) {
|
||||||
unsafe {
|
unsafe {
|
||||||
FRAMEBUFFER
|
FRAMEBUFFER
|
||||||
.partial_draw_batched(&mut display)
|
.partial_draw_batched(&mut display)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Timer::after_millis(32).await; // 30 fps
|
Timer::after_millis(32).await; // 30 fps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Result<EntryFn, &str> {
|
|||||||
let entries: &[(CallAbiTable, usize)] = &[
|
let entries: &[(CallAbiTable, usize)] = &[
|
||||||
(CallAbiTable::Print, abi::print as usize),
|
(CallAbiTable::Print, abi::print as usize),
|
||||||
(CallAbiTable::Sleep, abi::sleep as usize),
|
(CallAbiTable::Sleep, abi::sleep as usize),
|
||||||
|
(CallAbiTable::LockDisplay, abi::lock_display as usize),
|
||||||
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
(CallAbiTable::DrawIter, abi::draw_iter as usize),
|
||||||
(CallAbiTable::GetKey, abi::get_key as usize),
|
(CallAbiTable::GetKey, abi::get_key as usize),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ use crate::{
|
|||||||
ui::{SELECTIONS, clear_selection, ui_handler},
|
ui::{SELECTIONS, clear_selection, ui_handler},
|
||||||
};
|
};
|
||||||
use abi_sys::EntryFn;
|
use abi_sys::EntryFn;
|
||||||
use alloc::string::String;
|
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
pixelcolor::Rgb565,
|
pixelcolor::Rgb565,
|
||||||
prelude::{DrawTarget, RgbColor},
|
prelude::{DrawTarget, RgbColor},
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
use crate::{
|
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 alloc::{str::FromStr, string::String, vec::Vec};
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
||||||
use embassy_time::Timer;
|
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
Drawable,
|
Drawable,
|
||||||
mono_font::{
|
mono_font::{MonoTextStyle, ascii::FONT_10X20},
|
||||||
MonoTextStyle,
|
|
||||||
ascii::{FONT_9X15, FONT_10X20},
|
|
||||||
},
|
|
||||||
pixelcolor::Rgb565,
|
pixelcolor::Rgb565,
|
||||||
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
|
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
|
||||||
primitives::{PrimitiveStyle, Rectangle},
|
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";
|
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();
|
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() {
|
if file_names.is_empty() {
|
||||||
TextBox::new(
|
TextBox::new(
|
||||||
&no_bins,
|
&no_bins,
|
||||||
@@ -124,6 +127,7 @@ async fn draw_selection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guard.changed = false;
|
guard.changed = false;
|
||||||
|
FB_PAUSED.store(false, Ordering::Release); // ensure all elements show up at once
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate alloc;
|
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 alloc::{format, string::String, vec, vec::Vec};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
@@ -57,6 +57,8 @@ pub fn main() {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
if dirty {
|
if dirty {
|
||||||
|
lock_display(true);
|
||||||
|
|
||||||
let style = PrimitiveStyle::with_fill(Rgb565::BLACK);
|
let style = PrimitiveStyle::with_fill(Rgb565::BLACK);
|
||||||
if let Some(area) = last_area {
|
if let Some(area) = last_area {
|
||||||
Rectangle::new(area.0.top_left, area.0.size)
|
Rectangle::new(area.0.top_left, area.0.size)
|
||||||
@@ -100,6 +102,7 @@ pub fn main() {
|
|||||||
eq_layout.draw(&mut display).unwrap();
|
eq_layout.draw(&mut display).unwrap();
|
||||||
|
|
||||||
dirty = false;
|
dirty = false;
|
||||||
|
lock_display(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(event) = get_key() {
|
if let Some(event) = get_key() {
|
||||||
|
|||||||
Reference in New Issue
Block a user