From b8e39871393fee1b6919308ad78879172a3acd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Hlusi=C4=8Dka?= Date: Sun, 15 Feb 2026 02:33:42 +0100 Subject: [PATCH] WIP2: Cyclic descriptor list --- firmware/acid-firmware/src/main.rs | 42 ++- firmware/acid-firmware/src/ui/dpi.rs | 455 +++++++++++++++++++-------- firmware/acid-firmware/src/ui/mod.rs | 6 +- 3 files changed, 357 insertions(+), 146 deletions(-) diff --git a/firmware/acid-firmware/src/main.rs b/firmware/acid-firmware/src/main.rs index 1b0c793..f1a48b0 100644 --- a/firmware/acid-firmware/src/main.rs +++ b/firmware/acid-firmware/src/main.rs @@ -38,7 +38,6 @@ use embassy_sync::signal::Signal; use embassy_time::{Duration, Timer}; use esp_alloc::{HeapRegion, MemoryCapability}; use esp_bootloader_esp_idf::partitions::PartitionTable; -use esp_hal::Blocking; use esp_hal::clock::CpuClock; use esp_hal::dma::{ BurstConfig, DmaDescriptor, DmaTxBuf, ExternalBurstConfig, InternalBurstConfig, @@ -46,9 +45,9 @@ use esp_hal::dma::{ use esp_hal::efuse::Efuse; use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull}; use esp_hal::i2c::master::{I2c, I2cAddress}; -use esp_hal::interrupt::software::SoftwareInterruptControl; +use esp_hal::interrupt::software::{SoftwareInterrupt, SoftwareInterruptControl}; use esp_hal::lcd_cam::LcdCam; -use esp_hal::lcd_cam::lcd::dpi::Dpi; +use esp_hal::lcd_cam::lcd::dpi::{Dpi, DpiTransfer}; use esp_hal::mcpwm::{McPwm, PeripheralClockConfig}; use esp_hal::peripherals::{DMA_CH0, SPI0, SPI2}; use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock}; @@ -58,7 +57,8 @@ use esp_hal::sha::ShaBackend; use esp_hal::spi::master::AnySpi; use esp_hal::system::Stack; use esp_hal::timer::timg::TimerGroup; -use esp_rtos::embassy::Executor; +use esp_hal::{Blocking, interrupt}; +use esp_rtos::embassy::{Executor, InterruptExecutor}; use esp_storage::FlashStorage; use indoc::writedoc; use itertools::Itertools; @@ -83,7 +83,7 @@ use crate::matrix::IoeMatrix; use crate::peripherals::st7701s::St7701s; use crate::proxy::create_hid_report_interceptor; use crate::ui::backend::{FramebufferPtr, SlintBackend}; -use crate::ui::dpi::{DmaTxBounceBuf, Framebuffer}; +use crate::ui::dpi::{DmaBounce, DmaTxBounceBuf, Framebuffer}; use crate::vial::{ CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID, VIAL_KEYBOARD_NAME, VIAL_PRODUCT_ID, VIAL_VENDOR_ID, @@ -133,14 +133,24 @@ static SIGNAL_LCD_SUBMIT: Signal = Signal::new(); /// Used to signal that the MCU is ready to render the GUI. static SIGNAL_UI_RENDER: Signal = Signal::new(); -async fn test_bounce_buffers(channel: DMA_CH0<'static>, peripheral: SPI2<'static>) -> ! { +async fn test_bounce_buffers( + channel: DMA_CH0<'static>, + peripheral: SPI2<'static>, + st7701s: St7701s<'static, Blocking>, +) -> DpiTransfer<'static, DmaTxBounceBuf, Blocking> { error!("TEST BOUNCE BUFFERS SECTION ENTERED"); let windows_len = 2; let window_size = 368 * core::mem::size_of::(); let buffer_src = Box::leak(vec![0_u8; windows_len * window_size].into_boxed_slice()); - let mut buf = DmaTxBounceBuf::new( + let mut counter: u8 = 0; + buffer_src.fill_with(|| { + counter = counter.wrapping_add(1); + counter + }); + let mut buf = DmaBounce::new( channel, AnySpi::from(peripheral), + st7701s.dpi, buffer_src, window_size, BurstConfig { @@ -148,9 +158,11 @@ async fn test_bounce_buffers(channel: DMA_CH0<'static>, peripheral: SPI2<'static external_memory: ExternalBurstConfig::Size32, }, ); - buf.send().await; + let _ = buf.send().await; error!("TEST BOUNCE BUFFERS SECTION DONE"); - loop {} + loop { + Timer::after_secs(10).await; + } } #[esp_rtos::main] @@ -231,6 +243,11 @@ async fn main(_spawner: Spawner) { timg0.timer0, /*, software_interrupt.software_interrupt0 */ ); + static EXECUTOR_CORE_0: StaticCell> = StaticCell::new(); + let executor_core_0 = InterruptExecutor::new(software_interrupt.software_interrupt2); + let executor_core_0 = EXECUTOR_CORE_0.init(executor_core_0); + let interrupt_core_0_spawner = executor_core_0.start(interrupt::Priority::Priority3); + info!("ESP-RTOS started!"); // Enable the TRNG source, so `Trng` can be constructed. @@ -404,7 +421,9 @@ async fn main(_spawner: Spawner) { info!("ST7701S-based LCD display initialized!"); - test_bounce_buffers(peripherals.DMA_CH0, peripherals.SPI2).await; + let lcd_task = test_bounce_buffers(peripherals.DMA_CH0, peripherals.SPI2, st7701s); + + let _ = lcd_task.await; return; // RMK config @@ -554,7 +573,8 @@ async fn main(_spawner: Spawner) { run_alloc_stats_reporter(), // We currently send the framebuffer data using the main core, which does not seem to slow // down the rest of the tasks too much. - ui::dpi::run_lcd(st7701s, framebuffer), + // ui::dpi::run_lcd(st7701s, framebuffer), + // lcd_task, run_devices! ( (matrix) => rmk::channel::EVENT_CHANNEL, ), diff --git a/firmware/acid-firmware/src/ui/dpi.rs b/firmware/acid-firmware/src/ui/dpi.rs index d30aa36..845d347 100644 --- a/firmware/acid-firmware/src/ui/dpi.rs +++ b/firmware/acid-firmware/src/ui/dpi.rs @@ -1,4 +1,8 @@ -use core::{alloc::Layout, pin::Pin}; +use core::{ + alloc::Layout, + pin::Pin, + sync::atomic::{self, AtomicBool}, +}; use alloc::{ alloc::{Allocator, Global}, @@ -6,6 +10,7 @@ use alloc::{ vec, }; use embassy_sync::channel::Channel; +use embassy_time::Timer; use esp_alloc::MemoryCapability; use esp_hal::{ Blocking, @@ -14,7 +19,9 @@ use esp_hal::{ DmaDescriptorFlags, DmaEligible, DmaRxStreamBuf, DmaTxBuf, DmaTxBuffer, DmaTxInterrupt, ExternalBurstConfig, Mem2Mem, }, - dma_descriptors, handler, interrupt, + dma_descriptors, handler, + interrupt::{self, Priority}, + lcd_cam::lcd::dpi::{Dpi, DpiTransfer}, peripherals::{DMA, DMA_CH0, Peripherals, SPI2}, ram, spi::master::AnySpi, @@ -22,17 +29,51 @@ use esp_hal::{ use esp_sync::RawMutex; use i_slint_core::software_renderer::Rgb565Pixel; use indoc::{formatdoc, indoc}; -use log::{error, info}; +use log::{error, info, warn}; use crate::{PSRAM_ALLOCATOR, SIGNAL_LCD_SUBMIT, SIGNAL_UI_RENDER, peripherals::st7701s::St7701s}; -pub struct DmaTxBounceBuf { +/// THIS IS TAKEN FROM https://github.com/esp-rs/esp-hal/blob/main/esp-hal/src/soc/esp32s3/mod.rs +/// Write back a specific range of data in the cache. +#[doc(hidden)] +#[unsafe(link_section = ".rwtext")] +pub unsafe fn cache_writeback_addr(addr: u32, size: u32) { + unsafe extern "C" { + fn rom_Cache_WriteBack_Addr(addr: u32, size: u32); + fn Cache_Suspend_DCache_Autoload() -> u32; + fn Cache_Resume_DCache_Autoload(value: u32); + } + // suspend autoload, avoid load cachelines being written back + unsafe { + let autoload = Cache_Suspend_DCache_Autoload(); + rom_Cache_WriteBack_Addr(addr, size); + Cache_Resume_DCache_Autoload(autoload); + } +} + +/// THIS IS TAKEN FROM https://github.com/esp-rs/esp-hal/blob/main/esp-hal/src/soc/esp32s3/mod.rs +/// Invalidate a specific range of addresses in the cache. +#[doc(hidden)] +#[unsafe(link_section = ".rwtext")] +pub unsafe fn cache_invalidate_addr(addr: u32, size: u32) { + unsafe extern "C" { + fn Cache_Invalidate_Addr(addr: u32, size: u32); + } + unsafe { + Cache_Invalidate_Addr(addr, size); + } +} + +pub struct DmaBounce { // TODO: Make these generic. // They currently cannot be generic, because they lacks a `reborrow` method. channel: DMA_CH0<'static>, // This can also be more generic, see `DmaEligible` in `Mem2Mem::new`. - peripheral: AnySpi<'static>, + peripheral_src: AnySpi<'static>, + // This can also be more generic, see `DmaEligible` in `Mem2Mem::new`. + peripheral_dst: Option>, + // TODO: Consider having a separate burst config for the two transfers. burst_config: BurstConfig, // rx: DmaRxStreamBuf, /// The size of each window. @@ -42,14 +83,23 @@ pub struct DmaTxBounceBuf { buffer_src: &'static mut [u8], // Two buffers of size `window_size`, // one of which is being written to, while the other is being read from. - bounce_buffer_dst: Box<[u8]>, - bounce_buffer_src: Box<[u8]>, + bounce_buffer_dst: &'static mut [u8], + bounce_buffer_src: &'static mut [u8], + // A descriptor list that spans a buffer of size `window_size`. + // The buffer pointers need to be updated before each transmission to point to the correct window in the source buffer `src_buffer`. + src_descs: &'static mut [DmaDescriptor], + // A descriptor list that spans a buffer of size `window_size`. + // The buffer pointers need to be updated before each transmission to point to the correct bounce buffer. + bounce_dst_descs: &'static mut [DmaDescriptor], + // A cyclic descriptor list that spans the buffers `bounce_buffer_dst` and `bounce_buffer_src`. + bounce_src_descs: &'static mut [DmaDescriptor], } -impl DmaTxBounceBuf { +impl DmaBounce { pub fn new( channel: DMA_CH0<'static>, - peripheral: AnySpi<'static>, + peripheral_src: AnySpi<'static>, + peripheral_dst: Dpi<'static, Blocking>, buffer_src: &'static mut [u8], window_size: usize, burst_config: BurstConfig, @@ -60,34 +110,49 @@ impl DmaTxBounceBuf { "the size of a source buffer must be a multiple of the window size ({window_size} bytes), but it is {len} bytes large", len = buffer_src.len() ); - // let dma_buf_descs_len = esp_hal::dma::descriptor_count( - // window_size, - // burst_config.max_compatible_chunk_size(), - // false, - // ); - // let dma_buf_descs = - // Box::leak(vec![DmaDescriptor::EMPTY; dma_buf_descs_len].into_boxed_slice()); - // let rx = DmaRxStreamBuf::new(dma_buf_descs, buffer_src).unwrap(); + let bounce_buffer_dst = Box::leak(allocate_dma_buffer_in(window_size, Global)); + let bounce_buffer_src = Box::leak(allocate_dma_buffer_in(window_size, Global)); + let src_descs = Self::linear_descriptors_for_buffer(window_size, burst_config, |desc| { + desc.reset_for_tx(desc.next.is_null()); + // Length for TX buffers must be set in software. + // In RX buffers, it is set by hardware. + desc.set_length(desc.size()); + }); + let bounce_dst_descs = + Self::linear_descriptors_for_buffer(window_size, burst_config, |_| {}); + let bounce_src_descs = Self::bounce_descriptors_for_buffer( + unsafe { + ( + &mut *(bounce_buffer_dst as *mut _), + &mut *(bounce_buffer_src as *mut _), + ) + }, + burst_config, + ); + Self { channel, - peripheral, + peripheral_src, + peripheral_dst: Some(peripheral_dst), burst_config, - // rx, window_size, windows_len: buffer_src.len() / window_size, buffer_src, - bounce_buffer_dst: allocate_dma_buffer_in(window_size, Global), - bounce_buffer_src: allocate_dma_buffer_in(window_size, Global), + bounce_buffer_dst, + bounce_buffer_src, + src_descs, + bounce_dst_descs, + bounce_src_descs, } } fn linear_descriptors_for_buffer( buffer_len: usize, - burst_config: &BurstConfig, + burst_config: BurstConfig, mut setup_desc: impl FnMut(&mut DmaDescriptor), ) -> &'static mut [DmaDescriptor] { let max_chunk_size = burst_config.max_compatible_chunk_size(); - let descriptors_len = esp_hal::dma::descriptor_count(buffer_len, max_chunk_size, false); + let descriptors_len = dma::descriptor_count(buffer_len, max_chunk_size, false); // TODO: This leaks memory. Ensure it's only called during setup. let descriptors = Box::leak(vec![DmaDescriptor::EMPTY; descriptors_len].into_boxed_slice()); @@ -101,6 +166,7 @@ impl DmaTxBounceBuf { // Prepare each descriptor's buffer size. let mut descriptors_it = descriptors.iter_mut(); let mut remaining_len = buffer_len; + while remaining_len > 0 { let chunk_size = core::cmp::min(max_chunk_size, remaining_len); let desc = descriptors_it.next().unwrap(); @@ -112,34 +178,84 @@ impl DmaTxBounceBuf { descriptors } - fn linear_descriptors_set_buffer( + fn bounce_descriptors_for_buffer( + bounce_buffers: (&'static mut [u8], &'static mut [u8]), + burst_config: BurstConfig, + ) -> &'static mut [DmaDescriptor] { + assert_eq!( + bounce_buffers.0.len(), + bounce_buffers.1.len(), + "bounce buffers must be equal in size" + ); + + let buffer_len = bounce_buffers.0.len(); + let max_chunk_size = burst_config.max_compatible_chunk_size(); + let descriptors_len = dma::descriptor_count(buffer_len, max_chunk_size, false); + // TODO: This leaks memory. Ensure it's only called during setup. + let descriptors_combined = + Box::leak(vec![DmaDescriptor::EMPTY; 2 * descriptors_len].into_boxed_slice()); + let descriptors_pair = descriptors_combined.split_at_mut(descriptors_len); + + // Link up the descriptors. + fn link_up_descriptors( + descriptors: &mut [DmaDescriptor], + descriptors_other: &mut [DmaDescriptor], + ) { + let mut next = descriptors_other.first_mut().unwrap(); + for desc in descriptors.iter_mut().rev() { + desc.next = next; + next = desc; + } + } + + link_up_descriptors(descriptors_pair.0, descriptors_pair.1); + link_up_descriptors(descriptors_pair.1, descriptors_pair.0); + + // Prepare each descriptor's buffer size. + for (bounce_buffer, descriptors) in [ + (bounce_buffers.0, descriptors_pair.0), + (bounce_buffers.1, descriptors_pair.1), + ] { + let mut descriptors_it = descriptors.iter_mut(); + let mut remaining_bounce_buffer = bounce_buffer; + + while !remaining_bounce_buffer.is_empty() { + let chunk_size = core::cmp::min(max_chunk_size, remaining_bounce_buffer.len()); + let desc = descriptors_it.next().unwrap(); + desc.buffer = remaining_bounce_buffer.as_mut_ptr(); + remaining_bounce_buffer = &mut remaining_bounce_buffer[chunk_size..]; + let is_last = remaining_bounce_buffer.is_empty(); + desc.set_size(chunk_size); + desc.set_length(chunk_size); + desc.reset_for_tx(is_last); + } + } + + descriptors_combined + } + + fn linear_descriptors_prepare( descriptors: &mut [DmaDescriptor], - mut buffer: &mut [u8], + mut buffer: Option<&mut [u8]>, mut setup_desc: impl FnMut(&mut DmaDescriptor), ) { for descriptor in descriptors.iter_mut() { - descriptor.buffer = buffer.as_mut_ptr(); + if let Some(inner_buffer) = buffer { + descriptor.buffer = inner_buffer.as_mut_ptr(); + buffer = Some(&mut inner_buffer[descriptor.size()..]); + } (setup_desc)(descriptor); - buffer = &mut buffer[descriptor.size()..]; } - assert!( - buffer.is_empty(), - "a buffer of an incompatible length was asssigned to a descriptor set" - ); + + if let Some(buffer) = buffer { + assert!( + buffer.is_empty(), + "a buffer of an incompatible length was asssigned to a descriptor set" + ); + } } - pub async fn send(&mut self) { - // TODO: Precompute as much as possible by moving to `Self::new()`. - let src_descs = - Self::linear_descriptors_for_buffer(self.window_size, &self.burst_config, |desc| { - desc.reset_for_tx(desc.next.is_null()); - // Length for TX buffers must be set in software. - // In RX buffers, it is set by hardware. - desc.set_length(desc.size()); - }); - let bounce_dst_descs = - Self::linear_descriptors_for_buffer(self.window_size, &self.burst_config, |_| {}); - + fn enable_interrupts() { // Enable interrupts for the peripheral interrupt::enable( esp_hal::peripherals::Interrupt::DMA_OUT_CH0, @@ -147,10 +263,15 @@ impl DmaTxBounceBuf { ) .unwrap(); interrupt::enable( - esp_hal::peripherals::Interrupt::SPI2_DMA, + esp_hal::peripherals::Interrupt::DMA_IN_CH0, dma_interrupt_handler.priority(), ) .unwrap(); + // interrupt::enable( + // esp_hal::peripherals::Interrupt::SPI2_DMA, + // dma_interrupt_handler.priority(), + // ) + // .unwrap(); // Bind the handler unsafe { @@ -159,9 +280,13 @@ impl DmaTxBounceBuf { dma_interrupt_handler.handler(), ); interrupt::bind_interrupt( - esp_hal::peripherals::Interrupt::SPI2_DMA, + esp_hal::peripherals::Interrupt::DMA_IN_CH0, dma_interrupt_handler.handler(), ); + // interrupt::bind_interrupt( + // esp_hal::peripherals::Interrupt::SPI2_DMA, + // dma_interrupt_handler.handler(), + // ); } // Enable interrupts in the peripheral. @@ -172,30 +297,104 @@ impl DmaTxBounceBuf { .ena() .modify(|_, w| { w.out_total_eof().bit(true); - w.out_dscr_err().bit(true); w.out_eof().bit(true); w.out_done().bit(true); w }); - SPI2::regs().dma_int_ena().modify(|_, w| { - w.slv_rd_dma_done().bit(true); - w.slv_wr_dma_done().bit(true); - w.dma_seg_trans_done().bit(true); - w.trans_done().bit(true); - w - }); + DMA::regs() + .ch(channel_number) + .in_int() + .ena() + .modify(|_, w| { + w.in_suc_eof().bit(true); + w.in_done().bit(true); + w + }); + // SPI2::regs().dma_int_ena().modify(|_, w| { + // w.slv_rd_dma_done().bit(true); + // w.slv_wr_dma_done().bit(true); + // w.dma_seg_trans_done().bit(true); + // w.trans_done().bit(true); + // w + // }); + } + + fn print_regs() { + let channel_number = 0; // TODO: Get from self.channel + let out_int_raw = DMA::regs() + .ch(channel_number as usize) + .out_int() + .st() + .read(); + let in_int_raw = DMA::regs().ch(channel_number as usize).in_int().st().read(); + log::error!( + indoc! {" + int_raw: + flag: {flag} + out: + total_eof: {out_total_eof} + eof: {out_eof} + done: {out_done} + in: + suc_eof: {in_suc_eof} + done: {in_done} + "}, + flag = FLAG.load(atomic::Ordering::SeqCst), + out_total_eof = out_int_raw.out_total_eof().bit_is_set(), + out_eof = out_int_raw.out_eof().bit_is_set(), + out_done = out_int_raw.out_done().bit_is_set(), + in_suc_eof = in_int_raw.in_suc_eof().bit_is_set(), + in_done = in_int_raw.in_done().bit_is_set(), + ); + error!("int_raw_msg: 0x{:08x?}", INT_CHANNEL.try_receive()); + } + + pub async fn send(&mut self) // -> DpiTransfer<'static, DmaTxBounceBuf, Blocking> + { + Self::enable_interrupts(); + + let mut dma_tx_buffer = self.get_dma_tx_buffer(); + let transfer = match self + .peripheral_dst + .take() + .unwrap() + .send(true /* Send perpetually */, dma_tx_buffer) + { + Ok(transfer) => { + // let result; + // let peripheral_dst; + // (result, peripheral_dst, dma_tx_buffer) = transfer.wait(); + // self.peripheral_dst = Some(peripheral_dst); + + // if let Err(error) = result { + // error!("DPI error during sending: {error:?}"); + // } + warn!("Sending data to DPI!"); + transfer + } + Err(error_tuple) => { + let error; + let peripheral_dst; + (error, peripheral_dst, dma_tx_buffer) = error_tuple; + self.peripheral_dst = Some(peripheral_dst); + panic!("DPI error when starting transfer: {error:?}"); + } + }; for window_index in 0..self.windows_len { // Descriptors are initialized by `DmaTxBuf::new`. let buffer_src_window = &mut self.buffer_src[window_index * self.window_size..][..self.window_size]; - Self::linear_descriptors_set_buffer(src_descs, buffer_src_window, |_| {}); - Self::linear_descriptors_set_buffer(bounce_dst_descs, buffer_src_window, |desc| { - desc.reset_for_rx(); - }); - - // let (channel_rx, channel_tx) = self.channel.split(); + Self::linear_descriptors_prepare(self.src_descs, Some(buffer_src_window), |_| {}); + // TODO: Precompute a descriptor list for each buffer, then use `None` instead of `Some(&mut *self.bounce_buffer_dst)`. + Self::linear_descriptors_prepare( + self.bounce_dst_descs, + Some(&mut *self.bounce_buffer_dst), + |desc| { + desc.reset_for_rx(); + }, + ); { // Extend the lifetime to 'static because it is required by Mem2Mem. @@ -203,69 +402,89 @@ impl DmaTxBounceBuf { // Safety: // Pointees are done being used by the driver before this scope ends, // this is because we `SimpleMem2MemTransfer::wait()` on the transfer to finish. - let bounce_dst_descs = unsafe { &mut *(bounce_dst_descs as *mut _) }; - let src_descs = unsafe { &mut *(src_descs as *mut _) }; - let mut mem2mem = Mem2Mem::new(self.channel.reborrow(), self.peripheral.reborrow()) - .with_descriptors(bounce_dst_descs, src_descs, self.burst_config) - .unwrap(); + let bounce_dst_descs = unsafe { &mut *(self.bounce_dst_descs as *mut _) }; + let src_descs = unsafe { &mut *(self.src_descs as *mut _) }; + let mut mem2mem = + Mem2Mem::new(self.channel.reborrow(), self.peripheral_src.reborrow()) + .with_descriptors(bounce_dst_descs, src_descs, self.burst_config) + .unwrap(); let transfer = mem2mem .start_transfer(&mut self.bounce_buffer_dst, buffer_src_window) .unwrap(); - let int_raw = DMA::regs() - .ch(channel_number as usize) - .out_int() - .raw() - .read(); - log::error!( - indoc! {" - int_raw: - total_eof: {total_eof} - eof: {eof} - done: {done} - dscr_err: {dscr_err} - "}, - total_eof = int_raw.out_total_eof().bit_is_set(), - eof = int_raw.out_eof().bit_is_set(), - done = int_raw.out_done().bit_is_set(), - dscr_err = int_raw.out_dscr_err().bit_is_set(), - ); - error!("int_raw_msg: 0x{:08x?}", INT_CHANNEL.try_receive()); - + Self::print_regs(); transfer.wait().unwrap(); } - let int_raw = DMA::regs() - .ch(channel_number as usize) - .out_int() - .raw() - .read(); - log::error!( - indoc! {" - int_raw: - total_eof: {total_eof} - eof: {eof} - done: {done} - dscr_err: {dscr_err} - "}, - total_eof = int_raw.out_total_eof().bit_is_set(), - eof = int_raw.out_eof().bit_is_set(), - done = int_raw.out_done().bit_is_set(), - dscr_err = int_raw.out_dscr_err().bit_is_set(), - ); - error!("int_raw_msg: 0x{:08x?}", INT_CHANNEL.try_receive()); + Self::print_regs(); // TODO: Get rid of this! - assert_eq!(&*self.bounce_buffer_dst, buffer_src_window); + unsafe { + cache_invalidate_addr( + self.bounce_buffer_dst.as_ptr() as u32, + self.bounce_buffer_dst.len() as u32, + ); + } + assert_eq!(self.bounce_buffer_dst, buffer_src_window); + } + + loop { + warn!("Still sending data to DPI? {}", !transfer.is_done()); + Timer::after_secs(10).await; + } + + // transfer + } + + fn get_dma_tx_buffer(&mut self) -> DmaTxBounceBuf { + DmaTxBounceBuf { + preparation: dma::Preparation { + start: self.bounce_src_descs.first_mut().unwrap(), + direction: dma::TransferDirection::Out, + accesses_psram: false, + burst_transfer: self.burst_config, + check_owner: Some(true), // Possibly want to set this to false + auto_write_back: false, // Possibly true + }, } } } -static INT_CHANNEL: Channel = Channel::new(); +pub struct DmaTxBounceBuf { + preparation: dma::Preparation, +} -#[handler] +unsafe impl DmaTxBuffer for DmaTxBounceBuf { + type View = Self; + type Final = Self; + + fn prepare(&mut self) -> dma::Preparation { + dma::Preparation { + start: self.preparation.start, + direction: self.preparation.direction, + accesses_psram: self.preparation.accesses_psram, + burst_transfer: self.preparation.burst_transfer, + check_owner: self.preparation.check_owner, + auto_write_back: self.preparation.auto_write_back, + } + } + + fn into_view(self) -> Self::View { + self + } + + fn from_view(view: Self::View) -> Self::Final { + view + } +} + +static INT_CHANNEL: Channel = Channel::new(); +static FLAG: AtomicBool = AtomicBool::new(false); + +#[handler(priority = Priority::Priority3)] #[ram] // Improves performance. fn dma_interrupt_handler() { + FLAG.store(true, atomic::Ordering::SeqCst); let int_raw = DMA::regs().ch(0).out_int().raw().read(); INT_CHANNEL.try_send(int_raw.bits()).unwrap(); @@ -293,30 +512,6 @@ fn dma_interrupt_handler() { // } } -// unsafe impl DmaTxBuffer for DmaTxStreamBuf { -// type View = Self; -// type Final = Self; - -// fn prepare(&mut self) -> dma::Preparation { -// dma::Preparation { -// start: (), -// direction: (), -// accesses_psram: false, -// burst_transfer: (), -// check_owner: (), -// auto_write_back: (), -// } -// } - -// fn into_view(self) -> Self::View { -// self -// } - -// fn from_view(view: Self::View) -> Self::Final { -// view -// } -// } - pub async fn run_lcd( mut st7701s: St7701s<'static, Blocking>, framebuffer: &'static mut Framebuffer, diff --git a/firmware/acid-firmware/src/ui/mod.rs b/firmware/acid-firmware/src/ui/mod.rs index fe26b73..d2011c7 100644 --- a/firmware/acid-firmware/src/ui/mod.rs +++ b/firmware/acid-firmware/src/ui/mod.rs @@ -144,11 +144,7 @@ struct State { impl State { async fn new(db: AcidDatabase, main: AppWindow) -> Rc> { - let users = { - let users = Self::load_users(&db).await; - warn!("Users: {users:#?}"); - users - }; + let users = Self::load_users(&db).await; let usernames = users.users.clone().map(|user| user.username); let state = Rc::new(RefCell::new(State {