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
|
||||
|
||||
* CRC
|
||||
* GPIO
|
||||
* 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 mod clocks;
|
||||
pub mod crc;
|
||||
pub mod gpio;
|
||||
pub mod iopctl;
|
||||
pub mod rng;
|
||||
|
||||
@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
|
||||
PPI_GROUP4,
|
||||
PPI_GROUP5,
|
||||
|
||||
// IPC
|
||||
IPC,
|
||||
|
||||
// GPIO port 0
|
||||
#[cfg(feature = "lfxo-pins-as-gpio")]
|
||||
P0_00,
|
||||
@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
|
||||
EGU5,
|
||||
}
|
||||
|
||||
impl_ipc!(IPC, IPC, IPC);
|
||||
|
||||
impl_usb!(USBD, USBD, USBD);
|
||||
|
||||
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
||||
|
||||
@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
|
||||
PPI_GROUP4,
|
||||
PPI_GROUP5,
|
||||
|
||||
// IPC
|
||||
IPC,
|
||||
|
||||
// GPIO port 0
|
||||
P0_00,
|
||||
P0_01,
|
||||
@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
|
||||
EGU0,
|
||||
}
|
||||
|
||||
impl_ipc!(IPC, IPC, IPC);
|
||||
|
||||
impl_uarte!(SERIAL0, UARTE0, SERIAL0);
|
||||
impl_spim!(SERIAL0, SPIM0, SERIAL0);
|
||||
impl_spis!(SERIAL0, SPIS0, SERIAL0);
|
||||
|
||||
363
embassy-nrf/src/ipc.rs
Normal file
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(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
pub mod i2s;
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
pub mod ipc;
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
#[cfg(any(
|
||||
feature = "nrf52832",
|
||||
|
||||
@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
|
||||
|
||||
[features]
|
||||
default = [ "rt" ]
|
||||
## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
|
||||
|
||||
## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac).
|
||||
## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that.
|
||||
## See <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> for more info.
|
||||
rt = [ "rp-pac/rt" ]
|
||||
|
||||
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
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,
|
||||
StateMachine,
|
||||
};
|
||||
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||
use crate::Peri;
|
||||
|
||||
/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
|
||||
@ -134,7 +135,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
|
||||
|
||||
let mut cfg = Config::default();
|
||||
cfg.use_program(&word_prg.prg, &[&e]);
|
||||
cfg.clock_divider = 125u8.into();
|
||||
|
||||
// Target 1 MHz PIO clock (each cycle is 1µs)
|
||||
cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
|
||||
|
||||
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||
cfg.shift_out = ShiftConfig {
|
||||
auto_fill: true,
|
||||
@ -160,7 +164,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
|
||||
|
||||
let mut cfg = Config::default();
|
||||
cfg.use_program(&seq_prg.prg, &[&e]);
|
||||
cfg.clock_divider = 8u8.into(); // ~64ns/insn
|
||||
|
||||
// Target ~15.6 MHz PIO clock (~64ns/insn)
|
||||
cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
|
||||
|
||||
cfg.set_jmp_pin(&db7);
|
||||
cfg.set_set_pins(&[&rs, &rw]);
|
||||
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
//! Pre-built pio programs for common interfaces
|
||||
|
||||
pub mod clock_divider;
|
||||
pub mod hd44780;
|
||||
pub mod i2s;
|
||||
pub mod onewire;
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
//! PIO backed quadrature encoder
|
||||
|
||||
use fixed::traits::ToFixed;
|
||||
|
||||
use crate::gpio::Pull;
|
||||
use crate::pio::{
|
||||
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
|
||||
};
|
||||
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||
use crate::Peri;
|
||||
|
||||
/// This struct represents an Encoder program loaded into pio instruction memory.
|
||||
@ -48,7 +47,10 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
|
||||
cfg.set_in_pins(&[&pin_a, &pin_b]);
|
||||
cfg.fifo_join = FifoJoin::RxOnly;
|
||||
cfg.shift_in.direction = ShiftDirection::Left;
|
||||
cfg.clock_divider = 10_000.to_fixed();
|
||||
|
||||
// Target 12.5 KHz PIO clock
|
||||
cfg.clock_divider = calculate_pio_clock_divider(12_500);
|
||||
|
||||
cfg.use_program(&program.prg, &[]);
|
||||
sm.set_config(&cfg);
|
||||
sm.set_enable(true);
|
||||
|
||||
@ -2,11 +2,8 @@
|
||||
|
||||
use core::mem::{self, MaybeUninit};
|
||||
|
||||
use fixed::traits::ToFixed;
|
||||
use fixed::types::extra::U8;
|
||||
use fixed::FixedU32;
|
||||
|
||||
use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
|
||||
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||
use crate::Peri;
|
||||
|
||||
/// This struct represents a Stepper driver program loaded into pio instruction memory.
|
||||
@ -64,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
|
||||
sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
|
||||
let mut cfg = Config::default();
|
||||
cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
|
||||
cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
|
||||
|
||||
cfg.clock_divider = calculate_pio_clock_divider(100 * 136);
|
||||
|
||||
cfg.use_program(&program.prg, &[]);
|
||||
sm.set_config(&cfg);
|
||||
sm.set_enable(true);
|
||||
@ -73,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
|
||||
|
||||
/// Set pulse frequency
|
||||
pub fn set_frequency(&mut self, freq: u32) {
|
||||
let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
|
||||
assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
|
||||
assert!(clock_divider >= 1, "clkdiv must be >= 1");
|
||||
let clock_divider = calculate_pio_clock_divider(freq * 136);
|
||||
let divider_f32 = clock_divider.to_num::<f32>();
|
||||
assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536");
|
||||
assert!(divider_f32 >= 1.0, "clkdiv must be >= 1");
|
||||
|
||||
self.sm.set_clock_divider(clock_divider);
|
||||
self.sm.clkdiv_restart();
|
||||
}
|
||||
|
||||
@ -34,28 +34,29 @@ impl State {
|
||||
}
|
||||
|
||||
/// Buffered UART driver.
|
||||
pub struct BufferedUart<'d, T: Instance> {
|
||||
pub(crate) rx: BufferedUartRx<'d, T>,
|
||||
pub(crate) tx: BufferedUartTx<'d, T>,
|
||||
pub struct BufferedUart {
|
||||
pub(super) rx: BufferedUartRx,
|
||||
pub(super) tx: BufferedUartTx,
|
||||
}
|
||||
|
||||
/// Buffered UART RX handle.
|
||||
pub struct BufferedUartRx<'d, T: Instance> {
|
||||
pub(crate) phantom: PhantomData<&'d mut T>,
|
||||
pub struct BufferedUartRx {
|
||||
pub(super) info: &'static Info,
|
||||
pub(super) state: &'static State,
|
||||
}
|
||||
|
||||
/// Buffered UART TX handle.
|
||||
pub struct BufferedUartTx<'d, T: Instance> {
|
||||
pub(crate) phantom: PhantomData<&'d mut T>,
|
||||
pub struct BufferedUartTx {
|
||||
pub(super) info: &'static Info,
|
||||
pub(super) state: &'static State,
|
||||
}
|
||||
|
||||
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
pub(super) fn init_buffers<'d>(
|
||||
info: &Info,
|
||||
state: &State,
|
||||
tx_buffer: Option<&'d mut [u8]>,
|
||||
rx_buffer: Option<&'d mut [u8]>,
|
||||
) {
|
||||
let state = T::buffered_state();
|
||||
|
||||
if let Some(tx_buffer) = tx_buffer {
|
||||
let len = tx_buffer.len();
|
||||
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
@ -76,61 +77,73 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
||||
// This means we can leave the interrupt enabled the whole time as long as
|
||||
// we clear it after it happens. The downside is that the we manually have
|
||||
// to pend the ISR when we want data transmission to start.
|
||||
let regs = T::regs();
|
||||
regs.uartimsc().write(|w| {
|
||||
info.regs.uartimsc().write(|w| {
|
||||
w.set_rxim(true);
|
||||
w.set_rtim(true);
|
||||
w.set_txim(true);
|
||||
});
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
info.interrupt.unpend();
|
||||
unsafe { info.interrupt.enable() };
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||
impl BufferedUart {
|
||||
/// Create a buffered UART instance.
|
||||
pub fn new(
|
||||
pub fn new<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config);
|
||||
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
|
||||
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, config);
|
||||
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
|
||||
|
||||
Self {
|
||||
rx: BufferedUartRx { phantom: PhantomData },
|
||||
tx: BufferedUartTx { phantom: PhantomData },
|
||||
rx: BufferedUartRx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
tx: BufferedUartTx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a buffered UART instance with flow control.
|
||||
pub fn new_with_rtscts(
|
||||
pub fn new_with_rtscts<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
rts: Peri<'d, impl RtsPin<T>>,
|
||||
cts: Peri<'d, impl CtsPin<T>>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(
|
||||
super::Uart::<'d, Async>::init(
|
||||
T::info(),
|
||||
Some(tx.into()),
|
||||
Some(rx.into()),
|
||||
Some(rts.into()),
|
||||
Some(cts.into()),
|
||||
config,
|
||||
);
|
||||
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
|
||||
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
|
||||
|
||||
Self {
|
||||
rx: BufferedUartRx { phantom: PhantomData },
|
||||
tx: BufferedUartTx { phantom: PhantomData },
|
||||
rx: BufferedUartRx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
tx: BufferedUartTx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,68 +173,75 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||
}
|
||||
|
||||
/// sets baudrate on runtime
|
||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||
super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
|
||||
pub fn set_baudrate<'d>(&mut self, baudrate: u32) {
|
||||
super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate);
|
||||
}
|
||||
|
||||
/// Split into separate RX and TX handles.
|
||||
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
|
||||
pub fn split(self) -> (BufferedUartTx, BufferedUartRx) {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
|
||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||
/// which is particularly useful when having two tasks correlating to
|
||||
/// transmitting and receiving.
|
||||
pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) {
|
||||
pub fn split_ref(&mut self) -> (&mut BufferedUartTx, &mut BufferedUartRx) {
|
||||
(&mut self.tx, &mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
impl BufferedUartRx {
|
||||
/// Create a new buffered UART RX.
|
||||
pub fn new(
|
||||
pub fn new<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config);
|
||||
init_buffers::<T>(irq, None, Some(rx_buffer));
|
||||
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||
init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new buffered UART RX with flow control.
|
||||
pub fn new_with_rts(
|
||||
pub fn new_with_rts<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
rts: Peri<'d, impl RtsPin<T>>,
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config);
|
||||
init_buffers::<T>(irq, None, Some(rx_buffer));
|
||||
super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config);
|
||||
init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
|
||||
fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a
|
||||
where
|
||||
T: 'd,
|
||||
{
|
||||
fn read<'a>(
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
buf: &'a mut [u8],
|
||||
) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||
poll_fn(move |cx| {
|
||||
if let Poll::Ready(r) = Self::try_read(buf) {
|
||||
if let Poll::Ready(r) = Self::try_read(info, state, buf) {
|
||||
return Poll::Ready(r);
|
||||
}
|
||||
T::buffered_state().rx_waker.register(cx.waker());
|
||||
state.rx_waker.register(cx.waker());
|
||||
Poll::Pending
|
||||
})
|
||||
}
|
||||
|
||||
fn get_rx_error() -> Option<Error> {
|
||||
let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed);
|
||||
fn get_rx_error(state: &State) -> Option<Error> {
|
||||
let errs = state.rx_error.swap(0, Ordering::Relaxed);
|
||||
if errs & RXE_OVERRUN != 0 {
|
||||
Some(Error::Overrun)
|
||||
} else if errs & RXE_BREAK != 0 {
|
||||
@ -235,15 +255,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_read(buf: &mut [u8]) -> Poll<Result<usize, Error>>
|
||||
where
|
||||
T: 'd,
|
||||
{
|
||||
fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
|
||||
if buf.is_empty() {
|
||||
return Poll::Ready(Ok(0));
|
||||
}
|
||||
|
||||
let state = T::buffered_state();
|
||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||
let n = rx_reader.pop(|data| {
|
||||
let n = data.len().min(buf.len());
|
||||
@ -252,7 +268,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
});
|
||||
|
||||
let result = if n == 0 {
|
||||
match Self::get_rx_error() {
|
||||
match Self::get_rx_error(state) {
|
||||
None => return Poll::Pending,
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
@ -262,8 +278,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
|
||||
// (Re-)Enable the interrupt to receive more data in case it was
|
||||
// disabled because the buffer was full or errors were detected.
|
||||
let regs = T::regs();
|
||||
regs.uartimsc().write_set(|w| {
|
||||
info.regs.uartimsc().write_set(|w| {
|
||||
w.set_rxim(true);
|
||||
w.set_rtim(true);
|
||||
});
|
||||
@ -274,23 +289,19 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
/// Read from UART RX buffer blocking execution until done.
|
||||
pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
loop {
|
||||
match Self::try_read(buf) {
|
||||
match Self::try_read(self.info, self.state, buf) {
|
||||
Poll::Ready(res) => return res,
|
||||
Poll::Pending => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>>
|
||||
where
|
||||
T: 'd,
|
||||
{
|
||||
fn fill_buf<'a>(state: &'static State) -> impl Future<Output = Result<&'a [u8], Error>> {
|
||||
poll_fn(move |cx| {
|
||||
let state = T::buffered_state();
|
||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||
let (p, n) = rx_reader.pop_buf();
|
||||
let result = if n == 0 {
|
||||
match Self::get_rx_error() {
|
||||
match Self::get_rx_error(state) {
|
||||
None => {
|
||||
state.rx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
@ -306,64 +317,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn consume(amt: usize) {
|
||||
let state = T::buffered_state();
|
||||
fn consume(info: &Info, state: &State, amt: usize) {
|
||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||
rx_reader.pop_done(amt);
|
||||
|
||||
// (Re-)Enable the interrupt to receive more data in case it was
|
||||
// disabled because the buffer was full or errors were detected.
|
||||
let regs = T::regs();
|
||||
regs.uartimsc().write_set(|w| {
|
||||
info.regs.uartimsc().write_set(|w| {
|
||||
w.set_rxim(true);
|
||||
w.set_rtim(true);
|
||||
});
|
||||
}
|
||||
|
||||
/// we are ready to read if there is data in the buffer
|
||||
fn read_ready() -> Result<bool, Error> {
|
||||
let state = T::buffered_state();
|
||||
fn read_ready(state: &State) -> Result<bool, Error> {
|
||||
Ok(!state.rx_buf.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
impl BufferedUartTx {
|
||||
/// Create a new buffered UART TX.
|
||||
pub fn new(
|
||||
pub fn new<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config);
|
||||
init_buffers::<T>(irq, Some(tx_buffer), None);
|
||||
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new buffered UART TX with flow control.
|
||||
pub fn new_with_cts(
|
||||
pub fn new_with_cts<'d, T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
cts: Peri<'d, impl CtsPin<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Self {
|
||||
super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config);
|
||||
init_buffers::<T>(irq, Some(tx_buffer), None);
|
||||
super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config);
|
||||
init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ {
|
||||
fn write<'d>(
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
buf: &'d [u8],
|
||||
) -> impl Future<Output = Result<usize, Error>> + 'd {
|
||||
poll_fn(move |cx| {
|
||||
if buf.is_empty() {
|
||||
return Poll::Ready(Ok(0));
|
||||
}
|
||||
|
||||
let state = T::buffered_state();
|
||||
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
||||
let n = tx_writer.push(|data| {
|
||||
let n = data.len().min(buf.len());
|
||||
@ -379,14 +396,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
// FIFO and the number of bytes drops below a threshold. When the
|
||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||
// TX data from the buffer into the FIFO.
|
||||
T::Interrupt::pend();
|
||||
info.interrupt.pend();
|
||||
Poll::Ready(Ok(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn flush() -> impl Future<Output = Result<(), Error>> {
|
||||
fn flush(state: &'static State) -> impl Future<Output = Result<(), Error>> {
|
||||
poll_fn(move |cx| {
|
||||
let state = T::buffered_state();
|
||||
if !state.tx_buf.is_empty() {
|
||||
state.tx_waker.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
@ -403,8 +419,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
}
|
||||
|
||||
loop {
|
||||
let state = T::buffered_state();
|
||||
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
||||
let mut tx_writer = unsafe { self.state.tx_buf.writer() };
|
||||
let n = tx_writer.push(|data| {
|
||||
let n = data.len().min(buf.len());
|
||||
data[..n].copy_from_slice(&buf[..n]);
|
||||
@ -416,7 +431,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
// FIFO and the number of bytes drops below a threshold. When the
|
||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||
// TX data from the buffer into the FIFO.
|
||||
T::Interrupt::pend();
|
||||
self.info.interrupt.pend();
|
||||
return Ok(n);
|
||||
}
|
||||
}
|
||||
@ -425,8 +440,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
/// Flush UART TX blocking execution until done.
|
||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||
loop {
|
||||
let state = T::buffered_state();
|
||||
if state.tx_buf.is_empty() {
|
||||
if self.state.tx_buf.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -434,7 +448,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
|
||||
/// Check if UART is busy.
|
||||
pub fn busy(&self) -> bool {
|
||||
T::regs().uartfr().read().busy()
|
||||
self.info.regs.uartfr().read().busy()
|
||||
}
|
||||
|
||||
/// Assert a break condition after waiting for the transmit buffers to empty,
|
||||
@ -445,7 +459,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
/// This method may block for a long amount of time since it has to wait
|
||||
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||
pub async fn send_break(&mut self, bits: u32) {
|
||||
let regs = T::regs();
|
||||
let regs = self.info.regs;
|
||||
let bits = bits.max({
|
||||
let lcr = regs.uartlcr_h().read();
|
||||
let width = lcr.wlen() as u32 + 5;
|
||||
@ -458,7 +472,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
let div_clk = clk_peri_freq() as u64 * 64;
|
||||
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
||||
|
||||
Self::flush().await.unwrap();
|
||||
Self::flush(self.state).await.unwrap();
|
||||
while self.busy() {}
|
||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||
Timer::after_micros(wait_usecs).await;
|
||||
@ -466,28 +480,26 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
|
||||
impl Drop for BufferedUartRx {
|
||||
fn drop(&mut self) {
|
||||
let state = T::buffered_state();
|
||||
unsafe { state.rx_buf.deinit() }
|
||||
unsafe { self.state.rx_buf.deinit() }
|
||||
|
||||
// TX is inactive if the buffer is not available.
|
||||
// We can now unregister the interrupt handler
|
||||
if !state.tx_buf.is_available() {
|
||||
T::Interrupt::disable();
|
||||
if !self.state.tx_buf.is_available() {
|
||||
self.info.interrupt.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
|
||||
impl Drop for BufferedUartTx {
|
||||
fn drop(&mut self) {
|
||||
let state = T::buffered_state();
|
||||
unsafe { state.tx_buf.deinit() }
|
||||
unsafe { self.state.tx_buf.deinit() }
|
||||
|
||||
// RX is inactive if the buffer is not available.
|
||||
// We can now unregister the interrupt handler
|
||||
if !state.rx_buf.is_available() {
|
||||
T::Interrupt::disable();
|
||||
if !self.state.rx_buf.is_available() {
|
||||
self.info.interrupt.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -499,7 +511,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let r = T::info().regs;
|
||||
if r.uartdmacr().read().rxdmae() {
|
||||
return;
|
||||
}
|
||||
@ -603,95 +615,95 @@ impl embedded_io::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> {
|
||||
impl embedded_io_async::ErrorType for BufferedUart {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> {
|
||||
impl embedded_io_async::ErrorType for BufferedUartRx {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> {
|
||||
impl embedded_io_async::ErrorType for BufferedUartTx {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> {
|
||||
impl embedded_io_async::Read for BufferedUart {
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
BufferedUartRx::<'d, T>::read(buf).await
|
||||
BufferedUartRx::read(self.rx.info, self.rx.state, buf).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> {
|
||||
impl embedded_io_async::Read for BufferedUartRx {
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
Self::read(buf).await
|
||||
Self::read(self.info, self.state, buf).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> {
|
||||
impl embedded_io_async::ReadReady for BufferedUart {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
BufferedUartRx::<'d, T>::read_ready()
|
||||
BufferedUartRx::read_ready(self.rx.state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> {
|
||||
impl embedded_io_async::ReadReady for BufferedUartRx {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
Self::read_ready()
|
||||
Self::read_ready(self.state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> {
|
||||
impl embedded_io_async::BufRead for BufferedUart {
|
||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||
BufferedUartRx::<'d, T>::fill_buf().await
|
||||
BufferedUartRx::fill_buf(self.rx.state).await
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
BufferedUartRx::<'d, T>::consume(amt)
|
||||
BufferedUartRx::consume(self.rx.info, self.rx.state, amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> {
|
||||
impl embedded_io_async::BufRead for BufferedUartRx {
|
||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||
Self::fill_buf().await
|
||||
Self::fill_buf(self.state).await
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
Self::consume(amt)
|
||||
Self::consume(self.info, self.state, amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> {
|
||||
impl embedded_io_async::Write for BufferedUart {
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
BufferedUartTx::<'d, T>::write(buf).await
|
||||
BufferedUartTx::write(self.tx.info, self.tx.state, buf).await
|
||||
}
|
||||
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
BufferedUartTx::<'d, T>::flush().await
|
||||
BufferedUartTx::flush(self.tx.state).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> {
|
||||
impl embedded_io_async::Write for BufferedUartTx {
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
Self::write(buf).await
|
||||
Self::write(self.info, self.state, buf).await
|
||||
}
|
||||
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Self::flush().await
|
||||
Self::flush(self.state).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> {
|
||||
impl embedded_io::Read for BufferedUart {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.rx.blocking_read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> {
|
||||
impl embedded_io::Read for BufferedUartRx {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.blocking_read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
|
||||
impl embedded_io::Write for BufferedUart {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.tx.blocking_write(buf)
|
||||
}
|
||||
@ -701,7 +713,7 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
|
||||
impl embedded_io::Write for BufferedUartTx {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.blocking_write(buf)
|
||||
}
|
||||
@ -711,11 +723,11 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> {
|
||||
impl embedded_hal_02::serial::Read<u8> for BufferedUartRx {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
if r.uartfr().read().rxfe() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -736,7 +748,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
|
||||
impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -755,7 +767,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> {
|
||||
impl embedded_hal_02::serial::Read<u8> for BufferedUart {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
@ -763,7 +775,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> {
|
||||
impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUart {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -782,25 +794,25 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> {
|
||||
impl embedded_hal_nb::serial::ErrorType for BufferedUartRx {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> {
|
||||
impl embedded_hal_nb::serial::ErrorType for BufferedUartTx {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> {
|
||||
impl embedded_hal_nb::serial::ErrorType for BufferedUart {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> {
|
||||
impl embedded_hal_nb::serial::Read for BufferedUartRx {
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
embedded_hal_02::serial::Read::read(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
|
||||
impl embedded_hal_nb::serial::Write for BufferedUartTx {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -810,13 +822,13 @@ impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> {
|
||||
impl embedded_hal_nb::serial::Read for BufferedUart {
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
|
||||
impl embedded_hal_nb::serial::Write for BufferedUart {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
||||
}
|
||||
|
||||
@ -13,7 +13,8 @@ use pac::uart::regs::Uartris;
|
||||
use crate::clocks::clk_peri_freq;
|
||||
use crate::dma::{AnyChannel, Channel};
|
||||
use crate::gpio::{AnyPin, SealedPin};
|
||||
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||
use crate::interrupt::typelevel::{Binding, Interrupt as _};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::pac::io::vals::{Inover, Outover};
|
||||
use crate::{interrupt, pac, peripherals, RegExt};
|
||||
|
||||
@ -135,37 +136,41 @@ pub struct DmaState {
|
||||
}
|
||||
|
||||
/// UART driver.
|
||||
pub struct Uart<'d, T: Instance, M: Mode> {
|
||||
tx: UartTx<'d, T, M>,
|
||||
rx: UartRx<'d, T, M>,
|
||||
pub struct Uart<'d, M: Mode> {
|
||||
tx: UartTx<'d, M>,
|
||||
rx: UartRx<'d, M>,
|
||||
}
|
||||
|
||||
/// UART TX driver.
|
||||
pub struct UartTx<'d, T: Instance, M: Mode> {
|
||||
pub struct UartTx<'d, M: Mode> {
|
||||
info: &'static Info,
|
||||
tx_dma: Option<Peri<'d, AnyChannel>>,
|
||||
phantom: PhantomData<(&'d mut T, M)>,
|
||||
phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
/// UART RX driver.
|
||||
pub struct UartRx<'d, T: Instance, M: Mode> {
|
||||
pub struct UartRx<'d, M: Mode> {
|
||||
info: &'static Info,
|
||||
dma_state: &'static DmaState,
|
||||
rx_dma: Option<Peri<'d, AnyChannel>>,
|
||||
phantom: PhantomData<(&'d mut T, M)>,
|
||||
phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> UartTx<'d, M> {
|
||||
/// Create a new DMA-enabled UART which can only send data
|
||||
pub fn new(
|
||||
pub fn new<T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
tx_dma: Peri<'d, impl Channel>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Uart::<T, M>::init(Some(tx.into()), None, None, None, config);
|
||||
Self::new_inner(Some(tx_dma.into()))
|
||||
Uart::<M>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||
Self::new_inner(T::info(), Some(tx_dma.into()))
|
||||
}
|
||||
|
||||
fn new_inner(tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
|
||||
fn new_inner(info: &'static Info, tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
|
||||
Self {
|
||||
info,
|
||||
tx_dma,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
|
||||
/// Transmit the provided buffer blocking execution until done.
|
||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
for &b in buffer {
|
||||
while r.uartfr().read().txff() {}
|
||||
r.uartdr().write(|w| w.set_data(b));
|
||||
@ -183,14 +188,13 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
|
||||
/// Flush UART TX blocking execution until done.
|
||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
while !r.uartfr().read().txfe() {}
|
||||
while !self.info.regs.uartfr().read().txfe() {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if UART is busy transmitting.
|
||||
pub fn busy(&self) -> bool {
|
||||
T::regs().uartfr().read().busy()
|
||||
self.info.regs.uartfr().read().busy()
|
||||
}
|
||||
|
||||
/// Assert a break condition after waiting for the transmit buffers to empty,
|
||||
@ -201,7 +205,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
/// This method may block for a long amount of time since it has to wait
|
||||
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||
pub async fn send_break(&mut self, bits: u32) {
|
||||
let regs = T::regs();
|
||||
let regs = self.info.regs;
|
||||
let bits = bits.max({
|
||||
let lcr = regs.uartlcr_h().read();
|
||||
let width = lcr.wlen() as u32 + 5;
|
||||
@ -222,65 +226,80 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartTx<'d, T, Blocking> {
|
||||
impl<'d> UartTx<'d, Blocking> {
|
||||
/// Create a new UART TX instance for blocking mode operations.
|
||||
pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
|
||||
Uart::<T, Blocking>::init(Some(tx.into()), None, None, None, config);
|
||||
Self::new_inner(None)
|
||||
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
|
||||
Uart::<Blocking>::init(T::info(), Some(tx.into()), None, None, None, config);
|
||||
Self::new_inner(T::info(), None)
|
||||
}
|
||||
|
||||
/// Convert this uart TX instance into a buffered uart using the provided
|
||||
/// irq and transmit buffer.
|
||||
pub fn into_buffered(
|
||||
pub fn into_buffered<T: Instance>(
|
||||
self,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> BufferedUartTx<'d, T> {
|
||||
buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
|
||||
) -> BufferedUartTx {
|
||||
buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
|
||||
|
||||
BufferedUartTx { phantom: PhantomData }
|
||||
BufferedUartTx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartTx<'d, T, Async> {
|
||||
impl<'d> UartTx<'d, Async> {
|
||||
/// Write to UART TX from the provided buffer using DMA.
|
||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
let ch = self.tx_dma.as_mut().unwrap().reborrow();
|
||||
let transfer = unsafe {
|
||||
T::regs().uartdmacr().write_set(|reg| {
|
||||
self.info.regs.uartdmacr().write_set(|reg| {
|
||||
reg.set_txdmae(true);
|
||||
});
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into())
|
||||
crate::dma::write(
|
||||
ch,
|
||||
buffer,
|
||||
self.info.regs.uartdr().as_ptr() as *mut _,
|
||||
self.info.tx_dreq.into(),
|
||||
)
|
||||
};
|
||||
transfer.await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> UartRx<'d, M> {
|
||||
/// Create a new DMA-enabled UART which can only receive data
|
||||
pub fn new(
|
||||
pub fn new<T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
_irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
|
||||
rx_dma: Peri<'d, impl Channel>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Uart::<T, M>::init(None, Some(rx.into()), None, None, config);
|
||||
Self::new_inner(true, Some(rx_dma.into()))
|
||||
Uart::<M>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||
Self::new_inner(T::info(), T::dma_state(), true, Some(rx_dma.into()))
|
||||
}
|
||||
|
||||
fn new_inner(has_irq: bool, rx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
|
||||
fn new_inner(
|
||||
info: &'static Info,
|
||||
dma_state: &'static DmaState,
|
||||
has_irq: bool,
|
||||
rx_dma: Option<Peri<'d, AnyChannel>>,
|
||||
) -> Self {
|
||||
debug_assert_eq!(has_irq, rx_dma.is_some());
|
||||
if has_irq {
|
||||
// disable all error interrupts initially
|
||||
T::regs().uartimsc().write(|w| w.0 = 0);
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
info.regs.uartimsc().write(|w| w.0 = 0);
|
||||
info.interrupt.unpend();
|
||||
unsafe { info.interrupt.enable() };
|
||||
}
|
||||
Self {
|
||||
info,
|
||||
dma_state,
|
||||
rx_dma,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
@ -299,7 +318,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||
/// encountered. in both cases, `len` is the number of *good* bytes copied into
|
||||
/// `buffer`.
|
||||
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
for (i, b) in buffer.iter_mut().enumerate() {
|
||||
if r.uartfr().read().rxfe() {
|
||||
return Ok(i);
|
||||
@ -323,12 +342,12 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> Drop for UartRx<'d, M> {
|
||||
fn drop(&mut self) {
|
||||
if self.rx_dma.is_some() {
|
||||
T::Interrupt::disable();
|
||||
self.info.interrupt.disable();
|
||||
// clear dma flags. irq handlers use these to disambiguate among themselves.
|
||||
T::regs().uartdmacr().write_clear(|reg| {
|
||||
self.info.regs.uartdmacr().write_clear(|reg| {
|
||||
reg.set_rxdmae(true);
|
||||
reg.set_txdmae(true);
|
||||
reg.set_dmaonerr(true);
|
||||
@ -337,23 +356,26 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartRx<'d, T, Blocking> {
|
||||
impl<'d> UartRx<'d, Blocking> {
|
||||
/// Create a new UART RX instance for blocking mode operations.
|
||||
pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
|
||||
Uart::<T, Blocking>::init(None, Some(rx.into()), None, None, config);
|
||||
Self::new_inner(false, None)
|
||||
pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
|
||||
Uart::<Blocking>::init(T::info(), None, Some(rx.into()), None, None, config);
|
||||
Self::new_inner(T::info(), T::dma_state(), false, None)
|
||||
}
|
||||
|
||||
/// Convert this uart RX instance into a buffered uart using the provided
|
||||
/// irq and receive buffer.
|
||||
pub fn into_buffered(
|
||||
pub fn into_buffered<T: Instance>(
|
||||
self,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
rx_buffer: &'d mut [u8],
|
||||
) -> BufferedUartRx<'d, T> {
|
||||
buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
|
||||
) -> BufferedUartRx {
|
||||
buffered::init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
|
||||
|
||||
BufferedUartRx { phantom: PhantomData }
|
||||
BufferedUartRx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +386,7 @@ pub struct InterruptHandler<T: Instance> {
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let uart = T::regs();
|
||||
let uart = T::info().regs;
|
||||
if !uart.uartdmacr().read().rxdmae() {
|
||||
return;
|
||||
}
|
||||
@ -380,13 +402,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
impl<'d> UartRx<'d, Async> {
|
||||
/// Read from UART RX into the provided buffer.
|
||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
// clear error flags before we drain the fifo. errors that have accumulated
|
||||
// in the flags will also be present in the fifo.
|
||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
||||
T::regs().uarticr().write(|w| {
|
||||
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
|
||||
self.info.regs.uarticr().write(|w| {
|
||||
w.set_oeic(true);
|
||||
w.set_beic(true);
|
||||
w.set_peic(true);
|
||||
@ -408,28 +430,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
// interrupt flags will have been raised, and those will be picked up immediately
|
||||
// by the interrupt handler.
|
||||
let ch = self.rx_dma.as_mut().unwrap().reborrow();
|
||||
T::regs().uartimsc().write_set(|w| {
|
||||
self.info.regs.uartimsc().write_set(|w| {
|
||||
w.set_oeim(true);
|
||||
w.set_beim(true);
|
||||
w.set_peim(true);
|
||||
w.set_feim(true);
|
||||
});
|
||||
T::regs().uartdmacr().write_set(|reg| {
|
||||
self.info.regs.uartdmacr().write_set(|reg| {
|
||||
reg.set_rxdmae(true);
|
||||
reg.set_dmaonerr(true);
|
||||
});
|
||||
let transfer = unsafe {
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into())
|
||||
crate::dma::read(
|
||||
ch,
|
||||
self.info.regs.uartdr().as_ptr() as *const _,
|
||||
buffer,
|
||||
self.info.rx_dreq.into(),
|
||||
)
|
||||
};
|
||||
|
||||
// wait for either the transfer to complete or an error to happen.
|
||||
let transfer_result = select(
|
||||
transfer,
|
||||
poll_fn(|cx| {
|
||||
T::dma_state().rx_err_waker.register(cx.waker());
|
||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
||||
self.dma_state.rx_err_waker.register(cx.waker());
|
||||
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
|
||||
0 => Poll::Pending,
|
||||
e => Poll::Ready(Uartris(e as u32)),
|
||||
}
|
||||
@ -441,7 +468,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
Either::First(()) => {
|
||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
||||
// byte, then we may still need to grab the error state!
|
||||
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
}
|
||||
Either::Second(e) => {
|
||||
// We're here because we errored, which means this is the error that
|
||||
@ -521,8 +548,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
) -> Result<usize, ReadToBreakError> {
|
||||
// clear error flags before we drain the fifo. errors that have accumulated
|
||||
// in the flags will also be present in the fifo.
|
||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
||||
T::regs().uarticr().write(|w| {
|
||||
self.dma_state.rx_errs.store(0, Ordering::Relaxed);
|
||||
self.info.regs.uarticr().write(|w| {
|
||||
w.set_oeic(true);
|
||||
w.set_beic(true);
|
||||
w.set_peic(true);
|
||||
@ -555,13 +582,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
// interrupt flags will have been raised, and those will be picked up immediately
|
||||
// by the interrupt handler.
|
||||
let ch = self.rx_dma.as_mut().unwrap();
|
||||
T::regs().uartimsc().write_set(|w| {
|
||||
self.info.regs.uartimsc().write_set(|w| {
|
||||
w.set_oeim(true);
|
||||
w.set_beim(true);
|
||||
w.set_peim(true);
|
||||
w.set_feim(true);
|
||||
});
|
||||
T::regs().uartdmacr().write_set(|reg| {
|
||||
self.info.regs.uartdmacr().write_set(|reg| {
|
||||
reg.set_rxdmae(true);
|
||||
reg.set_dmaonerr(true);
|
||||
});
|
||||
@ -572,9 +599,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::read(
|
||||
ch.reborrow(),
|
||||
T::regs().uartdr().as_ptr() as *const _,
|
||||
self.info.regs.uartdr().as_ptr() as *const _,
|
||||
sbuffer,
|
||||
T::RX_DREQ.into(),
|
||||
self.info.rx_dreq.into(),
|
||||
)
|
||||
};
|
||||
|
||||
@ -582,8 +609,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
let transfer_result = select(
|
||||
transfer,
|
||||
poll_fn(|cx| {
|
||||
T::dma_state().rx_err_waker.register(cx.waker());
|
||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
||||
self.dma_state.rx_err_waker.register(cx.waker());
|
||||
match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
|
||||
0 => Poll::Pending,
|
||||
e => Poll::Ready(Uartris(e as u32)),
|
||||
}
|
||||
@ -596,7 +623,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
Either::First(()) => {
|
||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
||||
// byte, then we may still need to grab the error state!
|
||||
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
}
|
||||
Either::Second(e) => {
|
||||
// We're here because we errored, which means this is the error that
|
||||
@ -635,7 +662,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let regs = T::regs();
|
||||
let regs = self.info.regs;
|
||||
let all_full = next_addr == eval;
|
||||
|
||||
// NOTE: This is off label usage of RSR! See the issue below for
|
||||
@ -685,9 +712,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
impl<'d> Uart<'d, Blocking> {
|
||||
/// Create a new UART without hardware flow control
|
||||
pub fn new_blocking(
|
||||
pub fn new_blocking<T: Instance>(
|
||||
uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
@ -697,7 +724,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
}
|
||||
|
||||
/// Create a new UART with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts_blocking(
|
||||
pub fn new_with_rtscts_blocking<T: Instance>(
|
||||
uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
@ -720,24 +747,30 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
|
||||
|
||||
/// Convert this uart instance into a buffered uart using the provided
|
||||
/// irq, transmit and receive buffers.
|
||||
pub fn into_buffered(
|
||||
pub fn into_buffered<T: Instance>(
|
||||
self,
|
||||
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
) -> BufferedUart<'d, T> {
|
||||
buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
|
||||
) -> BufferedUart {
|
||||
buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
|
||||
|
||||
BufferedUart {
|
||||
rx: BufferedUartRx { phantom: PhantomData },
|
||||
tx: BufferedUartTx { phantom: PhantomData },
|
||||
rx: BufferedUartRx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
tx: BufferedUartTx {
|
||||
info: T::info(),
|
||||
state: T::buffered_state(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
impl<'d> Uart<'d, Async> {
|
||||
/// Create a new DMA enabled UART without hardware flow control
|
||||
pub fn new(
|
||||
pub fn new<T: Instance>(
|
||||
uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
@ -760,7 +793,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
}
|
||||
|
||||
/// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
pub fn new_with_rtscts<T: Instance>(
|
||||
uart: Peri<'d, T>,
|
||||
tx: Peri<'d, impl TxPin<T>>,
|
||||
rx: Peri<'d, impl RxPin<T>>,
|
||||
@ -785,8 +818,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
fn new_inner(
|
||||
impl<'d, M: Mode> Uart<'d, M> {
|
||||
fn new_inner<T: Instance>(
|
||||
_uart: Peri<'d, T>,
|
||||
mut tx: Peri<'d, AnyPin>,
|
||||
mut rx: Peri<'d, AnyPin>,
|
||||
@ -798,6 +831,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::init(
|
||||
T::info(),
|
||||
Some(tx.reborrow()),
|
||||
Some(rx.reborrow()),
|
||||
rts.as_mut().map(|x| x.reborrow()),
|
||||
@ -806,19 +840,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
);
|
||||
|
||||
Self {
|
||||
tx: UartTx::new_inner(tx_dma),
|
||||
rx: UartRx::new_inner(has_irq, rx_dma),
|
||||
tx: UartTx::new_inner(T::info(), tx_dma),
|
||||
rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
info: &Info,
|
||||
tx: Option<Peri<'_, AnyPin>>,
|
||||
rx: Option<Peri<'_, AnyPin>>,
|
||||
rts: Option<Peri<'_, AnyPin>>,
|
||||
cts: Option<Peri<'_, AnyPin>>,
|
||||
config: Config,
|
||||
) {
|
||||
let r = T::regs();
|
||||
let r = info.regs;
|
||||
if let Some(pin) = &tx {
|
||||
let funcsel = {
|
||||
let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
|
||||
@ -896,7 +931,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
});
|
||||
}
|
||||
|
||||
Self::set_baudrate_inner(config.baudrate);
|
||||
Self::set_baudrate_inner(info, config.baudrate);
|
||||
|
||||
let (pen, eps) = match config.parity {
|
||||
Parity::ParityNone => (false, false),
|
||||
@ -926,8 +961,8 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
});
|
||||
}
|
||||
|
||||
fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
|
||||
let r = T::regs();
|
||||
fn lcr_modify<R>(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
|
||||
let r = info.regs;
|
||||
|
||||
// Notes from PL011 reference manual:
|
||||
//
|
||||
@ -978,11 +1013,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
|
||||
/// sets baudrate on runtime
|
||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||
Self::set_baudrate_inner(baudrate);
|
||||
Self::set_baudrate_inner(self.tx.info, baudrate);
|
||||
}
|
||||
|
||||
fn set_baudrate_inner(baudrate: u32) {
|
||||
let r = T::regs();
|
||||
fn set_baudrate_inner(info: &Info, baudrate: u32) {
|
||||
let r = info.regs;
|
||||
|
||||
let clk_base = crate::clocks::clk_peri_freq();
|
||||
|
||||
@ -1002,11 +1037,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
||||
|
||||
Self::lcr_modify(|_| {});
|
||||
Self::lcr_modify(info, |_| {});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> Uart<'d, M> {
|
||||
/// Transmit the provided buffer blocking execution until done.
|
||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.tx.blocking_write(buffer)
|
||||
@ -1034,19 +1069,19 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
|
||||
/// Split the Uart into a transmitter and receiver, which is particularly
|
||||
/// useful when having two tasks correlating to transmitting and receiving.
|
||||
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
|
||||
pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
|
||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||
/// which is particularly useful when having two tasks correlating to
|
||||
/// transmitting and receiving.
|
||||
pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
|
||||
pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) {
|
||||
(&mut self.tx, &mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
impl<'d> Uart<'d, Async> {
|
||||
/// Write to UART TX from the provided buffer.
|
||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.tx.write(buffer).await
|
||||
@ -1076,10 +1111,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
|
||||
type Error = Error;
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
if r.uartfr().read().rxfe() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -1100,11 +1135,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
if r.uartfr().read().txff() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -1114,7 +1149,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
if !r.uartfr().read().txfe() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -1122,7 +1157,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -1134,7 +1169,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
@ -1142,7 +1177,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
|
||||
@ -1154,7 +1189,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -1177,21 +1212,21 @@ impl embedded_hal_nb::serial::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
let r = T::regs();
|
||||
let r = self.info.regs;
|
||||
if r.uartfr().read().rxfe() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -1212,7 +1247,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -1222,11 +1257,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> {
|
||||
impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
|
||||
impl<'d> embedded_io::Write for UartTx<'d, Blocking> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.blocking_write(buf).map(|_| buf.len())
|
||||
}
|
||||
@ -1236,13 +1271,13 @@ impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
|
||||
impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -1252,11 +1287,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> {
|
||||
impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
|
||||
impl<'d> embedded_io::Write for Uart<'d, Blocking> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.blocking_write(buf).map(|_| buf.len())
|
||||
}
|
||||
@ -1266,13 +1301,17 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
struct Info {
|
||||
regs: pac::uart::Uart,
|
||||
tx_dreq: pac::dma::vals::TreqSel,
|
||||
rx_dreq: pac::dma::vals::TreqSel,
|
||||
interrupt: Interrupt,
|
||||
}
|
||||
|
||||
trait SealedMode {}
|
||||
|
||||
trait SealedInstance {
|
||||
const TX_DREQ: pac::dma::vals::TreqSel;
|
||||
const RX_DREQ: pac::dma::vals::TreqSel;
|
||||
|
||||
fn regs() -> pac::uart::Uart;
|
||||
fn info() -> &'static Info;
|
||||
|
||||
fn buffered_state() -> &'static buffered::State;
|
||||
|
||||
@ -1308,11 +1347,14 @@ pub trait Instance: SealedInstance + PeripheralType {
|
||||
macro_rules! impl_instance {
|
||||
($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||
impl SealedInstance for peripherals::$inst {
|
||||
const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
|
||||
const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
|
||||
|
||||
fn regs() -> pac::uart::Uart {
|
||||
pac::$inst
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
regs: pac::$inst,
|
||||
tx_dreq: $tx_dreq,
|
||||
rx_dreq: $rx_dreq,
|
||||
interrupt: crate::interrupt::typelevel::$irq::IRQ,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
|
||||
fn buffered_state() -> &'static buffered::State {
|
||||
|
||||
@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> {
|
||||
/// PWM pin config
|
||||
///
|
||||
/// This configures the pwm pin settings
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PwmPinConfig {
|
||||
/// PWM Pin output type
|
||||
pub output_type: OutputType,
|
||||
|
||||
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 {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
|
||||
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
|
||||
|
||||
struct MyType {
|
||||
inner: u32,
|
||||
|
||||
@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
|
||||
async fn reader(mut rx: BufferedUartRx) {
|
||||
info!("Reading...");
|
||||
loop {
|
||||
let mut buf = [0; 31];
|
||||
|
||||
@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
|
||||
async fn reader(mut rx: UartRx<'static, Async>) {
|
||||
info!("Reading...");
|
||||
loop {
|
||||
// read a total of 4 transmissions (32 / 8) and then print the result
|
||||
|
||||
@ -31,7 +31,7 @@ use rand::RngCore;
|
||||
use static_cell::{ConstStaticCell, StaticCell};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
|
||||
type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
|
||||
|
||||
struct MyType {
|
||||
inner: u32,
|
||||
|
||||
@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
|
||||
async fn reader(mut rx: BufferedUartRx) {
|
||||
info!("Reading...");
|
||||
loop {
|
||||
let mut buf = [0; 31];
|
||||
|
||||
@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: UartRx<'static, UART1, Async>) {
|
||||
async fn reader(mut rx: UartRx<'static, Async>) {
|
||||
info!("Reading...");
|
||||
loop {
|
||||
// read a total of 4 transmissions (32 / 8) and then print the result
|
||||
|
||||
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 embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Level, Output};
|
||||
use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx};
|
||||
use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> {
|
||||
fn read<const N: usize>(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
uart.blocking_read(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> {
|
||||
fn read1<const N: usize>(uart: &mut UartRx<'_, Blocking>) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
uart.blocking_read(&mut buf)?;
|
||||
Ok(buf)
|
||||
|
||||
@ -10,7 +10,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::gpio::{Level, Output};
|
||||
use embassy_rp::peripherals::UART0;
|
||||
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity};
|
||||
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity};
|
||||
use embassy_time::Timer;
|
||||
use embedded_io_async::{Read, ReadExactError, Write};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
|
||||
UART0_IRQ => BufferedInterruptHandler<UART0>;
|
||||
});
|
||||
|
||||
async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> {
|
||||
async fn read<const N: usize>(uart: &mut BufferedUart) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
match uart.read_exact(&mut buf).await {
|
||||
Ok(()) => Ok(buf),
|
||||
@ -29,7 +29,7 @@ async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Res
|
||||
}
|
||||
}
|
||||
|
||||
async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> {
|
||||
async fn read1<const N: usize>(uart: &mut BufferedUartRx) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
match uart.read_exact(&mut buf).await {
|
||||
Ok(()) => Ok(buf),
|
||||
|
||||
@ -10,7 +10,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::gpio::{Level, Output};
|
||||
use embassy_rp::peripherals::UART0;
|
||||
use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx};
|
||||
use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs {
|
||||
UART0_IRQ => InterruptHandler<UART0>;
|
||||
});
|
||||
|
||||
async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
|
||||
async fn read<const N: usize>(uart: &mut Uart<'_, Async>) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
uart.read(&mut buf).await?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> {
|
||||
async fn read1<const N: usize>(uart: &mut UartRx<'_, Async>) -> Result<[u8; N], Error> {
|
||||
let mut buf = [255; N];
|
||||
uart.read(&mut buf).await?;
|
||||
Ok(buf)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user