Skip to content

Commit

Permalink
Update and improve esp-lp-hal (#1754)
Browse files Browse the repository at this point in the history
* Fix warning in `esp-hal-procmacros` when building for `esp-lp-hal`

* Document cargo features, use `[email protected]` by default

* Derive more traits on public types, assorted cleanup and improvements

* Implement `embedded-hal-nb` and `embedded-io` traits for UART

* Update `CHANGELOG.md`

* Silence `clippy` for now...

* Module documentation for UART

* Update module documentation format
  • Loading branch information
jessebraham committed Jul 9, 2024
1 parent eb9bfd5 commit 2bef914
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 194 deletions.
2 changes: 1 addition & 1 deletion esp-hal-procmacros/src/lp_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use quote::quote;
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
use proc_macro2::{Ident, Span};
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{format_ident, quote};
use quote::format_ident;
use syn::{
parse::Error,
parse_macro_input,
Expand Down
3 changes: 3 additions & 0 deletions esp-lp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added basic `LP-I2C` driver for C6 (#1185)
- Add remaining GPIO pins for ESP32-S2/S3 (#1695)
- Add `wake_hp_core` for ESP32-C6 (#1723)
- Implement `[email protected]` traits by default instead of `[email protected]` (#1754)
- Implement `embedded-hal-nb` and `embedded-io` traits for UART driver (#1754)

### Changed

- Renamed to `esp-ulp-riscv-hal` (#916)
- Remove 2nd level generics from GPIO pin (#1526)
- GPIO Input/Output types have been converted to unit structs (#1754)

### Fixed

Expand Down
58 changes: 38 additions & 20 deletions esp-lp-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ description = "HAL for low-power RISC-V coprocessors found in ESP32 devices"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"

[lib]
bench = false
test = false

keywords = [
"embedded",
"embedded-hal",
Expand All @@ -21,16 +25,19 @@ categories = [
]

[dependencies]
cfg-if = "1.0.0"
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", optional = true, features = ["unproven"] }
embedded-hal-1 = { version = "1.0.0", package = "embedded-hal", optional = true }
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
nb = { version = "1.1.0", optional = true }
paste = { version = "1.0.14", optional = true }
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
riscv = { version = "0.11.0", features = ["critical-section-single-hart"] }
cfg-if = "1.0.0"
document-features = "0.2.8"
embedded-hal = { version = "1.0.0", optional = true }
embedded-hal-02 = { version = "0.2.7", optional = true, features = ["unproven"], package = "embedded-hal" }
embedded-hal-nb = { version = "1.0.0", optional = true }
embedded-io = { version = "0.6.1", optional = true }
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
nb = { version = "1.1.0", optional = true }
paste = { version = "1.0.15", optional = true }
procmacros = { version = "0.11.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
riscv = { version = "0.11.1", features = ["critical-section-single-hart"] }

[dev-dependencies]
panic-halt = "0.2.0"
Expand All @@ -39,31 +46,42 @@ panic-halt = "0.2.0"
esp-build = { version = "0.1.0", path = "../esp-build" }

[features]
default = ["embedded-hal-02"]

embedded-hal-02 = ["dep:embedded-hal-02"]
embedded-hal = ["dep:embedded-hal-1"]

esp32c6 = ["dep:esp32c6-lp", "procmacros/is-lp-core", "dep:nb", "dep:paste"]
esp32s2 = ["dep:esp32s2-ulp", "procmacros/is-ulp-core"]
esp32s3 = ["dep:esp32s3-ulp", "procmacros/is-ulp-core"]
default = ["embedded-hal"]

## Enable debug features in the HAL (used for development).
debug = [
"esp32c6-lp?/impl-register-debug",
"esp32s2-ulp?/impl-register-debug",
"esp32s3-ulp?/impl-register-debug",
]

# Chip Support Feature Flags
# Target the ESP32-C6.
esp32c6 = ["dep:esp32c6-lp", "procmacros/is-lp-core", "dep:nb", "dep:paste"]
# Target the ESP32-S2.
esp32s2 = ["dep:esp32s2-ulp", "procmacros/is-ulp-core"]
# Target the ESP32-S3.
esp32s3 = ["dep:esp32s3-ulp", "procmacros/is-ulp-core"]

#! ### Trait Implementation Feature Flags
## Implement the traits defined in the `0.2.x` release of `embedded-hal`.
embedded-hal-02 = ["dep:embedded-hal-02"]
## Implement the traits defined in the `1.0.0` releases of `embedded-hal` and
## `embedded-hal-nb` for the relevant peripherals.
embedded-hal = ["dep:embedded-hal", "dep:embedded-hal-nb"]
## Implement the traits defined in `embedded-io` for the relevant peripherals.
embedded-io = ["dep:embedded-io"]

[[example]]
name = "blinky"
required-features = ["embedded-hal-02"]

[[example]]
name = "uart"
name = "i2c"
required-features = ["embedded-hal-02", "esp32c6"]

[[example]]
name = "i2c"
name = "uart"
required-features = ["embedded-hal-02", "esp32c6"]

[lints.rust]
Expand Down
2 changes: 2 additions & 0 deletions esp-lp-hal/examples/blinky.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//!
//! Make sure the LP RAM is cleared before loading the code.

//% FEATURES: embedded-hal-02

#![no_std]
#![no_main]

Expand Down
1 change: 1 addition & 0 deletions esp-lp-hal/examples/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! - SCL => GPIO7

//% CHIPS: esp32c6
//% FEATURES: embedded-hal-02

#![no_std]
#![no_main]
Expand Down
1 change: 1 addition & 0 deletions esp-lp-hal/examples/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//! logs from LP_UART. Make sure the LP RAM is cleared before loading the code.

//% CHIPS: esp32c6
//% FEATURES: embedded-hal-02

#![no_std]
#![no_main]
Expand Down
25 changes: 19 additions & 6 deletions esp-lp-hal/src/delay.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
//! Simple blocking delay functionality.
//! # Delay driver
//!
//! ## Overview
//!
//! The delay driver provides blocking delay functionality. The driver
//! implements the relevant traits from `embedded-hal`.
//!
//! ## Examples
//!
//! ```rust
//! esp_lp_hal::delay::Delay.delay_micros(500);
//! ```

#[derive(Clone, Copy)]
/// Delay driver
#[derive(Debug, Clone, Copy)]
pub struct Delay;

impl Delay {
/// Delay for at least the number of specific microseconds.
pub fn delay_micros(&mut self, mut us: u32) {
pub fn delay_micros(&self, mut us: u32) {
const NANOS_PER_MICRO: u32 = 1_000;
const MAX_MICROS: u32 = u32::MAX / NANOS_PER_MICRO;

Expand All @@ -19,7 +31,7 @@ impl Delay {
}

/// Delay for at least the number of specific nanoseconds.
pub fn delay_nanos(&mut self, ns: u32) {
pub fn delay_nanos(&self, ns: u32) {
let ticks_seconds = unsafe { crate::CPU_CLOCK };
let clock = (ns as u64 * (ticks_seconds as u64)) / 1_000_000_000u64;
let t0 = cycles();
Expand Down Expand Up @@ -72,8 +84,9 @@ impl embedded_hal_02::blocking::delay::DelayMs<u32> for Delay {
}
}

#[cfg(feature = "embedded-hal-1")]
impl embedded_hal_1::delay::DelayNs for Delay {
#[cfg(feature = "embedded-hal")]
impl embedded_hal::delay::DelayNs for Delay {
#[inline(always)]
fn delay_ns(&mut self, ns: u32) {
self.delay_nanos(ns);
}
Expand Down
78 changes: 51 additions & 27 deletions esp-lp-hal/src/gpio.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,58 @@
//! Low-power GPIO driver
//! # General Purpose Input/Output
//!
//! ## Overview
//!
//! It's assumed that GPIOs are already configured correctly by the HP core.
//!
//! This driver supports various operations on GPIO pins, primarily manipulating
//! the pin state (setting high/low, toggling).
//!
//! This module also implements a number of traits from `embedded-hal` to
//! provide a common interface for GPIO pins.
//!
//! ## Examples
//!
//! ```rust
//! fn main(gpio0: Input<0>, gpio1: Output<1>) -> ! {
//! loop {
//! let input_state: bool = gpio0.input_state();
//! gpio.set_output(input_state);
//!
//! esp_lp_hal::delay::Delay.delay_millis(50);
//! }
//! }
//! ```

cfg_if::cfg_if! {
if #[cfg(feature = "esp32c6")] {
type LpIo = crate::pac::LP_IO;
const MAX_GPIO_PIN: u8 = 7;
} else {
type LpIo = crate::pac::RTC_IO;
const MAX_GPIO_PIN: u8 = 21;
}
}

#[cfg(feature = "esp32c6")]
type LpIo = crate::pac::LP_IO;
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
type LpIo = crate::pac::RTC_IO;

#[cfg(feature = "esp32c6")]
const MAX_GPIO_PIN: u8 = 7;
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
const MAX_GPIO_PIN: u8 = 21;

#[non_exhaustive]
pub struct Input<const PIN: u8> {}
/// GPIO input driver
pub struct Input<const PIN: u8>;

impl<const PIN: u8> Input<PIN> {
/// Read the input state/level of the pin.
pub fn input_state(&self) -> bool {
unsafe { &*LpIo::PTR }.in_().read().bits() >> PIN & 0x1 != 0
}
}

#[non_exhaustive]
pub struct Output<const PIN: u8> {}
/// GPIO output driver
pub struct Output<const PIN: u8>;

impl<const PIN: u8> Output<PIN> {
/// Read the output state/level of the pin.
pub fn output_state(&self) -> bool {
unsafe { &*LpIo::PTR }.out().read().bits() >> PIN & 0x1 != 0
}

/// Set the output state/level of the pin.
pub fn set_output(&mut self, on: bool) {
if on {
unsafe { &*LpIo::PTR }
Expand All @@ -48,7 +72,7 @@ pub unsafe fn conjure_output<const PIN: u8>() -> Option<Output<PIN>> {
if PIN > MAX_GPIO_PIN {
None
} else {
Some(Output {})
Some(Output)
}
}

Expand All @@ -58,7 +82,7 @@ pub unsafe fn conjure_input<const PIN: u8>() -> Option<Input<PIN>> {
if PIN > MAX_GPIO_PIN {
None
} else {
Some(Input {})
Some(Input)
}
}

Expand Down Expand Up @@ -104,18 +128,18 @@ impl<const PIN: u8> embedded_hal_02::digital::v2::StatefulOutputPin for Output<P
#[cfg(feature = "embedded-hal-02")]
impl<const PIN: u8> embedded_hal_02::digital::v2::toggleable::Default for Output<PIN> {}

#[cfg(feature = "embedded-hal-1")]
impl<const PIN: u8> embedded_hal_1::digital::ErrorType for Input<PIN> {
#[cfg(feature = "embedded-hal")]
impl<const PIN: u8> embedded_hal::digital::ErrorType for Input<PIN> {
type Error = core::convert::Infallible;
}

#[cfg(feature = "embedded-hal-1")]
impl<const PIN: u8> embedded_hal_1::digital::ErrorType for Output<PIN> {
#[cfg(feature = "embedded-hal")]
impl<const PIN: u8> embedded_hal::digital::ErrorType for Output<PIN> {
type Error = core::convert::Infallible;
}

#[cfg(feature = "embedded-hal-1")]
impl<const PIN: u8> embedded_hal_1::digital::InputPin for Input<PIN> {
#[cfg(feature = "embedded-hal")]
impl<const PIN: u8> embedded_hal::digital::InputPin for Input<PIN> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.input_state())
}
Expand All @@ -125,8 +149,8 @@ impl<const PIN: u8> embedded_hal_1::digital::InputPin for Input<PIN> {
}
}

#[cfg(feature = "embedded-hal-1")]
impl<const PIN: u8> embedded_hal_1::digital::OutputPin for Output<PIN> {
#[cfg(feature = "embedded-hal")]
impl<const PIN: u8> embedded_hal::digital::OutputPin for Output<PIN> {
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_output(false);
Ok(())
Expand All @@ -138,8 +162,8 @@ impl<const PIN: u8> embedded_hal_1::digital::OutputPin for Output<PIN> {
}
}

#[cfg(feature = "embedded-hal-1")]
impl<const PIN: u8> embedded_hal_1::digital::StatefulOutputPin for Output<PIN> {
#[cfg(feature = "embedded-hal")]
impl<const PIN: u8> embedded_hal::digital::StatefulOutputPin for Output<PIN> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.output_state())
}
Expand Down
Loading

0 comments on commit 2bef914

Please sign in to comment.