From 2dee0110bec392d5ac4ad2f52cc4d68a6e91f9a4 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 14 Aug 2023 07:45:17 -0700 Subject: [PATCH] [ESP32-C6-LP] Add input support for IO driver, implement more `embedded-hal` output traits (#720) * Add input support for IO driver, implement more `embedded-hal` output traits * Update CHANGELOG --- CHANGELOG.md | 1 + esp32c6-lp-hal/examples/blinky.rs | 6 +- esp32c6-lp-hal/src/gpio.rs | 101 ++++++++++++++++++++++-------- esp32c6-lp-hal/src/prelude.rs | 12 +++- 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 867ea3ddb..16dc67501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add the `esp32c6-lp-hal` package (#714) - Add GPIO (output) and delay functionality to `esp32c6-lp-hal` (#715) - Implement RTCIO pullup, pulldown and hold control for Xtensa MCUs (#684) +- Add GPIO input support and implement additional `embedded-hal` output traits for the C6's LP core [#720] ### Changed diff --git a/esp32c6-lp-hal/examples/blinky.rs b/esp32c6-lp-hal/examples/blinky.rs index 628a6067b..53ad8ccc0 100644 --- a/esp32c6-lp-hal/examples/blinky.rs +++ b/esp32c6-lp-hal/examples/blinky.rs @@ -4,7 +4,7 @@ #![no_std] #![no_main] -use esp32c6_lp_hal::{gpio::Io, prelude::*}; +use esp32c6_lp_hal::{delay::Delay, gpio::IO, prelude::*}; use panic_halt as _; #[entry] @@ -13,11 +13,11 @@ fn main() -> ! { let peripherals = esp32c6_lp::Peripherals::take().unwrap(); - let io = Io::new(peripherals.LP_IO); + let io = IO::new(peripherals.LP_IO); let mut gpio1 = io.gpio1.into_output(); let ptr = 0x5000_2000 as *mut u32; - let mut delay = delay::Delay::new(); + let mut delay = Delay::new(); loop { i = i.wrapping_add(1u32); diff --git a/esp32c6-lp-hal/src/gpio.rs b/esp32c6-lp-hal/src/gpio.rs index 8bc794208..8515f96d8 100644 --- a/esp32c6-lp-hal/src/gpio.rs +++ b/esp32c6-lp-hal/src/gpio.rs @@ -1,23 +1,14 @@ -//! LP-GPIO driver +//! Low-power GPIO driver //! //! It's assumed that GPIOs are already configured correctly by the HP core. use core::{convert::Infallible, marker::PhantomData}; -use embedded_hal::digital::v2::OutputPin; - -pub struct Unknown {} - -pub struct Output; +use esp32c6_lp::LP_IO; #[non_exhaustive] -pub struct GpioPin { - phantom: PhantomData, -} - -#[non_exhaustive] -pub struct Io { - _peripheral: esp32c6_lp::LP_IO, +pub struct IO { + _peripheral: LP_IO, pub gpio0: GpioPin<0, Unknown>, pub gpio1: GpioPin<1, Unknown>, @@ -29,10 +20,11 @@ pub struct Io { pub gpio7: GpioPin<7, Unknown>, } -impl Io { - pub fn new(peripheral: esp32c6_lp::LP_IO) -> Self { +impl IO { + pub fn new(peripheral: LP_IO) -> Self { Self { _peripheral: peripheral, + gpio0: GpioPin::new(), gpio1: GpioPin::new(), gpio2: GpioPin::new(), @@ -45,13 +37,30 @@ impl Io { } } +pub struct Unknown {} + +pub struct Input; + +pub struct Output; + +#[non_exhaustive] +pub struct GpioPin { + phantom: PhantomData, +} + impl GpioPin { fn new() -> Self { GpioPin { - phantom: PhantomData::default(), + phantom: PhantomData, } } + /// Assuming the GPIO is already configured by the HP core this makes the + /// GPIO into an input pin. + pub fn into_input(self) -> GpioPin { + GpioPin::new() + } + /// Assuming the GPIO is already configured by the HP core this makes the /// GPIO into an output pin. pub fn into_output(self) -> GpioPin { @@ -59,22 +68,64 @@ impl GpioPin { } } -impl OutputPin for GpioPin { +impl GpioPin { + fn input_state(&self) -> bool { + unsafe { &*LP_IO::PTR }.in_.read().bits() >> PIN & 0x1 != 0 + } +} + +impl GpioPin { + fn output_state(&self) -> bool { + unsafe { &*LP_IO::PTR }.out.read().bits() >> PIN & 0x1 != 0 + } + + fn set_output_low(&mut self) { + unsafe { &*LP_IO::PTR } + .out_w1tc + .write(|w| w.out_data_w1tc().variant(1 << PIN)); + } + + fn set_output_high(&mut self) { + unsafe { &*LP_IO::PTR } + .out_w1ts + .write(|w| w.out_data_w1ts().variant(1 << PIN)); + } +} + +impl embedded_hal::digital::v2::InputPin for GpioPin { + type Error = Infallible; + + fn is_high(&self) -> Result { + Ok(self.input_state()) + } + + fn is_low(&self) -> Result { + Ok(!self.is_high()?) + } +} + +impl embedded_hal::digital::v2::OutputPin for GpioPin { type Error = Infallible; fn set_low(&mut self) -> Result<(), Self::Error> { - let lp_gpio = unsafe { &*esp32c6_lp::LP_IO::PTR }; - lp_gpio - .out_w1tc - .write(|w| w.out_data_w1tc().variant(1 << PIN)); + self.set_output_low(); Ok(()) } fn set_high(&mut self) -> Result<(), Self::Error> { - let lp_gpio = unsafe { &*esp32c6_lp::LP_IO::PTR }; - lp_gpio - .out_w1ts - .write(|w| w.out_data_w1ts().variant(1 << PIN)); + self.set_output_high(); Ok(()) } } + +impl embedded_hal::digital::v2::StatefulOutputPin for GpioPin { + fn is_set_high(&self) -> Result { + Ok(self.output_state()) + } + + fn is_set_low(&self) -> Result { + Ok(!self.is_set_high()?) + } +} + +impl embedded_hal::digital::v2::toggleable::Default for GpioPin {} diff --git a/esp32c6-lp-hal/src/prelude.rs b/esp32c6-lp-hal/src/prelude.rs index 98a2bf555..3607608ba 100644 --- a/esp32c6-lp-hal/src/prelude.rs +++ b/esp32c6-lp-hal/src/prelude.rs @@ -3,7 +3,13 @@ //! Re-exports all traits required for interacting with the various peripheral //! drivers implemented in this crate. -pub use embedded_hal::{digital::v2::OutputPin, prelude::*}; +pub use embedded_hal::{ + digital::v2::{ + InputPin as _embedded_hal_digital_vs_InputPin, + OutputPin as _embedded_hal_digital_vs_OutputPin, + StatefulOutputPin as _embedded_hal_digital_vs_StatefulOutputPin, + ToggleableOutputPin as _embedded_hal_digital_vs_ToggleableOutputPin, + }, + prelude::*, +}; pub use riscv_rt_macros::entry; - -pub use crate::delay;