Async SPI (#385)

* ground work for async dma (gdma only atm)

* Add async DMA (GDMA) - esp32c3/esp32c2

* Add Async SPI impl for esp32c3/c2

* Remove private modules from DMA

* add async spi example for esp32c3

* Switch to assoc wakers instead of a static array

* add support for esp32/esp32s2

* add support for esp32s3

* run fmt

* add c2 example, fix CI

* Remove redundant comments
This commit is contained in:
Scott Mabin 2023-02-08 11:02:03 +00:00 committed by GitHub
parent e65cacee58
commit 3f7181fece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1893 additions and 579 deletions

View File

@ -46,6 +46,8 @@ jobs:
run: cd esp32-hal/ && cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0
- name: check esp32-hal (async, gpio)
run: cd esp32-hal/ && cargo check --example=embassy_wait --features=embassy,embassy-time-timg0,async
- name: check esp32-hal (async, spi)
run: cd esp32-hal/ && cargo check --example=embassy_spi --features=embassy,embassy-time-timg0,async
esp32c2-hal:
runs-on: ubuntu-latest
@ -77,6 +79,8 @@ jobs:
run: cd esp32c2-hal/ && cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0
- name: check esp32c2-hal (async, gpio)
run: cd esp32c2-hal/ && cargo check --example=embassy_wait --features=embassy,embassy-time-systick,async
- name: check esp32c2-hal (async, spi)
run: cd esp32c2-hal/ && cargo check --example=embassy_spi --features=embassy,embassy-time-systick,async
esp32c3-hal:
runs-on: ubuntu-latest
@ -111,6 +115,8 @@ jobs:
run: cargo check --manifest-path=esp32c3-hal/Cargo.toml --target=riscv32imc-unknown-none-elf --example=embassy_hello_world --features=embassy,embassy-time-timg0
- name: check esp32c3-hal (async, gpio)
run: cd esp32c3-hal/ && cargo check --example=embassy_wait --features=embassy,embassy-time-systick,async
- name: check esp32c3-hal (async, spi)
run: cd esp32c3-hal/ && cargo check --example=embassy_spi --features=embassy,embassy-time-systick,async
esp32s2-hal:
runs-on: ubuntu-latest
@ -139,6 +145,8 @@ jobs:
run: cd esp32s2-hal/ && cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0
- name: check esp32s2-hal (async, gpio)
run: cd esp32s2-hal/ && cargo check --example=embassy_wait --features=embassy,embassy-time-timg0,async
- name: check esp32s2-hal (async, spi)
run: cd esp32s2-hal/ && cargo check --example=embassy_spi --features=embassy,embassy-time-timg0,async
esp32s3-hal:
runs-on: ubuntu-latest
@ -170,6 +178,8 @@ jobs:
run: cd esp32s3-hal/ && cargo check --example=embassy_hello_world --features=embassy,embassy-time-timg0
- name: check esp32s3-hal (async, gpio)
run: cd esp32s3-hal/ && cargo check --example=embassy_wait --features=embassy,embassy-time-timg0,async
- name: check esp32s3-hal (async, spi)
run: cd esp32s3-hal/ && cargo check --example=embassy_spi --features=embassy,embassy-time-timg0,async
# --------------------------------------------------------------------------
# MSRV

View File

@ -33,6 +33,7 @@ usb-device = { version = "0.2.9", optional = true }
embedded-hal-async = { version = "0.2.0-alpha.0", optional = true }
embassy-sync = { version = "0.1.0", optional = true }
embassy-time = { version = "0.1.0", features = ["nightly"], optional = true }
embassy-futures = { version = "0.1.0", optional = true }
# RISC-V
esp-riscv-rt = { version = "0.1.0", optional = true }
@ -81,7 +82,7 @@ ufmt = ["ufmt-write"]
vectored = ["procmacros/interrupt"]
# Implement the `embedded-hal-async==1.0.0-alpha.x` traits
async = ["embedded-hal-async", "eh1", "embassy-sync"]
async = ["embedded-hal-async", "eh1", "embassy-sync", "embassy-futures"]
embassy = ["embassy-time"]
embassy-time-systick = []

View File

@ -1,7 +1,7 @@
//! Direct Memory Access
use crate::{
dma::gdma::private::*,
dma::*,
peripheral::PeripheralRef,
system::{Peripheral, PeripheralClockControl},
};
@ -263,15 +263,89 @@ macro_rules! impl_channel {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
dma.[<in_dscr_bf0_ch $num>].read().inlink_dscr_bf0().bits() as usize
}
fn is_listening_in_eof() -> bool {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<in_int_ena_ch $num>].read().in_suc_eof().bit_is_set()
} else {
dma.[<int_ena_ch $num>].read().in_suc_eof().bit_is_set()
}
}
}
fn is_listening_out_eof() -> bool {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<out_int_ena_ch $num>].read().out_total_eof().bit_is_set()
} else {
dma.[<int_ena_ch $num>].read().out_total_eof().bit_is_set()
}
}
}
fn listen_in_eof() {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<in_int_ena_ch $num>].modify(|_, w| w.in_suc_eof().set_bit())
} else {
dma.[<int_ena_ch $num>].modify(|_, w| w.in_suc_eof().set_bit())
}
}
}
fn listen_out_eof() {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<out_int_ena_ch $num>].modify(|_, w| w.out_total_eof().set_bit())
} else {
dma.[<int_ena_ch $num>].modify(|_, w| w.out_total_eof().set_bit())
}
}
}
fn unlisten_in_eof() {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<in_int_ena_ch $num>].modify(|_, w| w.in_suc_eof().clear_bit())
} else {
dma.[<int_ena_ch $num>].modify(|_, w| w.in_suc_eof().clear_bit())
}
}
}
fn unlisten_out_eof() {
let dma = unsafe { &*crate::peripherals::DMA::PTR };
cfg_if::cfg_if! {
if #[cfg(esp32s3)] {
dma.[<out_int_ena_ch $num>].modify(|_, w| w.out_total_eof().clear_bit())
} else {
dma.[<int_ena_ch $num>].modify(|_, w| w.out_total_eof().clear_bit())
}
}
}
}
pub struct [<Channel $num TxImpl>] {}
impl<'a> TxChannel<[<Channel $num>]> for [<Channel $num TxImpl>] {}
impl<'a> TxChannel<[<Channel $num>]> for [<Channel $num TxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<Channel $num RxImpl>] {}
impl<'a> RxChannel<[<Channel $num>]> for [<Channel $num RxImpl>] {}
impl<'a> RxChannel<[<Channel $num>]> for [<Channel $num RxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<ChannelCreator $num>] {}
@ -337,20 +411,15 @@ macro_rules! impl_channel {
};
}
/// Crate private implementatin details
pub(crate) mod private {
use crate::dma::{private::*, *};
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);
}
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
///

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
//! Direct Memory Access
use crate::{
dma::pdma::private::*,
dma::*,
peripheral::PeripheralRef,
system::{Peripheral, PeripheralClockControl},
};
@ -84,7 +84,8 @@ macro_rules! ImplSpiChannel {
fn is_out_done() -> bool {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_raw.read().out_done_int_raw().bit()
// FIXME this should be out_total_eof_int_raw? but on esp32 this interrupt doesn't seem to fire
spi.dma_int_raw.read().out_eof_int_raw().bit()
}
fn last_out_dscr_address() -> usize {
@ -162,15 +163,57 @@ macro_rules! ImplSpiChannel {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.inlink_dscr_bf0.read().dma_inlink_dscr_bf0().bits() as usize
}
fn is_listening_in_eof() -> bool {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.read().in_suc_eof_int_ena().bit_is_set()
}
fn is_listening_out_eof() -> bool {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.read().out_total_eof_int_ena().bit_is_set()
}
fn listen_in_eof() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.modify(|_, w| w.in_suc_eof_int_ena().set_bit());
}
fn listen_out_eof() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.modify(|_, w| w.out_total_eof_int_ena().set_bit());
}
fn unlisten_in_eof() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.modify(|_, w| w.in_suc_eof_int_ena().clear_bit());
}
fn unlisten_out_eof() {
let spi = unsafe { &*crate::peripherals::[<SPI $num>]::PTR };
spi.dma_int_ena.modify(|_, w| w.out_total_eof_int_ena().clear_bit());
}
}
pub struct [<Spi $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<Spi $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<Spi $num DmaChannelCreator>] {}
@ -368,15 +411,47 @@ macro_rules! ImplI2sChannel {
let reg_block = unsafe { &*crate::peripherals::[<$peripheral>]::PTR };
reg_block.inlink_dscr_bf0.read().inlink_dscr_bf0().bits() as usize
}
fn is_listening_in_eof() -> bool {
todo!()
}
fn is_listening_out_eof() -> bool {
todo!()
}
fn listen_in_eof() {
todo!()
}
fn listen_out_eof() {
todo!()
}
fn unlisten_in_eof() {
todo!()
}
fn unlisten_out_eof() {
todo!()
}
}
pub struct [<I2s $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelTxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<I2s $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelRxImpl>] {
#[cfg(feature = "async")]
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
}
pub struct [<I2s $num DmaChannelCreator>] {}
@ -436,42 +511,37 @@ macro_rules! ImplI2sChannel {
};
}
/// Crate private implementation details
pub(crate) mod private {
use crate::dma::{private::*, *};
pub struct Spi2DmaSuitablePeripheral {}
impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}
pub struct Spi2DmaSuitablePeripheral {}
impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}
pub struct Spi3DmaSuitablePeripheral {}
impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}
pub struct Spi3DmaSuitablePeripheral {}
impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}
ImplSpiChannel!(2);
ImplSpiChannel!(3);
ImplSpiChannel!(2);
ImplSpiChannel!(3);
pub struct I2s0DmaSuitablePeripheral {}
impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
pub struct I2s0DmaSuitablePeripheral {}
impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
#[cfg(esp32)]
ImplI2sChannel!(0, "I2S0");
#[cfg(esp32)]
ImplI2sChannel!(0, "I2S0");
#[cfg(esp32s2)]
ImplI2sChannel!(0, "I2S");
#[cfg(esp32s2)]
ImplI2sChannel!(0, "I2S");
pub struct I2s1DmaSuitablePeripheral {}
impl PeripheralMarker for I2s1DmaSuitablePeripheral {}
impl I2sPeripheral for I2s1DmaSuitablePeripheral {}
impl I2s1Peripheral for I2s1DmaSuitablePeripheral {}
pub struct I2s1DmaSuitablePeripheral {}
impl PeripheralMarker for I2s1DmaSuitablePeripheral {}
impl I2sPeripheral for I2s1DmaSuitablePeripheral {}
impl I2s1Peripheral for I2s1DmaSuitablePeripheral {}
#[cfg(esp32)]
ImplI2sChannel!(1, "I2S1");
}
#[cfg(esp32)]
ImplI2sChannel!(1, "I2S1");
/// DMA Peripheral
///

View File

@ -22,6 +22,7 @@
#![cfg_attr(xtensa, feature(asm_experimental_arch))]
#![cfg_attr(feature = "async", allow(incomplete_features))]
#![cfg_attr(feature = "async", feature(async_fn_in_trait))]
#![cfg_attr(feature = "async", feature(impl_trait_projections))]
#[cfg_attr(esp32, path = "peripherals/esp32.rs")]
#[cfg_attr(esp32c3, path = "peripherals/esp32c3.rs")]

View File

@ -577,6 +577,147 @@ pub mod dma {
}
}
#[cfg(feature = "async")]
mod asynch {
use super::*;
impl<'d, T, TX, RX, P> embedded_hal_async::spi::SpiBusWrite for SpiDma<'d, T, TX, RX, P>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
{
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
for chunk in words.chunks(MAX_DMA_SIZE) {
self.spi.start_write_bytes_dma(
chunk.as_ptr(),
chunk.len(),
&mut self.channel.tx,
)?;
crate::dma::asynch::DmaTxFuture::new(&mut self.channel.tx).await;
// FIXME: in the future we should use the peripheral DMA status registers to
// await on both the dma transfer _and_ the peripherals status
self.spi.flush()?;
}
Ok(())
}
}
impl<'d, T, TX, RX, P> embedded_hal_async::spi::SpiBusFlush for SpiDma<'d, T, TX, RX, P>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
{
async fn flush(&mut self) -> Result<(), Self::Error> {
// TODO use async flush in the future
self.spi.flush()
}
}
impl<'d, T, TX, RX, P> embedded_hal_async::spi::SpiBusRead for SpiDma<'d, T, TX, RX, P>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
{
async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.spi.start_read_bytes_dma(
words.as_mut_ptr(),
words.len(),
&mut self.channel.rx,
)?;
crate::dma::asynch::DmaRxFuture::new(&mut self.channel.rx).await;
Ok(())
}
}
impl<'d, T, TX, RX, P> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, TX, RX, P>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
{
async fn transfer<'a>(
&'a mut self,
read: &'a mut [u8],
write: &'a [u8],
) -> Result<(), Self::Error> {
let mut idx = 0;
loop {
let write_idx = isize::min(idx, write.len() as isize);
let write_len = usize::min(write.len() - idx as usize, MAX_DMA_SIZE);
let read_idx = isize::min(idx, read.len() as isize);
let read_len = usize::min(read.len() - idx as usize, MAX_DMA_SIZE);
self.spi.start_transfer_dma(
unsafe { write.as_ptr().offset(write_idx) },
write_len,
unsafe { read.as_mut_ptr().offset(read_idx) },
read_len,
&mut self.channel.tx,
&mut self.channel.rx,
)?;
embassy_futures::join::join(
crate::dma::asynch::DmaTxFuture::new(&mut self.channel.tx),
crate::dma::asynch::DmaRxFuture::new(&mut self.channel.rx),
)
.await;
// FIXME: in the future we should use the peripheral DMA status registers to
// await on both the dma transfer _and_ the peripherals status
self.spi.flush()?;
idx += MAX_DMA_SIZE as isize;
if idx >= write.len() as isize && idx >= read.len() as isize {
break;
}
}
Ok(())
}
async fn transfer_in_place<'a>(
&'a mut self,
words: &'a mut [u8],
) -> Result<(), Self::Error> {
for chunk in words.chunks_mut(MAX_DMA_SIZE) {
self.spi.start_transfer_dma(
chunk.as_ptr(),
chunk.len(),
chunk.as_mut_ptr(),
chunk.len(),
&mut self.channel.tx,
&mut self.channel.rx,
)?;
embassy_futures::join::join(
crate::dma::asynch::DmaTxFuture::new(&mut self.channel.tx),
crate::dma::asynch::DmaRxFuture::new(&mut self.channel.rx),
)
.await;
// FIXME: in the future we should use the peripheral DMA status registers to
// await on both the dma transfer _and_ the peripherals status
self.spi.flush()?;
}
Ok(())
}
}
}
#[cfg(feature = "eh1")]
mod ehal1 {
use embedded_hal_1::spi::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite};

View File

@ -77,3 +77,7 @@ required-features = ["embassy"]
[[example]]
name = "embassy_wait"
required-features = ["embassy", "async"]
[[example]]
name = "embassy_spi"
required-features = ["embassy", "async"]

View File

@ -0,0 +1,127 @@
//! embassy hello world
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use esp32_hal::{
clock::ClockControl,
dma::{DmaPriority, *},
embassy,
pdma::*,
peripherals::Peripherals,
prelude::*,
spi::{dma::SpiDma, Spi, SpiMode},
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use static_cell::StaticCell;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
pub type SpiType<'d> = SpiDma<
'd,
esp32_hal::peripherals::SPI2,
ChannelTx<'d, Spi2DmaChannelTxImpl, Spi2DmaChannel>,
ChannelRx<'d, Spi2DmaChannelRxImpl, Spi2DmaChannel>,
Spi2DmaSuitablePeripheral,
>;
#[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) {
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop {
let mut buffer = [0; 8];
esp_println::println!("Sending bytes");
embedded_hal_async::spi::SpiBus::transfer(spi, &mut buffer, &send_buffer)
.await
.unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[xtensa_lx_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let mut system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
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;
// Disable watchdog timers
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
#[cfg(feature = "embassy-time-systick")]
embassy::init(
&clocks,
esp32_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
);
#[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0);
esp32_hal::interrupt::enable(
esp32_hal::peripherals::Interrupt::SPI2_DMA,
esp32_hal::interrupt::Priority::Priority1,
)
.unwrap();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let sclk = io.pins.gpio19;
let miso = io.pins.gpio25;
let mosi = io.pins.gpio23;
let cs = io.pins.gpio22;
let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
let dma_channel = dma.spi2channel;
let descriptors = singleton!([0u32; 8 * 3]);
let rx_descriptors = singleton!([0u32; 8 * 3]);
let spi = singleton!(Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
)
.with_dma(dma_channel.configure(
false,
descriptors,
rx_descriptors,
DmaPriority::Priority0,
)));
let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(spi_task(spi)).ok();
});
}

View File

@ -72,4 +72,8 @@ required-features = ["embassy"]
[[example]]
name = "embassy_wait"
required-features = ["embassy", "async"]
[[example]]
name = "embassy_spi"
required-features = ["embassy", "async"]

View File

@ -0,0 +1,125 @@
//! embassy hello world
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use esp32c2_hal::{
clock::ClockControl,
dma::{DmaPriority, *},
embassy,
gdma::*,
peripherals::Peripherals,
prelude::*,
spi::{dma::SpiDma, Spi, SpiMode},
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use static_cell::StaticCell;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
pub type SpiType<'d> = SpiDma<
'd,
esp32c2_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32c2_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32c2_hal::gdma::Channel0>,
SuitablePeripheral0,
>;
#[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) {
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop {
let mut buffer = [0; 8];
esp_println::println!("Sending bytes");
embedded_hal_async::spi::SpiBus::transfer(spi, &mut buffer, &send_buffer)
.await
.unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[esp_riscv_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
#[cfg(feature = "embassy-time-systick")]
embassy::init(
&clocks,
esp32c2_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
);
#[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0);
esp32c2_hal::interrupt::enable(
esp32c2_hal::peripherals::Interrupt::DMA_CH0,
esp32c2_hal::interrupt::Priority::Priority1,
)
.unwrap();
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 descriptors = singleton!([0u32; 8 * 3]);
let rx_descriptors = singleton!([0u32; 8 * 3]);
let spi = singleton!(Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
)
.with_dma(dma_channel.configure(
false,
descriptors,
rx_descriptors,
DmaPriority::Priority0,
)));
let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(spi_task(spi)).ok();
});
}

View File

@ -85,3 +85,7 @@ required-features = ["embassy", "async"]
[profile.dev]
opt-level = 1
[[example]]
name = "embassy_spi"
required-features = ["embassy", "async"]

View File

@ -0,0 +1,128 @@
//! embassy hello world
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use esp32c3_hal::{
clock::ClockControl,
dma::{DmaPriority, *},
embassy,
gdma::*,
peripherals::Peripherals,
prelude::*,
spi::{dma::SpiDma, Spi, SpiMode},
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use static_cell::StaticCell;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
pub type SpiType<'d> = SpiDma<
'd,
esp32c3_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32c3_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32c3_hal::gdma::Channel0>,
SuitablePeripheral0,
>;
#[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) {
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop {
let mut buffer = [0; 8];
esp_println::println!("Sending bytes");
embedded_hal_async::spi::SpiBus::transfer(spi, &mut buffer, &send_buffer)
.await
.unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[esp_riscv_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
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;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
#[cfg(feature = "embassy-time-systick")]
embassy::init(
&clocks,
esp32c3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
);
#[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0);
esp32c3_hal::interrupt::enable(
esp32c3_hal::peripherals::Interrupt::DMA_CH0,
esp32c3_hal::interrupt::Priority::Priority1,
)
.unwrap();
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 descriptors = singleton!([0u32; 8 * 3]);
let rx_descriptors = singleton!([0u32; 8 * 3]);
let spi = singleton!(Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
)
.with_dma(dma_channel.configure(
false,
descriptors,
rx_descriptors,
DmaPriority::Priority0,
)));
let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(spi_task(spi)).ok();
});
}

View File

@ -82,4 +82,8 @@ required-features = ["embassy"]
[[example]]
name = "embassy_wait"
required-features = ["embassy", "async"]
[[example]]
name = "embassy_spi"
required-features = ["embassy", "async"]

View File

@ -0,0 +1,127 @@
//! embassy hello world
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use esp32s2_hal::{
clock::ClockControl,
dma::{DmaPriority, *},
embassy,
pdma::*,
peripherals::Peripherals,
prelude::*,
spi::{dma::SpiDma, Spi, SpiMode},
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use static_cell::StaticCell;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
pub type SpiType<'d> = SpiDma<
'd,
esp32s2_hal::peripherals::SPI2,
ChannelTx<'d, Spi2DmaChannelTxImpl, Spi2DmaChannel>,
ChannelRx<'d, Spi2DmaChannelRxImpl, Spi2DmaChannel>,
Spi2DmaSuitablePeripheral,
>;
#[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) {
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop {
let mut buffer = [0; 8];
esp_println::println!("Sending bytes");
embedded_hal_async::spi::SpiBus::transfer(spi, &mut buffer, &send_buffer)
.await
.unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[xtensa_lx_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
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;
// Disable watchdog timers
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
#[cfg(feature = "embassy-time-systick")]
embassy::init(
&clocks,
esp32s2_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
);
#[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0);
esp32s2_hal::interrupt::enable(
esp32s2_hal::peripherals::Interrupt::SPI2_DMA,
esp32s2_hal::interrupt::Priority::Priority1,
)
.unwrap();
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 descriptors = singleton!([0u32; 8 * 3]);
let rx_descriptors = singleton!([0u32; 8 * 3]);
let spi = singleton!(Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
)
.with_dma(dma_channel.configure(
false,
descriptors,
rx_descriptors,
DmaPriority::Priority0,
)));
let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(spi_task(spi)).ok();
});
}

View File

@ -82,4 +82,8 @@ required-features = ["embassy"]
[[example]]
name = "embassy_wait"
required-features = ["embassy", "async"]
[[example]]
name = "embassy_spi"
required-features = ["embassy", "async"]

View File

@ -0,0 +1,133 @@
//! embassy hello world
//!
//! This is an example of running the embassy executor with multiple tasks
//! concurrently.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use esp32s3_hal::{
clock::ClockControl,
dma::{DmaPriority, *},
embassy,
gdma::*,
peripherals::Peripherals,
prelude::*,
spi::{dma::SpiDma, Spi, SpiMode},
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use static_cell::StaticCell;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
pub type SpiType<'d> = SpiDma<
'd,
esp32s3_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32s3_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32s3_hal::gdma::Channel0>,
SuitablePeripheral0,
>;
#[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) {
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop {
let mut buffer = [0; 8];
esp_println::println!("Sending bytes");
embedded_hal_async::spi::SpiBus::transfer(spi, &mut buffer, &send_buffer)
.await
.unwrap();
esp_println::println!("Bytes recieved: {:?}", buffer);
Timer::after(Duration::from_millis(5_000)).await;
}
}
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
#[xtensa_lx_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
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;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
#[cfg(feature = "embassy-time-systick")]
embassy::init(
&clocks,
esp32s3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
);
#[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0);
esp32s3_hal::interrupt::enable(
esp32s3_hal::peripherals::Interrupt::DMA_IN_CH0,
esp32s3_hal::interrupt::Priority::Priority1,
)
.unwrap();
esp32s3_hal::interrupt::enable(
esp32s3_hal::peripherals::Interrupt::DMA_OUT_CH0,
esp32s3_hal::interrupt::Priority::Priority1,
)
.unwrap();
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 descriptors = singleton!([0u32; 8 * 3]);
let rx_descriptors = singleton!([0u32; 8 * 3]);
let spi = singleton!(Spi::new(
peripherals.SPI2,
sclk,
mosi,
miso,
cs,
100u32.kHz(),
SpiMode::Mode0,
&mut system.peripheral_clock_control,
&clocks,
)
.with_dma(dma_channel.configure(
false,
descriptors,
rx_descriptors,
DmaPriority::Priority0,
)));
let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(spi_task(spi)).ok();
});
}