Shared GPIO Implementation (#3)

* make esp32c3 examples run from flash / flashable
* use gpio3 for blinky
* direct boot in Cargo.toml
* have a shared gpio impl
* use PACs from their original locations again
This commit is contained in:
Björn Quentin 2022-01-06 16:57:55 +01:00 committed by GitHub
parent 4e9ad72839
commit 6d94b61268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1754 additions and 871 deletions

View File

@ -1,4 +1,7 @@
{
"rust-analyzer.cargo.features": [
"esp32c3"
],
"editor.formatOnSave": true,
"rust-analyzer.checkOnSave.allTargets": false
}
}

View File

@ -4,5 +4,5 @@ members = [
"esp32-hal",
"esp32c3-hal",
"esp32s2-hal",
"esp32s3-hal",
"esp32s3-hal"
]

View File

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2018"
[dependencies]
paste = "1.0.6"
embedded-hal = { version = "0.2", features = ["unproven"] }
nb = "1.0"
riscv = { version = "0.7", optional = true }
@ -12,7 +13,7 @@ xtensa-lx = { version = "0.4", optional = true }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
# corresponding feature.
esp32_pac = { package = "esp32", git = "https://github.com/jessebraham/esp32.git", branch = "develop", optional = true }
esp32_pac = { package = "esp32", git = "https://github.com/jessebraham/esp32.git", branch = "develop", optional = true }
esp32c3_pac = { package = "esp32c3", git = "https://github.com/jessebraham/esp32c3.git", branch = "develop", optional = true }
esp32s2_pac = { package = "esp32s2", git = "https://github.com/jessebraham/esp32s2.git", branch = "develop", optional = true }
esp32s3_pac = { package = "esp32s3", git = "https://github.com/jessebraham/esp32s3.git", branch = "develop", optional = true }

View File

@ -0,0 +1,758 @@
pub use crate::prelude::*;
pub use paste::paste;
#[macro_export]
macro_rules! impl_output {
(
$gpio_function:ident,
$pxi:ident:
(
$pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_set:ident, $out_en_clear:ident,
$out_set:ident, $out_clear:ident, $out_reg:ident
)
$( ,( $( $af_signal:ident: $af:ident ),* ))?
) => {
impl<MODE> embedded_hal::digital::v2::OutputPin for $pxi<Output<MODE>> {
type Error = Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
Ok(())
}
}
impl<MODE> embedded_hal::digital::v2::StatefulOutputPin for $pxi<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
unsafe { Ok((*GPIO::ptr()).$out_reg.read().bits() & (1 << $bit) != 0) }
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(!self.is_set_high()?)
}
}
impl<MODE> embedded_hal::digital::v2::ToggleableOutputPin for $pxi<Output<MODE>> {
type Error = Infallible;
fn toggle(&mut self) -> Result<(), Self::Error> {
if self.is_set_high()? {
Ok(self.set_low()?)
} else {
Ok(self.set_high()?)
}
}
}
impl<MODE> $pxi<MODE> {
pub fn into_pull_up_input(self) -> $pxi<Input<PullUp>> {
self.init_input(false, false);
$pxi { _mode: PhantomData }
}
pub fn into_pull_down_input(self) -> $pxi<Input<PullDown>> {
self.init_input(true, false);
$pxi { _mode: PhantomData }
}
fn init_output(&self, alternate: AlternateFunction, open_drain: bool) {
let gpio = unsafe { &*GPIO::ptr() };
let iomux = unsafe { &*IO_MUX::ptr() };
gpio.$out_en_set.write(|w| unsafe { w.bits(1 << $bit) });
gpio.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(open_drain));
gpio.func_out_sel_cfg[$pin_num]
.modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
paste! {
iomux.$iomux_reg.modify(|_, w| unsafe {
w.mcu_sel()
.bits(alternate as u8)
.fun_ie()
.clear_bit()
.fun_wpd()
.clear_bit()
.fun_wpu()
.clear_bit()
.fun_drv()
.bits(DriveStrength::I20mA as u8)
.slp_sel()
.clear_bit()
});
}
}
pub fn into_push_pull_output(self) -> $pxi<Output<PushPull>> {
self.init_output(AlternateFunction::$gpio_function, false);
$pxi { _mode: PhantomData }
}
pub fn into_open_drain_output(self) -> $pxi<Output<OpenDrain>> {
self.init_output(AlternateFunction::$gpio_function, true);
$pxi { _mode: PhantomData }
}
pub fn into_alternate_1(self) -> $pxi<Alternate<AF1>> {
self.init_output(AlternateFunction::Function1, false);
$pxi { _mode: PhantomData }
}
pub fn into_alternate_2(self) -> $pxi<Alternate<AF2>> {
self.init_output(AlternateFunction::Function2, false);
$pxi { _mode: PhantomData }
}
}
impl<MODE> OutputPin for $pxi<MODE> {
fn set_to_open_drain_output(&mut self) -> &mut Self {
self.init_output(AlternateFunction::$gpio_function, true);
self
}
fn set_to_push_pull_output(&mut self) -> &mut Self {
self.init_output(AlternateFunction::$gpio_function, false);
self
}
fn enable_output(&mut self, on: bool) -> &mut Self {
if on {
unsafe { &*GPIO::ptr() }
.$out_en_set
.write(|w| unsafe { w.bits(1 << $bit) });
} else {
unsafe { &*GPIO::ptr() }
.$out_en_clear
.write(|w| unsafe { w.bits(1 << $bit) });
}
self
}
fn set_output_high(&mut self, high: bool) -> &mut Self {
if high {
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
} else {
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
}
self
}
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) });
}
self
}
fn enable_open_drain(&mut self, on: bool) -> &mut Self {
unsafe { &*GPIO::ptr() }.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(on));
self
}
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.mcu_wpu().bit(on));
}
self
}
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self {
paste!{
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.mcu_wpd().bit(on));
}
self
}
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.mcu_oe().bit(on));
}
self
}
fn connect_peripheral_to_output_with_options(
&mut self,
signal: OutputSignal,
invert: bool,
invert_enable: bool,
enable_from_gpio: bool,
force_via_gpio_mux: bool,
) -> &mut Self {
let af = if force_via_gpio_mux {
AlternateFunction::$gpio_function
} else {
match signal {
$( $(
OutputSignal::$af_signal => AlternateFunction::$af,
)* )?
_ => AlternateFunction::$gpio_function
}
};
if af == AlternateFunction::$gpio_function && signal as usize > OUTPUT_SIGNAL_MAX as usize {
panic!("Cannot connect this peripheral to GPIO");
}
self.set_alternate_function(af);
let clipped_signal = if signal as usize <= OUTPUT_SIGNAL_MAX as usize { signal as OutputSignalType } else { OUTPUT_SIGNAL_MAX };
unsafe { &*GPIO::ptr() }.func_out_sel_cfg[$pin_num].modify(|_, w| unsafe {
w
.out_sel().bits(clipped_signal)
.inv_sel().bit(invert)
.oen_sel().bit(enable_from_gpio)
.oen_inv_sel().bit(invert_enable)
});
self
}
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
paste!{
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpu().bit(on));
}
self
}
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }.$iomux_reg.modify(|_, w| w.fun_wpd().bit(on));
}
self
}
}
};
}
#[macro_export]
macro_rules! impl_input {
($gpio_function:ident,
$pxi:ident:
($pin_num:expr, $iomux_reg:expr, $bit:expr, $out_en_clear:ident, $reg:ident, $reader:ident,
$status_w1tc:ident, $pcpu_int:ident, $pcpu_nmi:ident, $acpu_int:ident, $acpu_nmi:ident
) $( ,( $( $af_signal:ident : $af:ident ),* ))?
) => {
impl<MODE> embedded_hal::digital::v2::InputPin for $pxi<Input<MODE>> {
type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(unsafe { &*GPIO::ptr() }.$reg.read().$reader().bits() & (1 << $bit) != 0)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(!self.is_high()?)
}
}
impl<MODE> $pxi<MODE> {
fn init_input(&self, pull_down: bool, pull_up: bool) {
let gpio = unsafe { &*GPIO::ptr() };
let iomux = unsafe { &*IO_MUX::ptr() };
gpio.$out_en_clear
.write(|w| unsafe { w.bits(1 << $bit) });
gpio.func_out_sel_cfg[$pin_num]
.modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) });
paste! {
iomux.$iomux_reg.modify(|_, w| unsafe {
w.mcu_sel()
.bits(2)
.fun_ie()
.set_bit()
.fun_wpd()
.bit(pull_down)
.fun_wpu()
.bit(pull_up)
.slp_sel()
.clear_bit()
});
}
}
pub fn into_floating_input(self) -> $pxi<Input<Floating>> {
self.init_input(false, false);
$pxi { _mode: PhantomData }
}
}
impl<MODE> InputPin for $pxi<MODE> {
fn set_to_input(&mut self) -> &mut Self {
self.init_input(false, false);
self
}
fn enable_input(&mut self, on: bool) -> &mut Self {
paste!{
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.fun_ie().bit(on));
}
self
}
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.mcu_ie().bit(on));
}
self
}
fn is_input_high(&mut self) -> bool {
unsafe { &*GPIO::ptr() }.$reg.read().$reader().bits() & (1 << $bit) != 0
}
fn connect_input_to_peripheral_with_options(
&mut self,
signal: InputSignal,
invert: bool,
force_via_gpio_mux: bool,
) -> &mut Self {
let af = if force_via_gpio_mux
{
AlternateFunction::$gpio_function
}
else {
match signal {
$( $(
InputSignal::$af_signal => AlternateFunction::$af,
)* )?
_ => AlternateFunction::$gpio_function
}
};
if af == AlternateFunction::$gpio_function && signal as usize > INPUT_SIGNAL_MAX as usize {
panic!("Cannot connect GPIO to this peripheral");
}
self.set_alternate_function(af);
if (signal as usize) <= INPUT_SIGNAL_MAX as usize {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sel()
.set_bit()
.in_inv_sel()
.bit(invert)
.in_sel()
.bits($pin_num)
});
}
self
}
}
impl<MODE> Pin for $pxi<MODE> {
fn sleep_mode(&mut self, on: bool) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| w.slp_sel().bit(on));
}
self
}
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self {
paste! {
unsafe { &*IO_MUX::ptr() }
.$iomux_reg
.modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8) });
}
self
}
fn listen_with_options(&mut self, event: Event,
int_enable: bool, nmi_enable: bool,
wake_up_from_light_sleep: bool
) {
if wake_up_from_light_sleep {
match event {
Event::AnyEdge | Event::RisingEdge | Event::FallingEdge => {
panic!("Edge triggering is not supported for wake-up from light sleep");
},
_ => {}
}
}
unsafe {
(&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
w
.pin_int_ena().bits(int_enable as u8 | ((nmi_enable as u8) << 1))
.pin_int_type().bits(event as u8)
.pin_wakeup_enable().bit(wake_up_from_light_sleep)
);
}
}
fn unlisten(&mut self) {
unsafe { (&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
w.pin_int_ena().bits(0).pin_int_type().bits(0).pin_int_ena().bits(0) );
}
}
fn clear_interrupt(&mut self) {
unsafe {&*GPIO::ptr()}.$status_w1tc.write(|w|
unsafe {w.bits(1 << $bit)})
}
fn is_pcore_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$pcpu_int.read().bits() & (1 << $bit)) !=0
}
fn is_pcore_non_maskable_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$pcpu_nmi.read().bits() & (1 << $bit)) !=0
}
fn is_acore_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$acpu_int.read().bits() & (1 << $bit)) !=0
}
fn is_acore_non_maskable_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$acpu_nmi.read().bits() & (1 << $bit)) !=0
}
fn enable_hold(&mut self, _on: bool) {
todo!();
}
}
};
}
#[macro_export]
macro_rules! impl_pin_wrap {
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, SingleCore
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
) => {
impl_input!($gpio_function, $pxi: ($pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
status_w1tc, pcpu_int, pcpu_nmi_int, pcpu_int, pcpu_nmi_int)
$( ,( $( $af_input_signal: $af_input ),* ) )? );
};
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, SingleCore
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
) => {
impl_input!($gpio_function, $pxi: ($pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
status1_w1tc, pcpu_int1, pcpu_nmi_int1, pcpu_int1, pcpu_nmi_int1)
$( ,( $( $af_input_signal: $af_input ),* ) )? );
};
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank0, DualCore
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
) => {
impl_input!($gpio_function, $pxi: ($pin_num, $iomux_reg, $pin_num % 32, enable_w1tc, in_, data_next,
status_w1tc, pcpu_int, pcpu_nmi_int, acpu_int, acpu_nmi_int)
$( ,( $( $af_input_signal: $af_input ),* ) )? );
};
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, Bank1, DualCore
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
) => {
impl_input!($gpio_function, $pxi: ($pin_num, $iomux_reg, $pin_num % 32, enable1_w1tc, in1, data_next,
status1_w1tc, pcpu_int1, pcpu_nmi_int1, acpu_int1, acpu_nmi_int1)
$( ,( $( $af_input_signal: $af_input ),* ) )? );
};
}
#[macro_export]
macro_rules! impl_output_wrap {
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank0
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
) => {
impl_output!($gpio_function, $pxi:
($pin_num, $iomux_reg, $pin_num % 32, enable_w1ts, enable_w1tc, out_w1ts, out_w1tc, out)
$( ,( $( $af_output_signal: $af_output ),* ) )? );
};
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, IO, Bank1
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
) => {
impl_output!($gpio_function, $pxi:
($pin_num, $iomux_reg, $pin_num % 32, enable1_w1ts, enable1_w1tc, out1_w1ts, out1_w1tc, out1)
$( ,( $( $af_output_signal: $af_output ),* ) )? );
};
($gpio_function:ident, $pxi:ident, $pin_num:expr, $iomux_reg:expr, $type:ident, $bank:ident
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
) => {
};
}
#[macro_export]
macro_rules! gpio {
( $gpio_function:ident,
$cores:ident,
$($pxi:ident: ($pname:ident, $pin_num:literal, $iomux_reg:expr, $type:ident, $rtc:tt, $bank:ident ),
$(
( $( $af_input_signal:ident: $af_input:ident ),* ),
$(
( $( $af_output_signal:ident: $af_output:ident ),* ),
)?
)?
)+ ) => {
use core::{convert::Infallible, marker::PhantomData};
use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin as _};
use crate::pac::{GPIO, IO_MUX};
#[allow(dead_code)]
pub struct IO {
io_mux: IO_MUX,
pub pins: Pins,
}
impl IO {
pub fn new(gpio: GPIO, io_mux: IO_MUX) -> Self {
let pins = gpio.split();
let io = IO { io_mux, pins };
io
}
}
pub trait GpioExt {
type Parts;
fn split(self) -> Self::Parts;
}
pub trait Pin {
fn sleep_mode(&mut self, on: bool) -> &mut Self;
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self;
fn listen(&mut self, event: Event) {
self.listen_with_options(event, true, false, false)
}
fn listen_with_options(
&mut self,
event: Event,
int_enable: bool,
nmi_enable: bool,
wake_up_from_light_sleep: bool,
);
fn unlisten(&mut self);
fn clear_interrupt(&mut self);
fn is_pcore_interrupt_set(&mut self) -> bool;
fn is_pcore_non_maskable_interrupt_set(&mut self) -> bool;
fn is_acore_interrupt_set(&mut self) -> bool;
fn is_acore_non_maskable_interrupt_set(&mut self) -> bool;
fn enable_hold(&mut self, on: bool);
}
pub trait InputPin: Pin {
fn set_to_input(&mut self) -> &mut Self;
fn enable_input(&mut self, on: bool) -> &mut Self;
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn is_input_high(&mut self) -> bool;
fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self {
self.connect_input_to_peripheral_with_options(signal, false, false)
}
fn connect_input_to_peripheral_with_options(
&mut self,
signal: InputSignal,
invert: bool,
force_via_gpio_mux: bool,
) -> &mut Self;
}
pub trait OutputPin: Pin {
fn set_to_open_drain_output(&mut self) -> &mut Self;
fn set_to_push_pull_output(&mut self) -> &mut Self;
fn enable_output(&mut self, on: bool) -> &mut Self;
fn set_output_high(&mut self, on: bool) -> &mut Self;
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self;
fn enable_open_drain(&mut self, on: bool) -> &mut Self;
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self {
self.connect_peripheral_to_output_with_options(signal, false, false, false, false)
}
fn connect_peripheral_to_output_with_options(
&mut self,
signal: OutputSignal,
invert: bool,
invert_enable: bool,
enable_from_gpio: bool,
force_via_gpio_mux: bool,
) -> &mut Self;
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
}
pub trait RTCPin {}
pub trait AnalogPin {}
#[derive(Copy, Clone)]
pub enum Event {
RisingEdge = 1,
FallingEdge = 2,
AnyEdge = 3,
LowLevel = 4,
HighLevel = 5,
}
pub struct Unknown {}
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
pub struct RTCInput<MODE> {
_mode: PhantomData<MODE>,
}
pub struct Floating;
pub struct PullDown;
pub struct PullUp;
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
pub struct RTCOutput<MODE> {
_mode: PhantomData<MODE>,
}
pub struct OpenDrain;
pub struct PushPull;
pub struct Analog;
pub struct Alternate<MODE> {
_mode: PhantomData<MODE>,
}
pub struct AF0;
pub struct AF1;
pub struct AF2;
pub enum DriveStrength {
I5mA = 0,
I10mA = 1,
I20mA = 2,
I40mA = 3,
}
#[derive(PartialEq)]
pub enum AlternateFunction {
Function0 = 0,
Function1 = 1,
Function2 = 2,
Function3 = 3,
Function4 = 4,
Function5 = 5,
}
pub fn connect_low_to_peripheral(signal: InputSignal) {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sel()
.set_bit()
.in_inv_sel()
.bit(false)
.in_sel()
.bits(0x1f)
});
}
pub fn connect_high_to_peripheral(signal: InputSignal) {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sel()
.set_bit()
.in_inv_sel()
.bit(false)
.in_sel()
.bits(0x1e)
});
}
impl GpioExt for GPIO {
type Parts = Pins;
fn split(self) -> Self::Parts {
Pins {
$(
$pname: $pxi { _mode: PhantomData },
)+
}
}
}
pub struct Pins {
$(
pub $pname: $pxi<Unknown>,
)+
}
$(
pub struct $pxi<MODE> {
_mode: PhantomData<MODE>,
}
impl_pin_wrap!($gpio_function, $pxi, $pin_num, $iomux_reg, $type, $bank, $cores
$( ,( $( $af_input_signal: $af_input ),* ) )? );
impl_output_wrap!($gpio_function, $pxi, $pin_num, $iomux_reg, $type, $bank
$($( ,( $( $af_output_signal: $af_output ),* ) )? )? );
)+
};
}
pub use gpio;
pub use impl_input;
pub use impl_output;
pub use impl_output_wrap;
pub use impl_pin_wrap;

View File

@ -9,9 +9,11 @@ pub use esp32s2_pac as pac;
#[cfg(feature = "esp32s3")]
pub use esp32s3_pac as pac;
pub mod gpio;
pub mod prelude;
pub mod serial;
pub mod timer;
pub use gpio::*;
pub use serial::Serial;
pub use timer::Timer;

View File

@ -112,13 +112,6 @@ impl<T: Instance> Write<u8> for Serial<T> {
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.uart.get_tx_fifo_count() < UART_FIFO_SIZE {
#[cfg(feature = "esp32")]
self.uart
.register_block()
.fifo()
.write(|w| unsafe { w.rxfifo_rd_byte().bits(word) });
#[cfg(not(feature = "esp32"))]
self.uart
.register_block()
.fifo
@ -144,16 +137,6 @@ impl<T: Instance> Read<u8> for Serial<T> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if self.uart.get_rx_fifo_count() > 0 {
#[cfg(feature = "esp32")]
let value = self
.uart
.register_block()
.fifo()
.read()
.rxfifo_rd_byte()
.bits();
#[cfg(not(feature = "esp32"))]
let value = self
.uart
.register_block()

View File

@ -99,13 +99,17 @@ pub trait Instance {
reg_block
.wdtwprotect
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
.write(|w| unsafe { w.wdt_wkey().bits(0x50D8_3AA1u32) });
reg_block.wdtconfig0.write(|w| w.wdt_en().bit(enabled));
if !enabled {
reg_block.wdtconfig0.write(|w| unsafe { w.bits(0) });
} else {
reg_block.wdtconfig0.write(|w| w.wdt_en().bit(true));
}
reg_block
.wdtwprotect
.write(|w| unsafe { w.wdt_wkey().bits(0x50D8_3AA1u32) });
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
}
}

View File

@ -0,0 +1,27 @@
#![no_std]
#![no_main]
use esp32_hal::{gpio::IO, pac, prelude::*, Timer};
use nb::block;
use panic_halt as _;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = pac::Peripherals::take().unwrap();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut timer0 = Timer::new(peripherals.TIMG0);
timer0.disable();
let mut led = io.pins.gpio15.into_push_pull_output();
led.set_high().unwrap();
timer0.start(10_000_000u64);
loop {
led.toggle().unwrap();
block!(timer0.wait()).unwrap();
}
}

543
esp32-hal/src/gpio.rs Normal file
View File

@ -0,0 +1,543 @@
use esp_hal_common::gpio::gpio;
use crate::hal_gpio::*;
type OutputSignalType = u16;
const OUTPUT_SIGNAL_MAX: u16 = 548;
const INPUT_SIGNAL_MAX: u16 = 539;
/// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)]
pub enum InputSignal {
SPICLK = 0,
SPIQ = 1,
SPID = 2,
SPIHD = 3,
SPIWP = 4,
SPICS0 = 5,
SPICS1 = 6,
SPICS2 = 7,
HSPICLK = 8,
HSPIQ = 9,
HSPID = 10,
HSPICS0 = 11,
HSPIHD = 12,
HSPIWP = 13,
U0RXD = 14,
U0CTS = 15,
U0DSR = 16,
U1RXD = 17,
U1CTS = 18,
I2CM_SDA = 20,
EXT_I2C_SDA = 22,
I2S0O_BCK = 23,
I2S1O_BCK = 24,
I2S0O_WS = 25,
I2S1O_WS = 26,
I2S0I_BCK = 27,
I2S0I_WS = 28,
I2CEXT0_SCL = 29,
I2CEXT0_SDA = 30,
PWM0_SYNC0 = 31,
PWM0_SYNC1 = 32,
PWM0_SYNC2 = 33,
PWM0_F0 = 34,
PWM0_F1 = 35,
PWM0_F2 = 36,
GPIO_BT_ACTIVE = 37,
GPIO_BT_PRIORITY = 38,
PCNT_SIG_CH0_0 = 39,
PCNT_SIG_CH1_0 = 40,
PCNT_CTRL_CH0_0 = 41,
PCNT_CTRL_CH1_0 = 42,
PCNT_SIG_CH0_1 = 43,
PCNT_SIG_CH1_1 = 44,
PCNT_CTRL_CH0_1 = 45,
PCNT_CTRL_CH1_1 = 46,
PCNT_SIG_CH0_2 = 47,
PCNT_SIG_CH1_2 = 48,
PCNT_CTRL_CH0_2 = 49,
PCNT_CTRL_CH1_2 = 50,
PCNT_SIG_CH0_3 = 51,
PCNT_SIG_CH1_3 = 52,
PCNT_CTRL_CH0_3 = 53,
PCNT_CTRL_CH1_3 = 54,
PCNT_SIG_CH0_4 = 55,
PCNT_SIG_CH1_4 = 56,
PCNT_CTRL_CH0_4 = 57,
PCNT_CTRL_CH1_4 = 58,
HSPICS1 = 61,
HSPICS2 = 62,
VSPICLK = 63,
VSPIQ = 64,
VSPID = 65,
VSPIHD = 66,
VSPIWP = 67,
VSPICS0 = 68,
VSPICS1 = 69,
VSPICS2 = 70,
PCNT_SIG_CH0_5 = 71,
PCNT_SIG_CH1_5 = 72,
PCNT_CTRL_CH0_5 = 73,
PCNT_CTRL_CH1_5 = 74,
PCNT_SIG_CH0_6 = 75,
PCNT_SIG_CH1_6 = 76,
PCNT_CTRL_CH0_6 = 77,
PCNT_CTRL_CH1_6 = 78,
PCNT_SIG_CH0_7 = 79,
PCNT_SIG_CH1_7 = 80,
PCNT_CTRL_CH0_7 = 81,
PCNT_CTRL_CH1_7 = 82,
RMT_SIG_0 = 83,
RMT_SIG_1 = 84,
RMT_SIG_2 = 85,
RMT_SIG_3 = 86,
RMT_SIG_4 = 87,
RMT_SIG_5 = 88,
RMT_SIG_6 = 89,
RMT_SIG_7 = 90,
EXT_ADC_START = 93,
CAN_RX = 94,
I2CEXT1_SCL = 95,
I2CEXT1_SDA = 96,
HOST_CARD_DETECT_N_1 = 97,
HOST_CARD_DETECT_N_2 = 98,
HOST_CARD_WRITE_PRT_1 = 99,
HOST_CARD_WRITE_PRT_2 = 100,
HOST_CARD_INT_N_1 = 101,
HOST_CARD_INT_N_2 = 102,
PWM1_SYNC0 = 103,
PWM1_SYNC1 = 104,
PWM1_SYNC2 = 105,
PWM1_F0 = 106,
PWM1_F1 = 107,
PWM1_F2 = 108,
PWM0_CAP0 = 109,
PWM0_CAP1 = 110,
PWM0_CAP2 = 111,
PWM1_CAP0 = 112,
PWM1_CAP1 = 113,
PWM1_CAP2 = 114,
PWM2_FLTA = 115,
PWM2_FLTB = 116,
PWM2_CAP1 = 117,
PWM2_CAP2 = 118,
PWM2_CAP3 = 119,
PWM3_FLTA = 120,
PWM3_FLTB = 121,
PWM3_CAP1 = 122,
PWM3_CAP2 = 123,
PWM3_CAP3 = 124,
CAN_CLKOUT = 125,
SPID4 = 128,
SPID5 = 129,
SPID6 = 130,
SPID7 = 131,
HSPID4 = 132,
HSPID5 = 133,
HSPID6 = 134,
HSPID7 = 135,
VSPID4 = 136,
VSPID5 = 137,
VSPID6 = 138,
VSPID7 = 139,
I2S0I_DATA_0 = 140,
I2S0I_DATA_1 = 141,
I2S0I_DATA_2 = 142,
I2S0I_DATA_3 = 143,
I2S0I_DATA_4 = 144,
I2S0I_DATA_5 = 145,
I2S0I_DATA_6 = 146,
I2S0I_DATA_7 = 147,
I2S0I_DATA_8 = 148,
I2S0I_DATA_9 = 149,
I2S0I_DATA_10 = 150,
I2S0I_DATA_11 = 151,
I2S0I_DATA_12 = 152,
I2S0I_DATA_13 = 153,
I2S0I_DATA_14 = 154,
I2S0I_DATA_15 = 155,
I2S1I_BCK = 164,
I2S1I_WS = 165,
I2S1I_DATA_0 = 166,
I2S1I_DATA_1 = 167,
I2S1I_DATA_2 = 168,
I2S1I_DATA_3 = 169,
I2S1I_DATA_4 = 170,
I2S1I_DATA_5 = 171,
I2S1I_DATA_6 = 172,
I2S1I_DATA_7 = 173,
I2S1I_DATA_8 = 174,
I2S1I_DATA_9 = 175,
I2S1I_DATA_10 = 176,
I2S1I_DATA_11 = 177,
I2S1I_DATA_12 = 178,
I2S1I_DATA_13 = 179,
I2S1I_DATA_14 = 180,
I2S1I_DATA_15 = 181,
I2S0I_H_SYNC = 190,
I2S0I_V_SYNC = 191,
I2S0I_H_ENABLE = 192,
I2S1I_H_SYNC = 193,
I2S1I_V_SYNC = 194,
I2S1I_H_ENABLE = 195,
U2RXD = 198,
U2CTS = 199,
EMAC_MDC = 200,
EMAC_MDI = 201,
EMAC_CRS = 202,
EMAC_COL = 203,
PCMFSYNC = 204,
PCMCLK = 205,
PCMDIN = 206,
SIG_IN_FUNC224 = 224,
SIG_IN_FUNC225 = 225,
SIG_IN_FUNC226 = 226,
SIG_IN_FUNC227 = 227,
SIG_IN_FUNC228 = 228,
SD_DATA0 = 512,
SD_DATA1,
SD_DATA2,
SD_DATA3,
HS1_DATA0,
HS1_DATA1,
HS1_DATA2,
HS1_DATA3,
HS1_DATA4,
HS1_DATA5,
HS1_DATA6,
HS1_DATA7,
HS2_DATA0,
HS2_DATA1,
HS2_DATA2,
HS2_DATA3,
EMAC_TX_CLK,
EMAC_RXD2,
EMAC_TX_ER,
EMAC_RX_CLK,
EMAC_RX_ER,
EMAC_RXD3,
EMAC_RXD0,
EMAC_RXD1,
EMAC_RX_DV,
MTDI,
MTCK,
MTMS,
}
/// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)]
pub enum OutputSignal {
SPICLK = 0,
SPIQ = 1,
SPID = 2,
SPIHD = 3,
SPIWP = 4,
SPICS0 = 5,
SPICS1 = 6,
SPICS2 = 7,
HSPICLK = 8,
HSPIQ = 9,
HSPID = 10,
HSPICS0 = 11,
HSPIHD = 12,
HSPIWP = 13,
U0TXD = 14,
U0RTS = 15,
U0DTR = 16,
U1TXD = 17,
U1RTS = 18,
I2CM_SCL = 19,
I2CM_SDA = 20,
EXT2C_SCL = 21,
EXT2C_SDA = 22,
I2S0O_BCK = 23,
I2S1O_BCK = 24,
I2S0O_WS = 25,
I2S1O_WS = 26,
I2S0I_BCK = 27,
I2S0I_WS = 28,
I2CEXT0_SCL = 29,
I2CEXT0_SDA = 30,
SDIO_TOHOSTT = 31,
PWM0_0A = 32,
PWM0_0B = 33,
PWM0_1A = 34,
PWM0_1B = 35,
PWM0_2A = 36,
PWM0_2B = 37,
GPIO_WLAN_ACTIVE = 40,
BB_DIAG0 = 41,
BB_DIAG1 = 42,
BB_DIAG2 = 43,
BB_DIAG3 = 44,
BB_DIAG4 = 45,
BB_DIAG5 = 46,
BB_DIAG6 = 47,
BB_DIAG7 = 48,
BB_DIAG8 = 49,
BB_DIAG9 = 50,
BB_DIAG10 = 51,
BB_DIAG11 = 52,
BB_DIAG12 = 53,
BB_DIAG13 = 54,
BB_DIAG14 = 55,
BB_DIAG15 = 56,
BB_DIAG16 = 57,
BB_DIAG17 = 58,
BB_DIAG18 = 59,
BB_DIAG19 = 60,
HSPICS1 = 61,
HSPICS2 = 62,
VSPICLK = 63,
VSPIQ = 64,
VSPID = 65,
VSPIHD = 66,
VSPIWP = 67,
VSPICS0 = 68,
VSPICS1 = 69,
VSPICS2 = 70,
LEDC_HS_SIG_0 = 71,
LEDC_HS_SIG_1 = 72,
LEDC_HS_SIG_2 = 73,
LEDC_HS_SIG_3 = 74,
LEDC_HS_SIG_4 = 75,
LEDC_HS_SIG_5 = 76,
LEDC_HS_SIG_6 = 77,
LEDC_HS_SIG_7 = 78,
LEDC_LS_SIG_0 = 79,
LEDC_LS_SIG_1 = 80,
LEDC_LS_SIG_2 = 81,
LEDC_LS_SIG_3 = 82,
LEDC_LS_SIG_4 = 83,
LEDC_LS_SIG_5 = 84,
LEDC_LS_SIG_6 = 85,
LEDC_LS_SIG_7 = 86,
RMT_SIG_0 = 87,
RMT_SIG_1 = 88,
RMT_SIG_2 = 89,
RMT_SIG_3 = 90,
RMT_SIG_4 = 91,
RMT_SIG_5 = 92,
RMT_SIG_6 = 93,
RMT_SIG_7 = 94,
I2CEXT1_SCL = 95,
I2CEXT1_SDA = 96,
HOST_CCMD_OD_PULLUP_EN_N = 97,
HOST_RST_N_1 = 98,
HOST_RST_N_2 = 99,
GPIO_SD0 = 100,
GPIO_SD1 = 101,
GPIO_SD2 = 102,
GPIO_SD3 = 103,
GPIO_SD4 = 104,
GPIO_SD5 = 105,
GPIO_SD6 = 106,
GPIO_SD7 = 107,
PWM1_0A = 108,
PWM1_0B = 109,
PWM1_1A = 110,
PWM1_1B = 111,
PWM1_2A = 112,
PWM1_2B = 113,
PWM2_1H = 114,
PWM2_1L = 115,
PWM2_2H = 116,
PWM2_2L = 117,
PWM2_3H = 118,
PWM2_3L = 119,
PWM2_4H = 120,
PWM2_4L = 121,
CAN_TX = 123,
CAN_BUS_OFF_ON = 124,
SPID4 = 128,
SPID5 = 129,
SPID6 = 130,
SPID7 = 131,
HSPID4 = 132,
HSPID5 = 133,
HSPID6 = 134,
HSPID7 = 135,
VSPID4 = 136,
VSPID5 = 137,
VSPID6 = 138,
VSPID7 = 139,
I2S0O_DATA_0 = 140,
I2S0O_DATA_1 = 141,
I2S0O_DATA_2 = 142,
I2S0O_DATA_3 = 143,
I2S0O_DATA_4 = 144,
I2S0O_DATA_5 = 145,
I2S0O_DATA_6 = 146,
I2S0O_DATA_7 = 147,
I2S0O_DATA_8 = 148,
I2S0O_DATA_9 = 149,
I2S0O_DATA_10 = 150,
I2S0O_DATA_11 = 151,
I2S0O_DATA_12 = 152,
I2S0O_DATA_13 = 153,
I2S0O_DATA_14 = 154,
I2S0O_DATA_15 = 155,
I2S0O_DATA_16 = 156,
I2S0O_DATA_17 = 157,
I2S0O_DATA_18 = 158,
I2S0O_DATA_19 = 159,
I2S0O_DATA_20 = 160,
I2S0O_DATA_21 = 161,
I2S0O_DATA_22 = 162,
I2S0O_DATA_23 = 163,
I2S1I_BCK = 164,
I2S1I_WS = 165,
I2S1O_DATA_0 = 166,
I2S1O_DATA_1 = 167,
I2S1O_DATA_2 = 168,
I2S1O_DATA_3 = 169,
I2S1O_DATA_4 = 170,
I2S1O_DATA_5 = 171,
I2S1O_DATA_6 = 172,
I2S1O_DATA_7 = 173,
I2S1O_DATA_8 = 174,
I2S1O_DATA_9 = 175,
I2S1O_DATA_10 = 176,
I2S1O_DATA_11 = 177,
I2S1O_DATA_12 = 178,
I2S1O_DATA_13 = 179,
I2S1O_DATA_14 = 180,
I2S1O_DATA_15 = 181,
I2S1O_DATA_16 = 182,
I2S1O_DATA_17 = 183,
I2S1O_DATA_18 = 184,
I2S1O_DATA_19 = 185,
I2S1O_DATA_20 = 186,
I2S1O_DATA_21 = 187,
I2S1O_DATA_22 = 188,
I2S1O_DATA_23 = 189,
PWM3_1H = 190,
PWM3_1L = 191,
PWM3_2H = 192,
PWM3_2L = 193,
PWM3_3H = 194,
PWM3_3L = 195,
PWM3_4H = 196,
PWM3_4L = 197,
U2TXD = 198,
U2RTS = 199,
EMAC_MDC = 200,
EMAC_MDO = 201,
EMAC_CRS = 202,
EMAC_COL = 203,
BT_AUDIO0RQ = 204,
BT_AUDIO1RQ = 205,
BT_AUDIO2RQ = 206,
BLE_AUDIO0RQ = 207,
BLE_AUDIO1RQ = 208,
BLE_AUDIO2RQ = 209,
PCMFSYNC = 210,
PCMCLK = 211,
PCMDOUT = 212,
BLE_AUDIO_SYNC0_P = 213,
BLE_AUDIO_SYNC1_P = 214,
BLE_AUDIO_SYNC2_P = 215,
ANT_SEL0 = 216,
ANT_SEL1 = 217,
ANT_SEL2 = 218,
ANT_SEL3 = 219,
ANT_SEL4 = 220,
ANT_SEL5 = 221,
ANT_SEL6 = 222,
ANT_SEL7 = 223,
SIGNAL_224 = 224,
SIGNAL_225 = 225,
SIGNAL_226 = 226,
SIGNAL_227 = 227,
SIGNAL_228 = 228,
GPIO = 256,
CLK_OUT1 = 512,
CLK_OUT2,
CLK_OUT3,
SD_CLK,
SD_CMD,
SD_DATA0,
SD_DATA1,
SD_DATA2,
SD_DATA3,
HS1_CLK,
HS1_CMD,
HS1_DATA0,
HS1_DATA1,
HS1_DATA2,
HS1_DATA3,
HS1_DATA4,
HS1_DATA5,
HS1_DATA6,
HS1_DATA7,
HS1_STROBE,
HS2_CLK,
HS2_CMD,
HS2_DATA0,
HS2_DATA1,
HS2_DATA2,
HS2_DATA3,
EMAC_TX_CLK,
EMAC_TX_ER,
EMAC_TXD3,
EMAC_RX_ER,
EMAC_TXD2,
EMAC_CLK_OUT,
EMAC_CLK_180,
EMAC_TXD0,
EMAC_TX_EN,
EMAC_TXD1,
MTDO,
}
gpio! {
Function2,
DualCore,
Gpio0: (gpio0, 0, gpio0, IO, RTC, Bank0), (EMAC_TX_CLK: Function5), (CLK_OUT1: Function1),
Gpio1: (gpio1, 1, gpio1, IO, 0, Bank0), (EMAC_RXD2: Function5), (U0TXD: Function1, CLK_OUT3: Function1),
Gpio2: (gpio2, 2, gpio2, IO, RTC, Bank0), (HSPIWP: Function1, HS2_DATA0: Function3, SD_DATA0: Function4), (HS2_DATA0: Function3, SD_DATA0: Function4),
Gpio3: (gpio3, 3, gpio3, IO, 0, Bank0), (U0RXD: Function0), (CLK_OUT2: Function1),
Gpio4: (gpio4, 4, gpio4, IO, RTC, Bank0), (HSPIHD: Function1, HS2_DATA1: Function3, SD_DATA1: Function4, EMAC_TX_ER: Function5), (HS2_DATA1: Function3, SD_DATA1: Function4),
Gpio5: (gpio5, 5, gpio5, IO, 0, Bank0), (VSPICS0: Function1, HS1_DATA6: Function3, EMAC_RX_CLK: Function5), (HS1_DATA6: Function3),
Gpio6: (gpio6, 6, gpio6, IO, 0, Bank0), (U1CTS: Function4), (SD_CLK: Function0, SPICLK: Function1, HS1_CLK: Function3),
Gpio7: (gpio7, 7, gpio7, IO, 0, Bank0), (SD_DATA0: Function0, SPIQ: Function1, HS1_DATA0: Function3), (SD_DATA0: Function0, SPIQ: Function1, HS1_DATA0: Function3, U2RTS: Function4),
Gpio8: (gpio8, 8, gpio8, IO, 0, Bank0), (SD_DATA1: Function0, SPID: Function1, HS1_DATA1: Function3, U2CTS: Function4), (SD_DATA1: Function0, SPID: Function1, HS1_DATA1: Function3),
Gpio9: (gpio9, 9, gpio9, IO, 0, Bank0), (SD_DATA2: Function0, SPIHD: Function1, HS1_DATA2: Function3, U1RXD: Function4), (SD_DATA2: Function0, SPIHD: Function1, HS1_DATA2: Function3),
Gpio10: (gpio10, 10, gpio10, IO, 0, Bank0), (SD_DATA3: Function0, SPIWP: Function1, HS1_DATA3: Function3), (SD_DATA3: Function0, SPIWP: Function1, HS1_DATA3: Function3, U1TXD: Function4),
Gpio11: (gpio11, 11, gpio11, IO, 0, Bank0), (SPICS0: Function1), (SD_CMD: Function0, SPICS0: Function1, HS1_CMD: Function3, U1RTS: Function4),
Gpio12: (gpio12, 12, gpio12, IO, RTC, Bank0), (MTDI: Function0, HSPIQ: Function1, HS2_DATA2: Function3, SD_DATA2: Function4), (HSPIQ: Function1, HS2_DATA2: Function3, SD_DATA2: Function4, EMAC_TXD3: Function5),
Gpio13: (gpio13, 13, gpio13, IO, RTC, Bank0), (MTCK: Function0, HSPID: Function1, HS2_DATA3: Function3, SD_DATA3: Function4), (HSPID: Function1, HS2_DATA3: Function3, SD_DATA3: Function4, EMAC_RX_ER: Function5),
Gpio14: (gpio14, 14, gpio14, IO, RTC, Bank0), (MTMS: Function0, HSPICLK: Function1), (HSPICLK: Function1, HS2_CLK: Function3, SD_CLK: Function4, EMAC_TXD2: Function5),
Gpio15: (gpio15, 15, gpio15, IO, RTC, Bank0), (HSPICS0: Function1, EMAC_RXD3: Function5), (MTDO: Function0, HSPICS0: Function1, HS2_CMD: Function3, SD_CMD: Function4),
Gpio16: (gpio16, 16, gpio16, IO, 0, Bank0), (HS1_DATA4: Function3, U2RXD: Function4), (HS1_DATA4: Function3, EMAC_CLK_OUT: Function5),
Gpio17: (gpio17, 17, gpio17, IO, 0, Bank0), (HS1_DATA5: Function3), (HS1_DATA5: Function3, U2TXD: Function4, EMAC_CLK_180: Function5),
Gpio18: (gpio18, 18, gpio18, IO, 0, Bank0), (VSPICLK: Function1, HS1_DATA7: Function3), (VSPICLK: Function1, HS1_DATA7: Function3),
Gpio19: (gpio19, 19, gpio19, IO, 0, Bank0), (VSPIQ: Function1, U0CTS: Function3), (VSPIQ: Function1, EMAC_TXD0: Function5),
Gpio20: (gpio20, 20, gpio20, IO, 0, Bank0),
Gpio21: (gpio21, 21, gpio21, IO, 0, Bank0), (VSPIHD: Function1), (VSPIHD: Function1, EMAC_TX_EN: Function5),
Gpio22: (gpio22, 22, gpio22, IO, 0, Bank0), (VSPIWP: Function1), (VSPIWP: Function1, U0RTS: Function3, EMAC_TXD1: Function5),
Gpio23: (gpio23, 23, gpio23, IO, 0, Bank0), (VSPID: Function1), (VSPID: Function1, HS1_STROBE: Function3),
Gpio24: (gpio24, 24, gpio24, IO, 0, Bank0),
Gpio25: (gpio25, 25, gpio25, IO, 0, Bank0), (EMAC_RXD0: Function5), (),
Gpio26: (gpio26, 26, gpio26, IO, 0, Bank0), (EMAC_RXD1: Function5), (),
Gpio27: (gpio27, 27, gpio27, IO, 0, Bank0), (EMAC_RX_DV: Function5), (),
Gpio32: (gpio32, 32, gpio32, IO, 0, Bank1),
Gpio33: (gpio33, 33, gpio33, IO, 0, Bank1),
Gpio34: (gpio34, 34, gpio34, Input, 0, Bank1),
Gpio35: (gpio35, 35, gpio35, Input, 0, Bank1),
Gpio36: (gpio36, 36, gpio36, Input, 0, Bank1),
Gpio37: (gpio37, 37, gpio37, Input, 0, Bank1),
Gpio38: (gpio38, 38, gpio38, Input, 0, Bank1),
Gpio39: (gpio39, 39, gpio39, Input, 0, Bank1),
}

View File

@ -1,7 +1,9 @@
#![no_std]
pub use embedded_hal as ehal;
pub use esp_hal_common::{pac, prelude, Serial, Timer};
pub use esp_hal_common::{gpio as hal_gpio, pac, prelude, Serial, Timer};
pub mod gpio;
#[no_mangle]
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}

View File

@ -25,3 +25,6 @@ panic-halt = "0.2"
[features]
default = ["rt"]
rt = ["riscv-rt"]
[package.metadata.espflash]
format = "direct-boot"

View File

@ -14,6 +14,11 @@ fn main() {
.write_all(include_bytes!("esp32c3-link.x"))
.unwrap();
File::create(out.join("riscv-link.x"))
.unwrap()
.write_all(include_bytes!("riscv-link.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// Only re-run the build script when memory.x is changed,

View File

@ -1,2 +1,14 @@
INCLUDE memory.x
INCLUDE link.x
SECTIONS
{
.header : AT(0)
{
LONG(0xaedb041d)
LONG(0xaedb041d)
} > IROM
}
_stext = ORIGIN(IROM) + 8;
INCLUDE riscv-link.x

View File

@ -1,15 +1,39 @@
MEMORY
{
/*
https://github.com/espressif/esptool/blob/master/esptool.py#L1919
MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"],
[0x3C000000, 0x3C800000, "DROM"],
[0x3FC80000, 0x3FCE0000, "DRAM"],
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
[0x3FF00000, 0x3FF20000, "DROM_MASK"],
[0x40000000, 0x40060000, "IROM_MASK"],
[0x42000000, 0x42800000, "IROM"],
[0x4037C000, 0x403E0000, "IRAM"],
[0x50000000, 0x50002000, "RTC_IRAM"],
[0x50000000, 0x50002000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"]]
*/
/* 400K of on soc RAM, 16K reserved for cache */
ICACHE : ORIGIN = 0x4037C000, LENGTH = 0x4000
IRAM : ORIGIN = 0x4037C000 + 0x4000, LENGTH = 400K - 0x4000
/* 384K of on soc ROM */
IROM : ORIGIN = 0x42000020, LENGTH = 0x60000
ICACHE : ORIGIN = 0x4037C000, LENGTH = 0x4000
/* Instruction RAM */
IRAM : ORIGIN = 0x4037C000 + 0x4000, LENGTH = 400K - 0x4000
/* Data RAM */
DRAM : ORIGIN = 0x3FC80000, LENGTH = 0x50000
/* External flash */
/* Instruction ROM */
IROM : ORIGIN = 0x42000000, LENGTH = 0x400000
/* Data ROM */
DROM : ORIGIN = 0x3C000000, LENGTH = 0x400000
}
REGION_ALIAS("REGION_TEXT", IRAM);
REGION_ALIAS("REGION_RODATA", IRAM);
REGION_ALIAS("REGION_DATA", IRAM);
REGION_ALIAS("REGION_BSS", IRAM);
REGION_ALIAS("REGION_HEAP", IRAM);
REGION_ALIAS("REGION_STACK", IRAM);
REGION_ALIAS("REGION_TEXT", IROM);
REGION_ALIAS("REGION_RODATA", DROM);
REGION_ALIAS("REGION_DATA", DRAM);
REGION_ALIAS("REGION_BSS", DRAM);
REGION_ALIAS("REGION_HEAP", DRAM);
REGION_ALIAS("REGION_STACK", DRAM);

View File

@ -1,7 +1,7 @@
#![no_std]
#![no_main]
use esp32c3_hal::{pac, prelude::*, RtcCntl, Timer, IO};
use esp32c3_hal::{gpio::IO, pac, prelude::*, RtcCntl, Timer};
use nb::block;
use panic_halt as _;
use riscv_rt::entry;
@ -13,12 +13,14 @@ fn main() -> ! {
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut timer1 = Timer::new(peripherals.TIMG1);
rtc_cntl.set_super_wdt_enable(false);
rtc_cntl.set_wdt_enable(false);
timer0.disable();
timer1.disable();
let mut led = io.pins.gpio2.into_push_pull_output();
let mut led = io.pins.gpio5.into_push_pull_output();
led.set_high().unwrap();
timer0.start(10_000_000u64);

173
esp32c3-hal/riscv-link.x Normal file
View File

@ -0,0 +1,173 @@
PROVIDE(_stext = ORIGIN(REGION_TEXT));
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
PROVIDE(_max_hart_id = 0);
PROVIDE(_hart_stack_size = 2K);
PROVIDE(_heap_size = 0);
PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);
PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
/* # Pre-initialization function */
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
then the function this points to will be called before the RAM is initialized. */
PROVIDE(__pre_init = default_pre_init);
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
PROVIDE(_setup_interrupts = default_setup_interrupts);
/* # Multi-processing hook function
fn _mp_hook() -> bool;
This function is called from all the harts and must return true only for one hart,
which will perform memory initialization. For other harts it must return false
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
*/
PROVIDE(_mp_hook = default_mp_hook);
SECTIONS
{
.text.dummy (NOLOAD) :
{
/* This section is intended to make _stext address work */
. = ABSOLUTE(_stext);
} > REGION_TEXT
.text _stext :
{
/* Put reset handler first in .text section so it ends up as the entry */
/* point of the program. */
KEEP(*(.init));
KEEP(*(.init.rust));
. = ALIGN(4);
(*(.trap));
(*(.trap.rust));
*(.text .text.*);
_etext = .;
} > REGION_TEXT
_text_size = _etext - _stext + 8;
.rodata ORIGIN(DROM) + _text_size : AT(_text_size)
{
_srodata = .;
*(.srodata .srodata.*);
*(.rodata .rodata.*);
/* 4-byte align the end (VMA) of this section.
This is required by LLD to ensure the LMA of the following .data
section will have the correct alignment. */
. = ALIGN(4);
_erodata = .;
} > REGION_RODATA
_rodata_size = _erodata - _srodata + 8;
.data ORIGIN(DRAM) : AT(_text_size + _rodata_size)
{
_sidata = LOADADDR(.data);
_sdata = .;
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
. = ALIGN(4);
_edata = .;
} > REGION_DATA
.bss (NOLOAD) :
{
_sbss = .;
*(.sbss .sbss.* .bss .bss.*);
. = ALIGN(4);
_ebss = .;
} > REGION_BSS
/* fictitious region that represents the memory available for the heap */
.heap (NOLOAD) :
{
_sheap = .;
. += _heap_size;
. = ALIGN(4);
_eheap = .;
} > REGION_HEAP
/* fictitious region that represents the memory available for the stack */
.stack (NOLOAD) :
{
_estack = .;
. = ABSOLUTE(_stack_start);
_sstack = .;
} > REGION_STACK
/* fake output .got section */
/* Dynamic relocations are unsupported. This section is only used to detect
relocatable code in the input files and raise an error if relocatable code
is found */
.got (INFO) :
{
KEEP(*(.got .got.*));
}
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
}
/* Do not exceed this mark in the error messages above | */
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
ASSERT(_stext % 4 == 0, "
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, "
BUG(riscv-rt): .data is not 4-byte aligned");
ASSERT(_sidata % 4 == 0, "
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
BUG(riscv-rt): .bss is not 4-byte aligned");
ASSERT(_sheap % 4 == 0, "
BUG(riscv-rt): start of .heap is not 4-byte aligned");
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
Consider changing `_max_hart_id` or `_hart_stack_size`.");
ASSERT(SIZEOF(.got) == 0, "
.got section detected in the input files. Dynamic relocations are not
supported. If you are linking to C code compiled using the `gcc` crate
then modify your build script to compile the C code _without_ the
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
details.");
/* Do not exceed this mark in the error messages above | */

165
esp32c3-hal/src/gpio.rs Normal file
View File

@ -0,0 +1,165 @@
use esp_hal_common::gpio::gpio;
use crate::hal_gpio::*;
type OutputSignalType = u8;
const OUTPUT_SIGNAL_MAX: u8 = 128;
const INPUT_SIGNAL_MAX: u8 = 100;
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
pub enum InputSignal {
SPIQ = 0,
SPID = 1,
SPIHD = 2,
SPIWP = 3,
U0RXD = 6,
U0CTS = 7,
U0DSR = 8,
U1RXD = 9,
U1CTS = 10,
U1DSR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SI_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
GPIO_BT_PRIORITY = 18,
GPIO_BT_ACTIVE = 19,
CPU_GPIO_0 = 28,
CPU_GPIO_1 = 29,
CPU_GPIO_2 = 30,
CPU_GPIO_3 = 31,
CPU_GPIO_4 = 32,
CPU_GPIO_5 = 33,
CPU_GPIO_6 = 34,
CPU_GPIO_7 = 35,
EXT_ADC_START = 45,
RMT_SIG_0 = 51,
RMT_SIG_1 = 52,
I2CEXT0_SCL = 53,
I2CEXT0_SDA = 54,
FSPICLK = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
TWAI_RX = 74,
SIG_FUNC_97 = 97,
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
pub enum OutputSignal {
SPIQ = 0,
SPID = 1,
SPIHD = 2,
SPIWP = 3,
SPICLK_MUX = 4,
SPICS0 = 5,
U0TXD = 6,
U0RTS = 7,
U0DTR = 8,
U1TXD = 9,
U1RTS = 10,
U1DTR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SI_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
GPIO_WLAN_PRIO = 18,
GPIO_WLAN_ACTIVE = 19,
CPU_GPIO_0 = 28,
CPU_GPIO_1 = 29,
CPU_GPIO_2 = 30,
CPU_GPIO_3 = 31,
CPU_GPIO_4 = 32,
CPU_GPIO_5 = 33,
CPU_GPIO_6 = 34,
CPU_GPIO_7 = 35,
USB_JTAG_TCK = 36,
USB_JTAG_TMS = 37,
USB_JTAG_TDI = 38,
USB_JTAG_TDO = 39,
LEDC_LS_SIG0 = 45,
LEDC_LS_SIG1 = 46,
LEDC_LS_SIG2 = 47,
LEDC_LS_SIG3 = 48,
LEDC_LS_SIG4 = 49,
LEDC_LS_SIG5 = 50,
RMT_SIG_0 = 51,
RMT_SIG_1 = 52,
I2CEXT0_SCL = 53,
I2CEXT0_SDA = 54,
GPIO_SD0 = 55,
GPIO_SD1 = 56,
GPIO_SD2 = 57,
GPIO_SD3 = 58,
I2SO_SD1 = 59,
FSPICLK_MUX = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
FSPICS1 = 69,
FSPICS3 = 70,
FSPICS2 = 71,
FSPICS4 = 72,
FSPICS5 = 73,
TWAI_TX = 74,
TWAI_BUS_OFF_ON = 75,
TWAI_CLKOUT = 76,
ANT_SEL0 = 89,
ANT_SEL1 = 90,
ANT_SEL2 = 91,
ANT_SEL3 = 92,
ANT_SEL4 = 93,
ANT_SEL5 = 94,
ANT_SEL6 = 95,
ANT_SEL7 = 96,
SIG_FUNC_97 = 97,
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
CLK_OUT1 = 123,
CLK_OUT2 = 124,
CLK_OUT3 = 125,
SPICS1 = 126,
USB_JTAG_TRST = 127,
GPIO = 128,
}
gpio! {
Function1,
SingleCore,
Gpio0: (gpio0, 0, gpio[0], IO, RTC, Bank0),
Gpio1: (gpio1, 1, gpio[1], IO, RTC, Bank0),
Gpio2: (gpio2, 2, gpio[2], IO, RTC, Bank0), (FSPIQ: Function2), (FSPIQ: Function2),
Gpio3: (gpio3, 3, gpio[3], IO, RTC, Bank0),
Gpio4: (gpio4, 4, gpio[4], IO, RTC, Bank0), (FSPIHD: Function2), (USB_JTAG_TMS: Function0, FSPIHD: Function2),
Gpio5: (gpio5, 5, gpio[5], IO, RTC, Bank0), (FSPIWP: Function2), (USB_JTAG_TDI: Function0, FSPIWP: Function2),
Gpio6: (gpio6, 6, gpio[6], IO, 0, Bank0), (FSPICLK: Function2), (USB_JTAG_TCK: Function0, FSPICLK_MUX: Function2),
Gpio7: (gpio7, 7, gpio[7], IO, 0, Bank0), (FSPID: Function2), (USB_JTAG_TDO: Function0, FSPID: Function2),
Gpio8: (gpio8, 8, gpio[8], IO, 0, Bank0),
Gpio9: (gpio9, 9, gpio[9], IO, 0, Bank0),
Gpio10: (gpio10, 10, gpio[10], IO, 0, Bank0), (FSPICS0: Function2), (FSPICS0: Function2),
Gpio11: (gpio11, 11, gpio[11], IO, 0, Bank0),
Gpio12: (gpio12, 12, gpio[12], IO, 0, Bank0), (SPIHD: Function0), (SPIHD: Function0),
Gpio13: (gpio13, 13, gpio[13], IO, 0, Bank0), (SPIWP: Function0), (SPIWP: Function0),
Gpio14: (gpio14, 14, gpio[14], IO, 0, Bank0), (), (SPICS0: Function0),
Gpio15: (gpio15, 15, gpio[15], IO, 0, Bank0), (), (SPICLK_MUX: Function0),
Gpio16: (gpio16, 16, gpio[16], IO, 0, Bank0), (SPID: Function0), (SPID: Function0),
Gpio17: (gpio17, 17, gpio[17], IO, 0, Bank0), (SPIQ: Function0), (SPIQ: Function0),
Gpio18: (gpio18, 18, gpio[18], IO, 0, Bank0),
Gpio19: (gpio19, 19, gpio[19], IO, 0, Bank0),
Gpio20: (gpio20, 20, gpio[20], IO, 0, Bank0), (U0RXD: Function0), (),
Gpio21: (gpio21, 21, gpio[21], IO, 0, Bank0), (), (U0TXD: Function0),
}

View File

@ -1,698 +0,0 @@
use core::{convert::Infallible, marker::PhantomData};
use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin as _};
use crate::pac::{GPIO, IO_MUX};
mod mux;
pub use mux::*;
pub use crate::prelude::*;
#[allow(dead_code)]
pub struct IO {
io_mux: IO_MUX,
pub pins: Pins,
}
impl IO {
pub fn new(gpio: GPIO, io_mux: IO_MUX) -> Self {
let pins = gpio.split();
let io = IO { io_mux, pins };
io
}
}
pub trait GpioExt {
type Parts;
fn split(self) -> Self::Parts;
}
pub trait Pin {
fn sleep_mode(&mut self, on: bool) -> &mut Self;
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self;
fn listen(&mut self, event: Event) {
self.listen_with_options(event, true, false, false)
}
fn listen_with_options(
&mut self,
event: Event,
int_enable: bool,
nmi_enable: bool,
wake_up_from_light_sleep: bool,
);
fn unlisten(&mut self);
fn clear_interrupt(&mut self);
fn is_interrupt_set(&mut self) -> bool;
fn is_non_maskable_interrupt_set(&mut self) -> bool;
fn enable_hold(&mut self, on: bool);
}
pub trait InputPin: Pin {
fn set_to_input(&mut self) -> &mut Self;
fn enable_input(&mut self, on: bool) -> &mut Self;
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn is_input_high(&mut self) -> bool;
fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self {
self.connect_input_to_peripheral_with_options(signal, false, false)
}
fn connect_input_to_peripheral_with_options(
&mut self,
signal: InputSignal,
invert: bool,
force_via_gpio_mux: bool,
) -> &mut Self;
}
pub trait OutputPin: Pin {
fn set_to_open_drain_output(&mut self) -> &mut Self;
fn set_to_push_pull_output(&mut self) -> &mut Self;
fn enable_output(&mut self, on: bool) -> &mut Self;
fn set_output_high(&mut self, on: bool) -> &mut Self;
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self;
fn enable_open_drain(&mut self, on: bool) -> &mut Self;
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self;
fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self {
self.connect_peripheral_to_output_with_options(signal, false, false, false, false)
}
fn connect_peripheral_to_output_with_options(
&mut self,
signal: OutputSignal,
invert: bool,
invert_enable: bool,
enable_from_gpio: bool,
force_via_gpio_mux: bool,
) -> &mut Self;
fn internal_pull_up(&mut self, on: bool) -> &mut Self;
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
}
pub trait RTCPin {}
pub trait AnalogPin {}
#[derive(Copy, Clone)]
pub enum Event {
RisingEdge = 1,
FallingEdge = 2,
AnyEdge = 3,
LowLevel = 4,
HighLevel = 5,
}
pub struct Unknown {}
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
pub struct RTCInput<MODE> {
_mode: PhantomData<MODE>,
}
pub struct Floating;
pub struct PullDown;
pub struct PullUp;
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
pub struct RTCOutput<MODE> {
_mode: PhantomData<MODE>,
}
pub struct OpenDrain;
pub struct PushPull;
pub struct Analog;
pub struct Alternate<MODE> {
_mode: PhantomData<MODE>,
}
pub struct AF0;
pub struct AF1;
pub struct AF2;
pub enum DriveStrength {
I5mA = 0,
I10mA = 1,
I20mA = 2,
I40mA = 3,
}
#[derive(PartialEq)]
pub enum AlternateFunction {
Function0 = 0,
Function1 = 1,
Function2 = 2,
}
pub fn connect_low_to_peripheral(signal: InputSignal) {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sig_in_sel()
.set_bit()
.func_in_inv_sel()
.bit(false)
.func_in_sel()
.bits(0x1f)
});
}
pub fn connect_high_to_peripheral(signal: InputSignal) {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sig_in_sel()
.set_bit()
.func_in_inv_sel()
.bit(false)
.func_in_sel()
.bits(0x1e)
});
}
macro_rules! impl_output {
(
$pxi:ident:
(
$pin_num:expr, $bit:expr, $out_en_set:ident, $out_en_clear:ident,
$out_set:ident, $out_clear:ident, $out_reg:ident
)
$( ,( $( $af_signal:ident: $af:ident ),* ))?
) => {
impl<MODE> embedded_hal::digital::v2::OutputPin for $pxi<Output<MODE>> {
type Error = Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
Ok(())
}
}
impl<MODE> embedded_hal::digital::v2::StatefulOutputPin for $pxi<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
unsafe { Ok((*GPIO::ptr()).$out_reg.read().bits() & (1 << $bit) != 0) }
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(!self.is_set_high()?)
}
}
impl<MODE> embedded_hal::digital::v2::ToggleableOutputPin for $pxi<Output<MODE>> {
type Error = Infallible;
fn toggle(&mut self) -> Result<(), Self::Error> {
if self.is_set_high()? {
Ok(self.set_low()?)
} else {
Ok(self.set_high()?)
}
}
}
impl<MODE> $pxi<MODE> {
pub fn into_pull_up_input(self) -> $pxi<Input<PullUp>> {
self.init_input(false, false);
$pxi { _mode: PhantomData }
}
pub fn into_pull_down_input(self) -> $pxi<Input<PullDown>> {
self.init_input(true, false);
$pxi { _mode: PhantomData }
}
fn init_output(&self, alternate: AlternateFunction, open_drain: bool) {
let gpio = unsafe { &*GPIO::ptr() };
let iomux = unsafe { &*IO_MUX::ptr() };
gpio.$out_en_set.write(|w| unsafe { w.bits(1 << $bit) });
gpio.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(open_drain));
gpio.func_out_sel_cfg[$pin_num]
.modify(|_, w| unsafe { w.func_out_sel().bits(OutputSignal::GPIO as u8) });
iomux.gpio[$pin_num].modify(|_, w| unsafe {
w.mcu_sel()
.bits(alternate as u8)
.fun_ie()
.clear_bit()
.fun_wpd()
.clear_bit()
.fun_wpu()
.clear_bit()
.fun_drv()
.bits(DriveStrength::I20mA as u8)
.slp_sel()
.clear_bit()
});
}
pub fn into_push_pull_output(self) -> $pxi<Output<PushPull>> {
self.init_output(AlternateFunction::Function1, false);
$pxi { _mode: PhantomData }
}
pub fn into_open_drain_output(self) -> $pxi<Output<OpenDrain>> {
self.init_output(AlternateFunction::Function1, true);
$pxi { _mode: PhantomData }
}
pub fn into_alternate_1(self) -> $pxi<Alternate<AF1>> {
self.init_output(AlternateFunction::Function1, false);
$pxi { _mode: PhantomData }
}
pub fn into_alternate_2(self) -> $pxi<Alternate<AF2>> {
self.init_output(AlternateFunction::Function2, false);
$pxi { _mode: PhantomData }
}
}
impl<MODE> OutputPin for $pxi<MODE> {
fn set_to_open_drain_output(&mut self) -> &mut Self {
self.init_output(AlternateFunction::Function1, true);
self
}
fn set_to_push_pull_output(&mut self) -> &mut Self {
self.init_output(AlternateFunction::Function1, false);
self
}
fn enable_output(&mut self, on: bool) -> &mut Self {
if on {
unsafe { &*GPIO::ptr() }
.$out_en_set
.write(|w| unsafe { w.bits(1 << $bit) });
} else {
unsafe { &*GPIO::ptr() }
.$out_en_clear
.write(|w| unsafe { w.bits(1 << $bit) });
}
self
}
fn set_output_high(&mut self, high: bool) -> &mut Self {
if high {
unsafe { (*GPIO::ptr()).$out_set.write(|w| w.bits(1 << $bit)) };
} else {
unsafe { (*GPIO::ptr()).$out_clear.write(|w| w.bits(1 << $bit)) };
}
self
}
fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) });
self
}
fn enable_open_drain(&mut self, on: bool) -> &mut Self {
unsafe { &*GPIO::ptr() }.pin[$pin_num].modify(|_, w| w.pin_pad_driver().bit(on));
self
}
fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.mcu_wpu().bit(on));
self
}
fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.mcu_wpd().bit(on));
self
}
fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.mcu_oe().bit(on));
self
}
fn connect_peripheral_to_output_with_options(
&mut self,
signal: OutputSignal,
invert: bool,
invert_enable: bool,
enable_from_gpio: bool,
force_via_gpio_mux: bool,
) -> &mut Self {
let af = if force_via_gpio_mux {
AlternateFunction::Function1
} else {
match signal {
$( $(
OutputSignal::$af_signal => AlternateFunction::$af,
)* )?
_ => AlternateFunction::Function1
}
};
if af == AlternateFunction::Function1 && signal as usize > 128 {
panic!("Cannot connect this peripheral to GPIO");
}
self.set_alternate_function(af);
let clipped_signal = if signal as usize <= 128 { signal as u8 } else { 128u8 };
unsafe { &*GPIO::ptr() }.func_out_sel_cfg[$pin_num].modify(|_, w| unsafe {
w
.func_out_sel().bits(clipped_signal)
.func_out_inv_sel().bit(invert)
.func_oen_sel().bit(enable_from_gpio)
.func_oen_inv_sel().bit(invert_enable)
});
self
}
fn internal_pull_up(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }.gpio[$pin_num].modify(|_, w| w.fun_wpu().bit(on));
self
}
fn internal_pull_down(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }.gpio[$pin_num].modify(|_, w| w.fun_wpd().bit(on));
self
}
}
};
}
macro_rules! impl_input {
($pxi:ident:
($pin_num:expr, $bit:expr, $out_en_clear:ident, $reg:ident, $reader:ident,
$status_w1tc:ident, $pcpu_int:ident, $pcpu_nmi:ident
) $( ,( $( $af_signal:ident : $af:ident ),* ))?
) => {
impl<MODE> embedded_hal::digital::v2::InputPin for $pxi<Input<MODE>> {
type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(unsafe { &*GPIO::ptr() }.$reg.read().$reader().bits() & (1 << $bit) != 0)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(!self.is_high()?)
}
}
impl<MODE> $pxi<MODE> {
fn init_input(&self, pull_down: bool, pull_up: bool) {
let gpio = unsafe { &*GPIO::ptr() };
let iomux = unsafe { &*IO_MUX::ptr() };
gpio.$out_en_clear
.write(|w| unsafe { w.bits(1 << $bit) });
gpio.func_out_sel_cfg[$pin_num]
.modify(|_, w| unsafe { w.func_out_sel().bits(OutputSignal::GPIO as u8) });
iomux.gpio[$pin_num].modify(|_, w| unsafe {
w.mcu_sel()
.bits(2)
.fun_ie()
.set_bit()
.fun_wpd()
.bit(pull_down)
.fun_wpu()
.bit(pull_up)
.slp_sel()
.clear_bit()
});
}
pub fn into_floating_input(self) -> $pxi<Input<Floating>> {
self.init_input(false, false);
$pxi { _mode: PhantomData }
}
}
impl<MODE> InputPin for $pxi<MODE> {
fn set_to_input(&mut self) -> &mut Self {
self.init_input(false, false);
self
}
fn enable_input(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.fun_ie().bit(on));
self
}
fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.mcu_ie().bit(on));
self
}
fn is_input_high(&mut self) -> bool {
unsafe { &*GPIO::ptr() }.$reg.read().$reader().bits() & (1 << $bit) != 0
}
fn connect_input_to_peripheral_with_options(
&mut self,
signal: InputSignal,
invert: bool,
force_via_gpio_mux: bool,
) -> &mut Self {
let af = if force_via_gpio_mux
{
AlternateFunction::Function1
}
else {
match signal {
$( $(
InputSignal::$af_signal => AlternateFunction::$af,
)* )?
_ => AlternateFunction::Function1
}
};
if af == AlternateFunction::Function1 && signal as usize >= 128 {
panic!("Cannot connect GPIO to this peripheral");
}
self.set_alternate_function(af);
if (signal as usize) < 128 {
unsafe { &*GPIO::ptr() }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sig_in_sel()
.set_bit()
.func_in_inv_sel()
.bit(invert)
.func_in_sel()
.bits($pin_num)
});
}
self
}
}
impl<MODE> Pin for $pxi<MODE> {
fn sleep_mode(&mut self, on: bool) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| w.slp_sel().bit(on));
self
}
fn set_alternate_function(&mut self, alternate: AlternateFunction) -> &mut Self {
unsafe { &*IO_MUX::ptr() }
.gpio[$pin_num]
.modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8) });
self
}
fn listen_with_options(&mut self, event: Event,
int_enable: bool, nmi_enable: bool,
wake_up_from_light_sleep: bool
) {
if wake_up_from_light_sleep {
match event {
Event::AnyEdge | Event::RisingEdge | Event::FallingEdge => {
panic!("Edge triggering is not supported for wake-up from light sleep");
},
_ => {}
}
}
unsafe {
(&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
w
.pin_int_ena().bits(int_enable as u8 | ((nmi_enable as u8) << 1))
.pin_int_type().bits(event as u8)
.pin_wakeup_enable().bit(wake_up_from_light_sleep)
);
}
}
fn unlisten(&mut self) {
unsafe { (&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
w.pin_int_ena().bits(0).pin_int_type().bits(0).pin_int_ena().bits(0) );
}
}
fn clear_interrupt(&mut self) {
unsafe {&*GPIO::ptr()}.$status_w1tc.write(|w|
unsafe {w.bits(1 << $bit)})
}
fn is_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$pcpu_int.read().bits() & (1 << $bit)) !=0
}
fn is_non_maskable_interrupt_set(&mut self) -> bool {
(unsafe {&*GPIO::ptr()}.$pcpu_nmi.read().bits() & (1 << $bit)) !=0
}
fn enable_hold(&mut self, _on: bool) {
todo!();
}
}
};
}
macro_rules! impl_pin_wrap {
($pxi:ident, $pin_num:expr, IO
$( ,( $( $af_input_signal:ident : $af_input:ident ),* ) )?
) => {
impl_input!($pxi: ($pin_num, $pin_num % 32, enable_w1tc, in_, data_next,
status_w1tc, pcpu_int, pcpu_nmi_int)
$( ,( $( $af_input_signal: $af_input ),* ) )? );
};
}
macro_rules! impl_output_wrap {
($pxi:ident, $pin_num:expr, IO
$( ,( $( $af_output_signal:ident : $af_output:ident ),* ))?
) => {
impl_output!($pxi:
($pin_num, $pin_num % 32, enable_w1ts, enable_w1tc, out_w1ts, out_w1tc, out)
$( ,( $( $af_output_signal: $af_output ),* ) )? );
};
}
macro_rules! gpio {
( $($pxi:ident: ($pname:ident, $pin_num:literal,
$type:ident, $rtc:tt ),
$(
( $( $af_input_signal:ident: $af_input:ident ),* ),
$(
( $( $af_output_signal:ident: $af_output:ident ),* ),
)?
)?
)+ ) => {
impl GpioExt for GPIO {
type Parts = Pins;
fn split(self) -> Self::Parts {
Pins {
$(
$pname: $pxi { _mode: PhantomData },
)+
}
}
}
pub struct Pins {
$(
pub $pname: $pxi<Unknown>,
)+
}
$(
pub struct $pxi<MODE> {
_mode: PhantomData<MODE>,
}
impl_pin_wrap!($pxi, $pin_num, $type
$( ,( $( $af_input_signal: $af_input ),* ) )? );
impl_output_wrap!($pxi, $pin_num, $type
$($( ,( $( $af_output_signal: $af_output ),* ) )? )? );
)+
};
}
gpio! {
Gpio0: (gpio0, 0, IO, RTC),
Gpio1: (gpio1, 1, IO, RTC),
Gpio2: (gpio2, 2, IO, RTC), (FSPIQ: Function2), (FSPIQ: Function2),
Gpio3: (gpio3, 3, IO, RTC),
Gpio4: (gpio4, 4, IO, RTC), (FSPIHD: Function2), (USB_JTAG_TMS: Function0, FSPIHD: Function2),
Gpio5: (gpio5, 5, IO, RTC), (FSPIWP: Function2), (USB_JTAG_TDI: Function0, FSPIWP: Function2),
Gpio6: (gpio6, 6, IO, 0), (FSPICLK: Function2), (USB_JTAG_TCK: Function0, FSPICLK_MUX: Function2),
Gpio7: (gpio7, 7, IO, 0), (FSPID: Function2), (USB_JTAG_TDO: Function0, FSPID: Function2),
Gpio8: (gpio8, 8, IO, 0),
Gpio9: (gpio9, 9, IO, 0),
Gpio10: (gpio10, 10, IO, 0), (FSPICS0: Function2), (FSPICS0: Function2),
Gpio11: (gpio11, 11, IO, 0),
Gpio12: (gpio12, 12, IO, 0), (SPIHD: Function0), (SPIHD: Function0),
Gpio13: (gpio13, 13, IO, 0), (SPIWP: Function0), (SPIWP: Function0),
Gpio14: (gpio14, 14, IO, 0), (), (SPICS0: Function0),
Gpio15: (gpio15, 15, IO, 0), (), (SPICLK_MUX: Function0),
Gpio16: (gpio16, 16, IO, 0), (SPID: Function0), (SPID: Function0),
Gpio17: (gpio17, 17, IO, 0), (SPIQ: Function0), (SPIQ: Function0),
Gpio18: (gpio18, 18, IO, 0),
Gpio19: (gpio19, 19, IO, 0),
Gpio20: (gpio20, 20, IO, 0), (U0RXD: Function0), (),
Gpio21: (gpio21, 21, IO, 0), (), (U0TXD: Function0),
}

View File

@ -1,130 +0,0 @@
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
pub enum InputSignal {
SPIQ = 0,
SPID = 1,
SPIHD = 2,
SPIWP = 3,
U0RXD = 6,
U0CTS = 7,
U0DSR = 8,
U1RXD = 9,
U1CTS = 10,
U1DSR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SI_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
GPIO_BT_PRIORITY = 18,
GPIO_BT_ACTIVE = 19,
CPU_GPIO_0 = 28,
CPU_GPIO_1 = 29,
CPU_GPIO_2 = 30,
CPU_GPIO_3 = 31,
CPU_GPIO_4 = 32,
CPU_GPIO_5 = 33,
CPU_GPIO_6 = 34,
CPU_GPIO_7 = 35,
EXT_ADC_START = 45,
RMT_SIG_0 = 51,
RMT_SIG_1 = 52,
I2CEXT0_SCL = 53,
I2CEXT0_SDA = 54,
FSPICLK = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
TWAI_RX = 74,
SIG_FUNC_97 = 97,
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)]
pub enum OutputSignal {
SPIQ = 0,
SPID = 1,
SPIHD = 2,
SPIWP = 3,
SPICLK_MUX = 4,
SPICS0 = 5,
U0TXD = 6,
U0RTS = 7,
U0DTR = 8,
U1TXD = 9,
U1RTS = 10,
U1DTR = 11,
I2S_MCLK = 12,
I2SO_BCK = 13,
I2SO_WS = 14,
I2SI_SD = 15,
I2SI_BCK = 16,
I2SI_WS = 17,
GPIO_WLAN_PRIO = 18,
GPIO_WLAN_ACTIVE = 19,
CPU_GPIO_0 = 28,
CPU_GPIO_1 = 29,
CPU_GPIO_2 = 30,
CPU_GPIO_3 = 31,
CPU_GPIO_4 = 32,
CPU_GPIO_5 = 33,
CPU_GPIO_6 = 34,
CPU_GPIO_7 = 35,
USB_JTAG_TCK = 36,
USB_JTAG_TMS = 37,
USB_JTAG_TDI = 38,
USB_JTAG_TDO = 39,
LEDC_LS_SIG0 = 45,
LEDC_LS_SIG1 = 46,
LEDC_LS_SIG2 = 47,
LEDC_LS_SIG3 = 48,
LEDC_LS_SIG4 = 49,
LEDC_LS_SIG5 = 50,
RMT_SIG_0 = 51,
RMT_SIG_1 = 52,
I2CEXT0_SCL = 53,
I2CEXT0_SDA = 54,
GPIO_SD0 = 55,
GPIO_SD1 = 56,
GPIO_SD2 = 57,
GPIO_SD3 = 58,
I2SO_SD1 = 59,
FSPICLK_MUX = 63,
FSPIQ = 64,
FSPID = 65,
FSPIHD = 66,
FSPIWP = 67,
FSPICS0 = 68,
FSPICS1 = 69,
FSPICS3 = 70,
FSPICS2 = 71,
FSPICS4 = 72,
FSPICS5 = 73,
TWAI_TX = 74,
TWAI_BUS_OFF_ON = 75,
TWAI_CLKOUT = 76,
ANT_SEL0 = 89,
ANT_SEL1 = 90,
ANT_SEL2 = 91,
ANT_SEL3 = 92,
ANT_SEL4 = 93,
ANT_SEL5 = 94,
ANT_SEL6 = 95,
ANT_SEL7 = 96,
SIG_FUNC_97 = 97,
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
CLK_OUT1 = 123,
CLK_OUT2 = 124,
CLK_OUT3 = 125,
SPICS1 = 126,
USB_JTAG_TRST = 127,
GPIO = 128,
}

View File

@ -1,10 +1,10 @@
#![no_std]
pub use embedded_hal as ehal;
pub use esp_hal_common::{pac, prelude, Serial, Timer};
pub use esp_hal_common::{gpio as hal_gpio, pac, prelude, Serial, Timer};
pub mod gpio;
pub mod rtc_cntl;
pub use gpio::IO;
pub mod gpio;
pub use rtc_cntl::RtcCntl;

View File

@ -30,9 +30,13 @@ impl RtcCntl {
pub fn set_wdt_enable(&self, enable: bool) {
self.set_wdt_write_protection(false);
self.rtc_cntl
.rtc_wdtconfig0
.write(|w| w.wdt_en().bit(enable));
if !enable {
self.rtc_cntl.rtc_wdtconfig0.write(|w| unsafe { w.bits(0) });
} else {
self.rtc_cntl
.rtc_wdtconfig0
.write(|w| w.wdt_en().bit(enable));
}
self.set_wdt_write_protection(true);
}