Async DMA transfer
This commit is contained in:
parent
04f4070634
commit
ebf8205f2d
|
|
@ -38,3 +38,14 @@ ACID_COMPOSE_LOCALE = "cs_CZ.UTF-8"
|
|||
# This can be substituted with a `-Zbuild-std="core,alloc"` cargo flag.
|
||||
[unstable]
|
||||
build-std = ["alloc", "core"]
|
||||
|
||||
[patch.crates-io]
|
||||
esp-backtrace = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-hal = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-storage = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-alloc = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-println = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-radio = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-rtos = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-bootloader-esp-idf = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
esp-sync = { git = "https://github.com/Limeth/esp-hal.git", rev = "72e22e2de678297da65a185023309a76aef8a5ca" }
|
||||
|
|
|
|||
|
|
@ -289,9 +289,7 @@ async fn main(_spawner: Spawner) {
|
|||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||
let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||
esp_rtos::start(
|
||||
timg0.timer0, /*, software_interrupt.software_interrupt0 */
|
||||
);
|
||||
esp_rtos::start(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);
|
||||
|
|
@ -592,7 +590,7 @@ async fn main(_spawner: Spawner) {
|
|||
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
||||
esp_rtos::start_second_core(
|
||||
peripherals.CPU_CTRL,
|
||||
software_interrupt.software_interrupt0,
|
||||
// software_interrupt.software_interrupt0,
|
||||
software_interrupt.software_interrupt1,
|
||||
second_core_stack,
|
||||
move || {
|
||||
|
|
|
|||
|
|
@ -1276,7 +1276,7 @@ where
|
|||
//
|
||||
// Adafruit would use 11 MHz.
|
||||
// I had lowered the frequency, so that `DmaBounce` could keep up.
|
||||
.with_frequency(Rate::from_mhz(8)) // From Adafruit
|
||||
.with_frequency(Rate::from_mhz(7)) // From Adafruit
|
||||
.with_clock_mode(ClockMode {
|
||||
polarity: Polarity::IdleLow, // From Adafruit
|
||||
phase: Phase::ShiftHigh, // From Adafruit
|
||||
|
|
|
|||
|
|
@ -13,19 +13,19 @@ use embassy_sync::{
|
|||
channel::{Channel, TrySendError},
|
||||
signal::Signal,
|
||||
};
|
||||
use embassy_time::{Instant, Timer};
|
||||
use embassy_time::{Duration, Instant, Timer, WithTimeout};
|
||||
use esp_alloc::MemoryCapability;
|
||||
use esp_hal::{
|
||||
Blocking,
|
||||
dma::{
|
||||
self, AnyGdmaChannel, BufView, BurstConfig, DmaChannel, DmaChannelConvert, DmaDescriptor,
|
||||
DmaDescriptorFlags, DmaEligible, DmaRxStreamBuf, DmaTxBuf, DmaTxBuffer, DmaTxInterrupt,
|
||||
ExternalBurstConfig, Mem2Mem,
|
||||
ExternalBurstConfig, Mem2Mem, SimpleMem2MemTransfer,
|
||||
},
|
||||
dma_descriptors, handler,
|
||||
interrupt::{self, Priority},
|
||||
lcd_cam::lcd::dpi::{Dpi, DpiTransfer},
|
||||
peripherals::{DMA, DMA_CH0, Peripherals, SPI2},
|
||||
peripherals::{DMA, DMA_CH0, Interrupt, Peripherals, SPI2},
|
||||
ram,
|
||||
spi::master::AnySpi,
|
||||
};
|
||||
|
|
@ -74,6 +74,11 @@ pub unsafe fn cache_invalidate_addr(addr: u32, size: u32) {
|
|||
}
|
||||
}
|
||||
|
||||
// const DMA_CHANNEL_INBOUND: usize = 0;
|
||||
// const INTERRUPT_INBOUND: Interrupt = Interrupt::DMA_IN_CH0;
|
||||
const DMA_CHANNEL_OUTBOUND: usize = 2;
|
||||
const INTERRUPT_OUTBOUND: Interrupt = Interrupt::DMA_OUT_CH2;
|
||||
|
||||
pub struct DmaBounce {
|
||||
// TODO: Make these generic.
|
||||
// They currently cannot be generic, because they lacks a `reborrow` method.
|
||||
|
|
@ -344,21 +349,28 @@ impl DmaBounce {
|
|||
}
|
||||
|
||||
fn enable_interrupts() {
|
||||
// TODO: Get from self.channel
|
||||
let channel_number = 2;
|
||||
let interrupt = esp_hal::peripherals::Interrupt::DMA_OUT_CH2;
|
||||
|
||||
// Enable interrupts for the peripheral
|
||||
interrupt::enable(interrupt, dma_interrupt_handler.priority()).unwrap();
|
||||
// interrupt::enable(INTERRUPT_INBOUND, dma_inbound_interrupt_handler.priority()).unwrap();
|
||||
interrupt::enable(
|
||||
INTERRUPT_OUTBOUND,
|
||||
dma_outbound_interrupt_handler.priority(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Bind the handler
|
||||
unsafe {
|
||||
interrupt::bind_interrupt(interrupt, dma_interrupt_handler.handler());
|
||||
// interrupt::bind_interrupt(INTERRUPT_INBOUND, dma_inbound_interrupt_handler.handler());
|
||||
interrupt::bind_interrupt(INTERRUPT_OUTBOUND, dma_outbound_interrupt_handler.handler());
|
||||
}
|
||||
|
||||
// Enable interrupts in the peripheral.
|
||||
// DMA::regs()
|
||||
// .ch(DMA_CHANNEL_INBOUND)
|
||||
// .in_int()
|
||||
// .ena()
|
||||
// .modify(|_, w| w.in_done().bit(true));
|
||||
DMA::regs()
|
||||
.ch(channel_number)
|
||||
.ch(DMA_CHANNEL_OUTBOUND)
|
||||
.out_int()
|
||||
.ena()
|
||||
.modify(|_, w| w.out_eof().bit(true));
|
||||
|
|
@ -366,7 +378,7 @@ impl DmaBounce {
|
|||
|
||||
/// Receive a window of bytes into the current dst bounce buffer.
|
||||
/// Finally, swaps the bounce buffers.
|
||||
fn receive_window_blocking(&mut self) {
|
||||
async fn receive_window(&mut self) {
|
||||
// Descriptors are initialized by `DmaTxBuf::new`.
|
||||
let buffer_src_window =
|
||||
&mut self.buffer_src[self.window_index_next * self.window_size..][..self.window_size];
|
||||
|
|
@ -392,13 +404,15 @@ impl DmaBounce {
|
|||
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())
|
||||
.into_async()
|
||||
.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();
|
||||
|
||||
transfer.wait().unwrap();
|
||||
// INBOUND_TRANSFER_FINISHED.wait().await;
|
||||
transfer.wait_async().await.unwrap();
|
||||
}
|
||||
|
||||
self.increase_window_counter(1);
|
||||
|
|
@ -409,7 +423,7 @@ impl DmaBounce {
|
|||
core::mem::swap(&mut self.bounce_buffer_dst, &mut self.bounce_buffer_src);
|
||||
}
|
||||
|
||||
self.window_index_next = self.window_index_next + windows;
|
||||
self.window_index_next += windows;
|
||||
self.frame_index_next += self.window_index_next / self.windows_len;
|
||||
self.window_index_next = self.window_index_next % self.windows_len;
|
||||
}
|
||||
|
|
@ -419,7 +433,7 @@ impl DmaBounce {
|
|||
Self::enable_interrupts();
|
||||
|
||||
// Receive the first window, so that the outbound transfer can read valid data.
|
||||
self.receive_window_blocking();
|
||||
self.receive_window().await;
|
||||
|
||||
let mut dma_tx_buffer = self.get_dma_tx_buffer();
|
||||
let mut transfer = self
|
||||
|
|
@ -434,8 +448,15 @@ impl DmaBounce {
|
|||
let mut windows_skipped_total = 0;
|
||||
|
||||
loop {
|
||||
self.receive_window_blocking();
|
||||
let windows_skipped = WINDOWS_SKIPPED.wait().await;
|
||||
self.receive_window().await;
|
||||
let windows_skipped = WINDOWS_SKIPPED
|
||||
.wait()
|
||||
// .with_timeout(Duration::from_secs(1))
|
||||
.await;
|
||||
// .unwrap_or_else(|_| {
|
||||
// error!("Timed out while waiting for skipped windows");
|
||||
// 0
|
||||
// });
|
||||
|
||||
if windows_skipped > 0 {
|
||||
self.increase_window_counter(windows_skipped);
|
||||
|
|
@ -548,11 +569,12 @@ unsafe impl DmaTxBuffer for DmaTxBounceBuf {
|
|||
}
|
||||
|
||||
static WINDOWS_SKIPPED: Signal<RawMutex, usize> = Signal::new();
|
||||
// static INBOUND_TRANSFER_FINISHED: Signal<RawMutex, ()> = Signal::new();
|
||||
|
||||
#[handler(priority = Priority::Priority3)]
|
||||
#[ram] // Improves performance.
|
||||
fn dma_interrupt_handler() {
|
||||
let interrupt = DMA::regs().ch(2).out_int();
|
||||
fn dma_outbound_interrupt_handler() {
|
||||
let interrupt = DMA::regs().ch(DMA_CHANNEL_OUTBOUND).out_int();
|
||||
let bounce_buffer_processed = interrupt.st().read().out_eof().bit_is_set();
|
||||
if bounce_buffer_processed {
|
||||
// Clear the bit by writing 1 to the clear bits.
|
||||
|
|
@ -566,6 +588,25 @@ fn dma_interrupt_handler() {
|
|||
}
|
||||
}
|
||||
|
||||
// #[handler(priority = Priority::Priority3)]
|
||||
// #[ram] // Improves performance.
|
||||
// fn dma_inbound_interrupt_handler() {
|
||||
// warn!("Inbound");
|
||||
|
||||
// let interrupt = DMA::regs().ch(DMA_CHANNEL_INBOUND).in_int();
|
||||
// let bounce_buffer_processed = interrupt.st().read().in_done().bit_is_set();
|
||||
// if bounce_buffer_processed {
|
||||
// // Clear the bit by writing 1 to the clear bits.
|
||||
// interrupt.clr().write(|w| w.in_done().bit(true));
|
||||
|
||||
// assert!(
|
||||
// !INBOUND_TRANSFER_FINISHED.signaled(),
|
||||
// "inbound transfer already signalled"
|
||||
// );
|
||||
// INBOUND_TRANSFER_FINISHED.signal(());
|
||||
// }
|
||||
// }
|
||||
|
||||
pub async fn run_lcd(
|
||||
mut st7701s: St7701s<'static, Blocking>,
|
||||
framebuffer: &'static mut Framebuffer,
|
||||
|
|
|
|||
Loading…
Reference in a new issue