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
4 changes: 4 additions & 0 deletions esp-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ procmacros = { version = "0.6.0", package = "esp-hal-procmacros", path
strum = { version = "0.25.0", default-features = false, features = ["derive"] }
void = { version = "1.0.2", default-features = false }
usb-device = { version = "0.2.9", optional = true }
frunk = { version = "0.4.2", git = "https://github.com/Ben-PH/frunk-contrib.git", branch = "feature/list_build", default-features = false, optional = true }


# async
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true }
Expand Down Expand Up @@ -128,3 +130,5 @@ debug = [
"esp32s2?/impl-register-debug",
"esp32s3?/impl-register-debug",
]
# Enable list-based management of gpio-pins
frunk_list = ["frunk"]
25 changes: 21 additions & 4 deletions esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@

use core::{convert::Infallible, marker::PhantomData};

pub use frunk::hlist::{HList, Plucker};

use crate::peripherals::{GPIO, IO_MUX};
#[cfg(xtensa)]
pub(crate) use crate::rtc_pins;
pub use crate::soc::gpio::*;
pub(crate) use crate::{analog, gpio};
pub(crate) use crate::{analog, gpio, gpiopin_HList, gpiopin_hlist};

/// Convenience type-alias for a no-pin / don't care - pin
pub type NoPinType = Gpio0<Unknown>;
Expand Down Expand Up @@ -1278,12 +1280,12 @@ impl<MODE> embedded_hal_async::digital::Wait for AnyPin<Input<MODE>> {
}

/// General Purpose Input/Output driver
pub struct IO {
pub struct IO<T> {
_io_mux: IO_MUX,
pub pins: Pins,
pub pins: T,
}

impl IO {
impl IO<Pins> {
pub fn new(gpio: GPIO, io_mux: IO_MUX) -> Self {
let pins = gpio.split();
let io = IO {
Expand All @@ -1294,6 +1296,9 @@ impl IO {
}
}

#[cfg(feature = "frunk_list")]
mod frunk_list;

pub trait GpioProperties {
type Bank: BankGpioRegisterAccess;
type InterruptStatus: InterruptStatusRegisterAccess;
Expand Down Expand Up @@ -1333,6 +1338,18 @@ macro_rules! gpio {
}
}
}
/// A FP-like type-list collecting all initial pins
#[cfg(feature = "frunk_list")]
pub type InitialPinHList = crate::gpio::gpiopin_HList!($($gpionum),+);
#[cfg(feature = "frunk_list")]
impl GPIO {
/// Manage pins with an HList:
/// ```
/// let io = IO::`
pub fn hl_split(self) -> InitialPinHList {
crate::gpio::gpiopin_hlist!($($gpionum),+)
}
}

$(
impl<MODE> crate::gpio::GpioProperties for GpioPin<MODE, $gpionum> {
Expand Down
82 changes: 82 additions & 0 deletions esp-hal-common/src/gpio/frunk_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use super::{IO, IO_MUX, GPIO, InitialPinHList};
use frunk::hlist::Plucker;

impl IO<InitialPinHList> {
/// Manage pins using `frunk::hlist::HList` type:
///
/// ```no-run
/// // create list same as regular `new`
/// let io = IO::hl_new(peripherals.GPIO, peripherals.IO_MUX);
/// // move pin 4 out of the hl-list of pins, and into a variable
/// let (pin4, io): (GpioPin<Unknown, 4>, _) = io.pluck_pin::<4>();
/// ```
pub fn hl_new(gpio: GPIO, io_mux: IO_MUX) -> Self {
let pins = gpio.hl_split();
let io = IO {
_io_mux: io_mux,
pins,
};
io
}
}
impl<Ty, L0: Plucker<Ty, L1>, L1> Plucker<Ty, L1> for IO<L0>
{
type Remainder = IO<<L0 as Plucker<Ty, L1>>::Remainder>;
fn pluck(self) -> (Ty, IO<<L0 as Plucker<Ty, L1>>::Remainder>)
{
let (val, pins) = self.pins.pluck();
let res = IO {
_io_mux: self._io_mux,
pins,
};
(val, res)
}
}

/// ```
/// #[rustfmt::skip]
/// let expected = frunk::hlist!(
/// GpioPin::<Unknown>, 0>::new(),
/// GpioPin::<Unknown>, 1>::new(),
/// GpioPin::<Unknown>, 2>::new()
/// );
/// assert_eq!(gpio_hlist(0, 1, 2), expected);
/// ```
#[macro_export]
macro_rules! gpiopin_hlist {
($($gpionum:expr),+) => {
frunk::hlist![$(GpioPin::<Unknown, $gpionum>::new()),+]
};
}
/// ```
/// // This should macro-expand to the same as `Expected`
/// type GeneratedType = gpio_HList!(0, 1, 2);
///
/// // expected expantion
/// #[rustfmt::skip]
/// type ExpectedType = HCons<GpioPin<Unknown, { 0 }>,
/// HCons<GpioPin<Unknown, { 1 }>,
/// HCons<GpioPin<Unknown, { 2 }>,
/// HNil>>>;
///
/// // let's set up a means to put the type-checker to use
/// struct ExpectedMaker;
/// impl ExpectedMaker {
/// fn make() -> ExpectedType {
/// unimplemented!()
/// }
/// }
///
/// fn main() {
/// // validate that the make-method conforms with expected expansion
/// let expected: ExpectedType = ExpectedMaker::make();
/// // ...but if it doesn't conform to the actual expansion, this doc-test fails
/// let test: GeneratedType = ExpectedMaker::make();
/// }
/// ```
#[macro_export]
macro_rules! gpiopin_HList {
($($gpionum:expr),+) => {
frunk::HList![$(GpioPin<Unknown, { $gpionum }>),+]
};
}
3 changes: 3 additions & 0 deletions esp-hal-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ pub mod uart;
#[cfg(usb_device)]
pub mod usb_serial_jtag;

#[cfg(feature = "frunk_list")]
pub use frunk;

/// State of the CPU saved when entering exception or interrupt
pub mod trapframe {
#[cfg(riscv)]
Expand Down
4 changes: 2 additions & 2 deletions esp-hal-common/src/otg_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ pub use esp_synopsys_usb_otg::UsbBus;
use esp_synopsys_usb_otg::UsbPeripheral;

use crate::{
gpio::InputSignal,
gpio::{InputSignal},
peripheral::{Peripheral, PeripheralRef},
peripherals,
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
system::{Peripheral as PeripheralEnable, PeripheralClockControl}, IO,
};

#[doc(hidden)]
Expand Down
4 changes: 4 additions & 0 deletions esp32s3-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ async = ["esp-hal-common/async"]
embassy = ["esp-hal-common/embassy"]
embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"]
embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"]
frunk_list = ["esp-hal-common/frunk_list"]

psram = []
psram_2m = ["esp-hal-common/psram_2m", "psram"]
Expand All @@ -77,6 +78,9 @@ opsram_8m = ["esp-hal-common/opsram_8m", "psram"]
[profile.release]
debug = true

[[example]]
name = "blinky_double_pluck"
required-features = ["frunk_list"]
[[example]]
name = "spi_eh1_loopback"
required-features = ["eh1"]
Expand Down
94 changes: 94 additions & 0 deletions esp32s3-hal/examples/blinky_double_pluck.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Blinky, but manages the pins with an HList from the `frunk` crate
//!
//! This assumes that a LED is connected to the pin assigned in the `Blinker`s
//! pin-field

#![no_std]
#![no_main]

use esp32s3_hal::{
clock::ClockControl,
gpio::{Output, PushPull, Unknown, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
frunk,
frunk::ListBuild,
};
use esp_backtrace as _;
use esp_hal_common::gpio::GpioPin;

#[derive(frunk::ListBuild)]
struct PluckedBlinker {
pin4: GpioPin<Unknown, 4>,
pin5: GpioPin<Unknown, 5>,
pin6: GpioPin<Unknown, 6>,
}
impl From<PluckedBlinker> for Blinker {
fn from(value: PluckedBlinker) -> Self {
let mut pin4 = value.pin4.into_push_pull_output();
pin4.set_high().unwrap();
let mut pin5 = value.pin5.into_push_pull_output();
pin5.set_high().unwrap();
let mut pin6 = value.pin6.into_push_pull_output();
pin6.set_high().unwrap();
Self {
pin4,
pin5,
pin6
}
}
}
struct Blinker {
pin4: GpioPin<Output<PushPull>, 4>,
pin5: GpioPin<Output<PushPull>, 5>,
pin6: GpioPin<Output<PushPull>, 6>,
}


impl Blinker {
fn toggle(&mut self) {
self.pin4.toggle().unwrap();
self.pin5.toggle().unwrap();
self.pin6.toggle().unwrap();
}

fn blink_loop(mut self, delay: &mut Delay, rest_period: u16) -> ! {
loop {
self.toggle();
delay.delay_ms(rest_period);
}
}
}

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);

// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();

// Initialize a blinky-pin using pin#4
let io = IO::hl_new(peripherals.GPIO, peripherals.IO_MUX);
let (blinker, _io) = PluckedBlinker::hl_new(io.pins);
let blinker: Blinker = blinker.into();


// One job of the clock system is to manage short delays...
let mut delay = Delay::new(&clocks);

blinker.blink_loop(&mut delay, 500u16)
}
74 changes: 74 additions & 0 deletions esp32s3-hal/examples/blinky_hlist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! Blinky, but manages the pins with an HList from the `frunk` crate
//!
//! This assumes that a LED is connected to the pin assigned in the `Blinker`s
//! pin-field

#![no_std]
#![no_main]

use esp32s3_hal::{
clock::ClockControl,
gpio::{Output, Plucker, PushPull, Unknown, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use esp_hal_common::gpio::GpioPin;

struct Blinker {
pin: GpioPin<Output<PushPull>, 4>,
}

impl Blinker {
fn initialize<T, Remaining>(io: IO<T>) -> (Self, IO<T::Remainder>)
where
T: Plucker<GpioPin<Unknown, 4>, Remaining>,
{
let (pin, io) = io.pluck_pin();
let mut pin = pin.into_push_pull_output();
pin.set_high().unwrap();
(Self { pin }, io)
}

fn toggle(&mut self) {
self.pin.toggle().unwrap();
}

fn blink_loop(mut self, delay: &mut Delay, rest_period: u16) -> ! {
loop {
self.toggle();
delay.delay_ms(rest_period);
}
}
}

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);

// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();

// Initialize a blinky-pin using pin#4
let io = IO::hl_new(peripherals.GPIO, peripherals.IO_MUX);
let (blinker, _io) = Blinker::initialize(io);

// One job of the clock system is to manage short delays...
let mut delay = Delay::new(&clocks);

blinker.blink_loop(&mut delay, 500u16)
}