gif plays at low fps

This commit is contained in:
2025-10-27 18:53:22 -06:00
parent 999b22a96f
commit 4c58f66c94
14 changed files with 121 additions and 85 deletions

View File

@@ -3,7 +3,7 @@ use abi_sys::{
LockDisplay, PrintAbi, ReadFile, RngRequest, SleepMsAbi, keyboard::*,
};
use alloc::{string::ToString, vec::Vec};
use core::sync::atomic::Ordering;
use core::{alloc::GlobalAlloc, sync::atomic::Ordering};
use embassy_rp::clocks::{RoscRng, clk_sys_freq};
use embassy_time::Instant;
use embedded_graphics::draw_target::DrawTarget;
@@ -18,13 +18,25 @@ use crate::{
const _: AllocAbi = alloc;
pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
// SAFETY: caller guarantees layout is valid
unsafe { alloc::alloc::alloc(layout.into()) }
unsafe {
if cfg!(feature = "pimoroni2w") {
crate::heap::HEAP.alloc(layout.into())
} else {
alloc::alloc::alloc(layout.into())
}
}
}
const _: DeallocAbi = dealloc;
pub extern "C" fn dealloc(ptr: *mut u8, layout: CLayout) {
// SAFETY: caller guarantees ptr and layout are valid
unsafe { alloc::alloc::dealloc(ptr, layout.into()) };
unsafe {
if cfg!(feature = "pimoroni2w") {
crate::heap::HEAP.dealloc(ptr, layout.into())
} else {
alloc::alloc::dealloc(ptr, layout.into())
}
}
}
const _: PrintAbi = print;
@@ -66,7 +78,6 @@ pub extern "C" fn lock_display(lock: bool) {
}
const _: DrawIterAbi = draw_iter;
// TODO: maybe return result
pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let cpixels = unsafe { core::slice::from_raw_parts(cpixels, len) };

View File

@@ -6,7 +6,6 @@ use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicUsize, Ordering};
use embedded_alloc::LlffHeap as Heap;
#[global_allocator]
pub static HEAP: DualHeap = DualHeap::empty();
const HEAP_SIZE: usize = 64 * 1024;
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];

View File

@@ -10,7 +10,6 @@ mod abi;
mod display;
mod elf;
mod framebuffer;
#[cfg(feature = "pimoroni2w")]
mod heap;
mod peripherals;
mod psram;
@@ -37,13 +36,6 @@ use crate::{
};
use abi_sys::EntryFn;
use bumpalo::Bump;
use embedded_graphics::{
pixelcolor::Rgb565,
prelude::{DrawTarget, RgbColor},
};
use {defmt_rtt as _, panic_probe as _};
use core::sync::atomic::{AtomicBool, Ordering};
use embassy_executor::{Executor, Spawner};
use embassy_futures::{join::join, select::select};
@@ -55,20 +47,26 @@ use embassy_rp::{
peripherals::{
DMA_CH0, DMA_CH1, DMA_CH3, DMA_CH4, I2C1, PIN_2, PIN_3, PIN_6, PIN_7, PIN_10, PIN_11,
PIN_12, PIN_13, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, PIN_20, PIN_21, PIN_22,
PIO0, SPI0, SPI1, USB,
PIO0, SPI0, SPI1, USB, WATCHDOG,
},
pio,
spi::{self, Spi},
usb as embassy_rp_usb,
watchdog::{ResetReason, Watchdog},
};
use embassy_sync::{
blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, signal::Signal,
};
use embassy_time::{Delay, Instant, Timer};
use embassy_time::{Delay, Duration, Instant, Ticker, Timer};
use embedded_graphics::{
pixelcolor::Rgb565,
prelude::{DrawTarget, RgbColor},
};
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard as SdmmcSdCard;
use static_cell::StaticCell;
use talc::*;
use {defmt_rtt as _, panic_probe as _};
embassy_rp::bind_interrupts!(struct Irqs {
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
@@ -80,15 +78,32 @@ static mut CORE1_STACK: Stack<16384> = Stack::new();
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
#[cfg(not(feature = "pimoroni2w"))]
static mut ARENA: [u8; 200 * 1024] = [0; 200 * 1024];
static mut ARENA: [u8; 250 * 1024] = [0; 250 * 1024];
#[cfg(not(feature = "pimoroni2w"))]
#[global_allocator]
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
.lock();
#[embassy_executor::task]
async fn watchdog_task(mut watchdog: Watchdog) {
if let Some(reason) = watchdog.reset_reason() {
let reason = match reason {
ResetReason::Forced => "forced",
ResetReason::TimedOut => "timed out",
};
defmt::error!("Watchdog reset reason: {}", reason);
}
watchdog.start(Duration::from_secs(3));
let mut ticker = Ticker::every(Duration::from_secs(2));
loop {
watchdog.feed();
ticker.next().await;
}
}
static ENABLE_UI: AtomicBool = AtomicBool::new(true);
static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
@@ -141,7 +156,9 @@ async fn main(_spawner: Spawner) {
let executor0 = EXECUTOR0.init(Executor::new());
executor0.run(|spawner| {
spawner
.spawn(kernel_task(spawner, display, sd, psram, mcu, p.USB))
.spawn(kernel_task(
spawner, p.WATCHDOG, display, sd, psram, mcu, p.USB,
))
.unwrap()
});
}
@@ -244,26 +261,36 @@ async fn setup_display(display: Display, spawner: Spawner) {
// psram is kind of useless on the pico calc
// ive opted to use the pimoroni with on onboard xip psram instead
async fn setup_psram(psram: Psram) {
// let psram = init_psram(
// psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
// )
// .await;
let psram = init_psram(
psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
)
.await;
// #[cfg(feature = "defmt")]
// defmt::info!("psram size: {}", psram.size);
#[cfg(feature = "defmt")]
defmt::info!("psram size: {}", psram.size);
// if psram.size == 0 {
// #[cfg(feature = "defmt")]
// defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m");
// }
if psram.size == 0 {
#[cfg(feature = "defmt")]
defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m");
}
}
#[cfg(feature = "pimoroni2w")]
{
#[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);
defmt::info!("size: {}", psram_qmi_size);
Timer::after_millis(100).await;
if psram_qmi_size > 0 {
init_qmi_psram_heap(psram_qmi_size);
return;
}
defmt::info!("failed to init qmi psram... trying again");
tries -= 1;
}
panic!("qmi psram not initialized");
}
async fn setup_sd(sd: Sd) {
@@ -284,22 +311,27 @@ async fn setup_sd(sd: Sd) {
#[embassy_executor::task]
async fn kernel_task(
spawner: Spawner,
watchdog: Peri<'static, WATCHDOG>,
display: Display,
sd: Sd,
psram: Psram,
mcu: Mcu,
usb: Peri<'static, USB>,
) {
spawner
.spawn(watchdog_task(Watchdog::new(watchdog)))
.unwrap();
setup_mcu(mcu).await;
Timer::after_millis(250).await;
setup_display(display, spawner).await;
#[cfg(feature = "pimoroni2w")]
setup_psram(psram).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 {

View File

@@ -526,16 +526,10 @@ pub fn init_psram_qmi(
let psram_size = detect_psram_qmi(qmi);
if psram_size == 0 {
defmt::error!("qmi psram size 0");
return 0;
}
// Set PSRAM timing for APS6404
//
// Using an rxdelay equal to the divisor isn't enough when running the APS6404 close to 133MHz.
// So: don't allow running at divisor 1 above 100MHz (because delay of 2 would be too late),
// and add an extra 1 to the rxdelay if the divided clock is > 100MHz (i.e. sys clock > 200MHz).
const MAX_PSRAM_FREQ: u32 = 133_000_000;
let clock_hz = clk_peri_freq();
let mut divisor: u32 = (clock_hz + MAX_PSRAM_FREQ - 1) / MAX_PSRAM_FREQ;