Merge branch 'main' into add-rng

This commit is contained in:
Dario Nieuwenhuis 2025-05-13 22:33:56 +02:00 committed by GitHub
commit 102258c0b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 2146 additions and 337 deletions

View File

@ -9,5 +9,6 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb
The following peripherals have a HAL implementation at present
* CRC
* GPIO
* RNG

190
embassy-imxrt/src/crc.rs Normal file
View File

@ -0,0 +1,190 @@
//! Cyclic Redundancy Check (CRC)
use core::marker::PhantomData;
use crate::clocks::{enable_and_reset, SysconPeripheral};
pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial;
use crate::{peripherals, Peri, PeripheralType};
/// CRC driver.
pub struct Crc<'d> {
info: Info,
_config: Config,
_lifetime: PhantomData<&'d ()>,
}
/// CRC configuration
pub struct Config {
/// Polynomial to be used
pub polynomial: Polynomial,
/// Reverse bit order of input?
pub reverse_in: bool,
/// 1's complement input?
pub complement_in: bool,
/// Reverse CRC bit order?
pub reverse_out: bool,
/// 1's complement CRC?
pub complement_out: bool,
/// CRC Seed
pub seed: u32,
}
impl Config {
/// Create a new CRC config.
#[must_use]
pub fn new(
polynomial: Polynomial,
reverse_in: bool,
complement_in: bool,
reverse_out: bool,
complement_out: bool,
seed: u32,
) -> Self {
Config {
polynomial,
reverse_in,
complement_in,
reverse_out,
complement_out,
seed,
}
}
}
impl Default for Config {
fn default() -> Self {
Self {
polynomial: Polynomial::CrcCcitt,
reverse_in: false,
complement_in: false,
reverse_out: false,
complement_out: false,
seed: 0xffff,
}
}
}
impl<'d> Crc<'d> {
/// Instantiates new CRC peripheral and initializes to default values.
pub fn new<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self {
// enable CRC clock
enable_and_reset::<T>();
let mut instance = Self {
info: T::info(),
_config: config,
_lifetime: PhantomData,
};
instance.reconfigure();
instance
}
/// Reconfigured the CRC peripheral.
fn reconfigure(&mut self) {
self.info.regs.mode().write(|w| {
w.crc_poly()
.variant(self._config.polynomial)
.bit_rvs_wr()
.variant(self._config.reverse_in)
.cmpl_wr()
.variant(self._config.complement_in)
.bit_rvs_sum()
.variant(self._config.reverse_out)
.cmpl_sum()
.variant(self._config.complement_out)
});
// Init CRC value
self.info
.regs
.seed()
.write(|w| unsafe { w.crc_seed().bits(self._config.seed) });
}
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
pub fn feed_byte(&mut self, byte: u8) -> u32 {
self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) });
self.info.regs.sum().read().bits()
}
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() };
for b in prefix {
self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
}
for d in data {
self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) });
}
for b in suffix {
self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
}
self.info.regs.sum().read().bits()
}
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) });
self.info.regs.sum().read().bits()
}
/// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
for halfword in halfwords {
self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) });
}
self.info.regs.sum().read().bits()
}
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
pub fn feed_word(&mut self, word: u32) -> u32 {
self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) });
self.info.regs.sum().read().bits()
}
/// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
for word in words {
self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) });
}
self.info.regs.sum().read().bits()
}
}
struct Info {
regs: crate::pac::CrcEngine,
}
trait SealedInstance {
fn info() -> Info;
}
/// CRC instance trait.
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {}
impl Instance for peripherals::CRC {}
impl SealedInstance for peripherals::CRC {
fn info() -> Info {
// SAFETY: safe from single executor
Info {
regs: unsafe { crate::pac::CrcEngine::steal() },
}
}
}

View File

@ -18,6 +18,7 @@ compile_error!(
pub(crate) mod fmt;
pub mod clocks;
pub mod crc;
pub mod gpio;
pub mod iopctl;
pub mod rng;

View File

@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
PPI_GROUP4,
PPI_GROUP5,
// IPC
IPC,
// GPIO port 0
#[cfg(feature = "lfxo-pins-as-gpio")]
P0_00,
@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
EGU5,
}
impl_ipc!(IPC, IPC, IPC);
impl_usb!(USBD, USBD, USBD);
impl_uarte!(SERIAL0, UARTE0, SERIAL0);

View File

@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
PPI_GROUP4,
PPI_GROUP5,
// IPC
IPC,
// GPIO port 0
P0_00,
P0_01,
@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
EGU0,
}
impl_ipc!(IPC, IPC, IPC);
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
impl_spim!(SERIAL0, SPIM0, SERIAL0);
impl_spis!(SERIAL0, SPIS0, SERIAL0);

363
embassy-nrf/src/ipc.rs Normal file
View File

@ -0,0 +1,363 @@
//! InterProcessor Communication (IPC)
#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use crate::interrupt::typelevel::Interrupt;
use crate::{interrupt, pac, ppi};
const EVENT_COUNT: usize = 16;
/// IPC Event
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EventNumber {
/// IPC Event 0
Event0 = 0,
/// IPC Event 1
Event1 = 1,
/// IPC Event 2
Event2 = 2,
/// IPC Event 3
Event3 = 3,
/// IPC Event 4
Event4 = 4,
/// IPC Event 5
Event5 = 5,
/// IPC Event 6
Event6 = 6,
/// IPC Event 7
Event7 = 7,
/// IPC Event 8
Event8 = 8,
/// IPC Event 9
Event9 = 9,
/// IPC Event 10
Event10 = 10,
/// IPC Event 11
Event11 = 11,
/// IPC Event 12
Event12 = 12,
/// IPC Event 13
Event13 = 13,
/// IPC Event 14
Event14 = 14,
/// IPC Event 15
Event15 = 15,
}
const EVENTS: [EventNumber; EVENT_COUNT] = [
EventNumber::Event0,
EventNumber::Event1,
EventNumber::Event2,
EventNumber::Event3,
EventNumber::Event4,
EventNumber::Event5,
EventNumber::Event6,
EventNumber::Event7,
EventNumber::Event8,
EventNumber::Event9,
EventNumber::Event10,
EventNumber::Event11,
EventNumber::Event12,
EventNumber::Event13,
EventNumber::Event14,
EventNumber::Event15,
];
/// IPC Channel
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IpcChannel {
/// IPC Channel 0
Channel0,
/// IPC Channel 1
Channel1,
/// IPC Channel 2
Channel2,
/// IPC Channel 3
Channel3,
/// IPC Channel 4
Channel4,
/// IPC Channel 5
Channel5,
/// IPC Channel 6
Channel6,
/// IPC Channel 7
Channel7,
/// IPC Channel 8
Channel8,
/// IPC Channel 9
Channel9,
/// IPC Channel 10
Channel10,
/// IPC Channel 11
Channel11,
/// IPC Channel 12
Channel12,
/// IPC Channel 13
Channel13,
/// IPC Channel 14
Channel14,
/// IPC Channel 15
Channel15,
}
impl IpcChannel {
fn mask(self) -> u32 {
1 << (self as u32)
}
}
/// Interrupt Handler
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let regs = T::regs();
// Check if an event was generated, and if it was, trigger the corresponding waker
for event in EVENTS {
if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
T::state().wakers[event as usize].wake();
}
}
}
}
/// IPC driver
#[non_exhaustive]
pub struct Ipc<'d, T: Instance> {
/// Event 0
pub event0: Event<'d, T>,
/// Event 1
pub event1: Event<'d, T>,
/// Event 2
pub event2: Event<'d, T>,
/// Event 3
pub event3: Event<'d, T>,
/// Event 4
pub event4: Event<'d, T>,
/// Event 5
pub event5: Event<'d, T>,
/// Event 6
pub event6: Event<'d, T>,
/// Event 7
pub event7: Event<'d, T>,
/// Event 8
pub event8: Event<'d, T>,
/// Event 9
pub event9: Event<'d, T>,
/// Event 10
pub event10: Event<'d, T>,
/// Event 11
pub event11: Event<'d, T>,
/// Event 12
pub event12: Event<'d, T>,
/// Event 13
pub event13: Event<'d, T>,
/// Event 14
pub event14: Event<'d, T>,
/// Event 15
pub event15: Event<'d, T>,
}
impl<'d, T: Instance> Ipc<'d, T> {
/// Create a new IPC driver.
pub fn new(
_p: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
let _phantom = PhantomData;
#[rustfmt::skip]
let r = Self { // attributes on expressions are experimental
event0: Event { number: EventNumber::Event0, _phantom },
event1: Event { number: EventNumber::Event1, _phantom },
event2: Event { number: EventNumber::Event2, _phantom },
event3: Event { number: EventNumber::Event3, _phantom },
event4: Event { number: EventNumber::Event4, _phantom },
event5: Event { number: EventNumber::Event5, _phantom },
event6: Event { number: EventNumber::Event6, _phantom },
event7: Event { number: EventNumber::Event7, _phantom },
event8: Event { number: EventNumber::Event8, _phantom },
event9: Event { number: EventNumber::Event9, _phantom },
event10: Event { number: EventNumber::Event10, _phantom },
event11: Event { number: EventNumber::Event11, _phantom },
event12: Event { number: EventNumber::Event12, _phantom },
event13: Event { number: EventNumber::Event13, _phantom },
event14: Event { number: EventNumber::Event14, _phantom },
event15: Event { number: EventNumber::Event15, _phantom },
};
r
}
}
/// IPC event
pub struct Event<'d, T: Instance> {
number: EventNumber,
_phantom: PhantomData<&'d T>,
}
impl<'d, T: Instance> Event<'d, T> {
/// Trigger the event.
pub fn trigger(&self) {
let nr = self.number;
T::regs().tasks_send(nr as usize).write_value(1);
}
/// Wait for the event to be triggered.
pub async fn wait(&mut self) {
let regs = T::regs();
let nr = self.number as usize;
regs.intenset().write(|w| w.0 = 1 << nr);
poll_fn(|cx| {
T::state().wakers[nr].register(cx.waker());
if regs.events_receive(nr).read() == 1 {
regs.events_receive(nr).write_value(0x00);
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
/// Returns the [`EventNumber`] of the event.
pub fn number(&self) -> EventNumber {
self.number
}
/// Create a handle that can trigger the event.
pub fn trigger_handle(&self) -> EventTrigger<'d, T> {
EventTrigger {
number: self.number,
_phantom: PhantomData,
}
}
/// Configure the channels the event will broadcast to
pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
T::regs().send_cnf(self.number as usize).write(|w| {
for channel in channels {
w.0 |= channel.mask();
}
})
}
/// Configure the channels the event will listen on
pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
T::regs().receive_cnf(self.number as usize).write(|w| {
for channel in channels {
w.0 |= channel.mask();
}
});
}
/// Get the task for the IPC event to use with PPI.
pub fn task(&self) -> ppi::Task<'d> {
let nr = self.number as usize;
let regs = T::regs();
ppi::Task::from_reg(regs.tasks_send(nr))
}
/// Get the event for the IPC event to use with PPI.
pub fn event(&self) -> ppi::Event<'d> {
let nr = self.number as usize;
let regs = T::regs();
ppi::Event::from_reg(regs.events_receive(nr))
}
/// Reborrow into a "child" Event.
///
/// `self` will stay borrowed until the child Event is dropped.
pub fn reborrow(&mut self) -> Event<'_, T> {
Self { ..*self }
}
/// Steal an IPC event by number.
///
/// # Safety
///
/// The event number must not be in use by another [`Event`].
pub unsafe fn steal(number: EventNumber) -> Self {
Self {
number,
_phantom: PhantomData,
}
}
}
/// A handle that can trigger an IPC event.
///
/// This `struct` is returned by [`Event::trigger_handle`].
#[derive(Debug, Copy, Clone)]
pub struct EventTrigger<'d, T: Instance> {
number: EventNumber,
_phantom: PhantomData<&'d T>,
}
impl<T: Instance> EventTrigger<'_, T> {
/// Trigger the event.
pub fn trigger(&self) {
let nr = self.number;
T::regs().tasks_send(nr as usize).write_value(1);
}
/// Returns the [`EventNumber`] of the event.
pub fn number(&self) -> EventNumber {
self.number
}
}
pub(crate) struct State {
wakers: [AtomicWaker; EVENT_COUNT],
}
impl State {
pub(crate) const fn new() -> Self {
Self {
wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
}
}
}
pub(crate) trait SealedInstance {
fn regs() -> pac::ipc::Ipc;
fn state() -> &'static State;
}
/// IPC peripheral instance.
#[allow(private_bounds)]
pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
/// Interrupt for this peripheral.
type Interrupt: interrupt::typelevel::Interrupt;
}
macro_rules! impl_ipc {
($type:ident, $pac_type:ident, $irq:ident) => {
impl crate::ipc::SealedInstance for peripherals::$type {
fn regs() -> pac::ipc::Ipc {
pac::$pac_type
}
fn state() -> &'static crate::ipc::State {
static STATE: crate::ipc::State = crate::ipc::State::new();
&STATE
}
}
impl crate::ipc::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}

View File

@ -88,6 +88,8 @@ pub mod gpiote;
#[cfg(not(feature = "_nrf54l"))] // TODO
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
pub mod i2s;
#[cfg(feature = "_nrf5340")]
pub mod ipc;
#[cfg(not(feature = "_nrf54l"))] // TODO
#[cfg(any(
feature = "nrf52832",

View File

@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
[features]
default = [ "rt" ]
## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac).
## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that.
## See <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> for more info.
rt = [ "rp-pac/rt" ]
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
//! Helper functions for calculating PIO clock dividers
use fixed::traits::ToFixed;
use fixed::types::extra::U8;
use crate::clocks::clk_sys_freq;
/// Calculate a PIO clock divider value based on the desired target frequency.
///
/// # Arguments
///
/// * `target_hz` - The desired PIO clock frequency in Hz
///
/// # Returns
///
/// A fixed-point divider value suitable for use in a PIO state machine configuration
#[inline]
pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> {
// Requires a non-zero frequency
assert!(target_hz > 0, "PIO clock frequency cannot be zero");
// Calculate the divider
let divider = (clk_sys_freq() + target_hz / 2) / target_hz;
divider.to_fixed()
}

View File

@ -5,6 +5,7 @@ use crate::pio::{
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
StateMachine,
};
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
use crate::Peri;
/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
@ -134,7 +135,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
let mut cfg = Config::default();
cfg.use_program(&word_prg.prg, &[&e]);
cfg.clock_divider = 125u8.into();
// Target 1 MHz PIO clock (each cycle is 1µs)
cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
cfg.shift_out = ShiftConfig {
auto_fill: true,
@ -160,7 +164,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
let mut cfg = Config::default();
cfg.use_program(&seq_prg.prg, &[&e]);
cfg.clock_divider = 8u8.into(); // ~64ns/insn
// Target ~15.6 MHz PIO clock (~64ns/insn)
cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
cfg.set_jmp_pin(&db7);
cfg.set_set_pins(&[&rs, &rw]);
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);

View File

@ -1,5 +1,6 @@
//! Pre-built pio programs for common interfaces
pub mod clock_divider;
pub mod hd44780;
pub mod i2s;
pub mod onewire;

View File

@ -1,11 +1,10 @@
//! PIO backed quadrature encoder
use fixed::traits::ToFixed;
use crate::gpio::Pull;
use crate::pio::{
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
};
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
use crate::Peri;
/// This struct represents an Encoder program loaded into pio instruction memory.
@ -48,7 +47,10 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
cfg.set_in_pins(&[&pin_a, &pin_b]);
cfg.fifo_join = FifoJoin::RxOnly;
cfg.shift_in.direction = ShiftDirection::Left;
cfg.clock_divider = 10_000.to_fixed();
// Target 12.5 KHz PIO clock
cfg.clock_divider = calculate_pio_clock_divider(12_500);
cfg.use_program(&program.prg, &[]);
sm.set_config(&cfg);
sm.set_enable(true);

View File

@ -2,11 +2,8 @@
use core::mem::{self, MaybeUninit};
use fixed::traits::ToFixed;
use fixed::types::extra::U8;
use fixed::FixedU32;
use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
use crate::Peri;
/// This struct represents a Stepper driver program loaded into pio instruction memory.
@ -64,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
let mut cfg = Config::default();
cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
cfg.clock_divider = calculate_pio_clock_divider(100 * 136);
cfg.use_program(&program.prg, &[]);
sm.set_config(&cfg);
sm.set_enable(true);
@ -73,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
/// Set pulse frequency
pub fn set_frequency(&mut self, freq: u32) {
let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
assert!(clock_divider >= 1, "clkdiv must be >= 1");
let clock_divider = calculate_pio_clock_divider(freq * 136);
let divider_f32 = clock_divider.to_num::<f32>();
assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536");
assert!(divider_f32 >= 1.0, "clkdiv must be >= 1");
self.sm.set_clock_divider(clock_divider);
self.sm.clkdiv_restart();
}

View File

@ -34,28 +34,29 @@ impl State {
}
/// Buffered UART driver.
pub struct BufferedUart<'d, T: Instance> {
pub(crate) rx: BufferedUartRx<'d, T>,
pub(crate) tx: BufferedUartTx<'d, T>,
pub struct BufferedUart {
pub(super) rx: BufferedUartRx,
pub(super) tx: BufferedUartTx,
}
/// Buffered UART RX handle.
pub struct BufferedUartRx<'d, T: Instance> {
pub(crate) phantom: PhantomData<&'d mut T>,
pub struct BufferedUartRx {
pub(super) info: &'static Info,
pub(super) state: &'static State,
}
/// Buffered UART TX handle.
pub struct BufferedUartTx<'d, T: Instance> {
pub(crate) phantom: PhantomData<&'d mut T>,
pub struct BufferedUartTx {
pub(super) info: &'static Info,
pub(super) state: &'static State,
}
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
pub(super) fn init_buffers<'d>(
info: &Info,
state: &State,
tx_buffer: Option<&'d mut [u8]>,
rx_buffer: Option<&'d mut [u8]>,
) {
let state = T::buffered_state();
if let Some(tx_buffer) = tx_buffer {
let len = tx_buffer.len();
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
@ -76,61 +77,73 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
// This means we can leave the interrupt enabled the whole time as long as
// we clear it after it happens. The downside is that the we manually have
// to pend the ISR when we want data transmission to start.
let regs = T::regs();
regs.uartimsc().write(|w| {
info.regs.uartimsc().write(|w| {
w.set_rxim(true);
w.set_rtim(true);
w.set_txim(true);
});
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
info.interrupt.unpend();
unsafe { info.interrupt.enable() };
}
impl<'d, T: Instance> BufferedUart<'d, T> {
impl BufferedUart {
/// Create a buffered UART instance.
pub fn new(
pub fn new<'d, T: Instance>(
_uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config);
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, config);
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
Self {
rx: BufferedUartRx { phantom: PhantomData },
tx: BufferedUartTx { phantom: PhantomData },
rx: BufferedUartRx {
info: T::info(),
state: T::buffered_state(),
},
tx: BufferedUartTx {
info: T::info(),
state: T::buffered_state(),
},
}
}
/// Create a buffered UART instance with flow control.
pub fn new_with_rtscts(
pub fn new_with_rtscts<'d, T: Instance>(
_uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(
super::Uart::<'d, Async>::init(
T::info(),
Some(tx.into()),
Some(rx.into()),
Some(rts.into()),
Some(cts.into()),
config,
);
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
Self {
rx: BufferedUartRx { phantom: PhantomData },
tx: BufferedUartTx { phantom: PhantomData },
rx: BufferedUartRx {
info: T::info(),
state: T::buffered_state(),
},
tx: BufferedUartTx {
info: T::info(),
state: T::buffered_state(),
},
}
}
@ -160,68 +173,75 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
}
/// sets baudrate on runtime
pub fn set_baudrate(&mut self, baudrate: u32) {
super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
pub fn set_baudrate<'d>(&mut self, baudrate: u32) {
super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate);
}
/// Split into separate RX and TX handles.
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
pub fn split(self) -> (BufferedUartTx, BufferedUartRx) {
(self.tx, self.rx)
}
/// Split the Uart into a transmitter and receiver by mutable reference,
/// which is particularly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) {
pub fn split_ref(&mut self) -> (&mut BufferedUartTx, &mut BufferedUartRx) {
(&mut self.tx, &mut self.rx)
}
}
impl<'d, T: Instance> BufferedUartRx<'d, T> {
impl BufferedUartRx {
/// Create a new buffered UART RX.
pub fn new(
pub fn new<'d, T: Instance>(
_uart: Peri<'d, T>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
rx: Peri<'d, impl RxPin<T>>,
rx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config);
init_buffers::<T>(irq, None, Some(rx_buffer));
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config);
init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
Self { phantom: PhantomData }
Self {
info: T::info(),
state: T::buffered_state(),
}
}
/// Create a new buffered UART RX with flow control.
pub fn new_with_rts(
pub fn new_with_rts<'d, T: Instance>(
_uart: Peri<'d, T>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
rx: Peri<'d, impl RxPin<T>>,
rts: Peri<'d, impl RtsPin<T>>,
rx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config);
init_buffers::<T>(irq, None, Some(rx_buffer));
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config);
init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
Self { phantom: PhantomData }
Self {
info: T::info(),
state: T::buffered_state(),
}
}
fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a
where
T: 'd,
{
fn read<'a>(
info: &'static Info,
state: &'static State,
buf: &'a mut [u8],
) -> impl Future<Output = Result<usize, Error>> + 'a {
poll_fn(move |cx| {
if let Poll::Ready(r) = Self::try_read(buf) {
if let Poll::Ready(r) = Self::try_read(info, state, buf) {
return Poll::Ready(r);
}
T::buffered_state().rx_waker.register(cx.waker());
state.rx_waker.register(cx.waker());
Poll::Pending
})
}
fn get_rx_error() -> Option<Error> {
let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed);
fn get_rx_error(state: &State) -> Option<Error> {
let errs = state.rx_error.swap(0, Ordering::Relaxed);
if errs & RXE_OVERRUN != 0 {
Some(Error::Overrun)
} else if errs & RXE_BREAK != 0 {
@ -235,15 +255,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
}
}
fn try_read(buf: &mut [u8]) -> Poll<Result<usize, Error>>
where
T: 'd,
{
fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() };
let n = rx_reader.pop(|data| {
let n = data.len().min(buf.len());
@ -252,7 +268,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
});
let result = if n == 0 {
match Self::get_rx_error() {
match Self::get_rx_error(state) {
None => return Poll::Pending,
Some(e) => Err(e),
}
@ -262,8 +278,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
// (Re-)Enable the interrupt to receive more data in case it was
// disabled because the buffer was full or errors were detected.
let regs = T::regs();
regs.uartimsc().write_set(|w| {
info.regs.uartimsc().write_set(|w| {
w.set_rxim(true);
w.set_rtim(true);
});
@ -274,23 +289,19 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
/// Read from UART RX buffer blocking execution until done.
pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
loop {
match Self::try_read(buf) {
match Self::try_read(self.info, self.state, buf) {
Poll::Ready(res) => return res,
Poll::Pending => continue,
}
}
}
fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>>
where
T: 'd,
{
fn fill_buf<'a>(state: &'static State) -> impl Future<Output = Result<&'a [u8], Error>> {
poll_fn(move |cx| {
let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() };
let (p, n) = rx_reader.pop_buf();
let result = if n == 0 {
match Self::get_rx_error() {
match Self::get_rx_error(state) {
None => {
state.rx_waker.register(cx.waker());
return Poll::Pending;
@ -306,64 +317,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
})
}
fn consume(amt: usize) {
let state = T::buffered_state();
fn consume(info: &Info, state: &State, amt: usize) {
let mut rx_reader = unsafe { state.rx_buf.reader() };
rx_reader.pop_done(amt);
// (Re-)Enable the interrupt to receive more data in case it was
// disabled because the buffer was full or errors were detected.
let regs = T::regs();
regs.uartimsc().write_set(|w| {
info.regs.uartimsc().write_set(|w| {
w.set_rxim(true);
w.set_rtim(true);
});
}
/// we are ready to read if there is data in the buffer
fn read_ready() -> Result<bool, Error> {
let state = T::buffered_state();
fn read_ready(state: &State) -> Result<bool, Error> {
Ok(!state.rx_buf.is_empty())
}
}
impl<'d, T: Instance> BufferedUartTx<'d, T> {
impl BufferedUartTx {
/// Create a new buffered UART TX.
pub fn new(
pub fn new<'d, T: Instance>(
_uart: Peri<'d, T>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx: Peri<'d, impl TxPin<T>>,
tx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config);
init_buffers::<T>(irq, Some(tx_buffer), None);
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config);
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
Self { phantom: PhantomData }
Self {
info: T::info(),
state: T::buffered_state(),
}
}
/// Create a new buffered UART TX with flow control.
pub fn new_with_cts(
pub fn new_with_cts<'d, T: Instance>(
_uart: Peri<'d, T>,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx: Peri<'d, impl TxPin<T>>,
cts: Peri<'d, impl CtsPin<T>>,
tx_buffer: &'d mut [u8],
config: Config,
) -> Self {
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config);
init_buffers::<T>(irq, Some(tx_buffer), None);
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config);
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
Self { phantom: PhantomData }
Self {
info: T::info(),
state: T::buffered_state(),
}
}
fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ {
fn write<'d>(
info: &'static Info,
state: &'static State,
buf: &'d [u8],
) -> impl Future<Output = Result<usize, Error>> + 'd {
poll_fn(move |cx| {
if buf.is_empty() {
return Poll::Ready(Ok(0));
}
let state = T::buffered_state();
let mut tx_writer = unsafe { state.tx_buf.writer() };
let n = tx_writer.push(|data| {
let n = data.len().min(buf.len());
@ -379,14 +396,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
// FIFO and the number of bytes drops below a threshold. When the
// FIFO was empty we have to manually pend the interrupt to shovel
// TX data from the buffer into the FIFO.
T::Interrupt::pend();
info.interrupt.pend();
Poll::Ready(Ok(n))
})
}
fn flush() -> impl Future<Output = Result<(), Error>> {
fn flush(state: &'static State) -> impl Future<Output = Result<(), Error>> {
poll_fn(move |cx| {
let state = T::buffered_state();
if !state.tx_buf.is_empty() {
state.tx_waker.register(cx.waker());
return Poll::Pending;
@ -403,8 +419,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
}
loop {
let state = T::buffered_state();
let mut tx_writer = unsafe { state.tx_buf.writer() };
let mut tx_writer = unsafe { self.state.tx_buf.writer() };
let n = tx_writer.push(|data| {
let n = data.len().min(buf.len());
data[..n].copy_from_slice(&buf[..n]);
@ -416,7 +431,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
// FIFO and the number of bytes drops below a threshold. When the
// FIFO was empty we have to manually pend the interrupt to shovel
// TX data from the buffer into the FIFO.
T::Interrupt::pend();
self.info.interrupt.pend();
return Ok(n);
}
}
@ -425,8 +440,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
/// Flush UART TX blocking execution until done.
pub fn blocking_flush(&mut self) -> Result<(), Error> {
loop {
let state = T::buffered_state();
if state.tx_buf.is_empty() {
if self.state.tx_buf.is_empty() {
return Ok(());
}
}
@ -434,7 +448,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
/// Check if UART is busy.
pub fn busy(&self) -> bool {
T::regs().uartfr().read().busy()
self.info.regs.uartfr().read().busy()
}
/// Assert a break condition after waiting for the transmit buffers to empty,
@ -445,7 +459,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
/// This method may block for a long amount of time since it has to wait
/// for the transmit fifo to empty, which may take a while on slow links.
pub async fn send_break(&mut self, bits: u32) {
let regs = T::regs();
let regs = self.info.regs;
let bits = bits.max({
let lcr = regs.uartlcr_h().read();
let width = lcr.wlen() as u32 + 5;
@ -458,7 +472,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
let div_clk = clk_peri_freq() as u64 * 64;
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
Self::flush().await.unwrap();
Self::flush(self.state).await.unwrap();
while self.busy() {}
regs.uartlcr_h().write_set(|w| w.set_brk(true));
Timer::after_micros(wait_usecs).await;
@ -466,28 +480,26 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
}
}
impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
impl Drop for BufferedUartRx {
fn drop(&mut self) {
let state = T::buffered_state();
unsafe { state.rx_buf.deinit() }
unsafe { self.state.rx_buf.deinit() }
// TX is inactive if the buffer is not available.
// We can now unregister the interrupt handler
if !state.tx_buf.is_available() {
T::Interrupt::disable();
if !self.state.tx_buf.is_available() {
self.info.interrupt.disable();
}
}
}
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
impl Drop for BufferedUartTx {
fn drop(&mut self) {
let state = T::buffered_state();
unsafe { state.tx_buf.deinit() }
unsafe { self.state.tx_buf.deinit() }
// RX is inactive if the buffer is not available.
// We can now unregister the interrupt handler
if !state.rx_buf.is_available() {
T::Interrupt::disable();
if !self.state.rx_buf.is_available() {
self.info.interrupt.disable();
}
}
}
@ -499,7 +511,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
let r = T::info().regs;
if r.uartdmacr().read().rxdmae() {
return;
}
@ -603,95 +615,95 @@ impl embedded_io::Error for Error {
}
}
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> {
impl embedded_io_async::ErrorType for BufferedUart {
type Error = Error;
}
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> {
impl embedded_io_async::ErrorType for BufferedUartRx {
type Error = Error;
}
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> {
impl embedded_io_async::ErrorType for BufferedUartTx {
type Error = Error;
}
impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> {
impl embedded_io_async::Read for BufferedUart {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
BufferedUartRx::<'d, T>::read(buf).await
BufferedUartRx::read(self.rx.info, self.rx.state, buf).await
}
}
impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> {
impl embedded_io_async::Read for BufferedUartRx {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
Self::read(buf).await
Self::read(self.info, self.state, buf).await
}
}
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> {
impl embedded_io_async::ReadReady for BufferedUart {
fn read_ready(&mut self) -> Result<bool, Self::Error> {
BufferedUartRx::<'d, T>::read_ready()
BufferedUartRx::read_ready(self.rx.state)
}
}
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> {
impl embedded_io_async::ReadReady for BufferedUartRx {
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Self::read_ready()
Self::read_ready(self.state)
}
}
impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> {
impl embedded_io_async::BufRead for BufferedUart {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
BufferedUartRx::<'d, T>::fill_buf().await
BufferedUartRx::fill_buf(self.rx.state).await
}
fn consume(&mut self, amt: usize) {
BufferedUartRx::<'d, T>::consume(amt)
BufferedUartRx::consume(self.rx.info, self.rx.state, amt)
}
}
impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> {
impl embedded_io_async::BufRead for BufferedUartRx {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
Self::fill_buf().await
Self::fill_buf(self.state).await
}
fn consume(&mut self, amt: usize) {
Self::consume(amt)
Self::consume(self.info, self.state, amt)
}
}
impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> {
impl embedded_io_async::Write for BufferedUart {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
BufferedUartTx::<'d, T>::write(buf).await
BufferedUartTx::write(self.tx.info, self.tx.state, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
BufferedUartTx::<'d, T>::flush().await
BufferedUartTx::flush(self.tx.state).await
}
}
impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> {
impl embedded_io_async::Write for BufferedUartTx {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
Self::write(buf).await
Self::write(self.info, self.state, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
Self::flush().await
Self::flush(self.state).await
}
}
impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> {
impl embedded_io::Read for BufferedUart {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.blocking_read(buf)
}
}
impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> {
impl embedded_io::Read for BufferedUartRx {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.blocking_read(buf)
}
}
impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
impl embedded_io::Write for BufferedUart {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.blocking_write(buf)
}
@ -701,7 +713,7 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
}
}
impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
impl embedded_io::Write for BufferedUartTx {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)
}
@ -711,11 +723,11 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
}
}
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> {
impl embedded_hal_02::serial::Read<u8> for BufferedUartRx {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs();
let r = self.info.regs;
if r.uartfr().read().rxfe() {
return Err(nb::Error::WouldBlock);
}
@ -736,7 +748,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx {
type Error = Error;
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@ -755,7 +767,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
}
}
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> {
impl embedded_hal_02::serial::Read<u8> for BufferedUart {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@ -763,7 +775,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T>
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> {
impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUart {
type Error = Error;
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@ -782,25 +794,25 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
}
}
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> {
impl embedded_hal_nb::serial::ErrorType for BufferedUartRx {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> {
impl embedded_hal_nb::serial::ErrorType for BufferedUartTx {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> {
impl embedded_hal_nb::serial::ErrorType for BufferedUart {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> {
impl embedded_hal_nb::serial::Read for BufferedUartRx {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
embedded_hal_02::serial::Read::read(self)
}
}
impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
impl embedded_hal_nb::serial::Write for BufferedUartTx {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
}
@ -810,13 +822,13 @@ impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
}
}
impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> {
impl embedded_hal_nb::serial::Read for BufferedUart {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
impl embedded_hal_nb::serial::Write for BufferedUart {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
}

View File

@ -13,7 +13,8 @@ use pac::uart::regs::Uartris;
use crate::clocks::clk_peri_freq;
use crate::dma::{AnyChannel, Channel};
use crate::gpio::{AnyPin, SealedPin};
use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::interrupt::typelevel::{Binding, Interrupt as _};
use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac::io::vals::{Inover, Outover};
use crate::{interrupt, pac, peripherals, RegExt};
@ -135,37 +136,41 @@ pub struct DmaState {
}
/// UART driver.
pub struct Uart<'d, T: Instance, M: Mode> {
tx: UartTx<'d, T, M>,
rx: UartRx<'d, T, M>,
pub struct Uart<'d, M: Mode> {
tx: UartTx<'d, M>,
rx: UartRx<'d, M>,
}
/// UART TX driver.
pub struct UartTx<'d, T: Instance, M: Mode> {
pub struct UartTx<'d, M: Mode> {
info: &'static Info,
tx_dma: Option<Peri<'d, AnyChannel>>,
phantom: PhantomData<(&'d mut T, M)>,
phantom: PhantomData<M>,
}
/// UART RX driver.
pub struct UartRx<'d, T: Instance, M: Mode> {
pub struct UartRx<'d, M: Mode> {
info: &'static Info,
dma_state: &'static DmaState,
rx_dma: Option<Peri<'d, AnyChannel>>,
phantom: PhantomData<(&'d mut T, M)>,
phantom: PhantomData<M>,
}
impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
impl<'d, M: Mode> UartTx<'d, M> {
/// Create a new DMA-enabled UART which can only send data
pub fn new(
pub fn new<T: Instance>(
_uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
tx_dma: Peri<'d, impl Channel>,
config: Config,
) -> Self {
Uart::<T, M>::init(Some(tx.into()), None, None, None, config);
Self::new_inner(Some(tx_dma.into()))
Uart::<M>::init(T::info(), Some(tx.into()), None, None, None, config);
Self::new_inner(T::info(), Some(tx_dma.into()))
}
fn new_inner(tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
fn new_inner(info: &'static Info, tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
Self {
info,
tx_dma,
phantom: PhantomData,
}
@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
/// Transmit the provided buffer blocking execution until done.
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
let r = self.info.regs;
for &b in buffer {
while r.uartfr().read().txff() {}
r.uartdr().write(|w| w.set_data(b));
@ -183,14 +188,13 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
/// Flush UART TX blocking execution until done.
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs();
while !r.uartfr().read().txfe() {}
while !self.info.regs.uartfr().read().txfe() {}
Ok(())
}
/// Check if UART is busy transmitting.
pub fn busy(&self) -> bool {
T::regs().uartfr().read().busy()
self.info.regs.uartfr().read().busy()
}
/// Assert a break condition after waiting for the transmit buffers to empty,
@ -201,7 +205,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
/// This method may block for a long amount of time since it has to wait
/// for the transmit fifo to empty, which may take a while on slow links.
pub async fn send_break(&mut self, bits: u32) {
let regs = T::regs();
let regs = self.info.regs;
let bits = bits.max({
let lcr = regs.uartlcr_h().read();
let width = lcr.wlen() as u32 + 5;
@ -222,65 +226,80 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
}
}
impl<'d, T: Instance> UartTx<'d, T, Blocking> {
impl<'d> UartTx<'d, Blocking> {
/// Create a new UART TX instance for blocking mode operations.
pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
Uart::<T, Blocking>::init(Some(tx.into()), None, None, None, config);
Self::new_inner(None)
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
Uart::<Blocking>::init(T::info(), Some(tx.into()), None, None, None, config);
Self::new_inner(T::info(), None)
}
/// Convert this uart TX instance into a buffered uart using the provided
/// irq and transmit buffer.
pub fn into_buffered(
pub fn into_buffered<T: Instance>(
self,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
) -> BufferedUartTx<'d, T> {
buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
) -> BufferedUartTx {
buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
BufferedUartTx { phantom: PhantomData }
BufferedUartTx {
info: T::info(),
state: T::buffered_state(),
}
}
}
impl<'d, T: Instance> UartTx<'d, T, Async> {
impl<'d> UartTx<'d, Async> {
/// Write to UART TX from the provided buffer using DMA.
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let ch = self.tx_dma.as_mut().unwrap().reborrow();
let transfer = unsafe {
T::regs().uartdmacr().write_set(|reg| {
self.info.regs.uartdmacr().write_set(|reg| {
reg.set_txdmae(true);
});
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into())
crate::dma::write(
ch,
buffer,
self.info.regs.uartdr().as_ptr() as *mut _,
self.info.tx_dreq.into(),
)
};
transfer.await;
Ok(())
}
}
impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
impl<'d, M: Mode> UartRx<'d, M> {
/// Create a new DMA-enabled UART which can only receive data
pub fn new(
pub fn new<T: Instance>(
_uart: Peri<'d, T>,
rx: Peri<'d, impl RxPin<T>>,
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
rx_dma: Peri<'d, impl Channel>,
config: Config,
) -> Self {
Uart::<T, M>::init(None, Some(rx.into()), None, None, config);
Self::new_inner(true, Some(rx_dma.into()))
Uart::<M>::init(T::info(), None, Some(rx.into()), None, None, config);
Self::new_inner(T::info(), T::dma_state(), true, Some(rx_dma.into()))
}
fn new_inner(has_irq: bool, rx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
fn new_inner(
info: &'static Info,
dma_state: &'static DmaState,
has_irq: bool,
rx_dma: Option<Peri<'d, AnyChannel>>,
) -> Self {
debug_assert_eq!(has_irq, rx_dma.is_some());
if has_irq {
// disable all error interrupts initially
T::regs().uartimsc().write(|w| w.0 = 0);
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
info.regs.uartimsc().write(|w| w.0 = 0);
info.interrupt.unpend();
unsafe { info.interrupt.enable() };
}
Self {
info,
dma_state,
rx_dma,
phantom: PhantomData,
}
@ -299,7 +318,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
/// encountered. in both cases, `len` is the number of *good* bytes copied into
/// `buffer`.
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
let r = T::regs();
let r = self.info.regs;
for (i, b) in buffer.iter_mut().enumerate() {
if r.uartfr().read().rxfe() {
return Ok(i);
@ -323,12 +342,12 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
}
}
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
impl<'d, M: Mode> Drop for UartRx<'d, M> {
fn drop(&mut self) {
if self.rx_dma.is_some() {
T::Interrupt::disable();
self.info.interrupt.disable();
// clear dma flags. irq handlers use these to disambiguate among themselves.
T::regs().uartdmacr().write_clear(|reg| {
self.info.regs.uartdmacr().write_clear(|reg| {
reg.set_rxdmae(true);
reg.set_txdmae(true);
reg.set_dmaonerr(true);
@ -337,23 +356,26 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
}
}
impl<'d, T: Instance> UartRx<'d, T, Blocking> {
impl<'d> UartRx<'d, Blocking> {
/// Create a new UART RX instance for blocking mode operations.
pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
Uart::<T, Blocking>::init(None, Some(rx.into()), None, None, config);
Self::new_inner(false, None)
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
Uart::<Blocking>::init(T::info(), None, Some(rx.into()), None, None, config);
Self::new_inner(T::info(), T::dma_state(), false, None)
}
/// Convert this uart RX instance into a buffered uart using the provided
/// irq and receive buffer.
pub fn into_buffered(
pub fn into_buffered<T: Instance>(
self,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
rx_buffer: &'d mut [u8],
) -> BufferedUartRx<'d, T> {
buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
) -> BufferedUartRx {
buffered::init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
BufferedUartRx { phantom: PhantomData }
BufferedUartRx {
info: T::info(),
state: T::buffered_state(),
}
}
}
@ -364,7 +386,7 @@ pub struct InterruptHandler<T: Instance> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let uart = T::regs();
let uart = T::info().regs;
if !uart.uartdmacr().read().rxdmae() {
return;
}
@ -380,13 +402,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
}
}
impl<'d, T: Instance> UartRx<'d, T, Async> {
impl<'d> UartRx<'d, Async> {
/// Read from UART RX into the provided buffer.
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
// clear error flags before we drain the fifo. errors that have accumulated
// in the flags will also be present in the fifo.
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
T::regs().uarticr().write(|w| {
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
self.info.regs.uarticr().write(|w| {
w.set_oeic(true);
w.set_beic(true);
w.set_peic(true);
@ -408,28 +430,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
// interrupt flags will have been raised, and those will be picked up immediately
// by the interrupt handler.
let ch = self.rx_dma.as_mut().unwrap().reborrow();
T::regs().uartimsc().write_set(|w| {
self.info.regs.uartimsc().write_set(|w| {
w.set_oeim(true);
w.set_beim(true);
w.set_peim(true);
w.set_feim(true);
});
T::regs().uartdmacr().write_set(|reg| {
self.info.regs.uartdmacr().write_set(|reg| {
reg.set_rxdmae(true);
reg.set_dmaonerr(true);
});
let transfer = unsafe {
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into())
crate::dma::read(
ch,
self.info.regs.uartdr().as_ptr() as *const _,
buffer,
self.info.rx_dreq.into(),
)
};
// wait for either the transfer to complete or an error to happen.
let transfer_result = select(
transfer,
poll_fn(|cx| {
T::dma_state().rx_err_waker.register(cx.waker());
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
self.dma_state.rx_err_waker.register(cx.waker());
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
0 => Poll::Pending,
e => Poll::Ready(Uartris(e as u32)),
}
@ -441,7 +468,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
Either::First(()) => {
// We're here because the DMA finished, BUT if an error occurred on the LAST
// byte, then we may still need to grab the error state!
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
}
Either::Second(e) => {
// We're here because we errored, which means this is the error that
@ -521,8 +548,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
) -> Result<usize, ReadToBreakError> {
// clear error flags before we drain the fifo. errors that have accumulated
// in the flags will also be present in the fifo.
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
T::regs().uarticr().write(|w| {
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
self.info.regs.uarticr().write(|w| {
w.set_oeic(true);
w.set_beic(true);
w.set_peic(true);
@ -555,13 +582,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
// interrupt flags will have been raised, and those will be picked up immediately
// by the interrupt handler.
let ch = self.rx_dma.as_mut().unwrap();
T::regs().uartimsc().write_set(|w| {
self.info.regs.uartimsc().write_set(|w| {
w.set_oeim(true);
w.set_beim(true);
w.set_peim(true);
w.set_feim(true);
});
T::regs().uartdmacr().write_set(|reg| {
self.info.regs.uartdmacr().write_set(|reg| {
reg.set_rxdmae(true);
reg.set_dmaonerr(true);
});
@ -572,9 +599,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
// is held across an await and makes the future non-Send.
crate::dma::read(
ch.reborrow(),
T::regs().uartdr().as_ptr() as *const _,
self.info.regs.uartdr().as_ptr() as *const _,
sbuffer,
T::RX_DREQ.into(),
self.info.rx_dreq.into(),
)
};
@ -582,8 +609,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
let transfer_result = select(
transfer,
poll_fn(|cx| {
T::dma_state().rx_err_waker.register(cx.waker());
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
self.dma_state.rx_err_waker.register(cx.waker());
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
0 => Poll::Pending,
e => Poll::Ready(Uartris(e as u32)),
}
@ -596,7 +623,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
Either::First(()) => {
// We're here because the DMA finished, BUT if an error occurred on the LAST
// byte, then we may still need to grab the error state!
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
}
Either::Second(e) => {
// We're here because we errored, which means this is the error that
@ -635,7 +662,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
continue;
}
let regs = T::regs();
let regs = self.info.regs;
let all_full = next_addr == eval;
// NOTE: This is off label usage of RSR! See the issue below for
@ -685,9 +712,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
}
}
impl<'d, T: Instance> Uart<'d, T, Blocking> {
impl<'d> Uart<'d, Blocking> {
/// Create a new UART without hardware flow control
pub fn new_blocking(
pub fn new_blocking<T: Instance>(
uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
@ -697,7 +724,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
}
/// Create a new UART with hardware flow control (RTS/CTS)
pub fn new_with_rtscts_blocking(
pub fn new_with_rtscts_blocking<T: Instance>(
uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
@ -720,24 +747,30 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
/// Convert this uart instance into a buffered uart using the provided
/// irq, transmit and receive buffers.
pub fn into_buffered(
pub fn into_buffered<T: Instance>(
self,
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
) -> BufferedUart<'d, T> {
buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
) -> BufferedUart {
buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
BufferedUart {
rx: BufferedUartRx { phantom: PhantomData },
tx: BufferedUartTx { phantom: PhantomData },
rx: BufferedUartRx {
info: T::info(),
state: T::buffered_state(),
},
tx: BufferedUartTx {
info: T::info(),
state: T::buffered_state(),
},
}
}
}
impl<'d, T: Instance> Uart<'d, T, Async> {
impl<'d> Uart<'d, Async> {
/// Create a new DMA enabled UART without hardware flow control
pub fn new(
pub fn new<T: Instance>(
uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
@ -760,7 +793,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
}
/// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
pub fn new_with_rtscts(
pub fn new_with_rtscts<T: Instance>(
uart: Peri<'d, T>,
tx: Peri<'d, impl TxPin<T>>,
rx: Peri<'d, impl RxPin<T>>,
@ -785,8 +818,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
}
}
impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
fn new_inner(
impl<'d, M: Mode> Uart<'d, M> {
fn new_inner<T: Instance>(
_uart: Peri<'d, T>,
mut tx: Peri<'d, AnyPin>,
mut rx: Peri<'d, AnyPin>,
@ -798,6 +831,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
config: Config,
) -> Self {
Self::init(
T::info(),
Some(tx.reborrow()),
Some(rx.reborrow()),
rts.as_mut().map(|x| x.reborrow()),
@ -806,19 +840,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
);
Self {
tx: UartTx::new_inner(tx_dma),
rx: UartRx::new_inner(has_irq, rx_dma),
tx: UartTx::new_inner(T::info(), tx_dma),
rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
}
}
fn init(
info: &Info,
tx: Option<Peri<'_, AnyPin>>,
rx: Option<Peri<'_, AnyPin>>,
rts: Option<Peri<'_, AnyPin>>,
cts: Option<Peri<'_, AnyPin>>,
config: Config,
) {
let r = T::regs();
let r = info.regs;
if let Some(pin) = &tx {
let funcsel = {
let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
@ -896,7 +931,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
});
}
Self::set_baudrate_inner(config.baudrate);
Self::set_baudrate_inner(info, config.baudrate);
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
@ -926,8 +961,8 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
});
}
fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
let r = T::regs();
fn lcr_modify<R>(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
let r = info.regs;
// Notes from PL011 reference manual:
//
@ -978,11 +1013,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
/// sets baudrate on runtime
pub fn set_baudrate(&mut self, baudrate: u32) {
Self::set_baudrate_inner(baudrate);
Self::set_baudrate_inner(self.tx.info, baudrate);
}
fn set_baudrate_inner(baudrate: u32) {
let r = T::regs();
fn set_baudrate_inner(info: &Info, baudrate: u32) {
let r = info.regs;
let clk_base = crate::clocks::clk_peri_freq();
@ -1002,11 +1037,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
Self::lcr_modify(|_| {});
Self::lcr_modify(info, |_| {});
}
}
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
impl<'d, M: Mode> Uart<'d, M> {
/// Transmit the provided buffer blocking execution until done.
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
@ -1034,19 +1069,19 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
/// Split the Uart into a transmitter and receiver, which is particularly
/// useful when having two tasks correlating to transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
(self.tx, self.rx)
}
/// Split the Uart into a transmitter and receiver by mutable reference,
/// which is particularly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) {
(&mut self.tx, &mut self.rx)
}
}
impl<'d, T: Instance> Uart<'d, T, Async> {
impl<'d> Uart<'d, Async> {
/// Write to UART TX from the provided buffer.
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.write(buffer).await
@ -1076,10 +1111,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs();
let r = self.info.regs;
if r.uartfr().read().rxfe() {
return Err(nb::Error::WouldBlock);
}
@ -1100,11 +1135,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d,
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, M> {
type Error = Error;
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
let r = T::regs();
let r = self.info.regs;
if r.uartfr().read().txff() {
return Err(nb::Error::WouldBlock);
}
@ -1114,7 +1149,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
}
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
let r = T::regs();
let r = self.info.regs;
if !r.uartfr().read().txfe() {
return Err(nb::Error::WouldBlock);
}
@ -1122,7 +1157,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@ -1134,7 +1169,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@ -1142,7 +1177,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T,
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, M> {
type Error = Error;
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
@ -1154,7 +1189,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@ -1177,21 +1212,21 @@ impl embedded_hal_nb::serial::Error for Error {
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let r = T::regs();
let r = self.info.regs;
if r.uartfr().read().rxfe() {
return Err(nb::Error::WouldBlock);
}
@ -1212,7 +1247,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
@ -1222,11 +1257,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T,
}
}
impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> {
impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> {
type Error = Error;
}
impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
impl<'d> embedded_io::Write for UartTx<'d, Blocking> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf).map(|_| buf.len())
}
@ -1236,13 +1271,13 @@ impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
@ -1252,11 +1287,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M>
}
}
impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> {
impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> {
type Error = Error;
}
impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
impl<'d> embedded_io::Write for Uart<'d, Blocking> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf).map(|_| buf.len())
}
@ -1266,13 +1301,17 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
}
}
struct Info {
regs: pac::uart::Uart,
tx_dreq: pac::dma::vals::TreqSel,
rx_dreq: pac::dma::vals::TreqSel,
interrupt: Interrupt,
}
trait SealedMode {}
trait SealedInstance {
const TX_DREQ: pac::dma::vals::TreqSel;
const RX_DREQ: pac::dma::vals::TreqSel;
fn regs() -> pac::uart::Uart;
fn info() -> &'static Info;
fn buffered_state() -> &'static buffered::State;
@ -1308,11 +1347,14 @@ pub trait Instance: SealedInstance + PeripheralType {
macro_rules! impl_instance {
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
impl SealedInstance for peripherals::$inst {
const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
fn regs() -> pac::uart::Uart {
pac::$inst
fn info() -> &'static Info {
static INFO: Info = Info {
regs: pac::$inst,
tx_dreq: $tx_dreq,
rx_dreq: $rx_dreq,
interrupt: crate::interrupt::typelevel::$irq::IRQ,
};
&INFO
}
fn buffered_state() -> &'static buffered::State {

View File

@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> {
/// PWM pin config
///
/// This configures the pwm pin settings
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PwmPinConfig {
/// PWM Pin output type
pub output_type: OutputType,

View File

@ -0,0 +1,175 @@
#![no_std]
#![no_main]
extern crate embassy_imxrt_examples;
use defmt::*;
use embassy_executor::Spawner;
use embassy_imxrt::crc::{Config, Crc, Polynomial};
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut p = embassy_imxrt::init(Default::default());
let data = b"123456789";
info!("Initializing CRC");
// CRC-CCITT
let mut crc = Crc::new(p.CRC.reborrow(), Default::default());
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x29b1);
// CRC16-ARC
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc16,
reverse_in: true,
reverse_out: true,
complement_out: false,
seed: 0,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0xbb3d);
// CRC16-CMS
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc16,
reverse_in: false,
reverse_out: false,
complement_out: false,
seed: 0xffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0xaee7);
// CRC16-DDS-110
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc16,
reverse_in: false,
reverse_out: false,
complement_out: false,
seed: 0x800d,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x9ecf);
// CRC16-MAXIM-DOW
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc16,
reverse_in: true,
reverse_out: true,
complement_out: true,
seed: 0,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x44c2);
// CRC16-MODBUS
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc16,
reverse_in: true,
reverse_out: true,
complement_out: false,
seed: 0xffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x4b37);
// CRC32-BZIP2
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc32,
reverse_in: false,
reverse_out: false,
complement_out: true,
seed: 0xffff_ffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0xfc89_1918);
// CRC32-CKSUM
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc32,
reverse_in: false,
reverse_out: false,
complement_out: true,
seed: 0,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x765e_7680);
// CRC32-ISO-HDLC
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc32,
reverse_in: true,
reverse_out: true,
complement_out: true,
seed: 0xffff_ffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0xcbf4_3926);
// CRC32-JAMCRC
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc32,
reverse_in: true,
reverse_out: true,
complement_out: false,
seed: 0xffff_ffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x340b_c6d9);
// CRC32-MPEG-2
let mut crc = Crc::new(
p.CRC.reborrow(),
Config {
polynomial: Polynomial::Crc32,
reverse_in: false,
reverse_out: false,
complement_out: false,
seed: 0xffff_ffff,
..Default::default()
},
);
let output = crc.feed_bytes(data);
defmt::assert_eq!(output, 0x0376_e6e7);
info!("end program");
cortex_m::asm::bkpt();
}

View File

@ -0,0 +1,64 @@
//! # Overclocking the RP2040 to 200 MHz
//!
//! This example demonstrates how to configure the RP2040 to run at 200 MHz.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::clocks::{clk_sys_freq, ClockConfig};
use embassy_rp::config::Config;
use embassy_rp::gpio::{Level, Output};
use embassy_time::{Duration, Instant, Timer};
use {defmt_rtt as _, panic_probe as _};
const COUNT_TO: i64 = 10_000_000;
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
// Set up for clock frequency of 200 MHz, setting all necessary defaults.
let config = Config::new(ClockConfig::system_freq(200_000_000));
// Show the voltage scale for verification
info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage));
// Initialize the peripherals
let p = embassy_rp::init(config);
// Show CPU frequency for verification
let sys_freq = clk_sys_freq();
info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
// LED to indicate the system is running
let mut led = Output::new(p.PIN_25, Level::Low);
loop {
// Reset the counter at the start of measurement period
let mut counter = 0;
// Turn LED on while counting
led.set_high();
let start = Instant::now();
// This is a busy loop that will take some time to complete
while counter < COUNT_TO {
counter += 1;
}
let elapsed = Instant::now() - start;
// Report the elapsed time
led.set_low();
info!(
"At {}Mhz: Elapsed time to count to {}: {}ms",
sys_freq / 1_000_000,
counter,
elapsed.as_millis()
);
// Wait 2 seconds before starting the next measurement
Timer::after(Duration::from_secs(2)).await;
}
}

View File

@ -0,0 +1,79 @@
//! # Overclocking the RP2040 to 200 MHz manually
//!
//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz.
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::clocks;
use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig};
use embassy_rp::config::Config;
use embassy_rp::gpio::{Level, Output};
use embassy_time::{Duration, Instant, Timer};
use {defmt_rtt as _, panic_probe as _};
const COUNT_TO: i64 = 10_000_000;
/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings.
fn configure_manual_overclock() -> Config {
// Set the PLL configuration manually, starting from default values
let mut config = Config::default();
// Set the system clock to 200 MHz
config.clocks = ClockConfig::manual_pll(
12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value.
PllConfig {
refdiv: 1, // Reference divider
fbdiv: 100, // Feedback divider
post_div1: 3, // Post divider 1
post_div2: 2, // Post divider 2
},
CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz
);
config
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
// Initialize with our manual overclock configuration
let p = embassy_rp::init(configure_manual_overclock());
// Verify the actual system clock frequency
let sys_freq = clocks::clk_sys_freq();
info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
// LED to indicate the system is running
let mut led = Output::new(p.PIN_25, Level::Low);
loop {
// Reset the counter at the start of measurement period
let mut counter = 0;
// Turn LED on while counting
led.set_high();
let start = Instant::now();
// This is a busy loop that will take some time to complete
while counter < COUNT_TO {
counter += 1;
}
let elapsed = Instant::now() - start;
// Report the elapsed time
led.set_low();
info!(
"At {}Mhz: Elapsed time to count to {}: {}ms",
sys_freq / 1_000_000,
counter,
elapsed.as_millis()
);
// Wait 2 seconds before starting the next measurement
Timer::after(Duration::from_secs(2)).await;
}
}

View File

@ -31,7 +31,7 @@ use rand::RngCore;
use static_cell::{ConstStaticCell, StaticCell};
use {defmt_rtt as _, panic_probe as _};
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
struct MyType {
inner: u32,

View File

@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
async fn reader(mut rx: BufferedUartRx) {
info!("Reading...");
loop {
let mut buf = [0; 31];

View File

@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
async fn reader(mut rx: UartRx<'static, Async>) {
info!("Reading...");
loop {
// read a total of 4 transmissions (32 / 8) and then print the result

View File

@ -31,7 +31,7 @@ use rand::RngCore;
use static_cell::{ConstStaticCell, StaticCell};
use {defmt_rtt as _, panic_probe as _};
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
struct MyType {
inner: u32,

View File

@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
async fn reader(mut rx: BufferedUartRx) {
info!("Reading...");
loop {
let mut buf = [0; 31];

View File

@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
async fn reader(mut rx: UartRx<'static, Async>) {
info!("Reading...");
loop {
// read a total of 4 transmissions (32 / 8) and then print the result

View File

@ -0,0 +1,70 @@
#![no_std]
#![no_main]
#[cfg(feature = "rp2040")]
teleprobe_meta::target!(b"rpi-pico");
#[cfg(feature = "rp235xb")]
teleprobe_meta::target!(b"pimoroni-pico-plus-2");
use defmt::info;
#[cfg(feature = "rp2040")]
use defmt::{assert, assert_eq};
use embassy_executor::Spawner;
use embassy_rp::clocks;
#[cfg(feature = "rp2040")]
use embassy_rp::clocks::ClockConfig;
#[cfg(feature = "rp2040")]
use embassy_rp::clocks::CoreVoltage;
use embassy_rp::config::Config;
use embassy_time::Instant;
use {defmt_rtt as _, panic_probe as _};
const COUNT_TO: i64 = 10_000_000;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
#[cfg(feature = "rp2040")]
let mut config = Config::default();
#[cfg(not(feature = "rp2040"))]
let config = Config::default();
// Initialize with 200MHz clock configuration for RP2040, other chips will use default clock
#[cfg(feature = "rp2040")]
{
config.clocks = ClockConfig::system_freq(200_000_000);
let voltage = config.clocks.core_voltage;
assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15");
}
let _p = embassy_rp::init(config);
// Test the system speed
let (time_elapsed, clk_sys_freq) = {
let mut counter = 0;
let start = Instant::now();
while counter < COUNT_TO {
counter += 1;
}
let elapsed = Instant::now() - start;
(elapsed.as_millis(), clocks::clk_sys_freq())
};
// Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040
info!(
"At {}Mhz: Elapsed time to count to {}: {}ms",
clk_sys_freq / 1_000_000,
COUNT_TO,
time_elapsed
);
#[cfg(feature = "rp2040")]
{
// we should be at 200MHz
assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz");
// At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin
assert!(time_elapsed <= 606, "Elapsed time is too long");
}
cortex_m::asm::bkpt();
}

View File

@ -8,17 +8,17 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2");
use defmt::{assert_eq, *};
use embassy_executor::Spawner;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx};
use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> {
fn read<const N: usize>(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> {
let mut buf = [255; N];
uart.blocking_read(&mut buf)?;
Ok(buf)
}
fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> {
fn read1<const N: usize>(uart: &mut UartRx<'_, Blocking>) -> Result<[u8; N], Error> {
let mut buf = [255; N];
uart.blocking_read(&mut buf)?;
Ok(buf)

View File

@ -10,7 +10,7 @@ use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity};
use embassy_time::Timer;
use embedded_io_async::{Read, ReadExactError, Write};
use {defmt_rtt as _, panic_probe as _};
@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
UART0_IRQ => BufferedInterruptHandler<UART0>;
});
async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> {
async fn read<const N: usize>(uart: &mut BufferedUart) -> Result<[u8; N], Error> {
let mut buf = [255; N];
match uart.read_exact(&mut buf).await {
Ok(()) => Ok(buf),
@ -29,7 +29,7 @@ async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Res
}
}
async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> {
async fn read1<const N: usize>(uart: &mut BufferedUartRx) -> Result<[u8; N], Error> {
let mut buf = [255; N];
match uart.read_exact(&mut buf).await {
Ok(()) => Ok(buf),

View File

@ -10,7 +10,7 @@ use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx};
use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx};
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs {
UART0_IRQ => InterruptHandler<UART0>;
});
async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
async fn read<const N: usize>(uart: &mut Uart<'_, Async>) -> Result<[u8; N], Error> {
let mut buf = [255; N];
uart.read(&mut buf).await?;
Ok(buf)
}
async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
async fn read1<const N: usize>(uart: &mut UartRx<'_, Async>) -> Result<[u8; N], Error> {
let mut buf = [255; N];
uart.read(&mut buf).await?;
Ok(buf)