Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions diagram.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"version": 1,
"author": "Sergio Gasquez Arcos",
"editor": "wokwi",
"parts": [
{
"type": "board-esp32-c3-devkitm-1",
"id": "esp",
"top": 0,
"left": 0.67,
"attrs": {
"builder": "rust-std-esp32c3"
}
},
{
"type": "wokwi-pushbutton",
"id": "btn1",
"top": 107.93,
"left": 168.4,
"attrs": {
"color": "green"
}
}
],
"connections": [
[
"esp:TX",
"$serialMonitor:RX",
"",
[]
],
[
"esp:RX",
"$serialMonitor:TX",
"",
[]
],
[
"esp:5",
"btn1:2.l",
"green",
[
"h47.06",
"v34.63"
]
],
[
"esp:3V3.1",
"btn1:1.l",
"green",
[
"h-14.19",
"v-38.4",
"h164.8",
"v128.69"
]
],
[
"esp:3V3.1",
"esp:3V3.2",
"green",
[
"h0"
]
],
[
"esp:3V3.2",
"esp:5V.2",
"green",
[
"h0"
]
]
],
"serialMonitor": {
"display": "terminal"
}
}
129 changes: 129 additions & 0 deletions esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ pub trait Pin {
self.listen_with_options(event, true, false, false)
}

fn is_listening(&self) -> bool;

fn listen_with_options(
&mut self,
event: Event,
Expand Down Expand Up @@ -767,6 +769,11 @@ where
}
}

fn is_listening(&self) -> bool {
let bits = unsafe { &*GPIO::PTR }.pin[GPIONUM as usize].read().int_ena().bits();
bits != 0
}

fn unlisten(&mut self) {
unsafe {
(&*GPIO::PTR).pin[GPIONUM as usize]
Expand Down Expand Up @@ -1523,3 +1530,125 @@ pub(crate) use gpio;

pub use self::types::{InputSignal, OutputSignal};
use self::types::{ONE_INPUT, ZERO_INPUT};


#[cfg(feature = "async")]
mod asynch {
use core::task::{Context, Poll};
use super::*;

use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal_async::digital::Wait;

use crate::{pac, prelude::*};

#[allow(clippy::declare_interior_mutable_const)]
const NEW_AW: AtomicWaker = AtomicWaker::new();
#[cfg(feature = "esp32c3")]
const PIN_COUNT: usize = 26; // TODO cfg for each chip
static PIN_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT];


impl<MODE, RA, PINTYPE, const GPIONUM: u8> Wait for GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>
where
RA: BankGpioRegisterAccess,
PINTYPE: IsOutputPin,
{
type WaitForHighFuture<'a> = PinFuture<'a, GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>>
where PINTYPE: 'a,
RA: 'a,
MODE: 'a;

fn wait_for_high(&mut self) -> Self::WaitForHighFuture<'_> {
self.listen(Event::HighLevel);
PinFuture::new(self)
}

type WaitForLowFuture<'a> = PinFuture<'a, GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>>
where PINTYPE: 'a,
RA: 'a,
MODE: 'a;

fn wait_for_low(&mut self) -> Self::WaitForLowFuture<'_> {
self.listen(Event::LowLevel);
PinFuture::new(self)
}

type WaitForRisingEdgeFuture<'a> = PinFuture<'a, GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>>
where PINTYPE: 'a,
RA: 'a,
MODE: 'a;

fn wait_for_rising_edge(&mut self) -> Self::WaitForRisingEdgeFuture<'_> {
self.listen(Event::RisingEdge);
PinFuture::new(self)
}

type WaitForFallingEdgeFuture<'a> = PinFuture<'a, GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>>
where PINTYPE: 'a,
RA: 'a,
MODE: 'a;

fn wait_for_falling_edge(&mut self) -> Self::WaitForFallingEdgeFuture<'_> {
self.listen(Event::FallingEdge);
PinFuture::new(self)
}

type WaitForAnyEdgeFuture<'a> = PinFuture<'a, GpioPin<Input<MODE>, RA, PINTYPE, GPIONUM>>
where PINTYPE: 'a,
RA: 'a,
MODE: 'a;

fn wait_for_any_edge(&mut self) -> Self::WaitForAnyEdgeFuture<'_> {
self.listen(Event::AnyEdge);
PinFuture::new(self)
}
}

pub struct PinFuture<'a, P> {
pin: &'a P,
}

impl<'a, P> PinFuture<'a, P>
where
P: crate::gpio::Pin + embedded_hal_1::digital::ErrorType,
{
pub fn new(pin: &'a P) -> Self {
Self { pin }
}
}

impl<'a, P> core::future::Future for PinFuture<'a, P>
where
P: crate::gpio::Pin + embedded_hal_1::digital::ErrorType,
{
type Output = Result<(), P::Error>;

fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
PIN_WAKERS[self.pin.number() as usize].register(cx.waker());

// if pin is no longer listening its been triggered
// therefore the future has resolved
if !self.pin.is_listening() {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
}
}

#[interrupt]
unsafe fn GPIO() {
let gpio = crate::pac::GPIO::PTR;
let mut intrs = (*gpio).pcpu_int.read().bits();
(*gpio).status_w1tc.write(|w| w.bits(intrs)); // clear interrupts

while intrs != 0 {
let pin_nr = intrs.trailing_zeros();
// TODO in the future we could conjure a pin and reuse code in esp-hal
(*gpio).pin[pin_nr as usize].modify(|_, w| w.int_ena().bits(0)); // stop listening, this is the signal that the future is ready
PIN_WAKERS[pin_nr as usize].wake(); // wake task
intrs &= !(1u32 << pin_nr);
}
}
}
71 changes: 71 additions & 0 deletions esp32c3-hal/examples/embassy_wait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

use embassy_executor::Executor;
use embassy_time::{Duration, Timer};

use esp32c3_hal::{
clock::ClockControl,
prelude::*,
timer::TimerGroup,
Rtc, embassy, pac::Peripherals, IO,
};
use esp_backtrace as _;
use esp_hal_common::{PullDown, Bank0GpioRegisterAccess, InputOutputAnalogPinType, Input, GpioPin};
use static_cell::StaticCell;

use embedded_hal_async::digital::Wait;

#[embassy_executor::task]
async fn ping(mut pin: GpioPin<Input<PullDown>, Bank0GpioRegisterAccess, InputOutputAnalogPinType, 5>) {
loop {
esp_println::println!("Waiting...");
pin.wait_for_rising_edge().await.unwrap();
esp_println::println!("Ping!");
Timer::after(Duration::from_millis(100)).await;
}
}

static EXECUTOR: StaticCell<Executor> = StaticCell::new();

#[riscv_rt::entry]
fn main() -> ! {
esp_println::println!("Init!");
let peripherals = Peripherals::take().unwrap();
let 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);

// Set GPIO5 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let input = io.pins.gpio5.into_pull_down_input();

esp32c3_hal::interrupt::enable(
esp32c3_hal::pac::Interrupt::GPIO,
esp32c3_hal::interrupt::Priority::Priority1,
)
.unwrap();

let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| {
spawner.spawn(ping(input)).ok();
});
}
4 changes: 4 additions & 0 deletions wokwi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[wokwi]
version = 1
elf = "esp32c3-hal/target/riscv32imc-unknown-none-elf/debug/examples/embassy_wait"
firmware = "esp32c3-hal/target/riscv32imc-unknown-none-elf/debug/examples/embassy_wait"