diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 607c8f6..d890cba 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -11,7 +11,7 @@ doctest = false bench = false [features] -default = ["rp235x", "defmt", "pimoroni2w"] +default = ["rp235x", "defmt"] pimoroni2w = ["rp235x"] rp2040 = ["embassy-rp/rp2040"] rp235x = ["embassy-rp/rp235xb"] diff --git a/kernel/src/abi.rs b/kernel/src/abi.rs index e6c522e..9f64223 100644 --- a/kernel/src/abi.rs +++ b/kernel/src/abi.rs @@ -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()); 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); } diff --git a/kernel/src/display.rs b/kernel/src/display.rs index 10dd70a..c576c06 100644 --- a/kernel/src/display.rs +++ b/kernel/src/display.rs @@ -1,6 +1,6 @@ use crate::framebuffer::{self, AtomicFrameBuffer, FB_PAUSED}; -use alloc::vec; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::alloc::{GlobalAlloc, Layout}; +use core::sync::atomic::Ordering; use embassy_rp::{ Peri, gpio::{Level, Output}, @@ -8,8 +8,11 @@ use embassy_rp::{ spi::{Async, Spi}, }; use embassy_time::{Delay, Timer}; +use embedded_graphics::{ + pixelcolor::Rgb565, + prelude::{DrawTarget, RgbColor}, +}; use embedded_hal_bus::spi::ExclusiveDevice; -use once_cell::unsync::Lazy; use st7365p_lcd::ST7365P; type DISPLAY = ST7365P< @@ -22,10 +25,24 @@ type DISPLAY = ST7365P< pub const SCREEN_WIDTH: usize = 320; pub const SCREEN_HEIGHT: usize = 320; -pub static mut FRAMEBUFFER: Lazy = Lazy::new(|| { - static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE]; - AtomicFrameBuffer::new(unsafe { &mut BUF }) -}); +pub static mut FRAMEBUFFER: Option = None; + +fn init_fb() { + unsafe { + FRAMEBUFFER = Some(if cfg!(not(feature = "pimoroni2w")) { + static mut BUF: [u16; framebuffer::SIZE] = [0; framebuffer::SIZE]; + AtomicFrameBuffer::new(&mut BUF) + } else { + let slab = crate::heap::HEAP.alloc(Layout::array::(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( spi: Spi<'static, SPI1, Async>, @@ -33,6 +50,8 @@ pub async fn init_display( data: Peri<'static, PIN_14>, reset: Peri<'static, PIN_15>, ) -> DISPLAY { + init_fb(); + let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap(); let mut display = ST7365P::new( spi_device, @@ -44,7 +63,14 @@ pub async fn init_display( ); display.init().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 @@ -54,7 +80,14 @@ pub async fn init_display( pub async fn display_handler(mut display: DISPLAY) { loop { 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 diff --git a/kernel/src/main.rs b/kernel/src/main.rs index c9c6387..20f36f8 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -80,7 +80,10 @@ static mut CORE1_STACK: Stack<16384> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); +#[cfg(not(feature = "pimoroni2w"))] static mut ARENA: [u8; 250 * 1024] = [0; 250 * 1024]; +#[cfg(feature = "pimoroni2w")] +static mut ARENA: [u8; 400 * 1024] = [0; 400 * 1024]; #[global_allocator] static ALLOCATOR: Talck, ClaimOnOom> = @@ -90,12 +93,12 @@ static ALLOCATOR: Talck, ClaimOnOom> = #[embassy_executor::task] async fn watchdog_task(mut watchdog: Watchdog) { if let Some(reason) = watchdog.reset_reason() { - let reason = match reason { + let _reason = match reason { ResetReason::Forced => "forced", ResetReason::TimedOut => "timed out", }; #[cfg(feature = "debug")] - defmt::error!("Watchdog reset reason: {}", reason); + defmt::error!("Watchdog reset reason: {}", _reason); } watchdog.start(Duration::from_secs(3)); @@ -195,7 +198,7 @@ async fn userland_task() { { ENABLE_UI.store(true, Ordering::Release); UI_CHANGE.signal(()); - unsafe { FRAMEBUFFER.clear(Rgb565::BLACK).unwrap() }; + unsafe { FRAMEBUFFER.as_mut().unwrap().clear(Rgb565::BLACK).unwrap() }; let mut selections = SELECTIONS.lock().await; selections.set_changed(true); @@ -280,22 +283,18 @@ async fn setup_psram(psram: Psram) { #[cfg(feature = "pimoroni2w")] async fn setup_qmi_psram() { - let mut tries = 5; Timer::after_millis(250).await; - while tries > 1 { - let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL); - #[cfg(feature = "debug")] - defmt::info!("size: {}", psram_qmi_size); - Timer::after_millis(100).await; - if psram_qmi_size > 0 { - init_qmi_psram_heap(psram_qmi_size); - return; - } - #[cfg(feature = "debug")] - defmt::info!("failed to init qmi psram... trying again"); - tries -= 1; + let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL); + #[cfg(feature = "debug")] + defmt::info!("size: {}", psram_qmi_size); + Timer::after_millis(100).await; + + if psram_qmi_size > 0 { + init_qmi_psram_heap(psram_qmi_size); + return; + } else { + panic!("qmi psram not initialized"); } - panic!("qmi psram not initialized"); } async fn setup_sd(sd: Sd) { @@ -326,17 +325,19 @@ async fn kernel_task( spawner .spawn(watchdog_task(Watchdog::new(watchdog))) .unwrap(); + setup_mcu(mcu).await; + + // setup_psram(psram).await; + #[cfg(feature = "pimoroni2w")] + setup_qmi_psram().await; + setup_display(display, spawner).await; setup_sd(sd).await; let _usb = embassy_rp_usb::Driver::new(usb, Irqs); // spawner.spawn(usb_handler(usb)).unwrap(); - // setup_psram(psram).await; - #[cfg(feature = "pimoroni2w")] - setup_qmi_psram().await; - loop { let ui_enabled = ENABLE_UI.load(Ordering::Relaxed); if ui_enabled { diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index 64f81f6..dc6017c 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -68,7 +68,7 @@ pub async fn clear_selection() { if let Some(area) = sel.last_bounds { Rectangle::new(area.top_left, area.size) .into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK)) - .draw(unsafe { &mut *FRAMEBUFFER }) + .draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() }) .unwrap(); } } @@ -78,7 +78,7 @@ async fn draw_selection() { let file_names = &guard.selections.clone(); 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"; let no_bins = String::from_str(NO_BINS).unwrap(); @@ -94,7 +94,7 @@ async fn draw_selection() { ), text_style, ) - .draw(unsafe { &mut *FRAMEBUFFER }) + .draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() }) .unwrap(); } else { let mut views: alloc::vec::Vec>> = Vec::new(); @@ -119,12 +119,14 @@ async fn draw_selection() { .bounding_box(); Rectangle::new(selected_bounds.top_left, selected_bounds.size) .into_styled(PrimitiveStyle::with_stroke(Rgb565::WHITE, 1)) - .draw(unsafe { &mut *FRAMEBUFFER }) + .draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() }) .unwrap(); guard.last_bounds = Some(layout.bounds()); - layout.draw(unsafe { &mut *FRAMEBUFFER }).unwrap(); + layout + .draw(unsafe { &mut *FRAMEBUFFER.as_mut().unwrap() }) + .unwrap(); } guard.changed = false;