More cleanup

This commit is contained in:
Jakub Hlusička 2026-02-27 23:54:29 +01:00
parent bf5957a8bf
commit 3e52243efe
4 changed files with 161 additions and 156 deletions

View file

@ -8,7 +8,7 @@ use enumset::EnumSet;
use crate::ffi::string::__xkbc_memcpy; use crate::ffi::string::__xkbc_memcpy;
// Here we select the allocator to use for libxkbcommon. // Here we select the allocator to use for libxkbcommon.
pub use crate::PSRAM_ALLOCATOR as XKBC_ALLOCATOR; pub use crate::ram::PSRAM_ALLOCATOR as XKBC_ALLOCATOR;
// Implementation based on esp-alloc's `compat` feature. // Implementation based on esp-alloc's `compat` feature.

View file

@ -30,12 +30,10 @@ use embassy_sync::blocking_mutex;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel; use embassy_sync::channel::Channel;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use esp_alloc::{HeapRegion, MemoryCapability}; use esp_alloc::MemoryCapability;
use esp_hal::clock::CpuClock; use esp_hal::clock::CpuClock;
use esp_hal::dma::{BurstConfig, ExternalBurstConfig, InternalBurstConfig}; use esp_hal::dma::{BurstConfig, ExternalBurstConfig, InternalBurstConfig};
use esp_hal::efuse::Efuse; use esp_hal::efuse::Efuse;
#[cfg(not(feature = "alt-log"))]
use esp_hal::gpio::NoPin;
use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull}; use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull};
use esp_hal::i2c::master::{I2c, I2cAddress}; use esp_hal::i2c::master::{I2c, I2cAddress};
use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl}; use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl};
@ -44,7 +42,6 @@ use esp_hal::lcd_cam::lcd::dpi::Dpi;
use esp_hal::ledc::{self, LSGlobalClkSource, Ledc, LowSpeed}; use esp_hal::ledc::{self, LSGlobalClkSource, Ledc, LowSpeed};
use esp_hal::peripherals::{DMA_CH0, SPI2}; use esp_hal::peripherals::{DMA_CH0, SPI2};
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock}; use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
use esp_hal::ram;
use esp_hal::rng::TrngSource; use esp_hal::rng::TrngSource;
use esp_hal::sha::ShaBackend; use esp_hal::sha::ShaBackend;
use esp_hal::spi::master::AnySpi; use esp_hal::spi::master::AnySpi;
@ -78,6 +75,7 @@ use {esp_alloc as _, esp_backtrace as _};
use crate::matrix::IoeMatrix; use crate::matrix::IoeMatrix;
use crate::peripherals::st7701s::{St7701s, St7701sController}; use crate::peripherals::st7701s::{St7701s, St7701sController};
use crate::proxy::create_hid_report_interceptor; use crate::proxy::create_hid_report_interceptor;
use crate::ram::{PSRAM_ALLOCATOR, STACK_SIZE_CORE_APP};
use crate::ui::backend::SlintBackend; use crate::ui::backend::SlintBackend;
use crate::ui::dpi::Framebuffer; use crate::ui::dpi::Framebuffer;
use crate::vial::{ use crate::vial::{
@ -96,6 +94,7 @@ mod logging;
mod matrix; mod matrix;
mod peripherals; mod peripherals;
mod proxy; mod proxy;
mod ram;
mod ui; mod ui;
mod util; mod util;
mod vial; mod vial;
@ -107,20 +106,9 @@ mod console;
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> // For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!(); esp_bootloader_esp_idf::esp_app_desc!();
// Memory allocation regions.
// These can be debugged using `xtensa-esp32s3-elf-size -A <path-to-binary>`.
// A panic such as `memory allocation of 3740121773 bytes failed` is caused by a heap overflow. The size is `DEEDBAAD` in hex.
/// Total heap size
const HEAP_SIZE: usize = 112 * 1024;
/// Size of the app core's stack
const STACK_SIZE_CORE_APP: usize = 80 * 1024;
// const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS // const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS
const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS
pub static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
static KEYBOARD_REPORT_PROXY: Channel<CriticalSectionRawMutex, Report, 16> = Channel::new(); static KEYBOARD_REPORT_PROXY: Channel<CriticalSectionRawMutex, Report, 16> = Channel::new();
static LCD_ENABLED: AtomicBool = AtomicBool::new(false); static LCD_ENABLED: AtomicBool = AtomicBool::new(false);
@ -130,114 +118,6 @@ static LCD_ENABLED: AtomicBool = AtomicBool::new(false);
// /// Used to signal that the MCU is ready to render the GUI. // /// Used to signal that the MCU is ready to render the GUI.
// static SIGNAL_UI_RENDER: Signal<CriticalSectionRawMutex, ()> = Signal::new(); // static SIGNAL_UI_RENDER: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[embassy_executor::task]
async fn test_bounce_buffers_task(
channel: DMA_CH0<'static>,
peripheral: SPI2<'static>,
st7701s: St7701s<'static, Blocking>,
) {
test_bounce_buffers(channel, peripheral, st7701s).await;
}
#[allow(unused)]
async fn test_bounce_buffers(
channel: DMA_CH0<'static>,
peripheral: SPI2<'static>,
mut st7701s: St7701s<'static, Blocking>,
) {
error!("TEST BOUNCE BUFFERS SECTION ENTERED");
const BYTES_PER_PIXEL: usize = core::mem::size_of::<u16>();
// Assume highest burst config setting.
const EXTERNAL_BURST_CONFIG: ExternalBurstConfig = ExternalBurstConfig::Size32;
const ALIGNMENT_PIXELS: usize = EXTERNAL_BURST_CONFIG as usize / BYTES_PER_PIXEL;
// The total number of pixels demanded by the DPI, per row.
const WIDTH_TOTAL_PIXELS: usize = 368;
// The total number of rows demanded by the DPI, per frame.
const HEIGHT_PIXELS: usize = 960;
// The number of unused pixels at the start of the row.
const FRONT_PORCH_ACTUAL_PIXELS: usize = 120;
// The number of actually visible pixels, per row.
const WIDTH_VISIBLE_PIXELS: usize = 240;
// The number of pixels not stored in a bounce buffer, per row.
// This many arbitrary pixels are sent to the DPI.
const FRONT_PORCH_SKIPPED_PIXELS: usize =
(FRONT_PORCH_ACTUAL_PIXELS / ALIGNMENT_PIXELS) * ALIGNMENT_PIXELS;
const WIDTH_STORED_PIXELS: usize = WIDTH_TOTAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
const VISIBLE_OFFSET_IN_BUFFER_PIXELS: usize =
FRONT_PORCH_ACTUAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
const ROWS_PER_WINDOW: usize = 16;
let burst_config = BurstConfig {
internal_memory: InternalBurstConfig::Enabled,
external_memory: EXTERNAL_BURST_CONFIG,
};
let (swapchain_reader, mut swapchain_writer) = Swapchain {
framebuffers: [
Box::leak(allocate_dma_buffer_in(
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
burst_config,
&PSRAM_ALLOCATOR,
)),
Box::leak(allocate_dma_buffer_in(
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
burst_config,
&PSRAM_ALLOCATOR,
)),
],
}
.into_reader_writer();
{
let write_guard = &mut swapchain_writer.write();
let buffer_src = bytemuck::cast_slice_mut::<u8, Rgb565Pixel>(write_guard);
let colors = (0..WIDTH_VISIBLE_PIXELS as u8 / 2)
.rev()
.map(|val| Rgb565Pixel::from_rgb(0xFF, val * 2, 0))
.collect::<Vec<_>>();
for (index, pixel) in buffer_src.iter_mut().enumerate() {
let mut x =
(index % WIDTH_STORED_PIXELS) as i16 - VISIBLE_OFFSET_IN_BUFFER_PIXELS as i16;
let mut y = (index / WIDTH_STORED_PIXELS) as i16;
if x < WIDTH_VISIBLE_PIXELS as i16 {
x = core::cmp::min(x, WIDTH_VISIBLE_PIXELS as i16 - 1 - x);
y = core::cmp::min(y, HEIGHT_PIXELS as i16 - 1 - y);
let min = core::cmp::min(x, y);
*pixel = colors[min as usize % colors.len()];
continue;
}
*pixel = Rgb565Pixel::default();
}
}
let mut dma_bounce = DmaBounce::new(
Global,
channel,
AnySpi::from(peripheral),
st7701s.dpi,
swapchain_reader,
FRONT_PORCH_SKIPPED_PIXELS * BYTES_PER_PIXEL,
WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
ROWS_PER_WINDOW,
burst_config,
true,
);
let mut bb_controller = DmaBounceController::new(dma_bounce);
error!("TEST BOUNCE BUFFERS TASK LAUNCHED");
loop {
bb_controller.start().await.unwrap();
st7701s.controller.sleep_off().await;
Timer::after_secs(1).await;
st7701s.controller.sleep_on().await;
bb_controller.stop().await.unwrap();
Timer::after_secs(1).await;
}
}
#[esp_rtos::main] #[esp_rtos::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let config = esp_hal::Config::default() let config = esp_hal::Config::default()
@ -255,7 +135,7 @@ async fn main(_spawner: Spawner) {
#[cfg(feature = "alt-log")] #[cfg(feature = "alt-log")]
let (tx, rx) = (peripherals.GPIO12, peripherals.GPIO5); let (tx, rx) = (peripherals.GPIO12, peripherals.GPIO5);
#[cfg(not(feature = "alt-log"))] #[cfg(not(feature = "alt-log"))]
let (tx, rx) = (NoPin, NoPin); let (tx, rx) = (esp_hal::gpio::NoPin, esp_hal::gpio::NoPin);
Uart::new(peripherals.UART2, Default::default()) Uart::new(peripherals.UART2, Default::default())
.unwrap() .unwrap()
@ -271,32 +151,8 @@ async fn main(_spawner: Spawner) {
#[cfg(feature = "rtt-log")] #[cfg(feature = "rtt-log")]
logging::rtt::setup_logging(); logging::rtt::setup_logging();
// Use the internal DRAM as the heap. // Set up allocators.
// Memory reclaimed from the esp-idf bootloader. ram::initialize(peripherals.PSRAM);
const HEAP_SIZE_RECLAIMED: usize = const {
let range = esp_metadata_generated::memory_range!("DRAM2_UNINIT");
range.end - range.start
};
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: HEAP_SIZE_RECLAIMED);
esp_alloc::heap_allocator!(size: HEAP_SIZE - HEAP_SIZE_RECLAIMED);
info!("Heap initialized! {:#?}", esp_alloc::HEAP.stats());
// Initialize the PSRAM allocator.
{
let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM);
unsafe {
PSRAM_ALLOCATOR.add_region(HeapRegion::new(
psram_offset,
psram_size,
MemoryCapability::External.into(),
));
}
info!(
"PSRAM allocator initialized with capacity of {} MiB!",
psram_size / 1024 / 1024
);
}
// let mut io = Io::new(peripherals.IO_MUX); // let mut io = Io::new(peripherals.IO_MUX);
// io.set_interrupt_handler(interrupt_handler); // io.set_interrupt_handler(interrupt_handler);
@ -657,7 +513,7 @@ async fn main_task(peripherals: MainPeripherals) {
let window_size = [framebuffer.height, framebuffer.width]; let window_size = [framebuffer.height, framebuffer.width];
let swapchain_writer = framebuffer.swapchain.take().unwrap(); let swapchain_writer = framebuffer.swapchain.take().unwrap();
static SECOND_CORE_STACK: StaticCell<Stack<STACK_SIZE_CORE_APP>> = StaticCell::new(); static SECOND_CORE_STACK: StaticCell<Stack<{ STACK_SIZE_CORE_APP }>> = StaticCell::new();
let second_core_stack = SECOND_CORE_STACK.init(Stack::new()); let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
esp_rtos::start_second_core( esp_rtos::start_second_core(
peripherals.CPU_CTRL, peripherals.CPU_CTRL,

View file

@ -0,0 +1,44 @@
use esp_alloc::{HeapRegion, MemoryCapability};
use esp_hal::ram;
use log::info;
// Memory allocation regions.
// These can be debugged using `xtensa-esp32s3-elf-size -A <path-to-binary>`.
// A panic such as `memory allocation of 3740121773 bytes failed` is caused by a heap overflow. The size is `DEEDBAAD` in hex.
/// Total heap size
pub const HEAP_SIZE: usize = 112 * 1024;
/// Size of the app core's stack
pub const STACK_SIZE_CORE_APP: usize = 80 * 1024;
pub static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
pub fn initialize(psram_peripheral: esp_hal::peripherals::PSRAM) {
// Use the internal DRAM as the heap.
// Memory reclaimed from the esp-idf bootloader.
const HEAP_SIZE_RECLAIMED: usize = const {
let range = esp_metadata_generated::memory_range!("DRAM2_UNINIT");
range.end - range.start
};
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: HEAP_SIZE_RECLAIMED);
esp_alloc::heap_allocator!(size: HEAP_SIZE - HEAP_SIZE_RECLAIMED);
info!("IRAM heap initialized!\n{}", esp_alloc::HEAP.stats());
// Initialize the PSRAM allocator.
{
let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&psram_peripheral);
unsafe {
PSRAM_ALLOCATOR.add_region(HeapRegion::new(
psram_offset,
psram_size,
MemoryCapability::External.into(),
));
}
info!(
"PSRAM heap initialized with capacity of {} MiB!\n{}",
psram_size / 1024 / 1024,
PSRAM_ALLOCATOR.stats(),
);
}
}

View file

@ -1,10 +1,16 @@
use alloc::{alloc::Global, boxed::Box}; use alloc::{alloc::Global, boxed::Box, vec::Vec};
use embassy_time::Timer;
use esp_hal::{ use esp_hal::{
Blocking, dma::BurstConfig, lcd_cam::lcd::dpi::Dpi, peripherals::DMA_CH0, spi::master::AnySpi, Blocking,
dma::{BurstConfig, ExternalBurstConfig, InternalBurstConfig},
lcd_cam::lcd::dpi::Dpi,
spi::master::AnySpi,
}; };
use esp_hal_bounce_buffers::{DmaBounce, Swapchain, SwapchainWriter, allocate_dma_buffer_in}; use esp_hal_bounce_buffers::{DmaBounce, Swapchain, SwapchainWriter, allocate_dma_buffer_in};
use i_slint_core::software_renderer::{Rgb565Pixel, TargetPixel};
use log::error;
use crate::PSRAM_ALLOCATOR; use crate::{DmaBounceController, PSRAM_ALLOCATOR, peripherals::st7701s::St7701s};
// TODO: Rename or get rid of. // TODO: Rename or get rid of.
pub struct Framebuffer { pub struct Framebuffer {
@ -16,7 +22,7 @@ pub struct Framebuffer {
impl Framebuffer { impl Framebuffer {
pub fn new( pub fn new(
channel: DMA_CH0<'static>, channel: esp_hal::peripherals::DMA_CH0<'static>,
peripheral_src: AnySpi<'static>, peripheral_src: AnySpi<'static>,
peripheral_dst: Dpi<'static, Blocking>, peripheral_dst: Dpi<'static, Blocking>,
burst_config: BurstConfig, burst_config: BurstConfig,
@ -62,3 +68,102 @@ impl Framebuffer {
} }
} }
} }
#[allow(unused)]
async fn test_bounce_buffers(
channel: esp_hal::peripherals::DMA_CH0<'static>,
peripheral: esp_hal::peripherals::SPI2<'static>,
mut st7701s: St7701s<'static, Blocking>,
) {
error!("TEST BOUNCE BUFFERS SECTION ENTERED");
const BYTES_PER_PIXEL: usize = core::mem::size_of::<u16>();
// Assume highest burst config setting.
const EXTERNAL_BURST_CONFIG: ExternalBurstConfig = ExternalBurstConfig::Size32;
const ALIGNMENT_PIXELS: usize = EXTERNAL_BURST_CONFIG as usize / BYTES_PER_PIXEL;
// The total number of pixels demanded by the DPI, per row.
const WIDTH_TOTAL_PIXELS: usize = 368;
// The total number of rows demanded by the DPI, per frame.
const HEIGHT_PIXELS: usize = 960;
// The number of unused pixels at the start of the row.
const FRONT_PORCH_ACTUAL_PIXELS: usize = 120;
// The number of actually visible pixels, per row.
const WIDTH_VISIBLE_PIXELS: usize = 240;
// The number of pixels not stored in a bounce buffer, per row.
// This many arbitrary pixels are sent to the DPI.
const FRONT_PORCH_SKIPPED_PIXELS: usize =
(FRONT_PORCH_ACTUAL_PIXELS / ALIGNMENT_PIXELS) * ALIGNMENT_PIXELS;
const WIDTH_STORED_PIXELS: usize = WIDTH_TOTAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
const VISIBLE_OFFSET_IN_BUFFER_PIXELS: usize =
FRONT_PORCH_ACTUAL_PIXELS - FRONT_PORCH_SKIPPED_PIXELS;
const ROWS_PER_WINDOW: usize = 16;
let burst_config = BurstConfig {
internal_memory: InternalBurstConfig::Enabled,
external_memory: EXTERNAL_BURST_CONFIG,
};
let (swapchain_reader, mut swapchain_writer) = Swapchain {
framebuffers: [
Box::leak(allocate_dma_buffer_in(
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
burst_config,
&PSRAM_ALLOCATOR,
)),
Box::leak(allocate_dma_buffer_in(
HEIGHT_PIXELS * WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
burst_config,
&PSRAM_ALLOCATOR,
)),
],
}
.into_reader_writer();
{
let write_guard = &mut swapchain_writer.write();
let buffer_src = bytemuck::cast_slice_mut::<u8, Rgb565Pixel>(write_guard);
let colors = (0..WIDTH_VISIBLE_PIXELS as u8 / 2)
.rev()
.map(|val| Rgb565Pixel::from_rgb(0xFF, val * 2, 0))
.collect::<Vec<_>>();
for (index, pixel) in buffer_src.iter_mut().enumerate() {
let mut x =
(index % WIDTH_STORED_PIXELS) as i16 - VISIBLE_OFFSET_IN_BUFFER_PIXELS as i16;
let mut y = (index / WIDTH_STORED_PIXELS) as i16;
if x < WIDTH_VISIBLE_PIXELS as i16 {
x = core::cmp::min(x, WIDTH_VISIBLE_PIXELS as i16 - 1 - x);
y = core::cmp::min(y, HEIGHT_PIXELS as i16 - 1 - y);
let min = core::cmp::min(x, y);
*pixel = colors[min as usize % colors.len()];
continue;
}
*pixel = Rgb565Pixel::default();
}
}
let mut dma_bounce = DmaBounce::new(
Global,
channel,
AnySpi::from(peripheral),
st7701s.dpi,
swapchain_reader,
FRONT_PORCH_SKIPPED_PIXELS * BYTES_PER_PIXEL,
WIDTH_STORED_PIXELS * BYTES_PER_PIXEL,
ROWS_PER_WINDOW,
burst_config,
true,
);
let mut bb_controller = DmaBounceController::new(dma_bounce);
error!("TEST BOUNCE BUFFERS TASK LAUNCHED");
loop {
bb_controller.start().await.unwrap();
st7701s.controller.sleep_off().await;
Timer::after_secs(1).await;
st7701s.controller.sleep_on().await;
bb_controller.stop().await.unwrap();
Timer::after_secs(1).await;
}
}