This commit is contained in:
Björn Quentin 2023-02-05 17:53:43 +01:00 committed by bjoernQ
parent 94471721b6
commit ab9aeb2443
7 changed files with 614 additions and 2 deletions

View File

@ -1376,6 +1376,140 @@ where
}
}
impl<MODE> embedded_hal::digital::v2::InputPin for AnyPin<crate::Input<MODE>> {
type Error = core::convert::Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_input!(inner, target, { target.is_high() })
}
fn is_low(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_input!(inner, target, { target.is_low() })
}
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::ErrorType for AnyPin<Input<MODE>> {
type Error = Infallible;
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::InputPin for AnyPin<Input<MODE>> {
fn is_high(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_input!(inner, target, { target.is_high() })
}
fn is_low(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_input!(inner, target, { target.is_low() })
}
}
impl<MODE> embedded_hal::digital::v2::OutputPin for AnyPin<Output<MODE>> {
type Error = Infallible;
fn set_low(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.set_low() })
}
fn set_high(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.set_high() })
}
}
impl<MODE> embedded_hal::digital::v2::StatefulOutputPin for AnyPin<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_output!(inner, target, { target.is_set_high() })
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_output!(inner, target, { target.is_set_low() })
}
}
impl<MODE> embedded_hal::digital::v2::ToggleableOutputPin for AnyPin<Output<MODE>> {
type Error = Infallible;
fn toggle(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.toggle() })
}
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::ErrorType for AnyPin<Output<MODE>> {
type Error = Infallible;
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::OutputPin for AnyPin<Output<MODE>> {
fn set_low(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.set_low() })
}
fn set_high(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.set_high() })
}
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::StatefulOutputPin for AnyPin<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_output!(inner, target, { target.is_set_high() })
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
let inner = &self.inner;
handle_gpio_output!(inner, target, { target.is_set_low() })
}
}
#[cfg(feature = "eh1")]
impl<MODE> embedded_hal_1::digital::ToggleableOutputPin for AnyPin<Output<MODE>> {
fn toggle(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_output!(inner, target, { target.toggle() })
}
}
#[cfg(feature = "async")]
impl<MODE> embedded_hal_async::digital::Wait for AnyPin<Input<MODE>> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_input!(inner, target, { target.wait_for_high().await })
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_input!(inner, target, { target.wait_for_low().await })
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_input!(inner, target, { target.wait_for_rising_edge().await })
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_input!(inner, target, { target.wait_for_falling_edge().await })
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
let inner = &mut self.inner;
handle_gpio_input!(inner, target, { target.wait_for_any_edge().await })
}
}
pub struct IO {
_io_mux: IO_MUX,
pub pins: types::Pins,
@ -1471,6 +1605,65 @@ macro_rules! gpio {
$(
pub type [<Gpio $gpionum >]<MODE> = GpioPin<MODE, [< Bank $bank GpioRegisterAccess >], $crate::gpio::[< $cores CoreInteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [<Gpio $gpionum Signals>], $gpionum>;
)+
pub(crate) enum ErasedPin<MODE> {
$(
[<Gpio $gpionum >]([<Gpio $gpionum >]<MODE>),
)+
}
pub struct AnyPin<MODE> {
pub(crate) inner: ErasedPin<MODE>
}
$(
impl<MODE> From< [<Gpio $gpionum >]<MODE> > for AnyPin<MODE> {
fn from(value: [<Gpio $gpionum >]<MODE>) -> Self {
AnyPin {
inner: ErasedPin::[<Gpio $gpionum >](value)
}
}
}
impl<MODE> [<Gpio $gpionum >]<MODE> {
pub fn degrade(self) -> AnyPin<MODE> {
AnyPin {
inner: ErasedPin::[<Gpio $gpionum >](self)
}
}
}
impl<MODE> TryInto<[<Gpio $gpionum >]<MODE>> for AnyPin<MODE> {
type Error = ();
fn try_into(self) -> Result<[<Gpio $gpionum >]<MODE>, Self::Error> {
match self.inner {
ErasedPin::[<Gpio $gpionum >](gpio) => Ok(gpio),
_ => Err(()),
}
}
}
)+
procmacros::make_gpio_enum_dispatch_macro!(
handle_gpio_output
{ InputOutputAnalog, InputOutput, }
{
$(
$type,$gpionum
)+
}
);
procmacros::make_gpio_enum_dispatch_macro!(
handle_gpio_input
{ InputOutputAnalog, InputOutput, InputOnlyAnalog }
{
$(
$type,$gpionum
)+
}
);
}
};
}
@ -1665,7 +1858,7 @@ mod asynch {
for GpioPin<Input<MODE>, RA, IRA, PINTYPE, SIG, GPIONUM>
where
RA: BankGpioRegisterAccess,
PINTYPE: IsOutputPin,
PINTYPE: IsInputPin,
IRA: InteruptStatusRegisterAccess,
SIG: GpioSignal,
{

View File

@ -15,7 +15,11 @@ use syn::{
Type,
Visibility,
};
use syn::{parse_macro_input, AttributeArgs};
use syn::{
parse::{Parse, ParseStream},
parse_macro_input,
AttributeArgs,
};
#[derive(Debug, Default, FromMeta)]
#[darling(default)]
@ -306,3 +310,99 @@ fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
(cfgs, not_cfgs)
}
#[derive(Debug)]
struct MakeGpioEnumDispatchMacro {
name: String,
filter: Vec<String>,
elements: Vec<(String, usize)>,
}
impl Parse for MakeGpioEnumDispatchMacro {
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
let name = input.parse::<syn::Ident>()?.to_string();
let filter = input
.parse::<proc_macro2::Group>()?
.stream()
.into_iter()
.map(|v| match v {
proc_macro2::TokenTree::Group(_) => String::new(),
proc_macro2::TokenTree::Ident(ident) => ident.to_string(),
proc_macro2::TokenTree::Punct(_) => String::new(),
proc_macro2::TokenTree::Literal(_) => String::new(),
})
.filter(|p| !p.is_empty())
.collect();
let mut stream = input.parse::<proc_macro2::Group>()?.stream().into_iter();
let mut elements = vec![];
let mut element_name = String::new();
loop {
match stream.next() {
Some(v) => match v {
proc_macro2::TokenTree::Ident(ident) => {
element_name = ident.to_string();
}
proc_macro2::TokenTree::Literal(lit) => {
let index = lit.to_string().parse().unwrap();
elements.push((element_name.clone(), index));
}
_ => (),
},
None => break,
}
}
Ok(MakeGpioEnumDispatchMacro {
name,
filter,
elements,
})
}
}
#[proc_macro]
pub fn make_gpio_enum_dispatch_macro(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as MakeGpioEnumDispatchMacro);
let mut arms = Vec::new();
for (gpio_type, num) in input.elements {
let enum_name = quote::format_ident!("ErasedPin");
let variant_name = quote::format_ident!("Gpio{}", num);
if input.filter.contains(&gpio_type) {
let arm = {
quote! { #enum_name::#variant_name($target) => $body }
};
arms.push(arm);
} else {
let arm = {
quote! {
#[allow(unused)]
#enum_name::#variant_name($target) => { panic!("Unsupported") }
}
};
arms.push(arm);
}
}
let macro_name = quote::format_ident!("{}", input.name);
quote! {
#[doc(hidden)]
#[macro_export]
macro_rules! #macro_name {
($m:ident, $target:ident, $body:block) => {
match $m {
#(#arms)*
}
}
}
pub(crate) use #macro_name;
}
.into()
}

View File

@ -0,0 +1,62 @@
//! Blinks three LEDs
//!
//! This assumes that LEDs are connected to GPIO25, 26 and 27.
#![no_std]
#![no_main]
use esp32_hal::{
clock::ClockControl,
gpio::{AnyPin, Input, Output, PullDown, PushPull, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
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();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let led1 = io.pins.gpio25.into_push_pull_output();
let led2 = io.pins.gpio26.into_push_pull_output();
let led3 = io.pins.gpio27.into_push_pull_output();
let button = io.pins.gpio0.into_pull_down_input().degrade();
// you can use `into` or `degrade`
let mut pins = [led1.into(), led2.into(), led3.degrade()];
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
toggle_pins(&mut pins, &button);
delay.delay_ms(500u32);
}
}
fn toggle_pins(leds: &mut [AnyPin<Output<PushPull>>], button: &AnyPin<Input<PullDown>>) {
for pin in leds.iter_mut() {
pin.toggle().unwrap();
}
if button.is_low().unwrap() {
esp_println::println!("Button");
}
}

View File

@ -0,0 +1,64 @@
//! Blinks an LED
//!
//! This assumes that LEDs are connected to GPIO3, 4 and 5.
#![no_std]
#![no_main]
use esp32c2_hal::{
clock::ClockControl,
gpio::{AnyPin, Input, Output, PullDown, PushPull, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use esp_riscv_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let led1 = io.pins.gpio3.into_push_pull_output();
let led2 = io.pins.gpio4.into_push_pull_output();
let led3 = io.pins.gpio5.into_push_pull_output();
let button = io.pins.gpio9.into_pull_down_input().degrade();
// you can use `into` or `degrade`
let mut pins = [led1.into(), led2.into(), led3.degrade()];
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
toggle_pins(&mut pins, &button);
delay.delay_ms(500u32);
}
}
fn toggle_pins(leds: &mut [AnyPin<Output<PushPull>>], button: &AnyPin<Input<PullDown>>) {
for pin in leds.iter_mut() {
pin.toggle().unwrap();
}
if button.is_low().unwrap() {
esp_println::println!("Button");
}
}

View File

@ -0,0 +1,67 @@
//! Blinks an LED
//!
//! This assumes that LEDs are connected to GPIO3, 4 and 5.
#![no_std]
#![no_main]
use esp32c3_hal::{
clock::ClockControl,
gpio::{AnyPin, Input, Output, PullDown, PushPull, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use esp_riscv_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
// the RTC WDT, and the TIMG WDTs.
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;
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let led1 = io.pins.gpio3.into_push_pull_output();
let led2 = io.pins.gpio4.into_push_pull_output();
let led3 = io.pins.gpio5.into_push_pull_output();
let button = io.pins.gpio9.into_pull_down_input().degrade();
// you can use `into` or `degrade`
let mut pins = [led1.into(), led2.into(), led3.degrade()];
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
toggle_pins(&mut pins, &button);
delay.delay_ms(500u32);
}
}
fn toggle_pins(leds: &mut [AnyPin<Output<PushPull>>], button: &AnyPin<Input<PullDown>>) {
for pin in leds.iter_mut() {
pin.toggle().unwrap();
}
if button.is_low().unwrap() {
esp_println::println!("Button");
}
}

View File

@ -0,0 +1,63 @@
//! Blinks an LED
//!
//! This assumes that LEDs are connected to GPIO3, 4 and 5.
#![no_std]
#![no_main]
use esp32s2_hal::{
clock::ClockControl,
gpio::{AnyPin, Input, Output, PullDown, PushPull, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
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();
// Set GPIO4 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let led1 = io.pins.gpio3.into_push_pull_output();
let led2 = io.pins.gpio4.into_push_pull_output();
let led3 = io.pins.gpio5.into_push_pull_output();
let button = io.pins.gpio0.into_pull_down_input().degrade();
// you can use `into` or `degrade`
let mut pins = [led1.into(), led2.into(), led3.degrade()];
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
toggle_pins(&mut pins, &button);
delay.delay_ms(500u32);
}
}
fn toggle_pins(leds: &mut [AnyPin<Output<PushPull>>], button: &AnyPin<Input<PullDown>>) {
for pin in leds.iter_mut() {
pin.toggle().unwrap();
}
if button.is_low().unwrap() {
esp_println::println!("Button");
}
}

View File

@ -0,0 +1,63 @@
//! Blinks an LED
//!
//! This assumes that LEDs are connected to GPIO3, 4 and 5.
#![no_std]
#![no_main]
use esp32s3_hal::{
clock::ClockControl,
gpio::{AnyPin, Input, Output, PullDown, PushPull, IO},
peripherals::Peripherals,
prelude::*,
timer::TimerGroup,
Delay,
Rtc,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
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();
// Set GPIO4 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let led1 = io.pins.gpio3.into_push_pull_output();
let led2 = io.pins.gpio4.into_push_pull_output();
let led3 = io.pins.gpio5.into_push_pull_output();
let button = io.pins.gpio0.into_pull_down_input().degrade();
// you can use `into` or `degrade`
let mut pins = [led1.into(), led2.into(), led3.degrade()];
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
loop {
toggle_pins(&mut pins, &button);
delay.delay_ms(500u32);
}
}
fn toggle_pins(leds: &mut [AnyPin<Output<PushPull>>], button: &AnyPin<Input<PullDown>>) {
for pin in leds.iter_mut() {
pin.toggle().unwrap();
}
if button.is_low().unwrap() {
esp_println::println!("Button");
}
}