mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-27 15:55:25 +00:00
gif plays at low fps
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -19,6 +19,7 @@ dependencies = [
|
|||||||
"abi_sys",
|
"abi_sys",
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"embedded-sdmmc",
|
"embedded-sdmmc",
|
||||||
|
"once_cell",
|
||||||
"rand_core 0.9.3",
|
"rand_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ codegen-units = 1
|
|||||||
|
|
||||||
[profile.release-binary]
|
[profile.release-binary]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
codegen-units = 1
|
||||||
lto = true
|
lto = true
|
||||||
debug = false
|
debug = false
|
||||||
opt-level = "s"
|
opt-level = "z"
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ edition = "2024"
|
|||||||
embedded-sdmmc = { version = "0.9.0", default-features = false }
|
embedded-sdmmc = { version = "0.9.0", default-features = false }
|
||||||
embedded-graphics = "0.8.1"
|
embedded-graphics = "0.8.1"
|
||||||
abi_sys = { path = "../abi_sys" }
|
abi_sys = { path = "../abi_sys" }
|
||||||
|
once_cell = { version = "1", default-features = false }
|
||||||
rand_core = "0.9.3"
|
rand_core = "0.9.3"
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![allow(static_mut_refs)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub use abi_sys::keyboard;
|
pub use abi_sys::{self, keyboard};
|
||||||
use abi_sys::{RngRequest, alloc, dealloc, keyboard::KeyEvent};
|
use abi_sys::{RngRequest, alloc, dealloc, keyboard::KeyEvent};
|
||||||
|
pub use alloc::format;
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
|
|
||||||
@@ -22,8 +24,12 @@ unsafe impl GlobalAlloc for Alloc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(msg: &str) {
|
#[macro_export]
|
||||||
abi_sys::print(msg.as_ptr(), msg.len());
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
let s = $crate::format!($($arg)*);
|
||||||
|
$crate::abi_sys::print(s.as_ptr(), s.len());
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sleep(ms: u64) {
|
pub fn sleep(ms: u64) {
|
||||||
@@ -40,6 +46,7 @@ pub fn get_key() -> KeyEvent {
|
|||||||
|
|
||||||
pub mod display {
|
pub mod display {
|
||||||
use abi_sys::CPixel;
|
use abi_sys::CPixel;
|
||||||
|
use alloc::{vec, vec::Vec};
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
Pixel,
|
Pixel,
|
||||||
geometry::{Dimensions, Point},
|
geometry::{Dimensions, Point},
|
||||||
@@ -47,6 +54,7 @@ pub mod display {
|
|||||||
prelude::{DrawTarget, Size},
|
prelude::{DrawTarget, Size},
|
||||||
primitives::Rectangle,
|
primitives::Rectangle,
|
||||||
};
|
};
|
||||||
|
use once_cell::unsync::Lazy;
|
||||||
|
|
||||||
pub const SCREEN_WIDTH: usize = 320;
|
pub const SCREEN_WIDTH: usize = 320;
|
||||||
pub const SCREEN_HEIGHT: usize = 320;
|
pub const SCREEN_HEIGHT: usize = 320;
|
||||||
@@ -57,7 +65,9 @@ pub mod display {
|
|||||||
abi_sys::lock_display(lock);
|
abi_sys::lock_display(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BUF_SIZE: usize = 1024; // tune this for performance
|
const BUF_SIZE: usize = 250 * 1024; // tune this for performance
|
||||||
|
// static mut BUF: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE];
|
||||||
|
static mut BUF: Lazy<Vec<CPixel>> = Lazy::new(|| vec![const { CPixel::new() }; BUF_SIZE]);
|
||||||
|
|
||||||
pub struct Display;
|
pub struct Display;
|
||||||
|
|
||||||
@@ -81,21 +91,19 @@ pub mod display {
|
|||||||
where
|
where
|
||||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||||
{
|
{
|
||||||
let mut buf: [CPixel; BUF_SIZE] = [CPixel::new(); BUF_SIZE];
|
|
||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
for p in pixels {
|
for p in pixels {
|
||||||
buf[count] = p.into();
|
unsafe { BUF[count] = p.into() };
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
||||||
if count == BUF_SIZE {
|
if count == BUF_SIZE {
|
||||||
abi_sys::draw_iter(buf.as_ptr(), count);
|
abi_sys::draw_iter(unsafe { BUF.as_ptr() }, count);
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
abi_sys::draw_iter(buf.as_ptr(), count);
|
abi_sys::draw_iter(unsafe { BUF.as_ptr() }, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ pub struct CPixel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CPixel {
|
impl CPixel {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use abi_sys::{
|
|||||||
LockDisplay, PrintAbi, ReadFile, RngRequest, SleepMsAbi, keyboard::*,
|
LockDisplay, PrintAbi, ReadFile, RngRequest, SleepMsAbi, keyboard::*,
|
||||||
};
|
};
|
||||||
use alloc::{string::ToString, vec::Vec};
|
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_rp::clocks::{RoscRng, clk_sys_freq};
|
||||||
use embassy_time::Instant;
|
use embassy_time::Instant;
|
||||||
use embedded_graphics::draw_target::DrawTarget;
|
use embedded_graphics::draw_target::DrawTarget;
|
||||||
@@ -18,13 +18,25 @@ use crate::{
|
|||||||
const _: AllocAbi = alloc;
|
const _: AllocAbi = alloc;
|
||||||
pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
|
pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
|
||||||
// SAFETY: caller guarantees layout is valid
|
// 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;
|
const _: DeallocAbi = dealloc;
|
||||||
pub extern "C" fn dealloc(ptr: *mut u8, layout: CLayout) {
|
pub extern "C" fn dealloc(ptr: *mut u8, layout: CLayout) {
|
||||||
// SAFETY: caller guarantees ptr and layout are valid
|
// 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;
|
const _: PrintAbi = print;
|
||||||
@@ -66,7 +78,6 @@ pub extern "C" fn lock_display(lock: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _: DrawIterAbi = draw_iter;
|
const _: DrawIterAbi = draw_iter;
|
||||||
// TODO: maybe return result
|
|
||||||
pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) {
|
pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) {
|
||||||
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
|
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
|
||||||
let cpixels = unsafe { core::slice::from_raw_parts(cpixels, len) };
|
let cpixels = unsafe { core::slice::from_raw_parts(cpixels, len) };
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use core::mem::MaybeUninit;
|
|||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use embedded_alloc::LlffHeap as Heap;
|
use embedded_alloc::LlffHeap as Heap;
|
||||||
|
|
||||||
#[global_allocator]
|
|
||||||
pub static HEAP: DualHeap = DualHeap::empty();
|
pub static HEAP: DualHeap = DualHeap::empty();
|
||||||
const HEAP_SIZE: usize = 64 * 1024;
|
const HEAP_SIZE: usize = 64 * 1024;
|
||||||
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ mod abi;
|
|||||||
mod display;
|
mod display;
|
||||||
mod elf;
|
mod elf;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
#[cfg(feature = "pimoroni2w")]
|
|
||||||
mod heap;
|
mod heap;
|
||||||
mod peripherals;
|
mod peripherals;
|
||||||
mod psram;
|
mod psram;
|
||||||
@@ -37,13 +36,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use abi_sys::EntryFn;
|
use abi_sys::EntryFn;
|
||||||
use bumpalo::Bump;
|
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 core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use embassy_executor::{Executor, Spawner};
|
use embassy_executor::{Executor, Spawner};
|
||||||
use embassy_futures::{join::join, select::select};
|
use embassy_futures::{join::join, select::select};
|
||||||
@@ -55,20 +47,26 @@ use embassy_rp::{
|
|||||||
peripherals::{
|
peripherals::{
|
||||||
DMA_CH0, DMA_CH1, DMA_CH3, DMA_CH4, I2C1, PIN_2, PIN_3, PIN_6, PIN_7, PIN_10, PIN_11,
|
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,
|
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,
|
pio,
|
||||||
spi::{self, Spi},
|
spi::{self, Spi},
|
||||||
usb as embassy_rp_usb,
|
usb as embassy_rp_usb,
|
||||||
|
watchdog::{ResetReason, Watchdog},
|
||||||
};
|
};
|
||||||
use embassy_sync::{
|
use embassy_sync::{
|
||||||
blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel, signal::Signal,
|
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_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
use embedded_sdmmc::SdCard as SdmmcSdCard;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use talc::*;
|
use talc::*;
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
embassy_rp::bind_interrupts!(struct Irqs {
|
embassy_rp::bind_interrupts!(struct Irqs {
|
||||||
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
|
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
|
||||||
@@ -80,15 +78,32 @@ 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();
|
||||||
|
|
||||||
#[cfg(not(feature = "pimoroni2w"))]
|
static mut ARENA: [u8; 250 * 1024] = [0; 250 * 1024];
|
||||||
static mut ARENA: [u8; 200 * 1024] = [0; 200 * 1024];
|
|
||||||
|
|
||||||
#[cfg(not(feature = "pimoroni2w"))]
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> =
|
||||||
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
|
Talc::new(unsafe { ClaimOnOom::new(Span::from_array(core::ptr::addr_of!(ARENA).cast_mut())) })
|
||||||
.lock();
|
.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 ENABLE_UI: AtomicBool = AtomicBool::new(true);
|
||||||
static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
static UI_CHANGE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||||
|
|
||||||
@@ -141,7 +156,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
let executor0 = EXECUTOR0.init(Executor::new());
|
let executor0 = EXECUTOR0.init(Executor::new());
|
||||||
executor0.run(|spawner| {
|
executor0.run(|spawner| {
|
||||||
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()
|
.unwrap()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -244,26 +261,36 @@ async fn setup_display(display: Display, spawner: Spawner) {
|
|||||||
// psram is kind of useless on the pico calc
|
// psram is kind of useless on the pico calc
|
||||||
// ive opted to use the pimoroni with on onboard xip psram instead
|
// ive opted to use the pimoroni with on onboard xip psram instead
|
||||||
async fn setup_psram(psram: Psram) {
|
async fn setup_psram(psram: Psram) {
|
||||||
// let psram = init_psram(
|
let psram = init_psram(
|
||||||
// psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
|
psram.pio, psram.sclk, psram.mosi, psram.miso, psram.cs, psram.dma1, psram.dma2,
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// #[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
// defmt::info!("psram size: {}", psram.size);
|
defmt::info!("psram size: {}", psram.size);
|
||||||
|
|
||||||
// if psram.size == 0 {
|
if psram.size == 0 {
|
||||||
// #[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
// defmt::info!("\u{1b}[1mExternal PSRAM was NOT found!\u{1b}[0m");
|
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);
|
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 {
|
if psram_qmi_size > 0 {
|
||||||
init_qmi_psram_heap(psram_qmi_size);
|
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) {
|
async fn setup_sd(sd: Sd) {
|
||||||
@@ -284,22 +311,27 @@ async fn setup_sd(sd: Sd) {
|
|||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn kernel_task(
|
async fn kernel_task(
|
||||||
spawner: Spawner,
|
spawner: Spawner,
|
||||||
|
watchdog: Peri<'static, WATCHDOG>,
|
||||||
display: Display,
|
display: Display,
|
||||||
sd: Sd,
|
sd: Sd,
|
||||||
psram: Psram,
|
psram: Psram,
|
||||||
mcu: Mcu,
|
mcu: Mcu,
|
||||||
usb: Peri<'static, USB>,
|
usb: Peri<'static, USB>,
|
||||||
) {
|
) {
|
||||||
|
spawner
|
||||||
|
.spawn(watchdog_task(Watchdog::new(watchdog)))
|
||||||
|
.unwrap();
|
||||||
setup_mcu(mcu).await;
|
setup_mcu(mcu).await;
|
||||||
Timer::after_millis(250).await;
|
|
||||||
setup_display(display, spawner).await;
|
setup_display(display, spawner).await;
|
||||||
#[cfg(feature = "pimoroni2w")]
|
|
||||||
setup_psram(psram).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 {
|
||||||
|
|||||||
@@ -526,16 +526,10 @@ pub fn init_psram_qmi(
|
|||||||
let psram_size = detect_psram_qmi(qmi);
|
let psram_size = detect_psram_qmi(qmi);
|
||||||
|
|
||||||
if psram_size == 0 {
|
if psram_size == 0 {
|
||||||
|
defmt::error!("qmi psram size 0");
|
||||||
return 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 clock_hz = clk_peri_freq();
|
||||||
|
|
||||||
let mut divisor: u32 = (clock_hz + MAX_PSRAM_FREQ - 1) / MAX_PSRAM_FREQ;
|
let mut divisor: u32 = (clock_hz + MAX_PSRAM_FREQ - 1) / MAX_PSRAM_FREQ;
|
||||||
|
|||||||
@@ -28,11 +28,7 @@ use embedded_layout::{
|
|||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
print(&format!(
|
print!("user panic: {} @ {:?}", info.message(), info.location(),);
|
||||||
"user panic: {} @ {:?}",
|
|
||||||
info.message(),
|
|
||||||
info.location(),
|
|
||||||
));
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +38,7 @@ pub extern "Rust" fn _start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
print("Starting Calculator app");
|
print!("Starting Calculator app");
|
||||||
let mut display = Display;
|
let mut display = Display;
|
||||||
|
|
||||||
let mut input = vec!['e', 'x', 'p', 'r', ':', ' '];
|
let mut input = vec!['e', 'x', 'p', 'r', ':', ' '];
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use abi::{
|
|||||||
keyboard::{KeyCode, KeyState},
|
keyboard::{KeyCode, KeyState},
|
||||||
print,
|
print,
|
||||||
};
|
};
|
||||||
use alloc::{format, string::ToString};
|
use alloc::{format, string::ToString, vec};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
Drawable, image::Image, mono_font::MonoTextStyle, mono_font::ascii::FONT_6X10,
|
Drawable, image::Image, mono_font::MonoTextStyle, mono_font::ascii::FONT_6X10,
|
||||||
@@ -20,11 +20,7 @@ use tinybmp::Bmp;
|
|||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
print(&format!(
|
print!("user panic: {} @ {:?}", info.message(), info.location());
|
||||||
"user panic: {} @ {:?}",
|
|
||||||
info.message(),
|
|
||||||
info.location(),
|
|
||||||
));
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,8 +30,8 @@ pub extern "Rust" fn _start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
print("Starting Gallery app");
|
print!("Starting Gallery app");
|
||||||
static mut BMP_BUF: [u8; 100_000] = [0_u8; 100_000];
|
let mut bmp_buf = vec![0_u8; 100_000];
|
||||||
let mut display = Display;
|
let mut display = Display;
|
||||||
|
|
||||||
// Grid parameters
|
// Grid parameters
|
||||||
@@ -55,13 +51,13 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(f) = file {
|
if let Some(f) = file {
|
||||||
print(&format!("file: {}", f.name));
|
print!("file: {}", f.name);
|
||||||
if f.name.extension() == b"bmp" || f.name.extension() == b"BMP" {
|
if f.name.extension() == b"bmp" || f.name.extension() == b"BMP" {
|
||||||
let file = format!("/images/{}", f.name);
|
let file = format!("/images/{}", f.name);
|
||||||
|
|
||||||
let read = read_file(&file, 0, &mut unsafe { &mut BMP_BUF[..] });
|
let read = read_file(&file, 0, &mut &mut bmp_buf[..]);
|
||||||
if read > 0 {
|
if read > 0 {
|
||||||
let bmp = Bmp::from_slice(unsafe { &BMP_BUF }).expect("failed to parse bmp");
|
let bmp = Bmp::from_slice(&bmp_buf).expect("failed to parse bmp");
|
||||||
|
|
||||||
let row = images_drawn / grid_cols;
|
let row = images_drawn / grid_cols;
|
||||||
let col = images_drawn % grid_cols;
|
let col = images_drawn % grid_cols;
|
||||||
|
|||||||
@@ -9,18 +9,14 @@ use abi::{
|
|||||||
keyboard::{KeyCode, KeyState},
|
keyboard::{KeyCode, KeyState},
|
||||||
print, sleep,
|
print, sleep,
|
||||||
};
|
};
|
||||||
use alloc::{format, vec::Vec};
|
use alloc::vec;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use embedded_graphics::{image::ImageDrawable, pixelcolor::Rgb565};
|
use embedded_graphics::{image::ImageDrawable, pixelcolor::Rgb565};
|
||||||
use tinygif::Gif;
|
use tinygif::Gif;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
print(&format!(
|
print!("user panic: {} @ {:?}", info.message(), info.location(),);
|
||||||
"user panic: {} @ {:?}",
|
|
||||||
info.message(),
|
|
||||||
info.location(),
|
|
||||||
));
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,16 +26,18 @@ pub extern "Rust" fn _start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
print("Starting Gif app");
|
print!("Starting Gif app");
|
||||||
let mut display = Display;
|
let mut display = Display;
|
||||||
|
|
||||||
let size = file_len("/gifs/bad_apple.gif");
|
let size = file_len("/gifs/bad_apple.gif");
|
||||||
let mut buf = Vec::with_capacity(size);
|
let mut buf = vec![0_u8; size];
|
||||||
let read = read_file("/gifs/bad_apple.gif", 0, &mut buf);
|
let read = read_file("/gifs/bad_apple.gif", 0, &mut buf);
|
||||||
|
print!("read: {}, file size: {}", read, size);
|
||||||
assert!(read == size);
|
assert!(read == size);
|
||||||
|
|
||||||
let gif = Gif::<Rgb565>::from_slice(&buf).unwrap();
|
let gif = Gif::<Rgb565>::from_slice(&buf).unwrap();
|
||||||
|
|
||||||
|
let mut frame_num = 0;
|
||||||
loop {
|
loop {
|
||||||
for frame in gif.frames() {
|
for frame in gif.frames() {
|
||||||
let start = get_ms();
|
let start = get_ms();
|
||||||
@@ -48,6 +46,9 @@ pub fn main() {
|
|||||||
frame.draw(&mut display).unwrap();
|
frame.draw(&mut display).unwrap();
|
||||||
lock_display(false);
|
lock_display(false);
|
||||||
|
|
||||||
|
frame_num += 1;
|
||||||
|
print!("drew {}", frame_num);
|
||||||
|
|
||||||
sleep(((frame.delay_centis as u64) * 10).saturating_sub(start));
|
sleep(((frame.delay_centis as u64) * 10).saturating_sub(start));
|
||||||
|
|
||||||
let event = get_key();
|
let event = get_key();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
RAM : ORIGIN = 0x0, LENGTH = 150K
|
RAM : ORIGIN = 0x0, LENGTH = 250K
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
|
|||||||
@@ -9,18 +9,13 @@ use abi::{
|
|||||||
keyboard::{KeyCode, KeyState},
|
keyboard::{KeyCode, KeyState},
|
||||||
print, sleep,
|
print, sleep,
|
||||||
};
|
};
|
||||||
use alloc::format;
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor};
|
use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor};
|
||||||
use embedded_snake::{Direction, SnakeGame};
|
use embedded_snake::{Direction, SnakeGame};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
print(&format!(
|
print!("user panic: {} @ {:?}", info.message(), info.location(),);
|
||||||
"user panic: {} @ {:?}",
|
|
||||||
info.message(),
|
|
||||||
info.location(),
|
|
||||||
));
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +27,7 @@ pub extern "Rust" fn _start() {
|
|||||||
const CELL_SIZE: usize = 8;
|
const CELL_SIZE: usize = 8;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
print("Starting Snake app");
|
print!("Starting Snake app");
|
||||||
let mut display = Display;
|
let mut display = Display;
|
||||||
|
|
||||||
let mut game = SnakeGame::<100, Rgb565, Rng>::new(
|
let mut game = SnakeGame::<100, Rgb565, Rng>::new(
|
||||||
|
|||||||
Reference in New Issue
Block a user