WIP2: Cyclic descriptor list
This commit is contained in:
parent
74d7b6df5f
commit
b8e3987139
|
|
@ -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<CriticalSectionRawMutex, ()> = Signal::new();
|
|||
/// Used to signal that the MCU is ready to render the GUI.
|
||||
static SIGNAL_UI_RENDER: Signal<CriticalSectionRawMutex, ()> = 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::<u16>();
|
||||
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<InterruptExecutor<2>> = 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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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<Dpi<'static, Blocking>>,
|
||||
|
||||
// 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],
|
||||
mut buffer: &mut [u8],
|
||||
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: Option<&mut [u8]>,
|
||||
mut setup_desc: impl FnMut(&mut DmaDescriptor),
|
||||
) {
|
||||
for descriptor in descriptors.iter_mut() {
|
||||
descriptor.buffer = buffer.as_mut_ptr();
|
||||
(setup_desc)(descriptor);
|
||||
buffer = &mut buffer[descriptor.size()..];
|
||||
if let Some(inner_buffer) = buffer {
|
||||
descriptor.buffer = inner_buffer.as_mut_ptr();
|
||||
buffer = Some(&mut inner_buffer[descriptor.size()..]);
|
||||
}
|
||||
(setup_desc)(descriptor);
|
||||
}
|
||||
|
||||
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);
|
||||
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| {
|
||||
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();
|
||||
});
|
||||
|
||||
// let (channel_rx, channel_tx) = self.channel.split();
|
||||
},
|
||||
);
|
||||
|
||||
{
|
||||
// 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())
|
||||
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<RawMutex, u32, 128> = 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<RawMutex, u32, 128> = 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,
|
||||
|
|
|
|||
|
|
@ -144,11 +144,7 @@ struct State {
|
|||
|
||||
impl State {
|
||||
async fn new(db: AcidDatabase, main: AppWindow) -> Rc<RefCell<Self>> {
|
||||
let users = {
|
||||
let users = Self::load_users(&db).await;
|
||||
warn!("Users: {users:#?}");
|
||||
users
|
||||
};
|
||||
let usernames = users.users.clone().map(|user| user.username);
|
||||
|
||||
let state = Rc::new(RefCell::new(State {
|
||||
|
|
|
|||
Loading…
Reference in a new issue