mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 05:40:39 +00:00
Async RMT (#787)
* Async RMT * Add CHANGELOG item * Pin toml_edit transitive dependency
This commit is contained in:
parent
4c34ebe9e2
commit
a642ee40da
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- Implement enabling/disabling BLE clock on ESP32-C6 (#784)
|
||||
- Async support for RMT (#787)
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -459,6 +459,9 @@ macro_rules! impl_tx_channel_creator {
|
||||
}
|
||||
|
||||
impl<const CHANNEL: u8> $crate::rmt::TxChannel<CHANNEL> for $crate::rmt::[< Channel $channel >]<CHANNEL> {}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<const CHANNEL: u8> $crate::rmt::asynch::TxChannelAsync<CHANNEL> for $crate::rmt::[< Channel $channel >]<CHANNEL> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -474,6 +477,9 @@ macro_rules! impl_rx_channel_creator {
|
||||
}
|
||||
|
||||
impl<const CHANNEL: u8> $crate::rmt::RxChannel<CHANNEL> for $crate::rmt::[< Channel $channel >]<CHANNEL> {}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
impl<const CHANNEL: u8> $crate::rmt::asynch::RxChannelAsync<CHANNEL> for $crate::rmt::[< Channel $channel >]<CHANNEL> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -523,8 +529,8 @@ mod impl_for_chip {
|
||||
super::chip_specific::impl_tx_channel!(Channel0, RMT_SIG_0, 0);
|
||||
super::chip_specific::impl_tx_channel!(Channel1, RMT_SIG_1, 1);
|
||||
|
||||
super::chip_specific::impl_rx_channel!(Channel2, RMT_SIG_0, 2);
|
||||
super::chip_specific::impl_rx_channel!(Channel3, RMT_SIG_1, 3);
|
||||
super::chip_specific::impl_rx_channel!(Channel2, RMT_SIG_0, 2, 0);
|
||||
super::chip_specific::impl_rx_channel!(Channel3, RMT_SIG_1, 3, 1);
|
||||
}
|
||||
|
||||
#[cfg(any(esp32))]
|
||||
@ -740,10 +746,10 @@ mod impl_for_chip {
|
||||
super::chip_specific::impl_tx_channel!(Channel2, RMT_SIG_2, 2);
|
||||
super::chip_specific::impl_tx_channel!(Channel3, RMT_SIG_3, 3);
|
||||
|
||||
super::chip_specific::impl_rx_channel!(Channel4, RMT_SIG_0, 4);
|
||||
super::chip_specific::impl_rx_channel!(Channel5, RMT_SIG_1, 5);
|
||||
super::chip_specific::impl_rx_channel!(Channel6, RMT_SIG_2, 6);
|
||||
super::chip_specific::impl_rx_channel!(Channel7, RMT_SIG_3, 7);
|
||||
super::chip_specific::impl_rx_channel!(Channel4, RMT_SIG_0, 4, 0);
|
||||
super::chip_specific::impl_rx_channel!(Channel5, RMT_SIG_1, 5, 1);
|
||||
super::chip_specific::impl_rx_channel!(Channel6, RMT_SIG_2, 6, 2);
|
||||
super::chip_specific::impl_rx_channel!(Channel7, RMT_SIG_3, 7, 3);
|
||||
}
|
||||
|
||||
/// RMT Channel 0
|
||||
@ -909,9 +915,360 @@ pub trait RxChannel<const CHANNEL: u8>: private::RxChannelInternal<CHANNEL> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub mod asynch {
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use procmacros::interrupt;
|
||||
|
||||
use super::{private::Event, *};
|
||||
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
const NUM_CHANNELS: usize = 8;
|
||||
#[cfg(not(any(esp32, esp32s3)))]
|
||||
const NUM_CHANNELS: usize = 4;
|
||||
|
||||
const INIT: AtomicWaker = AtomicWaker::new();
|
||||
static WAKER: [AtomicWaker; NUM_CHANNELS] = [INIT; NUM_CHANNELS];
|
||||
|
||||
pub(crate) struct RmtTxFuture<T, const CHANNEL: u8>
|
||||
where
|
||||
T: TxChannelAsync<CHANNEL>,
|
||||
{
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> RmtTxFuture<T, CHANNEL>
|
||||
where
|
||||
T: TxChannelAsync<CHANNEL>,
|
||||
{
|
||||
pub fn new(_instance: &T) -> Self {
|
||||
Self {
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> core::future::Future for RmtTxFuture<T, CHANNEL>
|
||||
where
|
||||
T: TxChannelAsync<CHANNEL>,
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
WAKER[CHANNEL as usize].register(ctx.waker());
|
||||
|
||||
if T::is_error() || T::is_done() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TxChannelAsync<const CHANNEL: u8>: private::TxChannelInternal<CHANNEL> {
|
||||
/// Start transmitting the given pulse code sequence.
|
||||
/// The length of sequence cannot exceed the size of the allocated RMT
|
||||
/// RAM.
|
||||
async fn transmit<'a, T: Into<u32> + Copy>(&mut self, data: &'a [T]) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if data.len() > constants::RMT_CHANNEL_RAM_SIZE {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
Self::clear_interrupts();
|
||||
Self::listen_interrupt(super::private::Event::End);
|
||||
Self::listen_interrupt(super::private::Event::Error);
|
||||
Self::send_raw(data, false, 0);
|
||||
|
||||
RmtTxFuture::new(self).await;
|
||||
|
||||
if Self::is_error() {
|
||||
Err(Error::TransmissionError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RmtRxFuture<T, const CHANNEL: u8>
|
||||
where
|
||||
T: RxChannelAsync<CHANNEL>,
|
||||
{
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> RmtRxFuture<T, CHANNEL>
|
||||
where
|
||||
T: RxChannelAsync<CHANNEL>,
|
||||
{
|
||||
pub fn new(_instance: &T) -> Self {
|
||||
Self {
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> core::future::Future for RmtRxFuture<T, CHANNEL>
|
||||
where
|
||||
T: RxChannelAsync<CHANNEL>,
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
WAKER[CHANNEL as usize].register(ctx.waker());
|
||||
if T::is_error() || T::is_done() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RxChannelAsync<const CHANNEL: u8>: private::RxChannelInternal<CHANNEL> {
|
||||
/// Start receiving a pulse code sequence.
|
||||
/// The length of sequence cannot exceed the size of the allocated RMT
|
||||
/// RAM.
|
||||
async fn receive<'a, T: From<u32> + Copy>(&mut self, data: &'a mut [T]) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if data.len() > constants::RMT_CHANNEL_RAM_SIZE {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
Self::clear_interrupts();
|
||||
Self::listen_interrupt(super::private::Event::End);
|
||||
Self::listen_interrupt(super::private::Event::Error);
|
||||
Self::start_receive_raw();
|
||||
|
||||
RmtRxFuture::new(self).await;
|
||||
|
||||
if Self::is_error() {
|
||||
Err(Error::TransmissionError)
|
||||
} else {
|
||||
Self::stop();
|
||||
Self::clear_interrupts();
|
||||
Self::update();
|
||||
|
||||
let ptr = (constants::RMT_RAM_START
|
||||
+ CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4)
|
||||
as *mut u32;
|
||||
let len = data.len();
|
||||
for (idx, entry) in data.iter_mut().take(len).enumerate() {
|
||||
*entry = unsafe { ptr.add(idx).read_volatile().into() };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
#[interrupt]
|
||||
fn RMT() {
|
||||
if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() {
|
||||
use crate::rmt::private::{RxChannelInternal, TxChannelInternal};
|
||||
|
||||
match channel {
|
||||
0 => {
|
||||
super::Channel0::<0>::unlisten_interrupt(Event::End);
|
||||
super::Channel0::<0>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
1 => {
|
||||
super::Channel1::<1>::unlisten_interrupt(Event::End);
|
||||
super::Channel1::<1>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
2 => {
|
||||
super::Channel2::<2>::unlisten_interrupt(Event::End);
|
||||
super::Channel2::<2>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
3 => {
|
||||
super::Channel3::<3>::unlisten_interrupt(Event::End);
|
||||
super::Channel3::<3>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
|
||||
// TODO ... how to handle chips which can use a channel for tx AND rx?
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
4 => {
|
||||
super::Channel4::<4>::unlisten_interrupt(Event::End);
|
||||
super::Channel4::<4>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
5 => {
|
||||
super::Channel5::<5>::unlisten_interrupt(Event::End);
|
||||
super::Channel5::<5>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
6 => {
|
||||
super::Channel6::<6>::unlisten_interrupt(Event::End);
|
||||
super::Channel6::<6>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
7 => {
|
||||
super::Channel7::<7>::unlisten_interrupt(Event::End);
|
||||
super::Channel7::<7>::unlisten_interrupt(Event::Error);
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
rmt.int_ena.write(|w| unsafe { w.bits(0) });
|
||||
|
||||
WAKER[channel].wake();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
#[interrupt]
|
||||
fn RMT() {
|
||||
if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() {
|
||||
match channel {
|
||||
0 => {
|
||||
<Channel0<0> as super::private::TxChannelInternal<0>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel0<0> as super::private::TxChannelInternal<0>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel0<0> as super::private::RxChannelInternal<0>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel0<0> as super::private::RxChannelInternal<0>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
1 => {
|
||||
<Channel1<1> as super::private::TxChannelInternal<1>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel1<1> as super::private::TxChannelInternal<1>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel1<1> as super::private::RxChannelInternal<1>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel1<1> as super::private::RxChannelInternal<1>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
2 => {
|
||||
<Channel2<2> as super::private::TxChannelInternal<2>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel2<2> as super::private::TxChannelInternal<2>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel2<2> as super::private::RxChannelInternal<2>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel2<2> as super::private::RxChannelInternal<2>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
3 => {
|
||||
<Channel3<3> as super::private::TxChannelInternal<3>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel3<3> as super::private::TxChannelInternal<3>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel3<3> as super::private::RxChannelInternal<3>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel3<3> as super::private::RxChannelInternal<3>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
#[cfg(any(esp32))]
|
||||
4 => {
|
||||
<Channel4<4> as super::private::TxChannelInternal<4>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel4<4> as super::private::TxChannelInternal<4>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel4<4> as super::private::RxChannelInternal<4>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel4<4> as super::private::RxChannelInternal<4>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
5 => {
|
||||
<Channel5<5> as super::private::TxChannelInternal<5>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel5<5> as super::private::TxChannelInternal<5>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel5<5> as super::private::RxChannelInternal<5>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel5<5> as super::private::RxChannelInternal<5>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
6 => {
|
||||
<Channel6<6> as super::private::TxChannelInternal<6>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel6<6> as super::private::TxChannelInternal<6>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel6<6> as super::private::RxChannelInternal<6>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel6<6> as super::private::RxChannelInternal<6>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
7 => {
|
||||
<Channel7<7> as super::private::TxChannelInternal<7>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel7<7> as super::private::TxChannelInternal<7>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
<Channel7<7> as super::private::RxChannelInternal<7>>::unlisten_interrupt(
|
||||
Event::End,
|
||||
);
|
||||
<Channel7<7> as super::private::RxChannelInternal<7>>::unlisten_interrupt(
|
||||
Event::Error,
|
||||
);
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
rmt.int_ena.write(|w| unsafe { w.bits(0) });
|
||||
|
||||
WAKER[channel].wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
use crate::{peripheral::Peripheral, soc::constants};
|
||||
|
||||
pub enum Event {
|
||||
Error,
|
||||
Threshold,
|
||||
End,
|
||||
}
|
||||
|
||||
pub trait CreateInstance<'d> {
|
||||
fn create(peripheral: impl Peripheral<P = crate::peripherals::RMT> + 'd) -> Self;
|
||||
}
|
||||
@ -986,6 +1343,10 @@ mod private {
|
||||
}
|
||||
|
||||
fn stop();
|
||||
|
||||
fn listen_interrupt(event: Event);
|
||||
|
||||
fn unlisten_interrupt(event: Event);
|
||||
}
|
||||
|
||||
pub trait RxChannelInternal<const CHANNEL: u8> {
|
||||
@ -1024,6 +1385,10 @@ mod private {
|
||||
fn set_filter_threshold(value: u8);
|
||||
|
||||
fn set_idle_threshold(value: u16);
|
||||
|
||||
fn listen_interrupt(event: Event);
|
||||
|
||||
fn unlisten_interrupt(event: Event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1068,6 +1433,52 @@ mod chip_specific {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(not(esp32s3))]
|
||||
pub fn pending_interrupt_for_channel() -> Option<usize> {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
let st = rmt.int_st.read();
|
||||
|
||||
if st.ch0_tx_end().bit() || st.ch0_tx_err().bit() {
|
||||
Some(0)
|
||||
} else if st.ch1_tx_end().bit() || st.ch1_tx_err().bit() {
|
||||
Some(1)
|
||||
} else if st.ch2_rx_end().bit() || st.ch2_rx_err().bit() {
|
||||
Some(2)
|
||||
} else if st.ch3_rx_end().bit() || st.ch3_rx_err().bit() {
|
||||
Some(3)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(esp32s3)]
|
||||
pub fn pending_interrupt_for_channel() -> Option<usize> {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
let st = rmt.int_st.read();
|
||||
|
||||
if st.ch0_tx_end().bit() || st.ch0_tx_err().bit() {
|
||||
Some(0)
|
||||
} else if st.ch1_tx_end().bit() || st.ch1_tx_err().bit() {
|
||||
Some(1)
|
||||
} else if st.ch2_tx_end().bit() || st.ch2_tx_err().bit() {
|
||||
Some(2)
|
||||
} else if st.ch3_tx_end().bit() || st.ch3_tx_err().bit() {
|
||||
Some(3)
|
||||
} else if st.ch4_rx_end().bit() || st.ch4_rx_err().bit() {
|
||||
Some(4)
|
||||
} else if st.ch5_rx_end().bit() || st.ch5_rx_err().bit() {
|
||||
Some(5)
|
||||
} else if st.ch6_rx_end().bit() || st.ch6_rx_err().bit() {
|
||||
Some(6)
|
||||
} else if st.ch7_rx_end().bit() || st.ch7_rx_err().bit() {
|
||||
Some(7)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_tx_channel {
|
||||
($channel:ident, $signal:ident, $ch_num:literal) => {
|
||||
paste::paste! {
|
||||
@ -1222,13 +1633,43 @@ mod chip_specific {
|
||||
rmt.ch_tx_conf0[$ch_num].modify(|_, w| w.tx_stop().set_bit());
|
||||
Self::update();
|
||||
}
|
||||
|
||||
fn listen_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_err >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_end >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unlisten_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_err >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_end >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().clear_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_rx_channel {
|
||||
($channel:ident, $signal:ident, $ch_num:literal) => {
|
||||
($channel:ident, $signal:ident, $ch_num:literal, $ch_index:literal) => {
|
||||
paste::paste! {
|
||||
impl<const CHANNEL: u8> $crate::rmt::private::RxChannelInternal<CHANNEL> for $crate::rmt:: $channel <CHANNEL> {
|
||||
fn new() -> Self {
|
||||
@ -1270,7 +1711,7 @@ mod chip_specific {
|
||||
fn set_carrier(carrier: bool, high: u16, low: u16, level: bool) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
|
||||
rmt.ch_rx_carrier_rm[$ch_num].write(|w| {
|
||||
rmt.ch_rx_carrier_rm[$ch_index].write(|w| {
|
||||
w.carrier_high_thres()
|
||||
.variant(high)
|
||||
.carrier_low_thres()
|
||||
@ -1331,6 +1772,36 @@ mod chip_specific {
|
||||
|
||||
rmt.[< ch $ch_num _rx_conf0 >].modify(|_, w| w.idle_thres().variant(value));
|
||||
}
|
||||
|
||||
fn listen_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_err >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_end >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_thr_event >]().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unlisten_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_err >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_end >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_thr_event >]().clear_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1363,6 +1834,52 @@ mod chip_specific {
|
||||
rmt.apb_conf.modify(|_, w| w.clk_en().set_bit());
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(esp32)]
|
||||
pub fn pending_interrupt_for_channel() -> Option<usize> {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
let st = rmt.int_st.read();
|
||||
|
||||
if st.ch0_rx_end().bit() || st.ch0_tx_end().bit() || st.ch0_err().bit() {
|
||||
Some(0)
|
||||
} else if st.ch1_rx_end().bit() || st.ch1_tx_end().bit() || st.ch1_err().bit() {
|
||||
Some(1)
|
||||
} else if st.ch2_rx_end().bit() || st.ch2_tx_end().bit() || st.ch2_err().bit() {
|
||||
Some(2)
|
||||
} else if st.ch3_rx_end().bit() || st.ch3_tx_end().bit() || st.ch3_err().bit() {
|
||||
Some(3)
|
||||
} else if st.ch4_rx_end().bit() || st.ch4_tx_end().bit() || st.ch4_err().bit() {
|
||||
Some(4)
|
||||
} else if st.ch5_rx_end().bit() || st.ch5_tx_end().bit() || st.ch5_err().bit() {
|
||||
Some(5)
|
||||
} else if st.ch6_rx_end().bit() || st.ch6_tx_end().bit() || st.ch6_err().bit() {
|
||||
Some(6)
|
||||
} else if st.ch7_rx_end().bit() || st.ch7_tx_end().bit() || st.ch7_err().bit() {
|
||||
Some(7)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(esp32s2)]
|
||||
pub fn pending_interrupt_for_channel() -> Option<usize> {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
let st = rmt.int_st.read();
|
||||
|
||||
if st.ch0_rx_end().bit() || st.ch0_tx_end().bit() || st.ch0_err().bit() {
|
||||
Some(0)
|
||||
} else if st.ch1_rx_end().bit() || st.ch1_tx_end().bit() || st.ch1_err().bit() {
|
||||
Some(1)
|
||||
} else if st.ch2_rx_end().bit() || st.ch2_tx_end().bit() || st.ch2_err().bit() {
|
||||
Some(2)
|
||||
} else if st.ch3_rx_end().bit() || st.ch3_tx_end().bit() || st.ch3_err().bit() {
|
||||
Some(3)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_tx_channel {
|
||||
($channel:ident, $signal:ident, $ch_num:literal) => {
|
||||
paste::paste! {
|
||||
@ -1497,6 +2014,36 @@ mod chip_specific {
|
||||
rmt.[< ch $ch_num conf1 >].modify(|_, w| w.tx_stop().set_bit());
|
||||
}
|
||||
}
|
||||
|
||||
fn listen_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _err >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_end >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unlisten_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _err >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_end >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().clear_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1613,6 +2160,36 @@ mod chip_specific {
|
||||
|
||||
rmt.[< ch $ch_num conf0 >].modify(|_, w| w.idle_thres().variant(value));
|
||||
}
|
||||
|
||||
fn listen_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _err >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_end >]().set_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unlisten_interrupt(event: $crate::rmt::private::Event) {
|
||||
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
|
||||
match event {
|
||||
$crate::rmt::private::Event::Error => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _err >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::End => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _rx_end >]().clear_bit());
|
||||
}
|
||||
$crate::rmt::private::Event::Threshold => {
|
||||
rmt.int_ena.modify(|_,w| w.[< ch $ch_num _tx_thr_event >]().clear_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ proc-macro-error = "1.0.4"
|
||||
proc-macro2 = "1.0.66"
|
||||
quote = "1.0.33"
|
||||
syn = {version = "2.0.31", features = ["extra-traits", "full"]}
|
||||
# toml_edit is a dependency of proc-macro-crate. Unfortunately they raised their MSRV on 0.19.15 so we pin the version for now
|
||||
toml_edit = "=0.19.14"
|
||||
|
||||
[features]
|
||||
esp32 = []
|
||||
|
@ -121,3 +121,11 @@ required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
[[example]]
|
||||
name = "embassy_i2c"
|
||||
required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
136
esp32-hal/examples/embassy_rmt_rx.rs
Normal file
136
esp32-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,136 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! Connect GPIO15 to GPIO4
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel2, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_hal_common::gpio::{Gpio15, Output, PushPull};
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
compile_error!("Run this example in release mode");
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel2<2>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn signal_task(mut pin: Gpio15<Output<PushPull>>) {
|
||||
loop {
|
||||
for _ in 0..10 {
|
||||
pin.toggle().unwrap();
|
||||
Timer::after(Duration::from_micros(10)).await;
|
||||
}
|
||||
Timer::after(Duration::from_millis(1000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.DPORT.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
{
|
||||
let timer_group0 =
|
||||
esp32_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control);
|
||||
embassy::init(&clocks, timer_group0.timer0);
|
||||
}
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 80u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel2
|
||||
.configure(
|
||||
io.pins.gpio4,
|
||||
RxChannelConfig {
|
||||
clk_divider: 1,
|
||||
idle_threshold: 0b111_1111_1111_1111,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32_hal::interrupt::enable(
|
||||
esp32_hal::peripherals::Interrupt::RMT,
|
||||
esp32_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
spawner
|
||||
.spawn(signal_task(io.pins.gpio15.into_push_pull_output()))
|
||||
.ok();
|
||||
});
|
||||
}
|
88
esp32-hal/examples/embassy_rmt_tx.rs
Normal file
88
esp32-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,88 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO4 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.DPORT.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
{
|
||||
let timer_group0 =
|
||||
esp32_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control);
|
||||
embassy::init(&clocks, timer_group0.timer0);
|
||||
}
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 80u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio4.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32_hal::interrupt::enable(
|
||||
esp32_hal::peripherals::Interrupt::RMT,
|
||||
esp32_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
@ -106,6 +106,14 @@ required-features = ["embassy", "async"]
|
||||
name = "embassy_i2c"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "direct-vectoring"
|
||||
required-features = ["direct-vectoring"]
|
||||
|
126
esp32c3-hal/examples/embassy_rmt_rx.rs
Normal file
126
esp32c3-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! This uses the boot button as input - press the button a couple of
|
||||
//! times to generate a pulse sequence and then wait for the idle timeout to see
|
||||
//! the recorded pulse sequence
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use esp32c3_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel2, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel2<2>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
println!("received");
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c3_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel2
|
||||
.configure(
|
||||
io.pins.gpio9,
|
||||
RxChannelConfig {
|
||||
clk_divider: 255,
|
||||
idle_threshold: 10000,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32c3_hal::interrupt::enable(
|
||||
esp32c3_hal::peripherals::Interrupt::RMT,
|
||||
esp32c3_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
94
esp32c3-hal/examples/embassy_rmt_tx.rs
Normal file
94
esp32c3-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,94 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO1 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32c3_hal::{
|
||||
clock::ClockControl,
|
||||
embassy,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c3_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio1.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32c3_hal::interrupt::enable(
|
||||
esp32c3_hal::peripherals::Interrupt::RMT,
|
||||
esp32c3_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
@ -107,3 +107,11 @@ required-features = ["embassy", "async"]
|
||||
[[example]]
|
||||
name = "direct-vectoring"
|
||||
required-features = ["direct-vectoring"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
126
esp32c6-hal/examples/embassy_rmt_rx.rs
Normal file
126
esp32c6-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! This uses the boot button as input - press the button a couple of
|
||||
//! times to generate a pulse sequence and then wait for the idle timeout to see
|
||||
//! the recorded pulse sequence
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use esp32c6_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel2, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel2<2>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
println!("received");
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.PCR.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c6_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c6_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel2
|
||||
.configure(
|
||||
io.pins.gpio9,
|
||||
RxChannelConfig {
|
||||
clk_divider: 255,
|
||||
idle_threshold: 10000,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32c6_hal::interrupt::enable(
|
||||
esp32c6_hal::peripherals::Interrupt::RMT,
|
||||
esp32c6_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
94
esp32c6-hal/examples/embassy_rmt_tx.rs
Normal file
94
esp32c6-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,94 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO1 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32c6_hal::{
|
||||
clock::ClockControl,
|
||||
embassy,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.PCR.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c6_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c6_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio1.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32c6_hal::interrupt::enable(
|
||||
esp32c6_hal::peripherals::Interrupt::RMT,
|
||||
esp32c6_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
@ -100,6 +100,14 @@ required-features = ["async", "embassy"]
|
||||
name = "embassy_wait"
|
||||
required-features = ["async", "embassy"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "interrupt_preemption"
|
||||
required-features = ["interrupt-preemption"]
|
||||
|
126
esp32h2-hal/examples/embassy_rmt_rx.rs
Normal file
126
esp32h2-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! This uses the boot button as input - press the button a couple of
|
||||
//! times to generate a pulse sequence and then wait for the idle timeout to see
|
||||
//! the recorded pulse sequence
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel2, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel2<2>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
println!("received");
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.PCR.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32h2_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32h2_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel2
|
||||
.configure(
|
||||
io.pins.gpio9,
|
||||
RxChannelConfig {
|
||||
clk_divider: 255,
|
||||
idle_threshold: 10000,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32h2_hal::interrupt::enable(
|
||||
esp32h2_hal::peripherals::Interrupt::RMT,
|
||||
esp32h2_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
94
esp32h2-hal/examples/embassy_rmt_tx.rs
Normal file
94
esp32h2-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,94 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO1 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
embassy,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.PCR.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32h2_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32h2_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio1.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32h2_hal::interrupt::enable(
|
||||
esp32h2_hal::peripherals::Interrupt::RMT,
|
||||
esp32h2_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
@ -118,3 +118,11 @@ required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
[[example]]
|
||||
name = "embassy_i2c"
|
||||
required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
137
esp32s2-hal/examples/embassy_rmt_rx.rs
Normal file
137
esp32s2-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,137 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! Connect GPIO15 to GPIO4
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32s2_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel2, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_hal_common::gpio::{Gpio15, Output, PushPull};
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
use xtensa_atomic_emulation_trap as _;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
compile_error!("Run this example in release mode");
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel2<2>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn signal_task(mut pin: Gpio15<Output<PushPull>>) {
|
||||
loop {
|
||||
for _ in 0..10 {
|
||||
pin.toggle().unwrap();
|
||||
Timer::after(Duration::from_micros(10)).await;
|
||||
}
|
||||
Timer::after(Duration::from_millis(1000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
{
|
||||
let timer_group0 =
|
||||
esp32s2_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control);
|
||||
embassy::init(&clocks, timer_group0.timer0);
|
||||
}
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 80u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel2
|
||||
.configure(
|
||||
io.pins.gpio4,
|
||||
RxChannelConfig {
|
||||
clk_divider: 1,
|
||||
idle_threshold: 0b111_1111_1111_1111,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32s2_hal::interrupt::enable(
|
||||
esp32s2_hal::peripherals::Interrupt::RMT,
|
||||
esp32s2_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
spawner
|
||||
.spawn(signal_task(io.pins.gpio15.into_push_pull_output()))
|
||||
.ok();
|
||||
});
|
||||
}
|
89
esp32s2-hal/examples/embassy_rmt_tx.rs
Normal file
89
esp32s2-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO4 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32s2_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
use xtensa_atomic_emulation_trap as _;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
{
|
||||
let timer_group0 =
|
||||
esp32s2_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control);
|
||||
embassy::init(&clocks, timer_group0.timer0);
|
||||
}
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 80u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio4.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32s2_hal::interrupt::enable(
|
||||
esp32s2_hal::peripherals::Interrupt::RMT,
|
||||
esp32s2_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
@ -135,3 +135,11 @@ required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
[[example]]
|
||||
name = "embassy_i2c"
|
||||
required-features = ["embassy", "embassy-executor-thread", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_tx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
||||
[[example]]
|
||||
name = "embassy_rmt_rx"
|
||||
required-features = ["embassy", "async"]
|
||||
|
126
esp32s3-hal/examples/embassy_rmt_rx.rs
Normal file
126
esp32s3-hal/examples/embassy_rmt_rx.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Demonstrates decoding pulse sequences with RMT
|
||||
//! This uses the boot button as input - press the button a couple of
|
||||
//! times to generate a pulse sequence and then wait for the idle timeout to see
|
||||
//! the recorded pulse sequence
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use esp32s3_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::RxChannelAsync, Channel4, PulseCode, RxChannelConfig, RxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::{print, println};
|
||||
use static_cell::make_static;
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel4<4>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 1,
|
||||
level2: false,
|
||||
length2: 1,
|
||||
}; 48];
|
||||
|
||||
loop {
|
||||
println!("receive");
|
||||
channel.receive(&mut data).await.unwrap();
|
||||
println!("received");
|
||||
let mut total = 0usize;
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length1 as usize;
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
total += entry.length2 as usize;
|
||||
}
|
||||
|
||||
for entry in &data[..data.len()] {
|
||||
if entry.length1 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length1 as usize);
|
||||
let c = if entry.level1 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
|
||||
if entry.length2 == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let count = WIDTH / (total / entry.length2 as usize);
|
||||
let c = if entry.level2 { '-' } else { '_' };
|
||||
for _ in 0..count + 1 {
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32s3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
{
|
||||
let timer_group0 =
|
||||
esp32s3_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control);
|
||||
embassy::init(&clocks, timer_group0.timer0);
|
||||
}
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel4
|
||||
.configure(
|
||||
io.pins.gpio0,
|
||||
RxChannelConfig {
|
||||
clk_divider: 255,
|
||||
idle_threshold: 10000,
|
||||
..RxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32s3_hal::interrupt::enable(
|
||||
esp32s3_hal::peripherals::Interrupt::RMT,
|
||||
esp32s3_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
93
esp32s3-hal/examples/embassy_rmt_tx.rs
Normal file
93
esp32s3-hal/examples/embassy_rmt_tx.rs
Normal file
@ -0,0 +1,93 @@
|
||||
//! Demonstrates generating pulse sequences with RMT
|
||||
//! Connect a logic analyzer to GPIO1 to see the generated pulses.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32s3_hal::{
|
||||
clock::ClockControl,
|
||||
embassy::{self, executor::Executor},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rmt::{asynch::TxChannelAsync, Channel0, PulseCode, TxChannelConfig, TxChannelCreator},
|
||||
Rmt,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use static_cell::make_static;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn rmt_task(mut channel: Channel0<0>) {
|
||||
let mut data = [PulseCode {
|
||||
level1: true,
|
||||
length1: 200,
|
||||
level2: false,
|
||||
length2: 50,
|
||||
}; 20];
|
||||
|
||||
data[data.len() - 2] = PulseCode {
|
||||
level1: true,
|
||||
length1: 3000,
|
||||
level2: false,
|
||||
length2: 500,
|
||||
};
|
||||
data[data.len() - 1] = PulseCode::default();
|
||||
|
||||
loop {
|
||||
esp_println::println!("transmit");
|
||||
channel.transmit(&data).await.unwrap();
|
||||
esp_println::println!("transmitted\n");
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
esp_println::println!("Init!");
|
||||
let peripherals = Peripherals::take();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
let mut clock_control = system.peripheral_clock_control;
|
||||
|
||||
#[cfg(feature = "embassy-time-systick")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32c3_hal::systimer::SystemTimer::new(peripherals.SYSTIMER),
|
||||
);
|
||||
|
||||
#[cfg(feature = "embassy-time-timg0")]
|
||||
embassy::init(
|
||||
&clocks,
|
||||
esp32s3_hal::timer::TimerGroup::new(peripherals.TIMG0, &clocks, &mut clock_control).timer0,
|
||||
);
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let rmt = Rmt::new(peripherals.RMT, 8u32.MHz(), &mut clock_control, &clocks).unwrap();
|
||||
|
||||
let channel = rmt
|
||||
.channel0
|
||||
.configure(
|
||||
io.pins.gpio1.into_push_pull_output(),
|
||||
TxChannelConfig {
|
||||
clk_divider: 255,
|
||||
..TxChannelConfig::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// you have to enable the interrupt for async to work
|
||||
esp32s3_hal::interrupt::enable(
|
||||
esp32s3_hal::peripherals::Interrupt::RMT,
|
||||
esp32s3_hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let executor = make_static!(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(rmt_task(channel)).ok();
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user