mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 22:01:11 +00:00
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:
parent
e65cacee58
commit
3f7181fece
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -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
|
||||
|
||||
|
@ -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 = []
|
||||
|
@ -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
@ -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
|
||||
///
|
||||
|
@ -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")]
|
||||
|
@ -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};
|
||||
|
@ -77,3 +77,7 @@ required-features = ["embassy"]
|
||||
[[example]]
|
||||
name = "embassy_wait"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_spi"
|
||||
required-features = ["embassy", "async"]
|
||||
|
127
esp32-hal/examples/embassy_spi.rs
Normal file
127
esp32-hal/examples/embassy_spi.rs
Normal 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();
|
||||
});
|
||||
}
|
@ -72,4 +72,8 @@ required-features = ["embassy"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_wait"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_spi"
|
||||
required-features = ["embassy", "async"]
|
125
esp32c2-hal/examples/embassy_spi.rs
Normal file
125
esp32c2-hal/examples/embassy_spi.rs
Normal 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();
|
||||
});
|
||||
}
|
@ -85,3 +85,7 @@ required-features = ["embassy", "async"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
[[example]]
|
||||
name = "embassy_spi"
|
||||
required-features = ["embassy", "async"]
|
||||
|
128
esp32c3-hal/examples/embassy_spi.rs
Normal file
128
esp32c3-hal/examples/embassy_spi.rs
Normal 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();
|
||||
});
|
||||
}
|
@ -82,4 +82,8 @@ required-features = ["embassy"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_wait"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_spi"
|
||||
required-features = ["embassy", "async"]
|
127
esp32s2-hal/examples/embassy_spi.rs
Normal file
127
esp32s2-hal/examples/embassy_spi.rs
Normal 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();
|
||||
});
|
||||
}
|
@ -82,4 +82,8 @@ required-features = ["embassy"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_wait"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_spi"
|
||||
required-features = ["embassy", "async"]
|
133
esp32s3-hal/examples/embassy_spi.rs
Normal file
133
esp32s3-hal/examples/embassy_spi.rs
Normal 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();
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user