diff --git a/esp-hal-common/src/dma/gdma.rs b/esp-hal-common/src/dma/gdma.rs index 222980c37c9..43d20dcf81c 100644 --- a/esp-hal-common/src/dma/gdma.rs +++ b/esp-hal-common/src/dma/gdma.rs @@ -5,7 +5,7 @@ use crate::{ system::{Peripheral, PeripheralClockControl}, }; -macro_rules! ImplChannel { +macro_rules! impl_channel { ($num: literal) => { paste::paste! { pub struct [] {} @@ -18,23 +18,37 @@ macro_rules! ImplChannel { fn set_out_burstmode(burst_mode: bool) { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].modify(|_,w| { w.[]().bit(burst_mode) .[]().bit(burst_mode) }); + + #[cfg(esp32s3)] + dma.[].modify(|_,w| { + w.out_data_burst_en_ch().bit(burst_mode) + .outdscr_burst_en_ch().bit(burst_mode) + }); } fn set_out_priority(priority: DmaPriority) { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].write(|w| { w.[]().variant(priority as u8) }); + + #[cfg(esp32s3)] + dma.[].write(|w| { + w.tx_pri_ch().variant(priority as u8) + }); } fn clear_out_interrupts() { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].write(|w| { w.[]() .set_bit() @@ -49,62 +63,132 @@ macro_rules! ImplChannel { .[]() .set_bit() }); + + #[cfg(esp32s3)] + dma.[].write(|w| { + w.out_eof_ch_int_clr() + .set_bit() + .out_dscr_err_ch_int_clr() + .set_bit() + .out_done_ch_int_clr() + .set_bit() + .out_total_eof_ch_int_clr() + .set_bit() + .outfifo_ovf_l1_ch_int_clr() + .set_bit() + .outfifo_ovf_l3_ch_int_clr() + .set_bit() + .outfifo_udf_l1_ch_int_clr() + .set_bit() + .outfifo_udf_l3_ch_int_clr() + .set_bit() + }); } fn reset_out() { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[].modify(|_, w| w.[]().set_bit()); + #[cfg(not(esp32s3))] dma.[].modify(|_, w| w.[]().clear_bit()); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.out_rst_ch().set_bit()); + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.out_rst_ch().clear_bit()); } fn set_out_descriptors(address: u32) { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| unsafe { w.[]().bits(address) }); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| unsafe { w.outlink_addr_ch().bits(address) }); } fn has_out_descriptor_error() -> bool { let dma = unsafe { &*crate::pac::DMA::PTR }; - dma.[].read().[]().bit() + + #[cfg(esp32s3)] + let ret = dma.[].read().out_dscr_err_ch_int_raw().bit(); + + #[cfg(not(esp32s3))] + let ret = dma.[].read().[]().bit(); + + ret } fn set_out_peripheral(peripheral: u8) { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| w.[]().variant(peripheral)); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.peri_out_sel_ch().variant(peripheral)); } fn start_out() { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| w.[]().set_bit()); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.outlink_start_ch().set_bit()); } fn is_out_done() -> bool { let dma = unsafe { &*crate::pac::DMA::PTR }; - dma.[].read().[]().bit() + + #[cfg(not(esp32s3))] + let ret = dma.[].read().[]().bit(); + + #[cfg(esp32s3)] + let ret = dma.[].read().out_total_eof_ch_int_raw().bit(); + + ret } fn set_in_burstmode(burst_mode: bool) { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].modify(|_,w| { w.[]().bit(burst_mode) .[]().bit(burst_mode) }); + + #[cfg(esp32s3)] + dma.[].modify(|_,w| { + w.in_data_burst_en_ch().bit(burst_mode).indscr_burst_en_ch().bit(burst_mode) + }); } fn set_in_priority(priority: DmaPriority) { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].write(|w| { w.[]().variant(priority as u8) }); + + #[cfg(esp32s3)] + dma.[].write(|w| { + w.rx_pri_ch().variant(priority as u8) + }); } fn clear_in_interrupts() { let dma = unsafe { &*crate::pac::DMA::PTR }; + #[cfg(not(esp32s3))] dma.[].write(|w| { w.[]() .set_bit() @@ -121,40 +205,99 @@ macro_rules! ImplChannel { .[]() .set_bit() }); + + #[cfg(esp32s3)] + dma.[].write(|w| { + w.in_suc_eof_ch_int_clr() + .set_bit() + .in_err_eof_ch_int_clr() + .set_bit() + .in_dscr_err_ch_int_clr() + .set_bit() + .in_dscr_empty_ch_int_clr() + .set_bit() + .in_done_ch_int_clr() + .set_bit() + .infifo_ovf_l1_ch_int_clr() + .set_bit() + .infifo_ovf_l3_ch_int_clr() + .set_bit() + .infifo_udf_l1_ch_int_clr() + .set_bit() + .infifo_udf_l3_ch_int_clr() + .set_bit() + }); } fn reset_in() { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[].modify(|_, w| w.[]().set_bit()); + #[cfg(not(esp32s3))] dma.[].modify(|_, w| w.[]().clear_bit()); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.in_rst_ch().set_bit()); + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.in_rst_ch().clear_bit()); } fn set_in_descriptors(address: u32) { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| unsafe { w.[]().bits(address) }); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| unsafe { w.inlink_addr_ch().bits(address) }); } fn has_in_descriptor_error() -> bool { let dma = unsafe { &*crate::pac::DMA::PTR }; - dma.[].read().[]().bit() + + #[cfg(not(esp32s3))] + let ret = dma.[].read().[]().bit(); + + #[cfg(esp32s3)] + let ret = dma.[].read().in_dscr_err_ch_int_raw().bit(); + + ret } fn set_in_peripheral(peripheral: u8) { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| w.[]().variant(peripheral)); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.peri_in_sel_ch().variant(peripheral)); } fn start_in() { let dma = unsafe { &*crate::pac::DMA::PTR }; + + #[cfg(not(esp32s3))] dma.[] .modify(|_, w| w.[]().set_bit()); + + #[cfg(esp32s3)] + dma.[].modify(|_, w| w.inlink_start_ch().set_bit()); } fn is_in_done() -> bool { let dma = unsafe { &*crate::pac::DMA::PTR }; - dma.[].read().[]().bit() + + #[cfg(not(esp32s3))] + let ret = dma.[].read().[]().bit(); + + #[cfg(esp32s3)] + let ret = dma.[].read().in_suc_eof_ch_int_raw().bit(); + + ret } } @@ -166,8 +309,7 @@ macro_rules! ImplChannel { impl<'a> RxChannel<[]> for [] {} - pub struct [] { - } + pub struct [] {} impl [] { pub fn configure<'a>( @@ -219,9 +361,15 @@ macro_rules! ImplChannel { pub(crate) mod private { use crate::dma::{private::*, *}; - ImplChannel!(0); - ImplChannel!(1); - ImplChannel!(2); + impl_channel!(0); + #[cfg(not(esp32c2))] + impl_channel!(1); + #[cfg(not(esp32c2))] + impl_channel!(2); + #[cfg(esp32s3)] + impl_channel!(3); + #[cfg(esp32s3)] + impl_channel!(4); } /// GDMA Peripheral @@ -230,7 +378,9 @@ pub(crate) mod private { pub struct Gdma { _inner: crate::pac::DMA, pub channel0: ChannelCreator0, + #[cfg(not(esp32c2))] pub channel1: ChannelCreator1, + #[cfg(not(esp32c2))] pub channel2: ChannelCreator2, } @@ -248,7 +398,9 @@ impl Gdma { Gdma { _inner: dma, channel0: ChannelCreator0 {}, + #[cfg(not(esp32c2))] channel1: ChannelCreator1 {}, + #[cfg(not(esp32c2))] channel2: ChannelCreator2 {}, } } diff --git a/esp-hal-common/src/dma/mod.rs b/esp-hal-common/src/dma/mod.rs index 96ae45dd2fb..a08267798be 100644 --- a/esp-hal-common/src/dma/mod.rs +++ b/esp-hal-common/src/dma/mod.rs @@ -4,7 +4,7 @@ use core::{marker::PhantomData, sync::atomic::compiler_fence}; use private::*; -#[cfg(esp32c3)] +#[cfg(any(esp32c2, esp32c3, esp32s3))] pub mod gdma; #[cfg(any(esp32, esp32s2))] @@ -20,34 +20,38 @@ pub enum DmaError { } /// DMA Priorities -#[cfg(any(esp32c3, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32s3))] #[derive(Clone, Copy)] pub enum DmaPriority { - Priority0 = 0, - Priority1 = 1, - Priority2 = 2, - Priority3 = 3, - Priority4 = 4, - Priority5 = 5, - Priority6 = 6, - Priority7 = 7, - Priority8 = 8, - Priority9 = 9, - Priority10 = 10, - Priority11 = 11, - Priority12 = 12, - Priority13 = 13, - Priority14 = 14, - Priority15 = 15, + Priority0 = 0, + Priority1 = 1, + Priority2 = 2, + Priority3 = 3, + Priority4 = 4, + Priority5 = 5, + Priority6 = 6, + Priority7 = 7, + Priority8 = 8, + Priority9 = 9, } /// DMA Priorities +/// The values need to match the TRM #[cfg(any(esp32, esp32s2))] #[derive(Clone, Copy)] pub enum DmaPriority { Priority0 = 0, } +/// DMA capable peripherals +/// The values need to match the TRM +#[cfg(esp32c2)] +#[derive(Clone, Copy)] +pub enum DmaPeripheral { + Spi2 = 0, + Sha = 7, +} + /// DMA capable peripherals /// The values need to match the TRM #[cfg(esp32c3)] @@ -62,6 +66,7 @@ pub enum DmaPeripheral { } /// DMA capable peripherals +/// The values need to match the TRM #[cfg(any(esp32, esp32s2))] #[derive(Clone, Copy)] pub enum DmaPeripheral { @@ -69,6 +74,23 @@ pub enum DmaPeripheral { Spi3 = 1, } +/// DMA capable peripherals +/// The values need to match the TRM +#[cfg(esp32s3)] +#[derive(Clone, Copy)] +pub enum DmaPeripheral { + Spi2 = 0, + Spi3 = 1, + Uhci0 = 2, + I2s0 = 3, + I2s1 = 4, + LcdCam = 5, + Aes = 6, + Sha = 7, + Adc = 8, + Rmt = 9, +} + enum Owner { Cpu = 0, Dma = 1, @@ -175,7 +197,7 @@ pub(crate) mod private { pub trait Spi2Peripheral: SpiPeripheral + PeripheralMarker {} /// Marks channels as useable for SPI3 - #[cfg(any(esp32, esp32s2))] + #[cfg(any(esp32, esp32s2, esp32s3))] pub trait Spi3Peripheral: SpiPeripheral + PeripheralMarker {} /// DMA Rx diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 9f9dd9e7515..ff4380a3767 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -51,6 +51,7 @@ pub use self::{ pub mod analog; pub mod clock; pub mod delay; +pub mod dma; pub mod gpio; pub mod i2c; // FIXME: While the ESP32-C2 *does* have LEDC, it is not currently available in @@ -90,9 +91,6 @@ pub mod efuse; #[cfg_attr(xtensa, path = "interrupt/xtensa.rs")] pub mod interrupt; -#[cfg(any(esp32c3, esp32, esp32s2))] -pub mod dma; - /// Enumeration of CPU cores /// The actual number of available cores depends on the target. pub enum Cpu { diff --git a/esp-hal-common/src/spi.rs b/esp-hal-common/src/spi.rs index 708a34f24ef..e89ec265c6c 100644 --- a/esp-hal-common/src/spi.rs +++ b/esp-hal-common/src/spi.rs @@ -50,12 +50,13 @@ use fugit::HertzU32; -#[cfg(any(esp32c3, esp32, esp32s2))] -use crate::dma::private::{Rx, Tx}; -#[cfg(any(esp32c3, esp32, esp32s2))] -use crate::dma::{DmaError, DmaPeripheral}; use crate::{ clock::Clocks, + dma::{ + private::{Rx, Tx}, + DmaError, + DmaPeripheral, + }, pac::spi2::RegisterBlock, system::PeripheralClockControl, types::{InputSignal, OutputSignal}, @@ -76,13 +77,11 @@ const MAX_DMA_SIZE: usize = 32736; #[derive(Debug, Clone, Copy)] pub enum Error { - #[cfg(any(esp32c3, esp32, esp32s2))] DmaError(DmaError), MaxDmaTransferSizeExceeded, Unknown, } -#[cfg(any(esp32c3, esp32, esp32s2))] impl From for Error { fn from(value: DmaError) -> Self { Error::DmaError(value) @@ -262,7 +261,6 @@ where } } -#[cfg(any(esp32c3, esp32, esp32s2))] pub mod dma { use core::mem; @@ -916,7 +914,6 @@ mod ehal1 { } } -#[cfg(any(esp32c3, esp32, esp32s2))] pub trait InstanceDma: Instance where TX: Tx, @@ -1071,7 +1068,7 @@ where } } - #[cfg(esp32c3)] + #[cfg(any(esp32c2, esp32c3, esp32s3))] fn enable_dma(&self) { let reg_block = self.register_block(); reg_block.dma_conf.modify(|_, w| w.dma_tx_ena().set_bit()); @@ -1083,7 +1080,7 @@ where // for non GDMA this is done in `assign_tx_device` / `assign_rx_device` } - #[cfg(esp32c3)] + #[cfg(any(esp32c2, esp32c3, esp32s3))] fn clear_dma_interrupts(&self) { let reg_block = self.register_block(); reg_block.dma_int_clr.write(|w| { @@ -1126,7 +1123,6 @@ where } } -#[cfg(any(esp32c3, esp32, esp32s2))] impl InstanceDma for crate::pac::SPI2 where TX: Tx, @@ -1134,7 +1130,7 @@ where { } -#[cfg(any(esp32, esp32s2))] +#[cfg(any(esp32, esp32s2, esp32s3))] impl InstanceDma for crate::pac::SPI3 where TX: Tx, @@ -1706,10 +1702,10 @@ impl Instance for crate::pac::SPI3 { pub trait Spi2Instance {} -#[cfg(any(esp32, esp32s2))] +#[cfg(any(esp32, esp32s2, esp32s3))] pub trait Spi3Instance {} impl Spi2Instance for crate::pac::SPI2 {} -#[cfg(any(esp32, esp32s2))] +#[cfg(any(esp32, esp32s2, esp32s3))] impl Spi3Instance for crate::pac::SPI3 {} diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index 3b10de9bdf3..cc78e49781b 100644 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -26,7 +26,7 @@ pub enum Peripheral { Ledc, #[cfg(any(esp32c2, esp32c3))] ApbSarAdc, - #[cfg(esp32c3)] + #[cfg(any(esp32c2, esp32c3, esp32s3))] Gdma, #[cfg(any(esp32, esp32s2))] Dma, @@ -47,7 +47,7 @@ impl PeripheralClockControl { #[cfg(esp32)] let (perip_clk_en0, perip_rst_en0) = { (&system.perip_clk_en, &system.perip_rst_en) }; - #[cfg(esp32c3)] + #[cfg(any(esp32c2, esp32c3, esp32s3))] let (perip_clk_en1, perip_rst_en1) = { (&system.perip_clk_en1, &system.perip_rst_en1) }; match peripheral { @@ -89,7 +89,7 @@ impl PeripheralClockControl { perip_clk_en0.modify(|_, w| w.apb_saradc_clk_en().set_bit()); perip_rst_en0.modify(|_, w| w.apb_saradc_rst().clear_bit()); } - #[cfg(esp32c3)] + #[cfg(any(any(esp32c2, esp32c3, esp32s3)))] Peripheral::Gdma => { perip_clk_en1.modify(|_, w| w.dma_clk_en().set_bit()); perip_rst_en1.modify(|_, w| w.dma_rst().clear_bit()); diff --git a/esp32c2-hal/examples/spi_loopback_dma.rs b/esp32c2-hal/examples/spi_loopback_dma.rs new file mode 100644 index 00000000000..3b8eb46aaba --- /dev/null +++ b/esp32c2-hal/examples/spi_loopback_dma.rs @@ -0,0 +1,120 @@ +//! SPI loopback test using DMA +//! +//! Folowing pins are used: +//! SCLK GPIO6 +//! MISO GPIO2 +//! MOSI GPIO7 +//! CS GPIO10 +//! +//! Depending on your target and the board you are using you have to change the +//! pins. +//! +//! This example transfers data via SPI. +//! Connect MISO and MOSI pins to see the outgoing data is read as incoming +//! data. + +#![no_std] +#![no_main] + +use esp32c2_hal::{ + clock::ClockControl, + dma::{DmaPriority, DmaTransferRxTx}, + gdma::Gdma, + gpio::IO, + pac::Peripherals, + prelude::*, + spi::{dma::WithDmaSpi2, Spi, SpiMode}, + timer::TimerGroup, + Delay, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; +use riscv_rt::entry; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let mut system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-C2, this includes the Super WDT, + // the RTC WDT, and the TIMG WDT. + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); + let mut wdt0 = timer_group0.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let sclk = io.pins.gpio6; + let miso = io.pins.gpio2; + let mosi = io.pins.gpio7; + let cs = io.pins.gpio10; + + let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + + let mut spi = Spi::new( + peripherals.SPI2, + sclk, + mosi, + miso, + cs, + 100u32.kHz(), + SpiMode::Mode0, + &mut system.peripheral_clock_control, + &clocks, + ) + .with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); + + let mut delay = Delay::new(&clocks); + + // DMA buffer require a static life-time + let mut send = buffer1(); + let mut receive = buffer2(); + let mut i = 0; + + for (i, v) in send.iter_mut().enumerate() { + *v = (i % 255) as u8; + } + + loop { + send[0] = i; + send[send.len() - 1] = i; + i = i.wrapping_add(1); + + let transfer = spi.dma_transfer(send, receive).unwrap(); + // here we could do something else while DMA transfer is in progress + // the buffers and spi is moved into the transfer and we can get it back via + // `wait` + (receive, send, spi) = transfer.wait(); + println!( + "{:x?} .. {:x?}", + &receive[..10], + &receive[receive.len() - 10..] + ); + + delay.delay_ms(250u32); + } +} + +fn buffer1() -> &'static mut [u8; 32000] { + static mut BUFFER: [u8; 32000] = [0u8; 32000]; + unsafe { &mut BUFFER } +} + +fn buffer2() -> &'static mut [u8; 32000] { + static mut BUFFER: [u8; 32000] = [0u8; 32000]; + unsafe { &mut BUFFER } +} diff --git a/esp32c2-hal/src/lib.rs b/esp32c2-hal/src/lib.rs index a477c5636af..7c52addc1d9 100644 --- a/esp32c2-hal/src/lib.rs +++ b/esp32c2-hal/src/lib.rs @@ -5,6 +5,7 @@ use core::arch::global_asm; pub use embedded_hal as ehal; pub use esp_hal_common::{ clock, + dma::{self, gdma}, efuse, gpio as gpio_types, i2c, diff --git a/esp32s3-hal/examples/spi_loopback_dma.rs b/esp32s3-hal/examples/spi_loopback_dma.rs new file mode 100644 index 00000000000..dc16fa42e5a --- /dev/null +++ b/esp32s3-hal/examples/spi_loopback_dma.rs @@ -0,0 +1,123 @@ +//! SPI loopback test using DMA +//! +//! Folowing pins are used: +//! SCLK GPIO6 +//! MISO GPIO2 +//! MOSI GPIO7 +//! CS GPIO10 +//! +//! Depending on your target and the board you are using you have to change the +//! pins. +//! +//! This example transfers data via SPI. +//! Connect MISO and MOSI pins to see the outgoing data is read as incoming +//! data. + +#![no_std] +#![no_main] + +use esp32s3_hal::{ + clock::ClockControl, + dma::{DmaPriority, DmaTransferRxTx}, + gdma::Gdma, + gpio::IO, + pac::Peripherals, + prelude::*, + spi::{dma::WithDmaSpi2, Spi, SpiMode}, + timer::TimerGroup, + Delay, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; +use xtensa_lx_rt::entry; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let mut system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT, + // the RTC WDT, and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks); + let mut wdt1 = timer_group1.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let sclk = io.pins.gpio6; + let miso = io.pins.gpio2; + let mosi = io.pins.gpio7; + let cs = io.pins.gpio10; + + let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control); + let dma_channel = dma.channel0; + + let mut descriptors = [0u32; 8 * 3]; + let mut rx_descriptors = [0u32; 8 * 3]; + + let mut spi = Spi::new( + peripherals.SPI2, + sclk, + mosi, + miso, + cs, + 100u32.kHz(), + SpiMode::Mode0, + &mut system.peripheral_clock_control, + &clocks, + ) + .with_dma(dma_channel.configure( + false, + &mut descriptors, + &mut rx_descriptors, + DmaPriority::Priority0, + )); + + let mut delay = Delay::new(&clocks); + + // DMA buffer require a static life-time + let mut send = buffer1(); + let mut receive = buffer2(); + let mut i = 0; + + for (i, v) in send.iter_mut().enumerate() { + *v = (i % 255) as u8; + } + + loop { + send[0] = i; + send[send.len() - 1] = i; + i = i.wrapping_add(1); + + let transfer = spi.dma_transfer(send, receive).unwrap(); + // here we could do something else while DMA transfer is in progress + // the buffers and spi is moved into the transfer and we can get it back via + // `wait` + (receive, send, spi) = transfer.wait(); + println!( + "{:x?} .. {:x?}", + &receive[..10], + &receive[receive.len() - 10..] + ); + + delay.delay_ms(250u32); + } +} + +fn buffer1() -> &'static mut [u8; 32000] { + static mut BUFFER: [u8; 32000] = [0u8; 32000]; + unsafe { &mut BUFFER } +} + +fn buffer2() -> &'static mut [u8; 32000] { + static mut BUFFER: [u8; 32000] = [0u8; 32000]; + unsafe { &mut BUFFER } +} diff --git a/esp32s3-hal/src/lib.rs b/esp32s3-hal/src/lib.rs index e4ebb5928e3..2e219c3c1d5 100644 --- a/esp32s3-hal/src/lib.rs +++ b/esp32s3-hal/src/lib.rs @@ -6,6 +6,7 @@ pub use embedded_hal as ehal; pub use esp_hal_common::{ clock, cpu_control::CpuControl, + dma::{self, gdma}, efuse, gpio as gpio_types, i2c,