Update and improve esp-lp-hal (#1754)
* Fix warning in `esp-hal-procmacros` when building for `esp-lp-hal` * Document cargo features, use `embedded-hal@1.x.x` 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
This commit is contained in:
parent
eb9bfd52b1
commit
2bef914e7c
@ -6,7 +6,7 @@ use quote::quote;
|
|||||||
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
use proc_macro_crate::{crate_name, FoundCrate};
|
use proc_macro_crate::{crate_name, FoundCrate};
|
||||||
use quote::{format_ident, quote};
|
use quote::format_ident;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::Error,
|
parse::Error,
|
||||||
parse_macro_input,
|
parse_macro_input,
|
||||||
|
|||||||
@ -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)
|
- Added basic `LP-I2C` driver for C6 (#1185)
|
||||||
- Add remaining GPIO pins for ESP32-S2/S3 (#1695)
|
- Add remaining GPIO pins for ESP32-S2/S3 (#1695)
|
||||||
- Add `wake_hp_core` for ESP32-C6 (#1723)
|
- Add `wake_hp_core` for ESP32-C6 (#1723)
|
||||||
|
- Implement `embedded-hal@1.x.x` traits by default instead of `embedded-hal@0.2.x` (#1754)
|
||||||
|
- Implement `embedded-hal-nb` and `embedded-io` traits for UART driver (#1754)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Renamed to `esp-ulp-riscv-hal` (#916)
|
- Renamed to `esp-ulp-riscv-hal` (#916)
|
||||||
- Remove 2nd level generics from GPIO pin (#1526)
|
- Remove 2nd level generics from GPIO pin (#1526)
|
||||||
|
- GPIO Input/Output types have been converted to unit structs (#1754)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,10 @@ description = "HAL for low-power RISC-V coprocessors found in ESP32 devices"
|
|||||||
repository = "https://github.com/esp-rs/esp-hal"
|
repository = "https://github.com/esp-rs/esp-hal"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
bench = false
|
||||||
|
test = false
|
||||||
|
|
||||||
keywords = [
|
keywords = [
|
||||||
"embedded",
|
"embedded",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
@ -21,16 +25,19 @@ categories = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", optional = true, features = ["unproven"] }
|
document-features = "0.2.8"
|
||||||
embedded-hal-1 = { version = "1.0.0", package = "embedded-hal", optional = true }
|
embedded-hal = { version = "1.0.0", optional = true }
|
||||||
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
|
embedded-hal-02 = { version = "0.2.7", optional = true, features = ["unproven"], package = "embedded-hal" }
|
||||||
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
|
embedded-hal-nb = { version = "1.0.0", optional = true }
|
||||||
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5429637f079337eb77bad44fb80bded58478619", features = ["critical-section"], optional = true }
|
embedded-io = { version = "0.6.1", optional = true }
|
||||||
nb = { version = "1.1.0", optional = true }
|
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
|
||||||
paste = { version = "1.0.14", optional = true }
|
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
|
||||||
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
|
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "9c76169", features = ["critical-section"], optional = true }
|
||||||
riscv = { version = "0.11.0", features = ["critical-section-single-hart"] }
|
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]
|
[dev-dependencies]
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
@ -39,31 +46,42 @@ panic-halt = "0.2.0"
|
|||||||
esp-build = { version = "0.1.0", path = "../esp-build" }
|
esp-build = { version = "0.1.0", path = "../esp-build" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["embedded-hal-02"]
|
default = ["embedded-hal"]
|
||||||
|
|
||||||
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"]
|
|
||||||
|
|
||||||
|
## Enable debug features in the HAL (used for development).
|
||||||
debug = [
|
debug = [
|
||||||
"esp32c6-lp?/impl-register-debug",
|
"esp32c6-lp?/impl-register-debug",
|
||||||
"esp32s2-ulp?/impl-register-debug",
|
"esp32s2-ulp?/impl-register-debug",
|
||||||
"esp32s3-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]]
|
[[example]]
|
||||||
name = "blinky"
|
name = "blinky"
|
||||||
required-features = ["embedded-hal-02"]
|
required-features = ["embedded-hal-02"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "uart"
|
name = "i2c"
|
||||||
required-features = ["embedded-hal-02", "esp32c6"]
|
required-features = ["embedded-hal-02", "esp32c6"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "i2c"
|
name = "uart"
|
||||||
required-features = ["embedded-hal-02", "esp32c6"]
|
required-features = ["embedded-hal-02", "esp32c6"]
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
//!
|
//!
|
||||||
//! Make sure the LP RAM is cleared before loading the code.
|
//! Make sure the LP RAM is cleared before loading the code.
|
||||||
|
|
||||||
|
//% FEATURES: embedded-hal-02
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
//! - SCL => GPIO7
|
//! - SCL => GPIO7
|
||||||
|
|
||||||
//% CHIPS: esp32c6
|
//% CHIPS: esp32c6
|
||||||
|
//% FEATURES: embedded-hal-02
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
//! logs from LP_UART. Make sure the LP RAM is cleared before loading the code.
|
//! logs from LP_UART. Make sure the LP RAM is cleared before loading the code.
|
||||||
|
|
||||||
//% CHIPS: esp32c6
|
//% CHIPS: esp32c6
|
||||||
|
//% FEATURES: embedded-hal-02
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|||||||
@ -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;
|
pub struct Delay;
|
||||||
|
|
||||||
impl Delay {
|
impl Delay {
|
||||||
/// Delay for at least the number of specific microseconds.
|
/// 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 NANOS_PER_MICRO: u32 = 1_000;
|
||||||
const MAX_MICROS: u32 = u32::MAX / NANOS_PER_MICRO;
|
const MAX_MICROS: u32 = u32::MAX / NANOS_PER_MICRO;
|
||||||
|
|
||||||
@ -19,7 +31,7 @@ impl Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Delay for at least the number of specific nanoseconds.
|
/// 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 ticks_seconds = unsafe { crate::CPU_CLOCK };
|
||||||
let clock = (ns as u64 * (ticks_seconds as u64)) / 1_000_000_000u64;
|
let clock = (ns as u64 * (ticks_seconds as u64)) / 1_000_000_000u64;
|
||||||
let t0 = cycles();
|
let t0 = cycles();
|
||||||
@ -72,8 +84,9 @@ impl embedded_hal_02::blocking::delay::DelayMs<u32> for Delay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl embedded_hal_1::delay::DelayNs for Delay {
|
impl embedded_hal::delay::DelayNs for Delay {
|
||||||
|
#[inline(always)]
|
||||||
fn delay_ns(&mut self, ns: u32) {
|
fn delay_ns(&mut self, ns: u32) {
|
||||||
self.delay_nanos(ns);
|
self.delay_nanos(ns);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
//! 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(feature = "esp32c6")]
|
cfg_if::cfg_if! {
|
||||||
type LpIo = crate::pac::LP_IO;
|
if #[cfg(feature = "esp32c6")] {
|
||||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
type LpIo = crate::pac::LP_IO;
|
||||||
type LpIo = crate::pac::RTC_IO;
|
const MAX_GPIO_PIN: u8 = 7;
|
||||||
|
} else {
|
||||||
|
type LpIo = crate::pac::RTC_IO;
|
||||||
|
const MAX_GPIO_PIN: u8 = 21;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "esp32c6")]
|
/// GPIO input driver
|
||||||
const MAX_GPIO_PIN: u8 = 7;
|
pub struct Input<const PIN: u8>;
|
||||||
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
|
|
||||||
const MAX_GPIO_PIN: u8 = 21;
|
|
||||||
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct Input<const PIN: u8> {}
|
|
||||||
|
|
||||||
impl<const PIN: u8> Input<PIN> {
|
impl<const PIN: u8> Input<PIN> {
|
||||||
|
/// Read the input state/level of the pin.
|
||||||
pub fn input_state(&self) -> bool {
|
pub fn input_state(&self) -> bool {
|
||||||
unsafe { &*LpIo::PTR }.in_().read().bits() >> PIN & 0x1 != 0
|
unsafe { &*LpIo::PTR }.in_().read().bits() >> PIN & 0x1 != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
/// GPIO output driver
|
||||||
pub struct Output<const PIN: u8> {}
|
pub struct Output<const PIN: u8>;
|
||||||
|
|
||||||
impl<const PIN: u8> Output<PIN> {
|
impl<const PIN: u8> Output<PIN> {
|
||||||
|
/// Read the output state/level of the pin.
|
||||||
pub fn output_state(&self) -> bool {
|
pub fn output_state(&self) -> bool {
|
||||||
unsafe { &*LpIo::PTR }.out().read().bits() >> PIN & 0x1 != 0
|
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) {
|
pub fn set_output(&mut self, on: bool) {
|
||||||
if on {
|
if on {
|
||||||
unsafe { &*LpIo::PTR }
|
unsafe { &*LpIo::PTR }
|
||||||
@ -48,7 +72,7 @@ pub unsafe fn conjure_output<const PIN: u8>() -> Option<Output<PIN>> {
|
|||||||
if PIN > MAX_GPIO_PIN {
|
if PIN > MAX_GPIO_PIN {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Output {})
|
Some(Output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +82,7 @@ pub unsafe fn conjure_input<const PIN: u8>() -> Option<Input<PIN>> {
|
|||||||
if PIN > MAX_GPIO_PIN {
|
if PIN > MAX_GPIO_PIN {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Input {})
|
Some(Input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,18 +128,18 @@ impl<const PIN: u8> embedded_hal_02::digital::v2::StatefulOutputPin for Output<P
|
|||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<const PIN: u8> embedded_hal_02::digital::v2::toggleable::Default for Output<PIN> {}
|
impl<const PIN: u8> embedded_hal_02::digital::v2::toggleable::Default for Output<PIN> {}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl<const PIN: u8> embedded_hal_1::digital::ErrorType for Input<PIN> {
|
impl<const PIN: u8> embedded_hal::digital::ErrorType for Input<PIN> {
|
||||||
type Error = core::convert::Infallible;
|
type Error = core::convert::Infallible;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl<const PIN: u8> embedded_hal_1::digital::ErrorType for Output<PIN> {
|
impl<const PIN: u8> embedded_hal::digital::ErrorType for Output<PIN> {
|
||||||
type Error = core::convert::Infallible;
|
type Error = core::convert::Infallible;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl<const PIN: u8> embedded_hal_1::digital::InputPin for Input<PIN> {
|
impl<const PIN: u8> embedded_hal::digital::InputPin for Input<PIN> {
|
||||||
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
fn is_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
Ok(self.input_state())
|
Ok(self.input_state())
|
||||||
}
|
}
|
||||||
@ -125,8 +149,8 @@ impl<const PIN: u8> embedded_hal_1::digital::InputPin for Input<PIN> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl<const PIN: u8> embedded_hal_1::digital::OutputPin for Output<PIN> {
|
impl<const PIN: u8> embedded_hal::digital::OutputPin for Output<PIN> {
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
self.set_output(false);
|
self.set_output(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -138,8 +162,8 @@ impl<const PIN: u8> embedded_hal_1::digital::OutputPin for Output<PIN> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal-1")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
impl<const PIN: u8> embedded_hal_1::digital::StatefulOutputPin for Output<PIN> {
|
impl<const PIN: u8> embedded_hal::digital::StatefulOutputPin for Output<PIN> {
|
||||||
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
|
||||||
Ok(self.output_state())
|
Ok(self.output_state())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
//! Low-power I2C driver
|
//! # Inter-Integrated Circuit (I2C)
|
||||||
|
|
||||||
use esp32c6_lp::LP_I2C0;
|
#![allow(unused)] // TODO: Remove me when `embedded_hal::i2c::I2c` is implemented
|
||||||
|
|
||||||
|
use crate::pac::{lp_i2c0::COMD, LP_I2C0};
|
||||||
|
|
||||||
const LP_I2C_TRANS_COMPLETE_INT_ST_S: u32 = 7;
|
const LP_I2C_TRANS_COMPLETE_INT_ST_S: u32 = 7;
|
||||||
const LP_I2C_END_DETECT_INT_ST_S: u32 = 3;
|
const LP_I2C_END_DETECT_INT_ST_S: u32 = 3;
|
||||||
@ -20,8 +22,7 @@ pub unsafe fn conjure() -> LpI2c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// I2C-specific transmission errors
|
/// I2C-specific transmission errors
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
ExceedingFifo,
|
ExceedingFifo,
|
||||||
AckCheckFailed,
|
AckCheckFailed,
|
||||||
@ -32,17 +33,19 @@ pub enum Error {
|
|||||||
InvalidResponse,
|
InvalidResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
Write = 0,
|
Write = 0,
|
||||||
Read = 1,
|
Read = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Ack {
|
enum Ack {
|
||||||
Ack,
|
Ack,
|
||||||
Nack,
|
Nack,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
RStart = 6,
|
RStart = 6,
|
||||||
Write = 1,
|
Write = 1,
|
||||||
@ -51,7 +54,7 @@ enum Opcode {
|
|||||||
End = 4,
|
End = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Command {
|
enum Command {
|
||||||
Start,
|
Start,
|
||||||
Stop,
|
Stop,
|
||||||
@ -135,62 +138,11 @@ impl From<Command> for u16 {
|
|||||||
|
|
||||||
impl From<Command> for u32 {
|
impl From<Command> for u32 {
|
||||||
fn from(c: Command) -> u32 {
|
fn from(c: Command) -> u32 {
|
||||||
let opcode = match c {
|
u16::from(c) as u32
|
||||||
Command::Start => Opcode::RStart,
|
|
||||||
Command::Stop => Opcode::Stop,
|
|
||||||
Command::End => Opcode::End,
|
|
||||||
Command::Write { .. } => Opcode::Write,
|
|
||||||
Command::Read { .. } => Opcode::Read,
|
|
||||||
};
|
|
||||||
|
|
||||||
let length = match c {
|
|
||||||
Command::Start | Command::Stop | Command::End => 0,
|
|
||||||
Command::Write { length: l, .. } | Command::Read { length: l, .. } => l,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ack_exp = match c {
|
|
||||||
Command::Start | Command::Stop | Command::End | Command::Read { .. } => Ack::Nack,
|
|
||||||
Command::Write { ack_exp: exp, .. } => exp,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ack_check_en = match c {
|
|
||||||
Command::Start | Command::Stop | Command::End | Command::Read { .. } => false,
|
|
||||||
Command::Write {
|
|
||||||
ack_check_en: en, ..
|
|
||||||
} => en,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ack_value = match c {
|
|
||||||
Command::Start | Command::Stop | Command::End | Command::Write { .. } => Ack::Nack,
|
|
||||||
Command::Read { ack_value: ack, .. } => ack,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cmd: u32 = length.into();
|
|
||||||
|
|
||||||
if ack_check_en {
|
|
||||||
cmd |= 1 << 8;
|
|
||||||
} else {
|
|
||||||
cmd &= !(1 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ack_exp == Ack::Nack {
|
|
||||||
cmd |= 1 << 9;
|
|
||||||
} else {
|
|
||||||
cmd &= !(1 << 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ack_value == Ack::Nack {
|
|
||||||
cmd |= 1 << 10;
|
|
||||||
} else {
|
|
||||||
cmd &= !(1 << 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd |= (opcode as u32) << 11;
|
|
||||||
|
|
||||||
cmd
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum CommandRegister {
|
enum CommandRegister {
|
||||||
COMD0,
|
COMD0,
|
||||||
COMD1,
|
COMD1,
|
||||||
@ -232,8 +184,6 @@ pub struct LpI2c {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LpI2c {
|
impl LpI2c {
|
||||||
/// Send data bytes from the `bytes` array to a target slave with the
|
|
||||||
/// address `addr`
|
|
||||||
fn master_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
|
fn master_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
|
||||||
let mut cmd_iterator = CommandRegister::COMD0;
|
let mut cmd_iterator = CommandRegister::COMD0;
|
||||||
|
|
||||||
@ -423,16 +373,15 @@ impl LpI2c {
|
|||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// it would be possible to combine the write and read
|
// It would be possible to combine the write and read in one transaction, but
|
||||||
// in one transaction but filling the tx fifo with
|
// filling the tx fifo with the current code is somewhat slow even in release
|
||||||
// the current code is somewhat slow even in release mode
|
// mode which can cause issues.
|
||||||
// which can cause issues
|
|
||||||
self.master_write(addr, bytes)?;
|
self.master_write(addr, bytes)?;
|
||||||
self.master_read(addr, buffer)?;
|
self.master_read(addr, buffer)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update I2C configuration
|
|
||||||
fn lp_i2c_update(&self) {
|
fn lp_i2c_update(&self) {
|
||||||
self.i2c.ctr().modify(|_, w| w.conf_upgate().set_bit());
|
self.i2c.ctr().modify(|_, w| w.conf_upgate().set_bit());
|
||||||
}
|
}
|
||||||
@ -507,49 +456,12 @@ impl LpI2c {
|
|||||||
command_register: &mut CommandRegister,
|
command_register: &mut CommandRegister,
|
||||||
command: Command,
|
command: Command,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match *command_register {
|
self.i2c
|
||||||
CommandRegister::COMD0 => {
|
.comd(*command_register as usize)
|
||||||
self.i2c
|
.write(|w| unsafe { w.command().bits(command.into()) });
|
||||||
.comd(0)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD1 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(1)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD2 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(2)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD3 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(3)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD4 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(4)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD5 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(5)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD6 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(6)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
CommandRegister::COMD7 => {
|
|
||||||
self.i2c
|
|
||||||
.comd(7)
|
|
||||||
.write(|w| unsafe { w.command().bits(command.into()) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
command_register.advance();
|
command_register.advance();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,15 @@
|
|||||||
|
//! Bare-metal (`no_std`) HAL for the low power and ultra-low power cores found
|
||||||
|
//! in some Espressif devices. Where applicable, drivers implement the
|
||||||
|
//! [embedded-hal] traits.
|
||||||
|
//!
|
||||||
|
//! ## Choosing a device
|
||||||
|
//!
|
||||||
|
//! Depending on your target device, you need to enable the chip feature
|
||||||
|
//! for that device.
|
||||||
|
//!
|
||||||
|
//! ## Feature Flags
|
||||||
|
#![doc = document_features::document_features!()]
|
||||||
|
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
|
||||||
#![allow(asm_sub_register)]
|
#![allow(asm_sub_register)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
@ -10,15 +22,14 @@ pub mod i2c;
|
|||||||
#[cfg(esp32c6)]
|
#[cfg(esp32c6)]
|
||||||
pub mod uart;
|
pub mod uart;
|
||||||
|
|
||||||
pub mod pac {
|
#[cfg(feature = "esp32c6")]
|
||||||
#[cfg(feature = "esp32c6")]
|
pub use esp32c6_lp as pac;
|
||||||
pub use esp32c6_lp::*;
|
#[cfg(feature = "esp32s2")]
|
||||||
#[cfg(feature = "esp32s2")]
|
pub use esp32s2_ulp as pac;
|
||||||
pub use esp32s2_ulp::*;
|
#[cfg(feature = "esp32s3")]
|
||||||
#[cfg(feature = "esp32s3")]
|
pub use esp32s3_ulp as pac;
|
||||||
pub use esp32s3_ulp::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// The prelude
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use procmacros::entry;
|
pub use procmacros::entry;
|
||||||
}
|
}
|
||||||
@ -35,13 +46,14 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut CPU_CLOCK: u32 = LP_FAST_CLK_HZ;
|
pub(crate) static mut CPU_CLOCK: u32 = LP_FAST_CLK_HZ;
|
||||||
|
|
||||||
/// Wake up the HP core
|
/// Wake up the HP core
|
||||||
#[cfg(feature = "esp32c6")]
|
#[cfg(feature = "esp32c6")]
|
||||||
pub fn wake_hp_core() {
|
pub fn wake_hp_core() {
|
||||||
let pmu = unsafe { esp32c6_lp::PMU::steal() };
|
unsafe { &*esp32c6_lp::PMU::PTR }
|
||||||
pmu.hp_lp_cpu_comm().write(|w| w.lp_trigger_hp().set_bit());
|
.hp_lp_cpu_comm()
|
||||||
|
.write(|w| w.lp_trigger_hp().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "esp32c6")]
|
#[cfg(feature = "esp32c6")]
|
||||||
@ -49,8 +61,8 @@ global_asm!(
|
|||||||
r#"
|
r#"
|
||||||
.section .init.vector, "ax"
|
.section .init.vector, "ax"
|
||||||
/* This is the vector table. It is currently empty, but will be populated
|
/* This is the vector table. It is currently empty, but will be populated
|
||||||
* with exception and interrupt handlers when this is supported
|
* with exception and interrupt handlers when this is supported
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 0x4, 0xff
|
.align 0x4, 0xff
|
||||||
.global _vector_table
|
.global _vector_table
|
||||||
|
|||||||
@ -1,4 +1,38 @@
|
|||||||
//! Low-power UART driver
|
//! # Universal Asynchronous Receiver/Transmitter (UART)
|
||||||
|
//!
|
||||||
|
//! ## Overview
|
||||||
|
//!
|
||||||
|
//! The UART is a hardware peripheral which handles communication using serial
|
||||||
|
//! interfaces. This peripheral provides a cheap and ubiquitous method for full-
|
||||||
|
//! and half-duplex communication between devices.
|
||||||
|
//!
|
||||||
|
//! ## Configuration
|
||||||
|
//!
|
||||||
|
//! The usual setting such as baud rate, data bits, parity, and stop bits can
|
||||||
|
//! easily be configured. See the [config] module documentation for more
|
||||||
|
//! information.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! The UART driver implements a number of third-party traits, with the
|
||||||
|
//! intention of making the HAL inter-compatible with various device drivers
|
||||||
|
//! from the community. This includes the [embedded-hal], [embedded-hal-nb], and
|
||||||
|
//! [embedded-io] traits.
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! fn main(mut uart: LpUart) -> ! {
|
||||||
|
//! loop {
|
||||||
|
//! writeln!(uart, "Hello, world!").ok();
|
||||||
|
//! esp_lp_hal::delay::Delay.delay_ms(1000);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
|
||||||
|
//! [embedded-hal-nb]: https://docs.rs/embedded-hal-nb/latest/embedded_hal_nb/
|
||||||
|
//! [embedded-io]: https://docs.rs/embedded-io/latest/embedded_io/
|
||||||
|
|
||||||
use crate::pac::LP_UART;
|
use crate::pac::LP_UART;
|
||||||
|
|
||||||
@ -11,74 +45,105 @@ pub unsafe fn conjure() -> LpUart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// UART Error
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {}
|
pub enum Error {}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-hal")]
|
||||||
|
impl embedded_hal_nb::serial::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
|
||||||
|
embedded_hal_nb::serial::ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-io")]
|
||||||
|
impl embedded_io::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_io::ErrorKind {
|
||||||
|
embedded_io::ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// UART configuration
|
/// UART configuration
|
||||||
pub mod config {
|
pub mod config {
|
||||||
/// Number of data bits
|
/// Number of data bits
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum DataBits {
|
pub enum DataBits {
|
||||||
|
/// 5 data bits
|
||||||
DataBits5 = 0,
|
DataBits5 = 0,
|
||||||
|
/// 6 data bits
|
||||||
DataBits6 = 1,
|
DataBits6 = 1,
|
||||||
|
/// 7 data bits
|
||||||
DataBits7 = 2,
|
DataBits7 = 2,
|
||||||
|
/// 8 data bits
|
||||||
|
#[default]
|
||||||
DataBits8 = 3,
|
DataBits8 = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parity check
|
/// Parity check
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Parity {
|
pub enum Parity {
|
||||||
|
/// No parity
|
||||||
|
#[default]
|
||||||
ParityNone = 0,
|
ParityNone = 0,
|
||||||
|
/// Even parity
|
||||||
ParityEven = 1,
|
ParityEven = 1,
|
||||||
|
/// Odd parity
|
||||||
ParityOdd = 2,
|
ParityOdd = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of stop bits
|
/// Number of stop bits
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StopBits {
|
pub enum StopBits {
|
||||||
/// 1 stop bit
|
/// 1 stop bit
|
||||||
STOP1 = 1,
|
#[default]
|
||||||
|
Stop1 = 1,
|
||||||
/// 1.5 stop bits
|
/// 1.5 stop bits
|
||||||
STOP1P5 = 2,
|
Stop1p5 = 2,
|
||||||
/// 2 stop bits
|
/// 2 stop bits
|
||||||
STOP2 = 3,
|
Stop2 = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UART configuration
|
/// UART configuration
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub baudrate: u32,
|
baudrate: u32,
|
||||||
pub data_bits: DataBits,
|
data_bits: DataBits,
|
||||||
pub parity: Parity,
|
parity: Parity,
|
||||||
pub stop_bits: StopBits,
|
stop_bits: StopBits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
/// Configure the UART's baud rate
|
||||||
pub fn baudrate(mut self, baudrate: u32) -> Self {
|
pub fn baudrate(mut self, baudrate: u32) -> Self {
|
||||||
self.baudrate = baudrate;
|
self.baudrate = baudrate;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the UART to use no parity
|
||||||
pub fn parity_none(mut self) -> Self {
|
pub fn parity_none(mut self) -> Self {
|
||||||
self.parity = Parity::ParityNone;
|
self.parity = Parity::ParityNone;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the UART to use even parity
|
||||||
pub fn parity_even(mut self) -> Self {
|
pub fn parity_even(mut self) -> Self {
|
||||||
self.parity = Parity::ParityEven;
|
self.parity = Parity::ParityEven;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the UART to use odd parity
|
||||||
pub fn parity_odd(mut self) -> Self {
|
pub fn parity_odd(mut self) -> Self {
|
||||||
self.parity = Parity::ParityOdd;
|
self.parity = Parity::ParityOdd;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the UART's data bits
|
||||||
pub fn data_bits(mut self, data_bits: DataBits) -> Self {
|
pub fn data_bits(mut self, data_bits: DataBits) -> Self {
|
||||||
self.data_bits = data_bits;
|
self.data_bits = data_bits;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the UART's stop bits
|
||||||
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
|
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
|
||||||
self.stop_bits = stop_bits;
|
self.stop_bits = stop_bits;
|
||||||
self
|
self
|
||||||
@ -88,10 +153,10 @@ pub mod config {
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
baudrate: 115200,
|
baudrate: 115_200,
|
||||||
data_bits: DataBits::DataBits8,
|
data_bits: Default::default(),
|
||||||
parity: Parity::ParityNone,
|
parity: Default::default(),
|
||||||
stop_bits: StopBits::STOP1,
|
stop_bits: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,8 +188,13 @@ impl LpUart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> nb::Result<(), Error> {
|
fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
|
||||||
data.iter().try_for_each(|c| self.write_byte(*c))
|
let count = data.len();
|
||||||
|
|
||||||
|
data.iter()
|
||||||
|
.try_for_each(|c| nb::block!(self.write_byte(*c)))?;
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_tx(&mut self) -> nb::Result<(), Error> {
|
fn flush_tx(&mut self) -> nb::Result<(), Error> {
|
||||||
@ -150,7 +220,9 @@ impl LpUart {
|
|||||||
|
|
||||||
impl core::fmt::Write for LpUart {
|
impl core::fmt::Write for LpUart {
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
self.write_bytes(s.as_bytes()).map_err(|_| core::fmt::Error)
|
self.write_bytes(s.as_bytes())
|
||||||
|
.map_err(|_| core::fmt::Error)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,3 +247,78 @@ impl embedded_hal_02::serial::Write<u8> for LpUart {
|
|||||||
self.flush_tx()
|
self.flush_tx()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-hal")]
|
||||||
|
impl embedded_hal_nb::serial::ErrorType for LpUart {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-hal")]
|
||||||
|
impl embedded_hal_nb::serial::Read for LpUart {
|
||||||
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
self.read_byte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-hal")]
|
||||||
|
impl embedded_hal_nb::serial::Write for LpUart {
|
||||||
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
self.write_byte(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
|
self.flush_tx()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-io")]
|
||||||
|
impl embedded_io::ErrorType for LpUart {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-io")]
|
||||||
|
impl embedded_io::Read for LpUart {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.get_rx_fifo_count() == 0 {
|
||||||
|
// Block until we have received at least one byte
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
while self.get_rx_fifo_count() > 0 && count < buf.len() {
|
||||||
|
buf[count] = self.uart.fifo().read().rxfifo_rd_byte().bits();
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-io")]
|
||||||
|
impl embedded_io::ReadReady for LpUart {
|
||||||
|
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.get_rx_fifo_count() > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "embedded-io")]
|
||||||
|
impl embedded_io::Write for LpUart {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
self.write_bytes(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
loop {
|
||||||
|
match self.flush_tx() {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(nb::Error::WouldBlock) => { /* Wait */ }
|
||||||
|
Err(nb::Error::Other(e)) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user