Skip to content

Commit

Permalink
initial non-working attemt for dma from psram on esp32s3
Browse files Browse the repository at this point in the history
  • Loading branch information
liebman committed Jul 17, 2024
1 parent 32be53d commit f0f5a53
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 5 deletions.
28 changes: 28 additions & 0 deletions esp-hal/src/dma/gdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ impl<const N: u8> RegisterAccess for Channel<N> {
.modify(|_, w| w.mem_trans_en().bit(value));
}

#[cfg(esp32s3)]
fn set_out_ext_mem_block_size(size: DmaExtMemBKSize) {
Self::ch()
.out_conf1()
.modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
}

fn set_out_burstmode(burst_mode: bool) {
Self::ch().out_conf0().modify(|_, w| {
w.out_data_burst_en()
Expand Down Expand Up @@ -206,6 +213,13 @@ impl<const N: u8> RegisterAccess for Channel<N> {
.write(|w| w.out_eof().clear_bit_by_one());
}

#[cfg(esp32s3)]
fn set_in_ext_mem_block_size(size: DmaExtMemBKSize) {
Self::ch()
.in_conf1()
.modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
}

fn set_in_burstmode(burst_mode: bool) {
Self::ch().in_conf0().modify(|_, w| {
w.in_data_burst_en()
Expand Down Expand Up @@ -626,6 +640,8 @@ pub use m2m::*;
mod m2m {
use embedded_dma::{ReadBuffer, WriteBuffer};

#[cfg(esp32s3)]
use crate::dma::DmaExtMemBKSize;
use crate::dma::{
dma_private::{DmaSupport, DmaSupportRx},
Channel,
Expand Down Expand Up @@ -751,6 +767,18 @@ mod m2m {
.prepare_transfer_without_start(self.peripheral, &self.rx_chain)?;
self.channel.rx.set_mem2mem_mode(true);
}
#[cfg(esp32s3)]
if crate::soc::is_valid_psram_address(tx_ptr as u32) {
self.channel
.tx
.set_ext_mem_block_size(DmaExtMemBKSize::Size32);
}
#[cfg(esp32s3)]
if crate::soc::is_valid_psram_address(rx_ptr as u32) {
self.channel
.rx
.set_ext_mem_block_size(DmaExtMemBKSize::Size32);
}
self.channel.tx.start_transfer()?;
self.channel.rx.start_transfer()?;
Ok(DmaTransferRx::new(self))
Expand Down
39 changes: 34 additions & 5 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl Debug for DmaDescriptorFlags {
.field("size", &self.size())
.field("length", &self.length())
.field("suc_eof", &self.suc_eof())
.field("owner", &self.owner())
.field("owner", &(if self.owner() { "DMA" } else { "CPU" }))
.finish()
}
}
Expand Down Expand Up @@ -567,8 +567,8 @@ impl DescriptorChain {
) -> Result<(), DmaError> {
if !crate::soc::is_valid_ram_address(self.first() as u32)
|| !crate::soc::is_valid_ram_address(self.last() as u32)
|| !crate::soc::is_valid_ram_address(data as u32)
|| !crate::soc::is_valid_ram_address(unsafe { data.add(len) } as u32)
|| !crate::soc::is_valid_memory_address(data as u32)
|| !crate::soc::is_valid_memory_address(unsafe { data.add(len) } as u32)
{
return Err(DmaError::UnsupportedMemoryRegion);
}
Expand Down Expand Up @@ -639,8 +639,8 @@ impl DescriptorChain {
) -> Result<(), DmaError> {
if !crate::soc::is_valid_ram_address(self.first() as u32)
|| !crate::soc::is_valid_ram_address(self.last() as u32)
|| !crate::soc::is_valid_ram_address(data as u32)
|| !crate::soc::is_valid_ram_address(unsafe { data.add(len) } as u32)
|| !crate::soc::is_valid_memory_address(data as u32)
|| !crate::soc::is_valid_memory_address(unsafe { data.add(len) } as u32)
{
return Err(DmaError::UnsupportedMemoryRegion);
}
Expand Down Expand Up @@ -707,6 +707,15 @@ impl DescriptorChain {
}
}

/// Block size for transfers to/from psram
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum DmaExtMemBKSize {
Size16 = 0,
Size32 = 1,
Size64 = 2,
}

pub(crate) struct TxCircularState {
write_offset: usize,
write_descr_ptr: *mut DmaDescriptor,
Expand Down Expand Up @@ -967,6 +976,9 @@ pub trait RxPrivate: crate::private::Sealed {

fn start_transfer(&mut self) -> Result<(), DmaError>;

#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);

#[cfg(gdma)]
fn set_mem2mem_mode(&mut self, value: bool);

Expand Down Expand Up @@ -1126,6 +1138,11 @@ where
self.rx_impl.start_transfer()
}

#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
CH::Channel::set_in_ext_mem_block_size(size);
}

#[cfg(gdma)]
fn set_mem2mem_mode(&mut self, value: bool) {
CH::Channel::set_mem2mem_mode(value);
Expand Down Expand Up @@ -1244,6 +1261,9 @@ pub trait TxPrivate: crate::private::Sealed {

fn start_transfer(&mut self) -> Result<(), DmaError>;

#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize);

fn clear_ch_out_done(&self);

fn is_ch_out_done_set(&self) -> bool;
Expand Down Expand Up @@ -1410,6 +1430,11 @@ where
self.tx_impl.start_transfer()
}

#[cfg(esp32s3)]
fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
CH::Channel::set_out_ext_mem_block_size(size);
}

fn clear_ch_out_done(&self) {
self.tx_impl.clear_ch_out_done();
}
Expand Down Expand Up @@ -1489,6 +1514,8 @@ pub trait RegisterAccess: crate::private::Sealed {
fn init_channel();
#[cfg(gdma)]
fn set_mem2mem_mode(value: bool);
#[cfg(esp32s3)]
fn set_out_ext_mem_block_size(size: DmaExtMemBKSize);
fn set_out_burstmode(burst_mode: bool);
fn set_out_priority(priority: DmaPriority);
fn clear_out_interrupts();
Expand All @@ -1507,6 +1534,8 @@ pub trait RegisterAccess: crate::private::Sealed {
fn reset_out_eof_interrupt();
fn last_out_dscr_address() -> usize;

#[cfg(esp32s3)]
fn set_in_ext_mem_block_size(size: DmaExtMemBKSize);
fn set_in_burstmode(burst_mode: bool);
fn set_in_priority(priority: DmaPriority);
fn clear_in_interrupts();
Expand Down
17 changes: 17 additions & 0 deletions esp-hal/src/soc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,20 @@ impl self::efuse::Efuse {
pub(crate) fn is_valid_ram_address(address: u32) -> bool {
(self::constants::SOC_DRAM_LOW..=self::constants::SOC_DRAM_HIGH).contains(&address)
}

#[allow(unused)]
pub(crate) fn is_valid_psram_address(address: u32) -> bool {
#[cfg(psram)]
{
let start = crate::psram::psram_vaddr_start() as u32;
let end = start + crate::psram::PSRAM_BYTES as u32;
(start..=end).contains(&address)
}
#[cfg(not(psram))]
false
}

#[allow(unused)]
pub(crate) fn is_valid_memory_address(address: u32) -> bool {
is_valid_ram_address(address) || is_valid_psram_address(address)
}
1 change: 1 addition & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false

[dependencies]
aes = "0.8.4"
aligned = { version = "0.4.2", optional = true }
bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [ "macros", "async"] }
cfg-if = "1.0.0"
critical-section = "1.1.2"
Expand Down
126 changes: 126 additions & 0 deletions examples/src/bin/dma_extmem2mem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//! Uses DMA to copy psram to internal memory.
//% FEATURES: esp-hal/log opsram-2m aligned
//% CHIPS: esp32s3

#![no_std]
#![no_main]

use aligned::{Aligned, A64};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
dma::{Dma, DmaPriority, Mem2Mem},
dma_descriptors_chunk_size,
peripherals::Peripherals,
prelude::*,
system::SystemControl,
};
use log::{error, info};
extern crate alloc;

const DATA_SIZE: usize = 1024 * 10;
const CHUNK_SIZE: usize = 4032; // size is aligned to 64 bytes

macro_rules! dma_buffer_aligned {
($size:expr, $align:ty) => {{
static mut BUFFER: Aligned<$align, [u8; $size]> = Aligned([0; $size]);
unsafe { &mut *BUFFER }
}};
}

macro_rules! dma_alloc_buffer {
($size:expr, $align:expr) => {{
let layout = core::alloc::Layout::from_size_align($size, $align).unwrap();
unsafe {
let ptr = alloc::alloc::alloc(layout);
if ptr.is_null() {
error!("make_buffers: alloc failed");
alloc::alloc::handle_alloc_error(layout);
}
core::slice::from_raw_parts_mut(ptr, $size)
}
}};
}

#[global_allocator]
static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();

fn init_heap(psram: impl esp_hal::peripheral::Peripheral<P = esp_hal::peripherals::PSRAM>) {
esp_hal::psram::init_psram(psram);
info!(
"init_heap: start: 0x{:0x}",
esp_hal::psram::psram_vaddr_start()
);
unsafe {
ALLOCATOR.init(
esp_hal::psram::psram_vaddr_start() as *mut u8,
esp_hal::psram::PSRAM_BYTES,
);
}
}

#[entry]
fn main() -> ! {
esp_println::logger::init_logger(log::LevelFilter::Info);

let peripherals = Peripherals::take();
init_heap(peripherals.PSRAM);
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let delay = Delay::new(&clocks);

let mut rx_buffer: &mut [u8] = dma_alloc_buffer!(DATA_SIZE, 64);
let tx_buffer = dma_buffer_aligned!(DATA_SIZE, A64);
let (tx_descriptors, rx_descriptors) = dma_descriptors_chunk_size!(DATA_SIZE, CHUNK_SIZE);

let dma = Dma::new(peripherals.DMA);
let channel = dma.channel0.configure(false, DmaPriority::Priority0);
let dma_peripheral = peripherals.SPI2;

let mut mem2mem = Mem2Mem::new_with_chunk_size(
channel,
dma_peripheral,
tx_descriptors,
rx_descriptors,
CHUNK_SIZE,
)
.unwrap();

for i in 0..core::mem::size_of_val(tx_buffer) {
tx_buffer[i] = (i % 256) as u8;
}

info!("Starting transfer of {} bytes", DATA_SIZE);
let result = mem2mem.start_transfer(&tx_buffer, &mut rx_buffer);
match result {
Ok(dma_wait) => {
info!("Transfer started");
dma_wait.wait().unwrap();
info!("Transfer completed, comparing buffer");
let mut error = false;
for i in 0..core::mem::size_of_val(tx_buffer) {
if rx_buffer[i] != tx_buffer[i] {
error!(
"Error: tx_buffer[{}] = {}, rx_buffer[{}] = {}",
i, tx_buffer[i], i, rx_buffer[i]
);
error = true;
break;
}
}
if !error {
info!("Buffers are equal");
}
info!("Done");
}
Err(e) => {
error!("start_transfer: Error: {:?}", e);
}
}

loop {
delay.delay(2.secs());
}
}

0 comments on commit f0f5a53

Please sign in to comment.