Merge branch 'main' into add-rng
This commit is contained in:
commit
102258c0b0
@ -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
|
The following peripherals have a HAL implementation at present
|
||||||
|
|
||||||
|
* CRC
|
||||||
* GPIO
|
* GPIO
|
||||||
* RNG
|
* RNG
|
||||||
|
|||||||
190
embassy-imxrt/src/crc.rs
Normal file
190
embassy-imxrt/src/crc.rs
Normal 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() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ compile_error!(
|
|||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
|
||||||
pub mod clocks;
|
pub mod clocks;
|
||||||
|
pub mod crc;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod iopctl;
|
pub mod iopctl;
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
|
|||||||
@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
|
|||||||
PPI_GROUP4,
|
PPI_GROUP4,
|
||||||
PPI_GROUP5,
|
PPI_GROUP5,
|
||||||
|
|
||||||
|
// IPC
|
||||||
|
IPC,
|
||||||
|
|
||||||
// GPIO port 0
|
// GPIO port 0
|
||||||
#[cfg(feature = "lfxo-pins-as-gpio")]
|
#[cfg(feature = "lfxo-pins-as-gpio")]
|
||||||
P0_00,
|
P0_00,
|
||||||
@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
|
|||||||
EGU5,
|
EGU5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_ipc!(IPC, IPC, IPC);
|
||||||
|
|
||||||
impl_usb!(USBD, USBD, USBD);
|
impl_usb!(USBD, USBD, USBD);
|
||||||
|
|
||||||
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
||||||
|
|||||||
@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
|
|||||||
PPI_GROUP4,
|
PPI_GROUP4,
|
||||||
PPI_GROUP5,
|
PPI_GROUP5,
|
||||||
|
|
||||||
|
// IPC
|
||||||
|
IPC,
|
||||||
|
|
||||||
// GPIO port 0
|
// GPIO port 0
|
||||||
P0_00,
|
P0_00,
|
||||||
P0_01,
|
P0_01,
|
||||||
@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
|
|||||||
EGU0,
|
EGU0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_ipc!(IPC, IPC, IPC);
|
||||||
|
|
||||||
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
||||||
impl_spim!(SERIAL0, SPIM0, SERIAL0);
|
impl_spim!(SERIAL0, SPIM0, SERIAL0);
|
||||||
impl_spis!(SERIAL0, SPIS0, SERIAL0);
|
impl_spis!(SERIAL0, SPIS0, SERIAL0);
|
||||||
|
|||||||
363
embassy-nrf/src/ipc.rs
Normal file
363
embassy-nrf/src/ipc.rs
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -88,6 +88,8 @@ pub mod gpiote;
|
|||||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||||
pub mod i2s;
|
pub mod i2s;
|
||||||
|
#[cfg(feature = "_nrf5340")]
|
||||||
|
pub mod ipc;
|
||||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "nrf52832",
|
feature = "nrf52832",
|
||||||
|
|||||||
@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "rt" ]
|
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" ]
|
rt = [ "rp-pac/rt" ]
|
||||||
|
|
||||||
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
|
## 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
25
embassy-rp/src/pio_programs/clock_divider.rs
Normal file
25
embassy-rp/src/pio_programs/clock_divider.rs
Normal 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()
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ use crate::pio::{
|
|||||||
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
|
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
|
||||||
StateMachine,
|
StateMachine,
|
||||||
};
|
};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
|
/// 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();
|
let mut cfg = Config::default();
|
||||||
cfg.use_program(&word_prg.prg, &[&e]);
|
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.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||||
cfg.shift_out = ShiftConfig {
|
cfg.shift_out = ShiftConfig {
|
||||||
auto_fill: true,
|
auto_fill: true,
|
||||||
@ -160,7 +164,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
|
|||||||
|
|
||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.use_program(&seq_prg.prg, &[&e]);
|
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_jmp_pin(&db7);
|
||||||
cfg.set_set_pins(&[&rs, &rw]);
|
cfg.set_set_pins(&[&rs, &rw]);
|
||||||
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
//! Pre-built pio programs for common interfaces
|
//! Pre-built pio programs for common interfaces
|
||||||
|
|
||||||
|
pub mod clock_divider;
|
||||||
pub mod hd44780;
|
pub mod hd44780;
|
||||||
pub mod i2s;
|
pub mod i2s;
|
||||||
pub mod onewire;
|
pub mod onewire;
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
//! PIO backed quadrature encoder
|
//! PIO backed quadrature encoder
|
||||||
|
|
||||||
use fixed::traits::ToFixed;
|
|
||||||
|
|
||||||
use crate::gpio::Pull;
|
use crate::gpio::Pull;
|
||||||
use crate::pio::{
|
use crate::pio::{
|
||||||
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
|
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
|
||||||
};
|
};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents an Encoder program loaded into pio instruction memory.
|
/// 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.set_in_pins(&[&pin_a, &pin_b]);
|
||||||
cfg.fifo_join = FifoJoin::RxOnly;
|
cfg.fifo_join = FifoJoin::RxOnly;
|
||||||
cfg.shift_in.direction = ShiftDirection::Left;
|
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, &[]);
|
cfg.use_program(&program.prg, &[]);
|
||||||
sm.set_config(&cfg);
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
|
|||||||
@ -2,11 +2,8 @@
|
|||||||
|
|
||||||
use core::mem::{self, MaybeUninit};
|
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::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents a Stepper driver program loaded into pio instruction memory.
|
/// 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]);
|
sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
|
||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
|
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, &[]);
|
cfg.use_program(&program.prg, &[]);
|
||||||
sm.set_config(&cfg);
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
@ -73,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
|
|||||||
|
|
||||||
/// Set pulse frequency
|
/// Set pulse frequency
|
||||||
pub fn set_frequency(&mut self, freq: u32) {
|
pub fn set_frequency(&mut self, freq: u32) {
|
||||||
let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
|
let clock_divider = calculate_pio_clock_divider(freq * 136);
|
||||||
assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
|
let divider_f32 = clock_divider.to_num::<f32>();
|
||||||
assert!(clock_divider >= 1, "clkdiv must be >= 1");
|
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.set_clock_divider(clock_divider);
|
||||||
self.sm.clkdiv_restart();
|
self.sm.clkdiv_restart();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,28 +34,29 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Buffered UART driver.
|
/// Buffered UART driver.
|
||||||
pub struct BufferedUart<'d, T: Instance> {
|
pub struct BufferedUart {
|
||||||
pub(crate) rx: BufferedUartRx<'d, T>,
|
pub(super) rx: BufferedUartRx,
|
||||||
pub(crate) tx: BufferedUartTx<'d, T>,
|
pub(super) tx: BufferedUartTx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Buffered UART RX handle.
|
/// Buffered UART RX handle.
|
||||||
pub struct BufferedUartRx<'d, T: Instance> {
|
pub struct BufferedUartRx {
|
||||||
pub(crate) phantom: PhantomData<&'d mut T>,
|
pub(super) info: &'static Info,
|
||||||
|
pub(super) state: &'static State,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Buffered UART TX handle.
|
/// Buffered UART TX handle.
|
||||||
pub struct BufferedUartTx<'d, T: Instance> {
|
pub struct BufferedUartTx {
|
||||||
pub(crate) phantom: PhantomData<&'d mut T>,
|
pub(super) info: &'static Info,
|
||||||
|
pub(super) state: &'static State,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
pub(super) fn init_buffers<'d>(
|
||||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
info: &Info,
|
||||||
|
state: &State,
|
||||||
tx_buffer: Option<&'d mut [u8]>,
|
tx_buffer: Option<&'d mut [u8]>,
|
||||||
rx_buffer: Option<&'d mut [u8]>,
|
rx_buffer: Option<&'d mut [u8]>,
|
||||||
) {
|
) {
|
||||||
let state = T::buffered_state();
|
|
||||||
|
|
||||||
if let Some(tx_buffer) = tx_buffer {
|
if let Some(tx_buffer) = tx_buffer {
|
||||||
let len = tx_buffer.len();
|
let len = tx_buffer.len();
|
||||||
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), 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
|
// 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
|
// 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.
|
// to pend the ISR when we want data transmission to start.
|
||||||
let regs = T::regs();
|
info.regs.uartimsc().write(|w| {
|
||||||
regs.uartimsc().write(|w| {
|
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
w.set_txim(true);
|
w.set_txim(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
info.interrupt.unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { info.interrupt.enable() };
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUart<'d, T> {
|
impl BufferedUart {
|
||||||
/// Create a buffered UART instance.
|
/// Create a buffered UART instance.
|
||||||
pub fn new(
|
pub fn new<'d, T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<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],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config);
|
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, 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 {
|
Self {
|
||||||
rx: BufferedUartRx { phantom: PhantomData },
|
rx: BufferedUartRx {
|
||||||
tx: BufferedUartTx { phantom: PhantomData },
|
info: T::info(),
|
||||||
|
state: T::buffered_state(),
|
||||||
|
},
|
||||||
|
tx: BufferedUartTx {
|
||||||
|
info: T::info(),
|
||||||
|
state: T::buffered_state(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a buffered UART instance with flow control.
|
/// 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>,
|
_uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<T>>,
|
rx: Peri<'d, impl RxPin<T>>,
|
||||||
rts: Peri<'d, impl RtsPin<T>>,
|
rts: Peri<'d, impl RtsPin<T>>,
|
||||||
cts: Peri<'d, impl CtsPin<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],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(
|
super::Uart::<'d, Async>::init(
|
||||||
|
T::info(),
|
||||||
Some(tx.into()),
|
Some(tx.into()),
|
||||||
Some(rx.into()),
|
Some(rx.into()),
|
||||||
Some(rts.into()),
|
Some(rts.into()),
|
||||||
Some(cts.into()),
|
Some(cts.into()),
|
||||||
config,
|
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 {
|
Self {
|
||||||
rx: BufferedUartRx { phantom: PhantomData },
|
rx: BufferedUartRx {
|
||||||
tx: BufferedUartTx { phantom: PhantomData },
|
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
|
/// sets baudrate on runtime
|
||||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
pub fn set_baudrate<'d>(&mut self, baudrate: u32) {
|
||||||
super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
|
super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split into separate RX and TX handles.
|
/// 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)
|
(self.tx, self.rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||||
/// which is particularly useful when having two tasks correlating to
|
/// which is particularly useful when having two tasks correlating to
|
||||||
/// transmitting and receiving.
|
/// 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)
|
(&mut self.tx, &mut self.rx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
impl BufferedUartRx {
|
||||||
/// Create a new buffered UART RX.
|
/// Create a new buffered UART RX.
|
||||||
pub fn new(
|
pub fn new<'d, T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_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: Peri<'d, impl RxPin<T>>,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config);
|
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||||
init_buffers::<T>(irq, None, Some(rx_buffer));
|
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.
|
/// 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>,
|
_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: Peri<'d, impl RxPin<T>>,
|
||||||
rts: Peri<'d, impl RtsPin<T>>,
|
rts: Peri<'d, impl RtsPin<T>>,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config);
|
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config);
|
||||||
init_buffers::<T>(irq, None, Some(rx_buffer));
|
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
|
fn read<'a>(
|
||||||
where
|
info: &'static Info,
|
||||||
T: 'd,
|
state: &'static State,
|
||||||
{
|
buf: &'a mut [u8],
|
||||||
|
) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||||
poll_fn(move |cx| {
|
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);
|
return Poll::Ready(r);
|
||||||
}
|
}
|
||||||
T::buffered_state().rx_waker.register(cx.waker());
|
state.rx_waker.register(cx.waker());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rx_error() -> Option<Error> {
|
fn get_rx_error(state: &State) -> Option<Error> {
|
||||||
let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed);
|
let errs = state.rx_error.swap(0, Ordering::Relaxed);
|
||||||
if errs & RXE_OVERRUN != 0 {
|
if errs & RXE_OVERRUN != 0 {
|
||||||
Some(Error::Overrun)
|
Some(Error::Overrun)
|
||||||
} else if errs & RXE_BREAK != 0 {
|
} 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>>
|
fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
|
||||||
where
|
|
||||||
T: 'd,
|
|
||||||
{
|
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Poll::Ready(Ok(0));
|
return Poll::Ready(Ok(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = T::buffered_state();
|
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let n = rx_reader.pop(|data| {
|
let n = rx_reader.pop(|data| {
|
||||||
let n = data.len().min(buf.len());
|
let n = data.len().min(buf.len());
|
||||||
@ -252,7 +268,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let result = if n == 0 {
|
let result = if n == 0 {
|
||||||
match Self::get_rx_error() {
|
match Self::get_rx_error(state) {
|
||||||
None => return Poll::Pending,
|
None => return Poll::Pending,
|
||||||
Some(e) => Err(e),
|
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
|
// (Re-)Enable the interrupt to receive more data in case it was
|
||||||
// disabled because the buffer was full or errors were detected.
|
// disabled because the buffer was full or errors were detected.
|
||||||
let regs = T::regs();
|
info.regs.uartimsc().write_set(|w| {
|
||||||
regs.uartimsc().write_set(|w| {
|
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(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.
|
/// Read from UART RX buffer blocking execution until done.
|
||||||
pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
loop {
|
loop {
|
||||||
match Self::try_read(buf) {
|
match Self::try_read(self.info, self.state, buf) {
|
||||||
Poll::Ready(res) => return res,
|
Poll::Ready(res) => return res,
|
||||||
Poll::Pending => continue,
|
Poll::Pending => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>>
|
fn fill_buf<'a>(state: &'static State) -> impl Future<Output = Result<&'a [u8], Error>> {
|
||||||
where
|
|
||||||
T: 'd,
|
|
||||||
{
|
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let (p, n) = rx_reader.pop_buf();
|
let (p, n) = rx_reader.pop_buf();
|
||||||
let result = if n == 0 {
|
let result = if n == 0 {
|
||||||
match Self::get_rx_error() {
|
match Self::get_rx_error(state) {
|
||||||
None => {
|
None => {
|
||||||
state.rx_waker.register(cx.waker());
|
state.rx_waker.register(cx.waker());
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@ -306,64 +317,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(amt: usize) {
|
fn consume(info: &Info, state: &State, amt: usize) {
|
||||||
let state = T::buffered_state();
|
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
rx_reader.pop_done(amt);
|
rx_reader.pop_done(amt);
|
||||||
|
|
||||||
// (Re-)Enable the interrupt to receive more data in case it was
|
// (Re-)Enable the interrupt to receive more data in case it was
|
||||||
// disabled because the buffer was full or errors were detected.
|
// disabled because the buffer was full or errors were detected.
|
||||||
let regs = T::regs();
|
info.regs.uartimsc().write_set(|w| {
|
||||||
regs.uartimsc().write_set(|w| {
|
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// we are ready to read if there is data in the buffer
|
/// we are ready to read if there is data in the buffer
|
||||||
fn read_ready() -> Result<bool, Error> {
|
fn read_ready(state: &State) -> Result<bool, Error> {
|
||||||
let state = T::buffered_state();
|
|
||||||
Ok(!state.rx_buf.is_empty())
|
Ok(!state.rx_buf.is_empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
impl BufferedUartTx {
|
||||||
/// Create a new buffered UART TX.
|
/// Create a new buffered UART TX.
|
||||||
pub fn new(
|
pub fn new<'d, T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_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: Peri<'d, impl TxPin<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config);
|
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||||
init_buffers::<T>(irq, Some(tx_buffer), None);
|
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.
|
/// 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>,
|
_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: Peri<'d, impl TxPin<T>>,
|
||||||
cts: Peri<'d, impl CtsPin<T>>,
|
cts: Peri<'d, impl CtsPin<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config);
|
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config);
|
||||||
init_buffers::<T>(irq, Some(tx_buffer), None);
|
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| {
|
poll_fn(move |cx| {
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Poll::Ready(Ok(0));
|
return Poll::Ready(Ok(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = T::buffered_state();
|
|
||||||
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
||||||
let n = tx_writer.push(|data| {
|
let n = tx_writer.push(|data| {
|
||||||
let n = data.len().min(buf.len());
|
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 and the number of bytes drops below a threshold. When the
|
||||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||||
// TX data from the buffer into the FIFO.
|
// TX data from the buffer into the FIFO.
|
||||||
T::Interrupt::pend();
|
info.interrupt.pend();
|
||||||
Poll::Ready(Ok(n))
|
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| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
|
||||||
if !state.tx_buf.is_empty() {
|
if !state.tx_buf.is_empty() {
|
||||||
state.tx_waker.register(cx.waker());
|
state.tx_waker.register(cx.waker());
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
@ -403,8 +419,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let state = T::buffered_state();
|
let mut tx_writer = unsafe { self.state.tx_buf.writer() };
|
||||||
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
|
||||||
let n = tx_writer.push(|data| {
|
let n = tx_writer.push(|data| {
|
||||||
let n = data.len().min(buf.len());
|
let n = data.len().min(buf.len());
|
||||||
data[..n].copy_from_slice(&buf[..n]);
|
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 and the number of bytes drops below a threshold. When the
|
||||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||||
// TX data from the buffer into the FIFO.
|
// TX data from the buffer into the FIFO.
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
return Ok(n);
|
return Ok(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,8 +440,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
/// Flush UART TX blocking execution until done.
|
/// Flush UART TX blocking execution until done.
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = T::buffered_state();
|
if self.state.tx_buf.is_empty() {
|
||||||
if state.tx_buf.is_empty() {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -434,7 +448,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
|
|
||||||
/// Check if UART is busy.
|
/// Check if UART is busy.
|
||||||
pub fn busy(&self) -> bool {
|
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,
|
/// 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
|
/// 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.
|
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||||
pub async fn send_break(&mut self, bits: u32) {
|
pub async fn send_break(&mut self, bits: u32) {
|
||||||
let regs = T::regs();
|
let regs = self.info.regs;
|
||||||
let bits = bits.max({
|
let bits = bits.max({
|
||||||
let lcr = regs.uartlcr_h().read();
|
let lcr = regs.uartlcr_h().read();
|
||||||
let width = lcr.wlen() as u32 + 5;
|
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 div_clk = clk_peri_freq() as u64 * 64;
|
||||||
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
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() {}
|
while self.busy() {}
|
||||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||||
Timer::after_micros(wait_usecs).await;
|
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) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
unsafe { self.state.rx_buf.deinit() }
|
||||||
unsafe { state.rx_buf.deinit() }
|
|
||||||
|
|
||||||
// TX is inactive if the buffer is not available.
|
// TX is inactive if the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if !state.tx_buf.is_available() {
|
if !self.state.tx_buf.is_available() {
|
||||||
T::Interrupt::disable();
|
self.info.interrupt.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
|
impl Drop for BufferedUartTx {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
unsafe { self.state.tx_buf.deinit() }
|
||||||
unsafe { state.tx_buf.deinit() }
|
|
||||||
|
|
||||||
// RX is inactive if the buffer is not available.
|
// RX is inactive if the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if !state.rx_buf.is_available() {
|
if !self.state.rx_buf.is_available() {
|
||||||
T::Interrupt::disable();
|
self.info.interrupt.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,7 +511,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
|
|||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::info().regs;
|
||||||
if r.uartdmacr().read().rxdmae() {
|
if r.uartdmacr().read().rxdmae() {
|
||||||
return;
|
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;
|
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;
|
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;
|
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> {
|
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> {
|
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> {
|
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> {
|
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> {
|
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) {
|
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> {
|
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) {
|
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> {
|
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> {
|
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> {
|
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> {
|
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> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.rx.blocking_read(buf)
|
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> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_read(buf)
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.tx.blocking_write(buf)
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_write(buf)
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::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() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::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;
|
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;
|
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;
|
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> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
embedded_hal_02::serial::Read::read(self)
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
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>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ use pac::uart::regs::Uartris;
|
|||||||
use crate::clocks::clk_peri_freq;
|
use crate::clocks::clk_peri_freq;
|
||||||
use crate::dma::{AnyChannel, Channel};
|
use crate::dma::{AnyChannel, Channel};
|
||||||
use crate::gpio::{AnyPin, SealedPin};
|
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::pac::io::vals::{Inover, Outover};
|
||||||
use crate::{interrupt, pac, peripherals, RegExt};
|
use crate::{interrupt, pac, peripherals, RegExt};
|
||||||
|
|
||||||
@ -135,37 +136,41 @@ pub struct DmaState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// UART driver.
|
/// UART driver.
|
||||||
pub struct Uart<'d, T: Instance, M: Mode> {
|
pub struct Uart<'d, M: Mode> {
|
||||||
tx: UartTx<'d, T, M>,
|
tx: UartTx<'d, M>,
|
||||||
rx: UartRx<'d, T, M>,
|
rx: UartRx<'d, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UART TX driver.
|
/// 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>>,
|
tx_dma: Option<Peri<'d, AnyChannel>>,
|
||||||
phantom: PhantomData<(&'d mut T, M)>,
|
phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UART RX driver.
|
/// 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>>,
|
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
|
/// Create a new DMA-enabled UART which can only send data
|
||||||
pub fn new(
|
pub fn new<T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
tx_dma: Peri<'d, impl Channel>,
|
tx_dma: Peri<'d, impl Channel>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Uart::<T, M>::init(Some(tx.into()), None, None, None, config);
|
Uart::<M>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||||
Self::new_inner(Some(tx_dma.into()))
|
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 {
|
Self {
|
||||||
|
info,
|
||||||
tx_dma,
|
tx_dma,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
|||||||
|
|
||||||
/// Transmit the provided buffer blocking execution until done.
|
/// Transmit the provided buffer blocking execution until done.
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
for &b in buffer {
|
for &b in buffer {
|
||||||
while r.uartfr().read().txff() {}
|
while r.uartfr().read().txff() {}
|
||||||
r.uartdr().write(|w| w.set_data(b));
|
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.
|
/// Flush UART TX blocking execution until done.
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
while !self.info.regs.uartfr().read().txfe() {}
|
||||||
while !r.uartfr().read().txfe() {}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if UART is busy transmitting.
|
/// Check if UART is busy transmitting.
|
||||||
pub fn busy(&self) -> bool {
|
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,
|
/// 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
|
/// 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.
|
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||||
pub async fn send_break(&mut self, bits: u32) {
|
pub async fn send_break(&mut self, bits: u32) {
|
||||||
let regs = T::regs();
|
let regs = self.info.regs;
|
||||||
let bits = bits.max({
|
let bits = bits.max({
|
||||||
let lcr = regs.uartlcr_h().read();
|
let lcr = regs.uartlcr_h().read();
|
||||||
let width = lcr.wlen() as u32 + 5;
|
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.
|
/// 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 {
|
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
|
||||||
Uart::<T, Blocking>::init(Some(tx.into()), None, None, None, config);
|
Uart::<Blocking>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||||
Self::new_inner(None)
|
Self::new_inner(T::info(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this uart TX instance into a buffered uart using the provided
|
/// Convert this uart TX instance into a buffered uart using the provided
|
||||||
/// irq and transmit buffer.
|
/// irq and transmit buffer.
|
||||||
pub fn into_buffered(
|
pub fn into_buffered<T: Instance>(
|
||||||
self,
|
self,
|
||||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUartTx<'d, T> {
|
) -> BufferedUartTx {
|
||||||
buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
|
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.
|
/// Write to UART TX from the provided buffer using DMA.
|
||||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
let ch = self.tx_dma.as_mut().unwrap().reborrow();
|
let ch = self.tx_dma.as_mut().unwrap().reborrow();
|
||||||
let transfer = unsafe {
|
let transfer = unsafe {
|
||||||
T::regs().uartdmacr().write_set(|reg| {
|
self.info.regs.uartdmacr().write_set(|reg| {
|
||||||
reg.set_txdmae(true);
|
reg.set_txdmae(true);
|
||||||
});
|
});
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// 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;
|
transfer.await;
|
||||||
Ok(())
|
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
|
/// Create a new DMA-enabled UART which can only receive data
|
||||||
pub fn new(
|
pub fn new<T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_uart: Peri<'d, T>,
|
||||||
rx: Peri<'d, impl RxPin<T>>,
|
rx: Peri<'d, impl RxPin<T>>,
|
||||||
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||||
rx_dma: Peri<'d, impl Channel>,
|
rx_dma: Peri<'d, impl Channel>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Uart::<T, M>::init(None, Some(rx.into()), None, None, config);
|
Uart::<M>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||||
Self::new_inner(true, Some(rx_dma.into()))
|
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());
|
debug_assert_eq!(has_irq, rx_dma.is_some());
|
||||||
if has_irq {
|
if has_irq {
|
||||||
// disable all error interrupts initially
|
// disable all error interrupts initially
|
||||||
T::regs().uartimsc().write(|w| w.0 = 0);
|
info.regs.uartimsc().write(|w| w.0 = 0);
|
||||||
T::Interrupt::unpend();
|
info.interrupt.unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { info.interrupt.enable() };
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
|
info,
|
||||||
|
dma_state,
|
||||||
rx_dma,
|
rx_dma,
|
||||||
phantom: PhantomData,
|
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
|
/// encountered. in both cases, `len` is the number of *good* bytes copied into
|
||||||
/// `buffer`.
|
/// `buffer`.
|
||||||
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
|
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() {
|
for (i, b) in buffer.iter_mut().enumerate() {
|
||||||
if r.uartfr().read().rxfe() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Ok(i);
|
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) {
|
fn drop(&mut self) {
|
||||||
if self.rx_dma.is_some() {
|
if self.rx_dma.is_some() {
|
||||||
T::Interrupt::disable();
|
self.info.interrupt.disable();
|
||||||
// clear dma flags. irq handlers use these to disambiguate among themselves.
|
// 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_rxdmae(true);
|
||||||
reg.set_txdmae(true);
|
reg.set_txdmae(true);
|
||||||
reg.set_dmaonerr(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.
|
/// 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 {
|
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
|
||||||
Uart::<T, Blocking>::init(None, Some(rx.into()), None, None, config);
|
Uart::<Blocking>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||||
Self::new_inner(false, None)
|
Self::new_inner(T::info(), T::dma_state(), false, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this uart RX instance into a buffered uart using the provided
|
/// Convert this uart RX instance into a buffered uart using the provided
|
||||||
/// irq and receive buffer.
|
/// irq and receive buffer.
|
||||||
pub fn into_buffered(
|
pub fn into_buffered<T: Instance>(
|
||||||
self,
|
self,
|
||||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUartRx<'d, T> {
|
) -> BufferedUartRx {
|
||||||
buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
|
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> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let uart = T::regs();
|
let uart = T::info().regs;
|
||||||
if !uart.uartdmacr().read().rxdmae() {
|
if !uart.uartdmacr().read().rxdmae() {
|
||||||
return;
|
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.
|
/// Read from UART RX into the provided buffer.
|
||||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
// clear error flags before we drain the fifo. errors that have accumulated
|
// clear error flags before we drain the fifo. errors that have accumulated
|
||||||
// in the flags will also be present in the fifo.
|
// in the flags will also be present in the fifo.
|
||||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
|
||||||
T::regs().uarticr().write(|w| {
|
self.info.regs.uarticr().write(|w| {
|
||||||
w.set_oeic(true);
|
w.set_oeic(true);
|
||||||
w.set_beic(true);
|
w.set_beic(true);
|
||||||
w.set_peic(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
|
// interrupt flags will have been raised, and those will be picked up immediately
|
||||||
// by the interrupt handler.
|
// by the interrupt handler.
|
||||||
let ch = self.rx_dma.as_mut().unwrap().reborrow();
|
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_oeim(true);
|
||||||
w.set_beim(true);
|
w.set_beim(true);
|
||||||
w.set_peim(true);
|
w.set_peim(true);
|
||||||
w.set_feim(true);
|
w.set_feim(true);
|
||||||
});
|
});
|
||||||
T::regs().uartdmacr().write_set(|reg| {
|
self.info.regs.uartdmacr().write_set(|reg| {
|
||||||
reg.set_rxdmae(true);
|
reg.set_rxdmae(true);
|
||||||
reg.set_dmaonerr(true);
|
reg.set_dmaonerr(true);
|
||||||
});
|
});
|
||||||
let transfer = unsafe {
|
let transfer = unsafe {
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// 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.
|
// wait for either the transfer to complete or an error to happen.
|
||||||
let transfer_result = select(
|
let transfer_result = select(
|
||||||
transfer,
|
transfer,
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
T::dma_state().rx_err_waker.register(cx.waker());
|
self.dma_state.rx_err_waker.register(cx.waker());
|
||||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
|
||||||
0 => Poll::Pending,
|
0 => Poll::Pending,
|
||||||
e => Poll::Ready(Uartris(e as u32)),
|
e => Poll::Ready(Uartris(e as u32)),
|
||||||
}
|
}
|
||||||
@ -441,7 +468,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
Either::First(()) => {
|
Either::First(()) => {
|
||||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
// 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!
|
// 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) => {
|
Either::Second(e) => {
|
||||||
// We're here because we errored, which means this is the error that
|
// 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> {
|
) -> Result<usize, ReadToBreakError> {
|
||||||
// clear error flags before we drain the fifo. errors that have accumulated
|
// clear error flags before we drain the fifo. errors that have accumulated
|
||||||
// in the flags will also be present in the fifo.
|
// in the flags will also be present in the fifo.
|
||||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
|
||||||
T::regs().uarticr().write(|w| {
|
self.info.regs.uarticr().write(|w| {
|
||||||
w.set_oeic(true);
|
w.set_oeic(true);
|
||||||
w.set_beic(true);
|
w.set_beic(true);
|
||||||
w.set_peic(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
|
// interrupt flags will have been raised, and those will be picked up immediately
|
||||||
// by the interrupt handler.
|
// by the interrupt handler.
|
||||||
let ch = self.rx_dma.as_mut().unwrap();
|
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_oeim(true);
|
||||||
w.set_beim(true);
|
w.set_beim(true);
|
||||||
w.set_peim(true);
|
w.set_peim(true);
|
||||||
w.set_feim(true);
|
w.set_feim(true);
|
||||||
});
|
});
|
||||||
T::regs().uartdmacr().write_set(|reg| {
|
self.info.regs.uartdmacr().write_set(|reg| {
|
||||||
reg.set_rxdmae(true);
|
reg.set_rxdmae(true);
|
||||||
reg.set_dmaonerr(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.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::read(
|
crate::dma::read(
|
||||||
ch.reborrow(),
|
ch.reborrow(),
|
||||||
T::regs().uartdr().as_ptr() as *const _,
|
self.info.regs.uartdr().as_ptr() as *const _,
|
||||||
sbuffer,
|
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(
|
let transfer_result = select(
|
||||||
transfer,
|
transfer,
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
T::dma_state().rx_err_waker.register(cx.waker());
|
self.dma_state.rx_err_waker.register(cx.waker());
|
||||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
|
||||||
0 => Poll::Pending,
|
0 => Poll::Pending,
|
||||||
e => Poll::Ready(Uartris(e as u32)),
|
e => Poll::Ready(Uartris(e as u32)),
|
||||||
}
|
}
|
||||||
@ -596,7 +623,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
Either::First(()) => {
|
Either::First(()) => {
|
||||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
// 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!
|
// 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) => {
|
Either::Second(e) => {
|
||||||
// We're here because we errored, which means this is the error that
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = self.info.regs;
|
||||||
let all_full = next_addr == eval;
|
let all_full = next_addr == eval;
|
||||||
|
|
||||||
// NOTE: This is off label usage of RSR! See the issue below for
|
// 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
|
/// Create a new UART without hardware flow control
|
||||||
pub fn new_blocking(
|
pub fn new_blocking<T: Instance>(
|
||||||
uart: Peri<'d, T>,
|
uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<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)
|
/// 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>,
|
uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<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
|
/// Convert this uart instance into a buffered uart using the provided
|
||||||
/// irq, transmit and receive buffers.
|
/// irq, transmit and receive buffers.
|
||||||
pub fn into_buffered(
|
pub fn into_buffered<T: Instance>(
|
||||||
self,
|
self,
|
||||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
) -> BufferedUart<'d, T> {
|
) -> BufferedUart {
|
||||||
buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
|
buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
|
||||||
|
|
||||||
BufferedUart {
|
BufferedUart {
|
||||||
rx: BufferedUartRx { phantom: PhantomData },
|
rx: BufferedUartRx {
|
||||||
tx: BufferedUartTx { phantom: PhantomData },
|
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
|
/// Create a new DMA enabled UART without hardware flow control
|
||||||
pub fn new(
|
pub fn new<T: Instance>(
|
||||||
uart: Peri<'d, T>,
|
uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<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)
|
/// 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>,
|
uart: Peri<'d, T>,
|
||||||
tx: Peri<'d, impl TxPin<T>>,
|
tx: Peri<'d, impl TxPin<T>>,
|
||||||
rx: Peri<'d, impl RxPin<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> {
|
impl<'d, M: Mode> Uart<'d, M> {
|
||||||
fn new_inner(
|
fn new_inner<T: Instance>(
|
||||||
_uart: Peri<'d, T>,
|
_uart: Peri<'d, T>,
|
||||||
mut tx: Peri<'d, AnyPin>,
|
mut tx: Peri<'d, AnyPin>,
|
||||||
mut rx: 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,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::init(
|
Self::init(
|
||||||
|
T::info(),
|
||||||
Some(tx.reborrow()),
|
Some(tx.reborrow()),
|
||||||
Some(rx.reborrow()),
|
Some(rx.reborrow()),
|
||||||
rts.as_mut().map(|x| x.reborrow()),
|
rts.as_mut().map(|x| x.reborrow()),
|
||||||
@ -806,19 +840,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tx: UartTx::new_inner(tx_dma),
|
tx: UartTx::new_inner(T::info(), tx_dma),
|
||||||
rx: UartRx::new_inner(has_irq, rx_dma),
|
rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
|
info: &Info,
|
||||||
tx: Option<Peri<'_, AnyPin>>,
|
tx: Option<Peri<'_, AnyPin>>,
|
||||||
rx: Option<Peri<'_, AnyPin>>,
|
rx: Option<Peri<'_, AnyPin>>,
|
||||||
rts: Option<Peri<'_, AnyPin>>,
|
rts: Option<Peri<'_, AnyPin>>,
|
||||||
cts: Option<Peri<'_, AnyPin>>,
|
cts: Option<Peri<'_, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) {
|
) {
|
||||||
let r = T::regs();
|
let r = info.regs;
|
||||||
if let Some(pin) = &tx {
|
if let Some(pin) = &tx {
|
||||||
let funcsel = {
|
let funcsel = {
|
||||||
let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
|
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 {
|
let (pen, eps) = match config.parity {
|
||||||
Parity::ParityNone => (false, false),
|
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 {
|
fn lcr_modify<R>(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
|
||||||
let r = T::regs();
|
let r = info.regs;
|
||||||
|
|
||||||
// Notes from PL011 reference manual:
|
// Notes from PL011 reference manual:
|
||||||
//
|
//
|
||||||
@ -978,11 +1013,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
|
|
||||||
/// sets baudrate on runtime
|
/// sets baudrate on runtime
|
||||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
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) {
|
fn set_baudrate_inner(info: &Info, baudrate: u32) {
|
||||||
let r = T::regs();
|
let r = info.regs;
|
||||||
|
|
||||||
let clk_base = crate::clocks::clk_peri_freq();
|
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.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
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.
|
/// Transmit the provided buffer blocking execution until done.
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.tx.blocking_write(buffer)
|
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
|
/// Split the Uart into a transmitter and receiver, which is particularly
|
||||||
/// useful when having two tasks correlating to transmitting and receiving.
|
/// 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)
|
(self.tx, self.rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||||
/// which is particularly useful when having two tasks correlating to
|
/// which is particularly useful when having two tasks correlating to
|
||||||
/// transmitting and receiving.
|
/// 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)
|
(&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.
|
/// Write to UART TX from the provided buffer.
|
||||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.tx.write(buffer).await
|
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;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::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() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::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() {
|
if r.uartfr().read().txff() {
|
||||||
return Err(nb::Error::WouldBlock);
|
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>> {
|
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
if !r.uartfr().read().txfe() {
|
if !r.uartfr().read().txfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::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;
|
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;
|
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;
|
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> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
if r.uartfr().read().rxfe() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
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;
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_write(buf).map(|_| buf.len())
|
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>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
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;
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_write(buf).map(|_| buf.len())
|
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 SealedMode {}
|
||||||
|
|
||||||
trait SealedInstance {
|
trait SealedInstance {
|
||||||
const TX_DREQ: pac::dma::vals::TreqSel;
|
fn info() -> &'static Info;
|
||||||
const RX_DREQ: pac::dma::vals::TreqSel;
|
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart;
|
|
||||||
|
|
||||||
fn buffered_state() -> &'static buffered::State;
|
fn buffered_state() -> &'static buffered::State;
|
||||||
|
|
||||||
@ -1308,11 +1347,14 @@ pub trait Instance: SealedInstance + PeripheralType {
|
|||||||
macro_rules! impl_instance {
|
macro_rules! impl_instance {
|
||||||
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||||
impl SealedInstance for peripherals::$inst {
|
impl SealedInstance for peripherals::$inst {
|
||||||
const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
|
fn info() -> &'static Info {
|
||||||
const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
|
static INFO: Info = Info {
|
||||||
|
regs: pac::$inst,
|
||||||
fn regs() -> pac::uart::Uart {
|
tx_dreq: $tx_dreq,
|
||||||
pac::$inst
|
rx_dreq: $rx_dreq,
|
||||||
|
interrupt: crate::interrupt::typelevel::$irq::IRQ,
|
||||||
|
};
|
||||||
|
&INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffered_state() -> &'static buffered::State {
|
fn buffered_state() -> &'static buffered::State {
|
||||||
|
|||||||
@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> {
|
|||||||
/// PWM pin config
|
/// PWM pin config
|
||||||
///
|
///
|
||||||
/// This configures the pwm pin settings
|
/// This configures the pwm pin settings
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct PwmPinConfig {
|
pub struct PwmPinConfig {
|
||||||
/// PWM Pin output type
|
/// PWM Pin output type
|
||||||
pub output_type: OutputType,
|
pub output_type: OutputType,
|
||||||
|
|||||||
175
examples/mimxrt6/src/bin/crc.rs
Normal file
175
examples/mimxrt6/src/bin/crc.rs
Normal 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();
|
||||||
|
}
|
||||||
64
examples/rp/src/bin/overclock.rs
Normal file
64
examples/rp/src/bin/overclock.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
examples/rp/src/bin/overclock_manual.rs
Normal file
79
examples/rp/src/bin/overclock_manual.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -31,7 +31,7 @@ use rand::RngCore;
|
|||||||
use static_cell::{ConstStaticCell, StaticCell};
|
use static_cell::{ConstStaticCell, StaticCell};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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 {
|
struct MyType {
|
||||||
inner: u32,
|
inner: u32,
|
||||||
|
|||||||
@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
|
async fn reader(mut rx: BufferedUartRx) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 31];
|
let mut buf = [0; 31];
|
||||||
|
|||||||
@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
|
async fn reader(mut rx: UartRx<'static, Async>) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
loop {
|
loop {
|
||||||
// read a total of 4 transmissions (32 / 8) and then print the result
|
// read a total of 4 transmissions (32 / 8) and then print the result
|
||||||
|
|||||||
@ -31,7 +31,7 @@ use rand::RngCore;
|
|||||||
use static_cell::{ConstStaticCell, StaticCell};
|
use static_cell::{ConstStaticCell, StaticCell};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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 {
|
struct MyType {
|
||||||
inner: u32,
|
inner: u32,
|
||||||
|
|||||||
@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
|
async fn reader(mut rx: BufferedUartRx) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0; 31];
|
let mut buf = [0; 31];
|
||||||
|
|||||||
@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
|
async fn reader(mut rx: UartRx<'static, Async>) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
loop {
|
loop {
|
||||||
// read a total of 4 transmissions (32 / 8) and then print the result
|
// read a total of 4 transmissions (32 / 8) and then print the result
|
||||||
|
|||||||
70
tests/rp/src/bin/overclock.rs
Normal file
70
tests/rp/src/bin/overclock.rs
Normal 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();
|
||||||
|
}
|
||||||
@ -8,17 +8,17 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2");
|
|||||||
use defmt::{assert_eq, *};
|
use defmt::{assert_eq, *};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
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 embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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];
|
let mut buf = [255; N];
|
||||||
uart.blocking_read(&mut buf)?;
|
uart.blocking_read(&mut buf)?;
|
||||||
Ok(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];
|
let mut buf = [255; N];
|
||||||
uart.blocking_read(&mut buf)?;
|
uart.blocking_read(&mut buf)?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Level, Output};
|
||||||
use embassy_rp::peripherals::UART0;
|
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 embassy_time::Timer;
|
||||||
use embedded_io_async::{Read, ReadExactError, Write};
|
use embedded_io_async::{Read, ReadExactError, Write};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
|
|||||||
UART0_IRQ => BufferedInterruptHandler<UART0>;
|
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];
|
let mut buf = [255; N];
|
||||||
match uart.read_exact(&mut buf).await {
|
match uart.read_exact(&mut buf).await {
|
||||||
Ok(()) => Ok(buf),
|
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];
|
let mut buf = [255; N];
|
||||||
match uart.read_exact(&mut buf).await {
|
match uart.read_exact(&mut buf).await {
|
||||||
Ok(()) => Ok(buf),
|
Ok(()) => Ok(buf),
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Level, Output};
|
||||||
use embassy_rp::peripherals::UART0;
|
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 embassy_time::Timer;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs {
|
|||||||
UART0_IRQ => InterruptHandler<UART0>;
|
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];
|
let mut buf = [255; N];
|
||||||
uart.read(&mut buf).await?;
|
uart.read(&mut buf).await?;
|
||||||
Ok(buf)
|
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];
|
let mut buf = [255; N];
|
||||||
uart.read(&mut buf).await?;
|
uart.read(&mut buf).await?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user