mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 07:45:28 +00:00
move fb to psram to save 200KB for user apps
This commit is contained in:
@@ -81,7 +81,7 @@ pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) {
|
|||||||
let iter = cpixels.iter().copied().map(|c: CPixel| c.into());
|
let iter = cpixels.iter().copied().map(|c: CPixel| c.into());
|
||||||
|
|
||||||
FB_PAUSED.store(true, Ordering::Release);
|
FB_PAUSED.store(true, Ordering::Release);
|
||||||
unsafe { FRAMEBUFFER.draw_iter(iter).unwrap() }
|
unsafe { FRAMEBUFFER.as_mut().unwrap().draw_iter(iter).unwrap() }
|
||||||
FB_PAUSED.store(false, Ordering::Release);
|
FB_PAUSED.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::framebuffer::{self, AtomicFrameBuffer, FB_PAUSED};
|
use crate::framebuffer::{self, AtomicFrameBuffer, FB_PAUSED};
|
||||||
use alloc::vec;
|
use core::sync::atomic::Ordering;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
Peri,
|
Peri,
|
||||||
gpio::{Level, Output},
|
gpio::{Level, Output},
|
||||||
@@ -9,9 +8,16 @@ use embassy_rp::{
|
|||||||
};
|
};
|
||||||
use embassy_time::{Delay, Timer};
|
use embassy_time::{Delay, Timer};
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use once_cell::unsync::Lazy;
|
|
||||||
use st7365p_lcd::ST7365P;
|
use st7365p_lcd::ST7365P;
|
||||||
|
|
||||||
|
#[cfg(feature = "pimoroni2w")]
|
||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
#[cfg(feature = "pimoroni2w")]
|
||||||
|
use embedded_graphics::{
|
||||||
|
pixelcolor::Rgb565,
|
||||||
|
prelude::{DrawTarget, RgbColor},
|
||||||
|
};
|
||||||
|
|
||||||
type DISPLAY = ST7365P<
|
type DISPLAY = ST7365P<
|
||||||
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
|
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
|
||||||
Output<'static>,
|
Output<'static>,
|
||||||
@@ -22,10 +28,24 @@ type DISPLAY = ST7365P<
|
|||||||
pub const SCREEN_WIDTH: usize = 320;
|
pub const SCREEN_WIDTH: usize = 320;
|
||||||
pub const SCREEN_HEIGHT: usize = 320;
|
pub const SCREEN_HEIGHT: usize = 320;
|
||||||
|
|
||||||
pub static mut FRAMEBUFFER: Lazy<AtomicFrameBuffer> = Lazy::new(|| {
|
pub static mut FRAMEBUFFER: Option<AtomicFrameBuffer> = None;
|
||||||
|
|
||||||
|
fn init_fb() {
|
||||||
|
unsafe {
|
||||||
|
FRAMEBUFFER = Some(if cfg!(not(feature = "pimoroni2w")) {
|
||||||
static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE];
|
static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE];
|
||||||
AtomicFrameBuffer::new(unsafe { &mut BUF })
|
AtomicFrameBuffer::new(&mut BUF)
|
||||||
|
} else {
|
||||||
|
let slab = crate::heap::HEAP.alloc(Layout::array::<u16>(framebuffer::SIZE).unwrap())
|
||||||
|
as *mut u16;
|
||||||
|
let buf = core::slice::from_raw_parts_mut(slab, framebuffer::SIZE);
|
||||||
|
|
||||||
|
let mut fb = AtomicFrameBuffer::new(buf);
|
||||||
|
fb.clear(Rgb565::BLACK).unwrap();
|
||||||
|
fb
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn init_display(
|
pub async fn init_display(
|
||||||
spi: Spi<'static, SPI1, Async>,
|
spi: Spi<'static, SPI1, Async>,
|
||||||
@@ -33,6 +53,8 @@ pub async fn init_display(
|
|||||||
data: Peri<'static, PIN_14>,
|
data: Peri<'static, PIN_14>,
|
||||||
reset: Peri<'static, PIN_15>,
|
reset: Peri<'static, PIN_15>,
|
||||||
) -> DISPLAY {
|
) -> DISPLAY {
|
||||||
|
init_fb();
|
||||||
|
|
||||||
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
|
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
|
||||||
let mut display = ST7365P::new(
|
let mut display = ST7365P::new(
|
||||||
spi_device,
|
spi_device,
|
||||||
@@ -44,7 +66,14 @@ pub async fn init_display(
|
|||||||
);
|
);
|
||||||
display.init().await.unwrap();
|
display.init().await.unwrap();
|
||||||
display.set_custom_orientation(0x40).await.unwrap();
|
display.set_custom_orientation(0x40).await.unwrap();
|
||||||
unsafe { FRAMEBUFFER.draw(&mut display).await.unwrap() }
|
unsafe {
|
||||||
|
FRAMEBUFFER
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.draw(&mut display)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
display.set_on().await.unwrap();
|
display.set_on().await.unwrap();
|
||||||
|
|
||||||
display
|
display
|
||||||
@@ -54,7 +83,14 @@ pub async fn init_display(
|
|||||||
pub async fn display_handler(mut display: DISPLAY) {
|
pub async fn display_handler(mut display: DISPLAY) {
|
||||||
loop {
|
loop {
|
||||||
if !FB_PAUSED.load(Ordering::Acquire) {
|
if !FB_PAUSED.load(Ordering::Acquire) {
|
||||||
unsafe { FRAMEBUFFER.safe_draw(&mut display).await.unwrap() };
|
unsafe {
|
||||||
|
FRAMEBUFFER
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.safe_draw(&mut display)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// small yield to allow other tasks to run
|
// small yield to allow other tasks to run
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ static mut CORE1_STACK: Stack<16384> = Stack::new();
|
|||||||
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
|
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
|
||||||
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
|
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
|
||||||
|
|
||||||
static mut ARENA: [u8; 250 * 1024] = [0; 250 * 1024];
|
static mut ARENA: [u8; 400 * 1024] = [0; 400 * 1024];
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
||||||
@@ -90,12 +90,12 @@ static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
|||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn watchdog_task(mut watchdog: Watchdog) {
|
async fn watchdog_task(mut watchdog: Watchdog) {
|
||||||
if let Some(reason) = watchdog.reset_reason() {
|
if let Some(reason) = watchdog.reset_reason() {
|
||||||
let reason = match reason {
|
let _reason = match reason {
|
||||||
ResetReason::Forced => "forced",
|
ResetReason::Forced => "forced",
|
||||||
ResetReason::TimedOut => "timed out",
|
ResetReason::TimedOut => "timed out",
|
||||||
};
|
};
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
defmt::error!("Watchdog reset reason: {}", reason);
|
defmt::error!("Watchdog reset reason: {}", _reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
watchdog.start(Duration::from_secs(3));
|
watchdog.start(Duration::from_secs(3));
|
||||||
@@ -195,7 +195,7 @@ async fn userland_task() {
|
|||||||
{
|
{
|
||||||
ENABLE_UI.store(true, Ordering::Release);
|
ENABLE_UI.store(true, Ordering::Release);
|
||||||
UI_CHANGE.signal(());
|
UI_CHANGE.signal(());
|
||||||
unsafe { FRAMEBUFFER.clear(Rgb565::BLACK).unwrap() };
|
unsafe { FRAMEBUFFER.as_mut().unwrap().clear(Rgb565::BLACK).unwrap() };
|
||||||
|
|
||||||
let mut selections = SELECTIONS.lock().await;
|
let mut selections = SELECTIONS.lock().await;
|
||||||
selections.set_changed(true);
|
selections.set_changed(true);
|
||||||
@@ -280,23 +280,19 @@ async fn setup_psram(psram: Psram) {
|
|||||||
|
|
||||||
#[cfg(feature = "pimoroni2w")]
|
#[cfg(feature = "pimoroni2w")]
|
||||||
async fn setup_qmi_psram() {
|
async fn setup_qmi_psram() {
|
||||||
let mut tries = 5;
|
|
||||||
Timer::after_millis(250).await;
|
Timer::after_millis(250).await;
|
||||||
while tries > 1 {
|
|
||||||
let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL);
|
let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL);
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
defmt::info!("size: {}", psram_qmi_size);
|
defmt::info!("size: {}", psram_qmi_size);
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
if psram_qmi_size > 0 {
|
if psram_qmi_size > 0 {
|
||||||
init_qmi_psram_heap(psram_qmi_size);
|
init_qmi_psram_heap(psram_qmi_size);
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
defmt::info!("failed to init qmi psram... trying again");
|
|
||||||
tries -= 1;
|
|
||||||
}
|
|
||||||
panic!("qmi psram not initialized");
|
panic!("qmi psram not initialized");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn setup_sd(sd: Sd) {
|
async fn setup_sd(sd: Sd) {
|
||||||
let mut config = spi::Config::default();
|
let mut config = spi::Config::default();
|
||||||
@@ -326,17 +322,19 @@ async fn kernel_task(
|
|||||||
spawner
|
spawner
|
||||||
.spawn(watchdog_task(Watchdog::new(watchdog)))
|
.spawn(watchdog_task(Watchdog::new(watchdog)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
setup_mcu(mcu).await;
|
setup_mcu(mcu).await;
|
||||||
|
|
||||||
|
// setup_psram(psram).await;
|
||||||
|
#[cfg(feature = "pimoroni2w")]
|
||||||
|
setup_qmi_psram().await;
|
||||||
|
|
||||||
setup_display(display, spawner).await;
|
setup_display(display, spawner).await;
|
||||||
setup_sd(sd).await;
|
setup_sd(sd).await;
|
||||||
|
|
||||||
let _usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
let _usb = embassy_rp_usb::Driver::new(usb, Irqs);
|
||||||
// spawner.spawn(usb_handler(usb)).unwrap();
|
// spawner.spawn(usb_handler(usb)).unwrap();
|
||||||
|
|
||||||
// setup_psram(psram).await;
|
|
||||||
#[cfg(feature = "pimoroni2w")]
|
|
||||||
setup_qmi_psram().await;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let ui_enabled = ENABLE_UI.load(Ordering::Relaxed);
|
let ui_enabled = ENABLE_UI.load(Ordering::Relaxed);
|
||||||
if ui_enabled {
|
if ui_enabled {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub async fn clear_selection() {
|
|||||||
if let Some(area) = sel.last_bounds {
|
if let Some(area) = sel.last_bounds {
|
||||||
Rectangle::new(area.top_left, area.size)
|
Rectangle::new(area.top_left, area.size)
|
||||||
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
|
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
|
||||||
.draw(unsafe { &mut *FRAMEBUFFER })
|
.draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ async fn draw_selection() {
|
|||||||
let file_names = &guard.selections.clone();
|
let file_names = &guard.selections.clone();
|
||||||
|
|
||||||
let text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
let text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
|
||||||
let display_area = unsafe { FRAMEBUFFER.bounding_box() };
|
let display_area = unsafe { FRAMEBUFFER.as_mut().unwrap().bounding_box() };
|
||||||
|
|
||||||
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();
|
||||||
@@ -94,7 +94,7 @@ async fn draw_selection() {
|
|||||||
),
|
),
|
||||||
text_style,
|
text_style,
|
||||||
)
|
)
|
||||||
.draw(unsafe { &mut *FRAMEBUFFER })
|
.draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let mut views: alloc::vec::Vec<Text<MonoTextStyle<Rgb565>>> = Vec::new();
|
let mut views: alloc::vec::Vec<Text<MonoTextStyle<Rgb565>>> = Vec::new();
|
||||||
@@ -119,12 +119,14 @@ async fn draw_selection() {
|
|||||||
.bounding_box();
|
.bounding_box();
|
||||||
Rectangle::new(selected_bounds.top_left, selected_bounds.size)
|
Rectangle::new(selected_bounds.top_left, selected_bounds.size)
|
||||||
.into_styled(PrimitiveStyle::with_stroke(Rgb565::WHITE, 1))
|
.into_styled(PrimitiveStyle::with_stroke(Rgb565::WHITE, 1))
|
||||||
.draw(unsafe { &mut *FRAMEBUFFER })
|
.draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
guard.last_bounds = Some(layout.bounds());
|
guard.last_bounds = Some(layout.bounds());
|
||||||
|
|
||||||
layout.draw(unsafe { &mut *FRAMEBUFFER }).unwrap();
|
layout
|
||||||
|
.draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() })
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
guard.changed = false;
|
guard.changed = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user