From 3e4710b822d21f9673873757f8c3330e147065c6 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Tue, 25 Oct 2022 13:37:48 +0200 Subject: [PATCH] Add DMA support for ESP32-S2 --- esp-hal-common/src/analog/adc/esp32s3.rs | 12 ++- esp-hal-common/src/dma/mod.rs | 6 +- esp-hal-common/src/dma/pdma.rs | 31 +++--- esp-hal-common/src/lib.rs | 2 +- esp-hal-common/src/spi.rs | 34 +++---- esp-hal-common/src/system.rs | 17 +++- esp32s2-hal/examples/adc.rs | 5 +- esp32s2-hal/examples/hello_world.rs | 2 +- esp32s2-hal/examples/spi_loopback_dma.rs | 119 +++++++++++++++++++++++ esp32s2-hal/src/lib.rs | 2 + 10 files changed, 185 insertions(+), 45 deletions(-) create mode 100644 esp32s2-hal/examples/spi_loopback_dma.rs diff --git a/esp-hal-common/src/analog/adc/esp32s3.rs b/esp-hal-common/src/analog/adc/esp32s3.rs index 1d46e609fe2..ac75c1549e7 100644 --- a/esp-hal-common/src/analog/adc/esp32s3.rs +++ b/esp-hal-common/src/analog/adc/esp32s3.rs @@ -161,7 +161,11 @@ impl RegisterAccess for ADC1 { fn read_done_sar() -> bool { let sensors = unsafe { &*SENS::ptr() }; - sensors.sar_meas1_ctrl2.read().sar_meas1_done_sar().bit_is_set() + sensors + .sar_meas1_ctrl2 + .read() + .sar_meas1_done_sar() + .bit_is_set() } fn read_data_sar() -> u16 { @@ -238,7 +242,11 @@ impl RegisterAccess for ADC2 { fn read_done_sar() -> bool { let sensors = unsafe { &*SENS::ptr() }; - sensors.sar_meas2_ctrl2.read().sar_meas2_done_sar().bit_is_set() + sensors + .sar_meas2_ctrl2 + .read() + .sar_meas2_done_sar() + .bit_is_set() } fn read_data_sar() -> u16 { diff --git a/esp-hal-common/src/dma/mod.rs b/esp-hal-common/src/dma/mod.rs index ebeaf8a674c..96ae45dd2fb 100644 --- a/esp-hal-common/src/dma/mod.rs +++ b/esp-hal-common/src/dma/mod.rs @@ -7,7 +7,7 @@ use private::*; #[cfg(esp32c3)] pub mod gdma; -#[cfg(esp32)] +#[cfg(any(esp32, esp32s2))] pub mod pdma; /// DMA Errors @@ -62,7 +62,7 @@ pub enum DmaPeripheral { } /// DMA capable peripherals -#[cfg(esp32)] +#[cfg(any(esp32, esp32s2))] #[derive(Clone, Copy)] pub enum DmaPeripheral { Spi2 = 0, @@ -175,7 +175,7 @@ pub(crate) mod private { pub trait Spi2Peripheral: SpiPeripheral + PeripheralMarker {} /// Marks channels as useable for SPI3 - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] pub trait Spi3Peripheral: SpiPeripheral + PeripheralMarker {} /// DMA Rx diff --git a/esp-hal-common/src/dma/pdma.rs b/esp-hal-common/src/dma/pdma.rs index 3e14f74eecc..96c48f0e32a 100644 --- a/esp-hal-common/src/dma/pdma.rs +++ b/esp-hal-common/src/dma/pdma.rs @@ -13,20 +13,23 @@ macro_rules! ImplSpiChannel { impl RegisterAccess for [] { fn init_channel() { // (only) on ESP32 we need to configure DPORT for the SPI DMA channels - let dport = unsafe { &*crate::pac::DPORT::PTR }; - - match $num { - 2 => { - dport - .spi_dma_chan_sel - .modify(|_, w| w.spi2_dma_chan_sel().variant(1)); - }, - 3 => { - dport - .spi_dma_chan_sel - .modify(|_, w| w.spi3_dma_chan_sel().variant(2)); - }, - _ => panic!("Only SPI2 and SPI3 supported"), + #[cfg(esp32)] + { + let dport = unsafe { &*crate::pac::DPORT::PTR }; + + match $num { + 2 => { + dport + .spi_dma_chan_sel + .modify(|_, w| w.spi2_dma_chan_sel().variant(1)); + }, + 3 => { + dport + .spi_dma_chan_sel + .modify(|_, w| w.spi3_dma_chan_sel().variant(2)); + }, + _ => panic!("Only SPI2 and SPI3 supported"), + } } } diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index ced0edfa135..9f9dd9e7515 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -90,7 +90,7 @@ pub mod efuse; #[cfg_attr(xtensa, path = "interrupt/xtensa.rs")] pub mod interrupt; -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] pub mod dma; /// Enumeration of CPU cores diff --git a/esp-hal-common/src/spi.rs b/esp-hal-common/src/spi.rs index 0e56b4d55b9..708a34f24ef 100644 --- a/esp-hal-common/src/spi.rs +++ b/esp-hal-common/src/spi.rs @@ -50,9 +50,9 @@ use fugit::HertzU32; -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] use crate::dma::private::{Rx, Tx}; -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] use crate::dma::{DmaError, DmaPeripheral}; use crate::{ clock::Clocks, @@ -76,13 +76,13 @@ const MAX_DMA_SIZE: usize = 32736; #[derive(Debug, Clone, Copy)] pub enum Error { - #[cfg(any(esp32c3, esp32))] + #[cfg(any(esp32c3, esp32, esp32s2))] DmaError(DmaError), MaxDmaTransferSizeExceeded, Unknown, } -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] impl From for Error { fn from(value: DmaError) -> Self { Error::DmaError(value) @@ -262,16 +262,16 @@ where } } -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] pub mod dma { use core::mem; use embedded_dma::{ReadBuffer, WriteBuffer}; - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] use super::Spi3Instance; use super::{Instance, InstanceDma, Spi, Spi2Instance, MAX_DMA_SIZE}; - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] use crate::dma::private::Spi3Peripheral; use crate::dma::{ private::{Rx, Spi2Peripheral, SpiPeripheral, Tx}, @@ -290,7 +290,7 @@ pub mod dma { fn with_dma(self, channel: Channel) -> SpiDma; } - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] pub trait WithDmaSpi3 where T: Instance + Spi3Instance, @@ -318,7 +318,7 @@ pub mod dma { } } - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] impl WithDmaSpi3 for Spi where T: Instance + Spi3Instance, @@ -916,7 +916,7 @@ mod ehal1 { } } -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] pub trait InstanceDma: Instance where TX: Tx, @@ -1065,7 +1065,7 @@ where fn dma_peripheral(&self) -> DmaPeripheral { match self.spi_num() { 2 => DmaPeripheral::Spi2, - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] 3 => DmaPeripheral::Spi3, _ => panic!("Illegal SPI instance"), } @@ -1078,7 +1078,7 @@ where reg_block.dma_conf.modify(|_, w| w.dma_rx_ena().set_bit()); } - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] fn enable_dma(&self) { // for non GDMA this is done in `assign_tx_device` / `assign_rx_device` } @@ -1100,7 +1100,7 @@ where }); } - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] fn clear_dma_interrupts(&self) { let reg_block = self.register_block(); reg_block.dma_int_clr.write(|w| { @@ -1126,7 +1126,7 @@ where } } -#[cfg(any(esp32c3, esp32))] +#[cfg(any(esp32c3, esp32, esp32s2))] impl InstanceDma for crate::pac::SPI2 where TX: Tx, @@ -1134,7 +1134,7 @@ where { } -#[cfg(any(esp32))] +#[cfg(any(esp32, esp32s2))] impl InstanceDma for crate::pac::SPI3 where TX: Tx, @@ -1706,10 +1706,10 @@ impl Instance for crate::pac::SPI3 { pub trait Spi2Instance {} -#[cfg(esp32)] +#[cfg(any(esp32, esp32s2))] pub trait Spi3Instance {} impl Spi2Instance for crate::pac::SPI2 {} -#[cfg(esp32)] +#[cfg(any(esp32, esp32s2))] impl Spi3Instance for crate::pac::SPI3 {} diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index 138e05388f2..3b10de9bdf3 100644 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -28,7 +28,7 @@ pub enum Peripheral { ApbSarAdc, #[cfg(esp32c3)] Gdma, - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] Dma, } @@ -99,6 +99,13 @@ impl PeripheralClockControl { perip_clk_en0.modify(|_, w| w.spi_dma_clk_en().set_bit()); perip_rst_en0.modify(|_, w| w.spi_dma_rst().clear_bit()); } + #[cfg(esp32s2)] + Peripheral::Dma => { + perip_clk_en0.modify(|_, w| w.spi2_dma_clk_en().set_bit()); + perip_rst_en0.modify(|_, w| w.spi2_dma_rst().clear_bit()); + perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().set_bit()); + perip_rst_en0.modify(|_, w| w.spi3_dma_rst().clear_bit()); + } } } } @@ -113,8 +120,8 @@ pub struct CpuControl { _private: (), } -/// Controls the configuration of the chip's clocks. -#[cfg(esp32)] +/// Dummy DMA peripheral. +#[cfg(any(esp32, esp32s2))] pub struct Dma { _private: (), } @@ -125,7 +132,7 @@ pub struct SystemParts { pub peripheral_clock_control: PeripheralClockControl, pub clock_control: SystemClockControl, pub cpu_control: CpuControl, - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] pub dma: Dma, } @@ -147,7 +154,7 @@ impl SystemExt for SystemPeripheral { peripheral_clock_control: PeripheralClockControl { _private: () }, clock_control: SystemClockControl { _private: () }, cpu_control: CpuControl { _private: () }, - #[cfg(esp32)] + #[cfg(any(esp32, esp32s2))] dma: Dma { _private: () }, } } diff --git a/esp32s2-hal/examples/adc.rs b/esp32s2-hal/examples/adc.rs index b8a818c3334..a40f21886a0 100644 --- a/esp32s2-hal/examples/adc.rs +++ b/esp32s2-hal/examples/adc.rs @@ -34,14 +34,15 @@ fn main() -> ! { rtc.rwdt.disable(); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - //let pin3 = io.pins.gpio3.into_analog(); + // let pin3 = io.pins.gpio3.into_analog(); // Create ADC instances let analog = peripherals.SENS.split(); let mut adc1_config = AdcConfig::new(); - let mut pin3 = adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB); + let mut pin3 = + adc1_config.enable_pin(io.pins.gpio3.into_analog(), Attenuation::Attenuation11dB); let mut adc1 = ADC::::adc(analog.adc1, adc1_config).unwrap(); diff --git a/esp32s2-hal/examples/hello_world.rs b/esp32s2-hal/examples/hello_world.rs index e8d702382ee..7e71719fbdf 100644 --- a/esp32s2-hal/examples/hello_world.rs +++ b/esp32s2-hal/examples/hello_world.rs @@ -40,4 +40,4 @@ fn main() -> ! { writeln!(serial0, "Hello world!").unwrap(); block!(timer0.wait()).unwrap(); } -} \ No newline at end of file +} diff --git a/esp32s2-hal/examples/spi_loopback_dma.rs b/esp32s2-hal/examples/spi_loopback_dma.rs new file mode 100644 index 00000000000..de44b11100f --- /dev/null +++ b/esp32s2-hal/examples/spi_loopback_dma.rs @@ -0,0 +1,119 @@ +//! SPI loopback test using DMA +//! +//! Folowing pins are used: +//! SCLK GPIO36 +//! MISO GPIO37 +//! MOSI GPIO35 +//! CS GPIO34 +//! +//! 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 esp32s2_hal::{ + clock::ClockControl, + dma::{DmaPriority, DmaTransferRxTx}, + gpio::IO, + pac::Peripherals, + pdma::Dma, + 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 wdt = timer_group0.wdt; + + wdt.disable(); + rtc.rwdt.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let sclk = io.pins.gpio36; + let miso = io.pins.gpio37; + let mosi = io.pins.gpio35; + let cs = io.pins.gpio34; + + let dma = Dma::new(system.dma, &mut system.peripheral_clock_control); + let dma_channel = dma.spi2channel; + + 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/esp32s2-hal/src/lib.rs b/esp32s2-hal/src/lib.rs index 2f5e4a41bf0..592f646fc67 100644 --- a/esp32s2-hal/src/lib.rs +++ b/esp32s2-hal/src/lib.rs @@ -3,6 +3,8 @@ pub use embedded_hal as ehal; pub use esp_hal_common::{ clock, + dma, + dma::pdma, efuse, gpio as gpio_types, i2c::{self, I2C},