move to shared UART Module
This commit is contained in:
parent
81eaf8127c
commit
c450e8423e
@ -31,7 +31,7 @@ use va108xx_hal::{
|
|||||||
uart::{
|
uart::{
|
||||||
self, on_interrupt_rx_overwriting,
|
self, on_interrupt_rx_overwriting,
|
||||||
rx_asynch::{on_interrupt_rx, RxAsync},
|
rx_asynch::{on_interrupt_rx, RxAsync},
|
||||||
RxAsyncOverwriting, Tx, UartId,
|
Bank, RxAsyncOverwriting, Tx,
|
||||||
},
|
},
|
||||||
InterruptConfig,
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
@ -145,7 +145,7 @@ async fn uart_b_task(mut async_rx: RxAsyncOverwriting<256>, mut tx: Tx) {
|
|||||||
fn OC2() {
|
fn OC2() {
|
||||||
let mut prod =
|
let mut prod =
|
||||||
critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap());
|
critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap());
|
||||||
let errors = on_interrupt_rx(UartId::A, &mut prod);
|
let errors = on_interrupt_rx(Bank::Uart0, &mut prod);
|
||||||
critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod));
|
critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod));
|
||||||
// In a production app, we could use a channel to send the errors to the main task.
|
// In a production app, we could use a channel to send the errors to the main task.
|
||||||
if let Err(errors) = errors {
|
if let Err(errors) = errors {
|
||||||
@ -158,7 +158,7 @@ fn OC2() {
|
|||||||
fn OC3() {
|
fn OC3() {
|
||||||
let mut prod =
|
let mut prod =
|
||||||
critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap());
|
critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap());
|
||||||
let errors = on_interrupt_rx_overwriting(UartId::B, &mut prod, &CONSUMER_UART_B);
|
let errors = on_interrupt_rx_overwriting(Bank::Uart1, &mut prod, &CONSUMER_UART_B);
|
||||||
critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod));
|
critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod));
|
||||||
// In a production app, we could use a channel to send the errors to the main task.
|
// In a production app, we could use a channel to send the errors to the main task.
|
||||||
if let Err(errors) = errors {
|
if let Err(errors) = errors {
|
||||||
|
@ -21,7 +21,7 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
pins::PinsA,
|
pins::PinsA,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
uart::{self, on_interrupt_tx, TxAsync, UartId},
|
uart::{self, on_interrupt_tx, Bank, TxAsync},
|
||||||
InterruptConfig,
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,5 +91,5 @@ async fn main(_spawner: Spawner) {
|
|||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn OC2() {
|
fn OC2() {
|
||||||
on_interrupt_tx(UartId::A);
|
on_interrupt_tx(Bank::Uart0);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ portable-atomic = "1"
|
|||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
rt = ["va108xx/rt"]
|
rt = ["va108xx/rt"]
|
||||||
defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03"]
|
defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03", "vorago-shared-periphs/defmt"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -3,239 +3,4 @@
|
|||||||
//! This module contains the pin singletons. It allows creating those singletons
|
//! This module contains the pin singletons. It allows creating those singletons
|
||||||
//! to access the [Pin] structures of individual ports in a safe way with checked ownership
|
//! to access the [Pin] structures of individual ports in a safe way with checked ownership
|
||||||
//! rules.
|
//! rules.
|
||||||
use vorago_shared_periphs::sysconfig::reset_peripheral_for_cycles;
|
pub use vorago_shared_periphs::pins::*;
|
||||||
|
|
||||||
pub use crate::gpio::{Pin, PinId, PinIdProvider, Port};
|
|
||||||
|
|
||||||
use crate::sealed::Sealed;
|
|
||||||
use crate::PeripheralSelect;
|
|
||||||
|
|
||||||
pub trait PinMarker: Sealed {
|
|
||||||
const ID: PinId;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! pin_id {
|
|
||||||
($Id:ident, $Port:path, $num:literal) => {
|
|
||||||
// Need paste macro to use ident in doc attribute
|
|
||||||
paste::paste! {
|
|
||||||
#[doc = "Pin ID representing pin " $Id]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum $Id {}
|
|
||||||
|
|
||||||
impl $crate::sealed::Sealed for $Id {}
|
|
||||||
impl PinIdProvider for $Id {
|
|
||||||
const ID: PinId = PinId::new_unchecked($Port, $num);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PinMarker for Pin<$Id> {
|
|
||||||
const ID: PinId = $Id::ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: PinIdProvider + Sealed> Sealed for Pin<I> {}
|
|
||||||
|
|
||||||
pin_id!(Pa0, Port::A, 0);
|
|
||||||
pin_id!(Pa1, Port::A, 1);
|
|
||||||
pin_id!(Pa2, Port::A, 2);
|
|
||||||
pin_id!(Pa3, Port::A, 3);
|
|
||||||
pin_id!(Pa4, Port::A, 4);
|
|
||||||
pin_id!(Pa5, Port::A, 5);
|
|
||||||
pin_id!(Pa6, Port::A, 6);
|
|
||||||
pin_id!(Pa7, Port::A, 7);
|
|
||||||
pin_id!(Pa8, Port::A, 8);
|
|
||||||
pin_id!(Pa9, Port::A, 9);
|
|
||||||
pin_id!(Pa10, Port::A, 10);
|
|
||||||
pin_id!(Pa11, Port::A, 11);
|
|
||||||
pin_id!(Pa12, Port::A, 12);
|
|
||||||
pin_id!(Pa13, Port::A, 13);
|
|
||||||
pin_id!(Pa14, Port::A, 14);
|
|
||||||
pin_id!(Pa15, Port::A, 15);
|
|
||||||
pin_id!(Pa16, Port::A, 16);
|
|
||||||
pin_id!(Pa17, Port::A, 17);
|
|
||||||
pin_id!(Pa18, Port::A, 18);
|
|
||||||
pin_id!(Pa19, Port::A, 19);
|
|
||||||
pin_id!(Pa20, Port::A, 20);
|
|
||||||
pin_id!(Pa21, Port::A, 21);
|
|
||||||
pin_id!(Pa22, Port::A, 22);
|
|
||||||
pin_id!(Pa23, Port::A, 23);
|
|
||||||
pin_id!(Pa24, Port::A, 24);
|
|
||||||
pin_id!(Pa25, Port::A, 25);
|
|
||||||
pin_id!(Pa26, Port::A, 26);
|
|
||||||
pin_id!(Pa27, Port::A, 27);
|
|
||||||
pin_id!(Pa28, Port::A, 28);
|
|
||||||
pin_id!(Pa29, Port::A, 29);
|
|
||||||
pin_id!(Pa30, Port::A, 30);
|
|
||||||
pin_id!(Pa31, Port::A, 31);
|
|
||||||
|
|
||||||
pin_id!(Pb0, Port::B, 0);
|
|
||||||
pin_id!(Pb1, Port::B, 1);
|
|
||||||
pin_id!(Pb2, Port::B, 2);
|
|
||||||
pin_id!(Pb3, Port::B, 3);
|
|
||||||
pin_id!(Pb4, Port::B, 4);
|
|
||||||
pin_id!(Pb5, Port::B, 5);
|
|
||||||
pin_id!(Pb6, Port::B, 6);
|
|
||||||
pin_id!(Pb7, Port::B, 7);
|
|
||||||
pin_id!(Pb8, Port::B, 8);
|
|
||||||
pin_id!(Pb9, Port::B, 9);
|
|
||||||
pin_id!(Pb10, Port::B, 10);
|
|
||||||
pin_id!(Pb11, Port::B, 11);
|
|
||||||
pin_id!(Pb12, Port::B, 12);
|
|
||||||
pin_id!(Pb13, Port::B, 13);
|
|
||||||
pin_id!(Pb14, Port::B, 14);
|
|
||||||
pin_id!(Pb15, Port::B, 15);
|
|
||||||
pin_id!(Pb16, Port::B, 16);
|
|
||||||
pin_id!(Pb17, Port::B, 17);
|
|
||||||
pin_id!(Pb18, Port::B, 18);
|
|
||||||
pin_id!(Pb19, Port::B, 19);
|
|
||||||
pin_id!(Pb20, Port::B, 20);
|
|
||||||
pin_id!(Pb21, Port::B, 21);
|
|
||||||
pin_id!(Pb22, Port::B, 22);
|
|
||||||
pin_id!(Pb23, Port::B, 23);
|
|
||||||
|
|
||||||
pub struct PinsA {
|
|
||||||
pub pa0: Pin<Pa0>,
|
|
||||||
pub pa1: Pin<Pa1>,
|
|
||||||
pub pa2: Pin<Pa2>,
|
|
||||||
pub pa3: Pin<Pa3>,
|
|
||||||
pub pa4: Pin<Pa4>,
|
|
||||||
pub pa5: Pin<Pa5>,
|
|
||||||
pub pa6: Pin<Pa6>,
|
|
||||||
pub pa7: Pin<Pa7>,
|
|
||||||
pub pa8: Pin<Pa8>,
|
|
||||||
pub pa9: Pin<Pa9>,
|
|
||||||
pub pa10: Pin<Pa10>,
|
|
||||||
pub pa11: Pin<Pa11>,
|
|
||||||
pub pa12: Pin<Pa12>,
|
|
||||||
pub pa13: Pin<Pa13>,
|
|
||||||
pub pa14: Pin<Pa14>,
|
|
||||||
pub pa15: Pin<Pa15>,
|
|
||||||
pub pa16: Pin<Pa16>,
|
|
||||||
pub pa17: Pin<Pa17>,
|
|
||||||
pub pa18: Pin<Pa18>,
|
|
||||||
pub pa19: Pin<Pa19>,
|
|
||||||
pub pa20: Pin<Pa20>,
|
|
||||||
pub pa21: Pin<Pa21>,
|
|
||||||
pub pa22: Pin<Pa22>,
|
|
||||||
pub pa23: Pin<Pa23>,
|
|
||||||
pub pa24: Pin<Pa24>,
|
|
||||||
pub pa25: Pin<Pa25>,
|
|
||||||
pub pa26: Pin<Pa26>,
|
|
||||||
pub pa27: Pin<Pa27>,
|
|
||||||
pub pa28: Pin<Pa28>,
|
|
||||||
pub pa29: Pin<Pa29>,
|
|
||||||
pub pa30: Pin<Pa30>,
|
|
||||||
pub pa31: Pin<Pa31>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PinsA {
|
|
||||||
pub fn new(_port_a: va108xx::Porta) -> Self {
|
|
||||||
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
|
||||||
reset_peripheral_for_cycles(PeripheralSelect::PortA, 2);
|
|
||||||
syscfg.peripheral_clk_enable().modify(|_, w| {
|
|
||||||
w.porta().set_bit();
|
|
||||||
w.gpio().set_bit();
|
|
||||||
w.ioconfig().set_bit()
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
pa0: Pin::__new(),
|
|
||||||
pa1: Pin::__new(),
|
|
||||||
pa2: Pin::__new(),
|
|
||||||
pa3: Pin::__new(),
|
|
||||||
pa4: Pin::__new(),
|
|
||||||
pa5: Pin::__new(),
|
|
||||||
pa6: Pin::__new(),
|
|
||||||
pa7: Pin::__new(),
|
|
||||||
pa8: Pin::__new(),
|
|
||||||
pa9: Pin::__new(),
|
|
||||||
pa10: Pin::__new(),
|
|
||||||
pa11: Pin::__new(),
|
|
||||||
pa12: Pin::__new(),
|
|
||||||
pa13: Pin::__new(),
|
|
||||||
pa14: Pin::__new(),
|
|
||||||
pa15: Pin::__new(),
|
|
||||||
pa16: Pin::__new(),
|
|
||||||
pa17: Pin::__new(),
|
|
||||||
pa18: Pin::__new(),
|
|
||||||
pa19: Pin::__new(),
|
|
||||||
pa20: Pin::__new(),
|
|
||||||
pa21: Pin::__new(),
|
|
||||||
pa22: Pin::__new(),
|
|
||||||
pa23: Pin::__new(),
|
|
||||||
pa24: Pin::__new(),
|
|
||||||
pa25: Pin::__new(),
|
|
||||||
pa26: Pin::__new(),
|
|
||||||
pa27: Pin::__new(),
|
|
||||||
pa28: Pin::__new(),
|
|
||||||
pa29: Pin::__new(),
|
|
||||||
pa30: Pin::__new(),
|
|
||||||
pa31: Pin::__new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PinsB {
|
|
||||||
pub pb0: Pin<Pb0>,
|
|
||||||
pub pb1: Pin<Pb1>,
|
|
||||||
pub pb2: Pin<Pb2>,
|
|
||||||
pub pb3: Pin<Pb3>,
|
|
||||||
pub pb4: Pin<Pb4>,
|
|
||||||
pub pb5: Pin<Pb5>,
|
|
||||||
pub pb6: Pin<Pb6>,
|
|
||||||
pub pb7: Pin<Pb7>,
|
|
||||||
pub pb8: Pin<Pb8>,
|
|
||||||
pub pb9: Pin<Pb9>,
|
|
||||||
pub pb10: Pin<Pb10>,
|
|
||||||
pub pb11: Pin<Pb11>,
|
|
||||||
pub pb12: Pin<Pb12>,
|
|
||||||
pub pb13: Pin<Pb13>,
|
|
||||||
pub pb14: Pin<Pb14>,
|
|
||||||
pub pb15: Pin<Pb15>,
|
|
||||||
pub pb16: Pin<Pb16>,
|
|
||||||
pub pb17: Pin<Pb17>,
|
|
||||||
pub pb18: Pin<Pb18>,
|
|
||||||
pub pb19: Pin<Pb19>,
|
|
||||||
pub pb20: Pin<Pb20>,
|
|
||||||
pub pb21: Pin<Pb21>,
|
|
||||||
pub pb22: Pin<Pb22>,
|
|
||||||
pub pb23: Pin<Pb23>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PinsB {
|
|
||||||
pub fn new(_port_b: va108xx::Portb) -> Self {
|
|
||||||
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
|
||||||
reset_peripheral_for_cycles(PeripheralSelect::PortB, 2);
|
|
||||||
syscfg.peripheral_clk_enable().modify(|_, w| {
|
|
||||||
w.portb().set_bit();
|
|
||||||
w.gpio().set_bit();
|
|
||||||
w.ioconfig().set_bit()
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
pb0: Pin::__new(),
|
|
||||||
pb1: Pin::__new(),
|
|
||||||
pb2: Pin::__new(),
|
|
||||||
pb3: Pin::__new(),
|
|
||||||
pb4: Pin::__new(),
|
|
||||||
pb5: Pin::__new(),
|
|
||||||
pb6: Pin::__new(),
|
|
||||||
pb7: Pin::__new(),
|
|
||||||
pb8: Pin::__new(),
|
|
||||||
pb9: Pin::__new(),
|
|
||||||
pb10: Pin::__new(),
|
|
||||||
pb11: Pin::__new(),
|
|
||||||
pb12: Pin::__new(),
|
|
||||||
pb13: Pin::__new(),
|
|
||||||
pb14: Pin::__new(),
|
|
||||||
pb15: Pin::__new(),
|
|
||||||
pb16: Pin::__new(),
|
|
||||||
pb17: Pin::__new(),
|
|
||||||
pb18: Pin::__new(),
|
|
||||||
pb19: Pin::__new(),
|
|
||||||
pb20: Pin::__new(),
|
|
||||||
pb21: Pin::__new(),
|
|
||||||
pb22: Pin::__new(),
|
|
||||||
pb23: Pin::__new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -698,9 +698,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
reg_block
|
reg_block.ctrl1().modify(|_, w| w.mtxpause().clear_bit());
|
||||||
.ctrl1()
|
|
||||||
.modify(|_, w| w.mtxpause().clear_bit());
|
|
||||||
}
|
}
|
||||||
current_write_idx
|
current_write_idx
|
||||||
}
|
}
|
||||||
@ -724,9 +722,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
reg_block
|
reg_block.ctrl1().modify(|_, w| w.mtxpause().clear_bit());
|
||||||
.ctrl1()
|
|
||||||
.modify(|_, w| w.mtxpause().clear_bit());
|
|
||||||
}
|
}
|
||||||
current_write_idx
|
current_write_idx
|
||||||
}
|
}
|
||||||
@ -747,9 +743,7 @@ where
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_fifo_unchecked(&mut self, data: u32) {
|
fn write_fifo_unchecked(&mut self, data: u32) {
|
||||||
self.reg_block()
|
self.reg_block().data().write(|w| unsafe { w.bits(data) });
|
||||||
.data()
|
|
||||||
.write(|w| unsafe { w.bits(data) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -27,7 +27,8 @@ pub trait PinMiso: PinMarker {
|
|||||||
const FUN_SEL: FunSel;
|
const FUN_SEL: FunSel;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HwCsProvider: PinMarker {
|
pub trait HwCsProvider {
|
||||||
|
const PIN_ID: PinId;
|
||||||
const SPI_ID: SpiId;
|
const SPI_ID: SpiId;
|
||||||
const FUN_SEL: FunSel;
|
const FUN_SEL: FunSel;
|
||||||
const CS_ID: HwChipSelectId;
|
const CS_ID: HwChipSelectId;
|
||||||
@ -37,6 +38,7 @@ macro_rules! hw_cs_pins {
|
|||||||
($SpiId:path, $(($Px:ident, $FunSel:path, $HwCsIdent:path),)+) => {
|
($SpiId:path, $(($Px:ident, $FunSel:path, $HwCsIdent:path),)+) => {
|
||||||
$(
|
$(
|
||||||
impl HwCsProvider for Pin<$Px> {
|
impl HwCsProvider for Pin<$Px> {
|
||||||
|
const PIN_ID: PinId = $Px::ID;
|
||||||
const SPI_ID: SpiId = $SpiId;
|
const SPI_ID: SpiId = $SpiId;
|
||||||
const FUN_SEL: FunSel = $FunSel;
|
const FUN_SEL: FunSel = $FunSel;
|
||||||
const CS_ID: HwChipSelectId = $HwCsIdent;
|
const CS_ID: HwChipSelectId = $HwCsIdent;
|
||||||
@ -72,11 +74,8 @@ macro_rules! hw_cs_multi_pin {
|
|||||||
|
|
||||||
impl Sealed for $name {}
|
impl Sealed for $name {}
|
||||||
|
|
||||||
impl PinMarker for $name {
|
|
||||||
const ID: PinId = <$pin_id as PinIdProvider>::ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HwCsProvider for $name {
|
impl HwCsProvider for $name {
|
||||||
|
const PIN_ID: PinId = <$pin_id as PinIdProvider>::ID;
|
||||||
const SPI_ID: SpiId = $spi_id;
|
const SPI_ID: SpiId = $spi_id;
|
||||||
const FUN_SEL: FunSel = $fun_sel;
|
const FUN_SEL: FunSel = $fun_sel;
|
||||||
const CS_ID: HwChipSelectId = $cs_id;
|
const CS_ID: HwChipSelectId = $cs_id;
|
||||||
|
@ -1,26 +1,2 @@
|
|||||||
//! Time units
|
//! Time units
|
||||||
|
pub use vorago_shared_periphs::time::*;
|
||||||
// Frequency based
|
|
||||||
|
|
||||||
/// Hertz
|
|
||||||
pub type Hertz = fugit::HertzU32;
|
|
||||||
|
|
||||||
/// KiloHertz
|
|
||||||
pub type KiloHertz = fugit::KilohertzU32;
|
|
||||||
|
|
||||||
/// MegaHertz
|
|
||||||
pub type MegaHertz = fugit::MegahertzU32;
|
|
||||||
|
|
||||||
// Period based
|
|
||||||
|
|
||||||
/// Seconds
|
|
||||||
pub type Seconds = fugit::SecsDurationU32;
|
|
||||||
|
|
||||||
/// Milliseconds
|
|
||||||
pub type Milliseconds = fugit::MillisDurationU32;
|
|
||||||
|
|
||||||
/// Microseconds
|
|
||||||
pub type Microseconds = fugit::MicrosDurationU32;
|
|
||||||
|
|
||||||
/// Nanoseconds
|
|
||||||
pub type Nanoseconds = fugit::NanosDurationU32;
|
|
||||||
|
@ -20,6 +20,7 @@ use fugit::RateExtU32;
|
|||||||
use vorago_shared_periphs::{
|
use vorago_shared_periphs::{
|
||||||
gpio::{Pin, PinId, PinIdProvider},
|
gpio::{Pin, PinId, PinIdProvider},
|
||||||
ioconfig::regs::FunSel,
|
ioconfig::regs::FunSel,
|
||||||
|
pins::PinMarker,
|
||||||
sysconfig::enable_peripheral_clock,
|
sysconfig::enable_peripheral_clock,
|
||||||
PeripheralSelect,
|
PeripheralSelect,
|
||||||
};
|
};
|
||||||
@ -160,7 +161,7 @@ impl CascadeSource {
|
|||||||
// Valid TIM and PIN combinations
|
// Valid TIM and PIN combinations
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
pub trait TimPin: Sealed {
|
pub trait TimPin: PinMarker {
|
||||||
const PIN_ID: PinId;
|
const PIN_ID: PinId;
|
||||||
const FUN_SEL: FunSel;
|
const FUN_SEL: FunSel;
|
||||||
const TIM_ID: TimId;
|
const TIM_ID: TimId;
|
||||||
|
File diff suppressed because it is too large
Load Diff
1387
va108xx-hal/src/uart_tmp/mod.rs
Normal file
1387
va108xx-hal/src/uart_tmp/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,10 +11,18 @@ derive-mmio = { path = "../../../ROMEO/derive-mmio" }
|
|||||||
bitbybit = "1.3"
|
bitbybit = "1.3"
|
||||||
arbitrary-int = "1.3"
|
arbitrary-int = "1.3"
|
||||||
static_assertions = "1.1"
|
static_assertions = "1.1"
|
||||||
|
nb = "1"
|
||||||
|
heapless = "0.8"
|
||||||
|
critical-section = "1"
|
||||||
embedded-hal = { version = "1.0" }
|
embedded-hal = { version = "1.0" }
|
||||||
embedded-hal-async = "1"
|
embedded-hal-async = "1"
|
||||||
|
embedded-hal-nb = "1"
|
||||||
|
embedded-io = "0.6"
|
||||||
|
embedded-io-async = "0.6"
|
||||||
|
raw-slicee = "0.1"
|
||||||
thiserror = { version = "2", default-features = false }
|
thiserror = { version = "2", default-features = false }
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
fugit = "0.3"
|
||||||
embassy-sync = "0.6"
|
embassy-sync = "0.6"
|
||||||
defmt = { version = "1", optional = true }
|
defmt = { version = "1", optional = true }
|
||||||
va108xx = { version = "0.5", default-features = false, optional = true }
|
va108xx = { version = "0.5", default-features = false, optional = true }
|
||||||
|
@ -37,7 +37,7 @@ static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PORT_B] =
|
|||||||
pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
|
pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
|
||||||
let gpio = unsafe { port.steal_gpio() };
|
let gpio = unsafe { port.steal_gpio() };
|
||||||
|
|
||||||
let irq_enb = gpio.read_irq_enb();
|
let irq_enb = gpio.read_irq_enable();
|
||||||
let edge_status = gpio.read_edge_status();
|
let edge_status = gpio.read_edge_status();
|
||||||
let (wakers, edge_detection) = match port {
|
let (wakers, edge_detection) = match port {
|
||||||
Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()),
|
Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()),
|
||||||
|
@ -255,7 +255,7 @@ impl LowLevelGpio {
|
|||||||
if irq_cfg.enable_in_nvic {
|
if irq_cfg.enable_in_nvic {
|
||||||
unsafe { crate::enable_nvic_interrupt(irq_cfg.id) };
|
unsafe { crate::enable_nvic_interrupt(irq_cfg.id) };
|
||||||
}
|
}
|
||||||
self.gpio.modify_irq_enb(|mut value| {
|
self.gpio.modify_irq_enable(|mut value| {
|
||||||
value |= 1 << self.id.offset;
|
value |= 1 << self.id.offset;
|
||||||
value
|
value
|
||||||
});
|
});
|
||||||
@ -267,7 +267,7 @@ impl LowLevelGpio {
|
|||||||
self.reset_irqsel();
|
self.reset_irqsel();
|
||||||
}
|
}
|
||||||
// We only manipulate our own bit.
|
// We only manipulate our own bit.
|
||||||
self.gpio.modify_irq_enb(|mut value| {
|
self.gpio.modify_irq_enable(|mut value| {
|
||||||
value &= !(1 << self.id.offset);
|
value &= !(1 << self.id.offset);
|
||||||
value
|
value
|
||||||
});
|
});
|
||||||
|
@ -50,14 +50,14 @@ pub struct Gpio {
|
|||||||
irq_sen: u32,
|
irq_sen: u32,
|
||||||
irq_edge: u32,
|
irq_edge: u32,
|
||||||
irq_evt: u32,
|
irq_evt: u32,
|
||||||
irq_enb: u32,
|
irq_enable: u32,
|
||||||
/// Raw interrupt status. This register is not latched and may not indicated edge sensitive
|
/// Raw interrupt status. This register is not latched and may not indicated edge sensitive
|
||||||
/// events.
|
/// events.
|
||||||
#[mmio(PureRead)]
|
#[mmio(PureRead)]
|
||||||
irq_raw: u32,
|
irq_raw: u32,
|
||||||
/// Read only register which shows the AND of IRQ_RAW and IRQ_ENB. Called IRQ_END by Vorago.
|
/// Read-only register which shows enabled and active interrupts. Called IRQ_end by Vorago.
|
||||||
#[mmio(PureRead)]
|
#[mmio(PureRead)]
|
||||||
irq_active: u32,
|
irq_status: u32,
|
||||||
#[mmio(PureRead)]
|
#[mmio(PureRead)]
|
||||||
edge_status: u32,
|
edge_status: u32,
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod ioconfig;
|
pub mod ioconfig;
|
||||||
|
pub mod pins;
|
||||||
pub mod sysconfig;
|
pub mod sysconfig;
|
||||||
|
pub mod time;
|
||||||
|
pub mod uart;
|
||||||
|
|
||||||
|
pub use sysconfig::{disable_peripheral_clock, enable_peripheral_clock};
|
||||||
|
|
||||||
#[cfg(not(feature = "_family-selected"))]
|
#[cfg(not(feature = "_family-selected"))]
|
||||||
compile_error!("no Vorago CPU family was select. Choices: vor1x or vor4x");
|
compile_error!("no Vorago CPU family was select. Choices: vor1x or vor4x");
|
||||||
|
236
vorago-shared-periphs/src/pins.rs
Normal file
236
vorago-shared-periphs/src/pins.rs
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
use crate::sysconfig::reset_peripheral_for_cycles;
|
||||||
|
|
||||||
|
pub use crate::gpio::{Pin, PinId, PinIdProvider, Port};
|
||||||
|
|
||||||
|
use crate::PeripheralSelect;
|
||||||
|
use crate::sealed::Sealed;
|
||||||
|
|
||||||
|
pub trait PinMarker: Sealed {
|
||||||
|
const ID: PinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pin_id {
|
||||||
|
($Id:ident, $Port:path, $num:literal) => {
|
||||||
|
// Need paste macro to use ident in doc attribute
|
||||||
|
paste::paste! {
|
||||||
|
#[doc = "Pin ID representing pin " $Id]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum $Id {}
|
||||||
|
|
||||||
|
impl $crate::sealed::Sealed for $Id {}
|
||||||
|
impl PinIdProvider for $Id {
|
||||||
|
const ID: PinId = PinId::new_unchecked($Port, $num);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PinMarker for Pin<$Id> {
|
||||||
|
const ID: PinId = $Id::ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: PinIdProvider + Sealed> Sealed for Pin<I> {}
|
||||||
|
|
||||||
|
pin_id!(Pa0, Port::A, 0);
|
||||||
|
pin_id!(Pa1, Port::A, 1);
|
||||||
|
pin_id!(Pa2, Port::A, 2);
|
||||||
|
pin_id!(Pa3, Port::A, 3);
|
||||||
|
pin_id!(Pa4, Port::A, 4);
|
||||||
|
pin_id!(Pa5, Port::A, 5);
|
||||||
|
pin_id!(Pa6, Port::A, 6);
|
||||||
|
pin_id!(Pa7, Port::A, 7);
|
||||||
|
pin_id!(Pa8, Port::A, 8);
|
||||||
|
pin_id!(Pa9, Port::A, 9);
|
||||||
|
pin_id!(Pa10, Port::A, 10);
|
||||||
|
pin_id!(Pa11, Port::A, 11);
|
||||||
|
pin_id!(Pa12, Port::A, 12);
|
||||||
|
pin_id!(Pa13, Port::A, 13);
|
||||||
|
pin_id!(Pa14, Port::A, 14);
|
||||||
|
pin_id!(Pa15, Port::A, 15);
|
||||||
|
pin_id!(Pa16, Port::A, 16);
|
||||||
|
pin_id!(Pa17, Port::A, 17);
|
||||||
|
pin_id!(Pa18, Port::A, 18);
|
||||||
|
pin_id!(Pa19, Port::A, 19);
|
||||||
|
pin_id!(Pa20, Port::A, 20);
|
||||||
|
pin_id!(Pa21, Port::A, 21);
|
||||||
|
pin_id!(Pa22, Port::A, 22);
|
||||||
|
pin_id!(Pa23, Port::A, 23);
|
||||||
|
pin_id!(Pa24, Port::A, 24);
|
||||||
|
pin_id!(Pa25, Port::A, 25);
|
||||||
|
pin_id!(Pa26, Port::A, 26);
|
||||||
|
pin_id!(Pa27, Port::A, 27);
|
||||||
|
pin_id!(Pa28, Port::A, 28);
|
||||||
|
pin_id!(Pa29, Port::A, 29);
|
||||||
|
pin_id!(Pa30, Port::A, 30);
|
||||||
|
pin_id!(Pa31, Port::A, 31);
|
||||||
|
|
||||||
|
pin_id!(Pb0, Port::B, 0);
|
||||||
|
pin_id!(Pb1, Port::B, 1);
|
||||||
|
pin_id!(Pb2, Port::B, 2);
|
||||||
|
pin_id!(Pb3, Port::B, 3);
|
||||||
|
pin_id!(Pb4, Port::B, 4);
|
||||||
|
pin_id!(Pb5, Port::B, 5);
|
||||||
|
pin_id!(Pb6, Port::B, 6);
|
||||||
|
pin_id!(Pb7, Port::B, 7);
|
||||||
|
pin_id!(Pb8, Port::B, 8);
|
||||||
|
pin_id!(Pb9, Port::B, 9);
|
||||||
|
pin_id!(Pb10, Port::B, 10);
|
||||||
|
pin_id!(Pb11, Port::B, 11);
|
||||||
|
pin_id!(Pb12, Port::B, 12);
|
||||||
|
pin_id!(Pb13, Port::B, 13);
|
||||||
|
pin_id!(Pb14, Port::B, 14);
|
||||||
|
pin_id!(Pb15, Port::B, 15);
|
||||||
|
pin_id!(Pb16, Port::B, 16);
|
||||||
|
pin_id!(Pb17, Port::B, 17);
|
||||||
|
pin_id!(Pb18, Port::B, 18);
|
||||||
|
pin_id!(Pb19, Port::B, 19);
|
||||||
|
pin_id!(Pb20, Port::B, 20);
|
||||||
|
pin_id!(Pb21, Port::B, 21);
|
||||||
|
pin_id!(Pb22, Port::B, 22);
|
||||||
|
pin_id!(Pb23, Port::B, 23);
|
||||||
|
|
||||||
|
pub struct PinsA {
|
||||||
|
pub pa0: Pin<Pa0>,
|
||||||
|
pub pa1: Pin<Pa1>,
|
||||||
|
pub pa2: Pin<Pa2>,
|
||||||
|
pub pa3: Pin<Pa3>,
|
||||||
|
pub pa4: Pin<Pa4>,
|
||||||
|
pub pa5: Pin<Pa5>,
|
||||||
|
pub pa6: Pin<Pa6>,
|
||||||
|
pub pa7: Pin<Pa7>,
|
||||||
|
pub pa8: Pin<Pa8>,
|
||||||
|
pub pa9: Pin<Pa9>,
|
||||||
|
pub pa10: Pin<Pa10>,
|
||||||
|
pub pa11: Pin<Pa11>,
|
||||||
|
pub pa12: Pin<Pa12>,
|
||||||
|
pub pa13: Pin<Pa13>,
|
||||||
|
pub pa14: Pin<Pa14>,
|
||||||
|
pub pa15: Pin<Pa15>,
|
||||||
|
pub pa16: Pin<Pa16>,
|
||||||
|
pub pa17: Pin<Pa17>,
|
||||||
|
pub pa18: Pin<Pa18>,
|
||||||
|
pub pa19: Pin<Pa19>,
|
||||||
|
pub pa20: Pin<Pa20>,
|
||||||
|
pub pa21: Pin<Pa21>,
|
||||||
|
pub pa22: Pin<Pa22>,
|
||||||
|
pub pa23: Pin<Pa23>,
|
||||||
|
pub pa24: Pin<Pa24>,
|
||||||
|
pub pa25: Pin<Pa25>,
|
||||||
|
pub pa26: Pin<Pa26>,
|
||||||
|
pub pa27: Pin<Pa27>,
|
||||||
|
pub pa28: Pin<Pa28>,
|
||||||
|
pub pa29: Pin<Pa29>,
|
||||||
|
pub pa30: Pin<Pa30>,
|
||||||
|
pub pa31: Pin<Pa31>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PinsA {
|
||||||
|
pub fn new(_port_a: va108xx::Porta) -> Self {
|
||||||
|
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
||||||
|
reset_peripheral_for_cycles(PeripheralSelect::PortA, 2);
|
||||||
|
syscfg.peripheral_clk_enable().modify(|_, w| {
|
||||||
|
w.porta().set_bit();
|
||||||
|
w.gpio().set_bit();
|
||||||
|
w.ioconfig().set_bit()
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
pa0: Pin::__new(),
|
||||||
|
pa1: Pin::__new(),
|
||||||
|
pa2: Pin::__new(),
|
||||||
|
pa3: Pin::__new(),
|
||||||
|
pa4: Pin::__new(),
|
||||||
|
pa5: Pin::__new(),
|
||||||
|
pa6: Pin::__new(),
|
||||||
|
pa7: Pin::__new(),
|
||||||
|
pa8: Pin::__new(),
|
||||||
|
pa9: Pin::__new(),
|
||||||
|
pa10: Pin::__new(),
|
||||||
|
pa11: Pin::__new(),
|
||||||
|
pa12: Pin::__new(),
|
||||||
|
pa13: Pin::__new(),
|
||||||
|
pa14: Pin::__new(),
|
||||||
|
pa15: Pin::__new(),
|
||||||
|
pa16: Pin::__new(),
|
||||||
|
pa17: Pin::__new(),
|
||||||
|
pa18: Pin::__new(),
|
||||||
|
pa19: Pin::__new(),
|
||||||
|
pa20: Pin::__new(),
|
||||||
|
pa21: Pin::__new(),
|
||||||
|
pa22: Pin::__new(),
|
||||||
|
pa23: Pin::__new(),
|
||||||
|
pa24: Pin::__new(),
|
||||||
|
pa25: Pin::__new(),
|
||||||
|
pa26: Pin::__new(),
|
||||||
|
pa27: Pin::__new(),
|
||||||
|
pa28: Pin::__new(),
|
||||||
|
pa29: Pin::__new(),
|
||||||
|
pa30: Pin::__new(),
|
||||||
|
pa31: Pin::__new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PinsB {
|
||||||
|
pub pb0: Pin<Pb0>,
|
||||||
|
pub pb1: Pin<Pb1>,
|
||||||
|
pub pb2: Pin<Pb2>,
|
||||||
|
pub pb3: Pin<Pb3>,
|
||||||
|
pub pb4: Pin<Pb4>,
|
||||||
|
pub pb5: Pin<Pb5>,
|
||||||
|
pub pb6: Pin<Pb6>,
|
||||||
|
pub pb7: Pin<Pb7>,
|
||||||
|
pub pb8: Pin<Pb8>,
|
||||||
|
pub pb9: Pin<Pb9>,
|
||||||
|
pub pb10: Pin<Pb10>,
|
||||||
|
pub pb11: Pin<Pb11>,
|
||||||
|
pub pb12: Pin<Pb12>,
|
||||||
|
pub pb13: Pin<Pb13>,
|
||||||
|
pub pb14: Pin<Pb14>,
|
||||||
|
pub pb15: Pin<Pb15>,
|
||||||
|
pub pb16: Pin<Pb16>,
|
||||||
|
pub pb17: Pin<Pb17>,
|
||||||
|
pub pb18: Pin<Pb18>,
|
||||||
|
pub pb19: Pin<Pb19>,
|
||||||
|
pub pb20: Pin<Pb20>,
|
||||||
|
pub pb21: Pin<Pb21>,
|
||||||
|
pub pb22: Pin<Pb22>,
|
||||||
|
pub pb23: Pin<Pb23>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PinsB {
|
||||||
|
pub fn new(_port_b: va108xx::Portb) -> Self {
|
||||||
|
let syscfg = unsafe { va108xx::Sysconfig::steal() };
|
||||||
|
reset_peripheral_for_cycles(PeripheralSelect::PortB, 2);
|
||||||
|
syscfg.peripheral_clk_enable().modify(|_, w| {
|
||||||
|
w.portb().set_bit();
|
||||||
|
w.gpio().set_bit();
|
||||||
|
w.ioconfig().set_bit()
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
pb0: Pin::__new(),
|
||||||
|
pb1: Pin::__new(),
|
||||||
|
pb2: Pin::__new(),
|
||||||
|
pb3: Pin::__new(),
|
||||||
|
pb4: Pin::__new(),
|
||||||
|
pb5: Pin::__new(),
|
||||||
|
pb6: Pin::__new(),
|
||||||
|
pb7: Pin::__new(),
|
||||||
|
pb8: Pin::__new(),
|
||||||
|
pb9: Pin::__new(),
|
||||||
|
pb10: Pin::__new(),
|
||||||
|
pb11: Pin::__new(),
|
||||||
|
pb12: Pin::__new(),
|
||||||
|
pb13: Pin::__new(),
|
||||||
|
pb14: Pin::__new(),
|
||||||
|
pb15: Pin::__new(),
|
||||||
|
pb16: Pin::__new(),
|
||||||
|
pb17: Pin::__new(),
|
||||||
|
pb18: Pin::__new(),
|
||||||
|
pb19: Pin::__new(),
|
||||||
|
pb20: Pin::__new(),
|
||||||
|
pb21: Pin::__new(),
|
||||||
|
pb22: Pin::__new(),
|
||||||
|
pb23: Pin::__new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
vorago-shared-periphs/src/time.rs
Normal file
26
vorago-shared-periphs/src/time.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//! Time units
|
||||||
|
|
||||||
|
// Frequency based
|
||||||
|
|
||||||
|
/// Hertz
|
||||||
|
pub type Hertz = fugit::HertzU32;
|
||||||
|
|
||||||
|
/// KiloHertz
|
||||||
|
pub type KiloHertz = fugit::KilohertzU32;
|
||||||
|
|
||||||
|
/// MegaHertz
|
||||||
|
pub type MegaHertz = fugit::MegahertzU32;
|
||||||
|
|
||||||
|
// Period based
|
||||||
|
|
||||||
|
/// Seconds
|
||||||
|
pub type Seconds = fugit::SecsDurationU32;
|
||||||
|
|
||||||
|
/// Milliseconds
|
||||||
|
pub type Milliseconds = fugit::MillisDurationU32;
|
||||||
|
|
||||||
|
/// Microseconds
|
||||||
|
pub type Microseconds = fugit::MicrosDurationU32;
|
||||||
|
|
||||||
|
/// Nanoseconds
|
||||||
|
pub type Nanoseconds = fugit::NanosDurationU32;
|
1261
vorago-shared-periphs/src/uart/mod.rs
Normal file
1261
vorago-shared-periphs/src/uart/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
112
vorago-shared-periphs/src/uart/pins_vor1x.rs
Normal file
112
vorago-shared-periphs/src/uart/pins_vor1x.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// UART A pins
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
FunSel,
|
||||||
|
pins::{
|
||||||
|
Pa2, Pa3, Pa8, Pa9, Pa16, Pa17, Pa18, Pa19, Pa26, Pa27, Pa30, Pa31, Pb6, Pb7, Pb8, Pb9,
|
||||||
|
Pb18, Pb19, Pb20, Pb21, Pb22, Pb23, Pin,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{Bank, RxPin, TxPin};
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa9> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa8> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa17> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa16> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa31> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa30> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pb9> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pb8> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pb23> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pb22> {
|
||||||
|
const BANK: Bank = Bank::Uart0;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UART B pins
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa3> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa2> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa19> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa18> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pa27> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pa26> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pb7> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pb6> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pb19> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pb18> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel2;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxPin for Pin<Pb21> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
||||||
|
impl RxPin for Pin<Pb20> {
|
||||||
|
const BANK: Bank = Bank::Uart1;
|
||||||
|
const FUN_SEL: FunSel = FunSel::Sel1;
|
||||||
|
}
|
303
vorago-shared-periphs/src/uart/regs.rs
Normal file
303
vorago-shared-periphs/src/uart/regs.rs
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use arbitrary_int::{u5, u6, u18};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Bank {
|
||||||
|
Uart0 = 0,
|
||||||
|
Uart1 = 1,
|
||||||
|
#[cfg(feature = "vor4x")]
|
||||||
|
Uart2 = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bank {
|
||||||
|
/// Unsafely steal the GPIO peripheral block for the given port.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Circumvents ownership and safety guarantees by the HAL.
|
||||||
|
pub unsafe fn steal_regs(&self) -> MmioUart<'static> {
|
||||||
|
Uart::new_mmio(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "vor1x")] {
|
||||||
|
/// UART A base address
|
||||||
|
const BASE_ADDR_0: usize = 0x4004_0000;
|
||||||
|
/// UART B base address
|
||||||
|
const BASE_ADDR_1: usize = 0x4004_1000;
|
||||||
|
} else if #[cfg(feature = "vor4x")] {
|
||||||
|
/// UART 0 base address
|
||||||
|
const BASE_ADDR_0: usize = 0x4002_4000;
|
||||||
|
/// UART 1 base address
|
||||||
|
const BASE_ADDR_1: usize = 0x4002_5000;
|
||||||
|
/// UART 2 base address
|
||||||
|
const BASE_ADDR_2: usize = 0x4001_7000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Data {
|
||||||
|
#[bit(15, rw)]
|
||||||
|
dparity: bool,
|
||||||
|
#[bits(0..=7, rw)]
|
||||||
|
value: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Enable {
|
||||||
|
#[bit(1, rw)]
|
||||||
|
tx: bool,
|
||||||
|
#[bit(0, rw)]
|
||||||
|
rx: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Stopbits {
|
||||||
|
One = 0,
|
||||||
|
Two = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitenum(u2, exhaustive = true)]
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum WordSize {
|
||||||
|
Five = 0b00,
|
||||||
|
Six = 0b01,
|
||||||
|
Seven = 0b10,
|
||||||
|
Eight = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Control {
|
||||||
|
#[bit(11, rw)]
|
||||||
|
baud8: bool,
|
||||||
|
#[bit(10, rw)]
|
||||||
|
auto_rts: bool,
|
||||||
|
#[bit(9, rw)]
|
||||||
|
def_rts: bool,
|
||||||
|
#[bit(8, rw)]
|
||||||
|
auto_cts: bool,
|
||||||
|
#[bit(7, rw)]
|
||||||
|
loopback_block: bool,
|
||||||
|
#[bit(6, rw)]
|
||||||
|
loopback: bool,
|
||||||
|
#[bits(4..=5, rw)]
|
||||||
|
wordsize: WordSize,
|
||||||
|
#[bit(3, rw)]
|
||||||
|
stopbits: Stopbits,
|
||||||
|
#[bit(2, rw)]
|
||||||
|
parity_manual: bool,
|
||||||
|
#[bit(1, rw)]
|
||||||
|
parity_even: bool,
|
||||||
|
#[bit(0, rw)]
|
||||||
|
parity_enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ClkScale {
|
||||||
|
#[bits(6..=23, rw)]
|
||||||
|
int: u18,
|
||||||
|
#[bits(0..=5, rw)]
|
||||||
|
frac: u6,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RxStatus {
|
||||||
|
#[bit(15, r)]
|
||||||
|
rx_rtsn: bool,
|
||||||
|
#[bit(9, r)]
|
||||||
|
rx_addr9: bool,
|
||||||
|
#[bit(8, r)]
|
||||||
|
busy_break: bool,
|
||||||
|
#[bit(7, r)]
|
||||||
|
break_error: bool,
|
||||||
|
#[bit(6, r)]
|
||||||
|
parity_error: bool,
|
||||||
|
#[bit(5, r)]
|
||||||
|
framing_error: bool,
|
||||||
|
#[bit(4, r)]
|
||||||
|
overrun_error: bool,
|
||||||
|
#[bit(3, r)]
|
||||||
|
timeout: bool,
|
||||||
|
#[bit(2, r)]
|
||||||
|
busy: bool,
|
||||||
|
#[bit(1, r)]
|
||||||
|
not_full: bool,
|
||||||
|
#[bit(0, r)]
|
||||||
|
data_available: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TxStatus {
|
||||||
|
#[bit(15, r)]
|
||||||
|
tx_ctsn: bool,
|
||||||
|
#[bit(3, r)]
|
||||||
|
wr_lost: bool,
|
||||||
|
#[bit(2, r)]
|
||||||
|
tx_busy: bool,
|
||||||
|
#[bit(1, r)]
|
||||||
|
write_busy: bool,
|
||||||
|
/// There is space in the FIFO to write data.
|
||||||
|
#[bit(0, r)]
|
||||||
|
ready: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FifoClear {
|
||||||
|
#[bit(1, w)]
|
||||||
|
tx: bool,
|
||||||
|
#[bit(0, w)]
|
||||||
|
rx: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterruptControl {
|
||||||
|
/// Generate an interrrupt when the RX FIFO is at least half-full (FIFO count >= trigger level)
|
||||||
|
#[bit(0, rw)]
|
||||||
|
rx: bool,
|
||||||
|
/// Interrupts for status conditions (overrun, framing, parity and break)
|
||||||
|
#[bit(1, rw)]
|
||||||
|
rx_status: bool,
|
||||||
|
/// Interrupt on timeout conditions.
|
||||||
|
#[bit(2, rw)]
|
||||||
|
rx_timeout: bool,
|
||||||
|
|
||||||
|
/// Generates an interrupt when the TX FIFO is at least half-empty (FIFO count < trigger level)
|
||||||
|
#[bit(4, rw)]
|
||||||
|
tx: bool,
|
||||||
|
/// Generates an interrupt on TX FIFO overflow.
|
||||||
|
#[bit(5, rw)]
|
||||||
|
tx_status: bool,
|
||||||
|
/// Generates an interrupt when the transmit FIFO is empty and TXBUSY is 0.
|
||||||
|
#[bit(6, rw)]
|
||||||
|
tx_empty: bool,
|
||||||
|
#[bit(7, rw)]
|
||||||
|
tx_cts: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterruptStatus {
|
||||||
|
/// Generate an interrrupt when the RX FIFO is at least half-full (FIFO count >= trigger level)
|
||||||
|
#[bit(0, r)]
|
||||||
|
rx: bool,
|
||||||
|
/// Interrupts for status conditions (overrun, framing, parity and break)
|
||||||
|
#[bit(1, r)]
|
||||||
|
rx_status: bool,
|
||||||
|
/// Interrupt on timeout conditions.
|
||||||
|
#[bit(2, r)]
|
||||||
|
rx_timeout: bool,
|
||||||
|
|
||||||
|
/// Generates an interrupt when the TX FIFO is at least half-empty (FIFO count < trigger level)
|
||||||
|
#[bit(4, r)]
|
||||||
|
tx: bool,
|
||||||
|
/// Generates an interrupt on TX FIFO overflow.
|
||||||
|
#[bit(5, r)]
|
||||||
|
tx_status: bool,
|
||||||
|
/// Generates an interrupt when the transmit FIFO is empty and TXBUSY is 0.
|
||||||
|
#[bit(6, r)]
|
||||||
|
tx_empty: bool,
|
||||||
|
#[bit(7, r)]
|
||||||
|
tx_cts: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// As specified in the VA416x0 Programmers Guide, only the RX overflow bit can be cleared.
|
||||||
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterruptClear {
|
||||||
|
#[bit(1, w)]
|
||||||
|
rx_overrun: bool,
|
||||||
|
/// Not sure if this does anything, the programmer guides are not consistent on this..
|
||||||
|
#[bit(5, w)]
|
||||||
|
tx_overrun: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FifoTrigger {
|
||||||
|
#[bits(0..=4, rw)]
|
||||||
|
level: u5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct State {
|
||||||
|
#[bits(0..=7, r)]
|
||||||
|
rx_state: u8,
|
||||||
|
/// Data count.
|
||||||
|
#[bits(8..=12, r)]
|
||||||
|
rx_fifo: u5,
|
||||||
|
#[bits(16..=23, r)]
|
||||||
|
tx_state: u8,
|
||||||
|
/// Data count.
|
||||||
|
#[bits(24..=28, r)]
|
||||||
|
tx_fifo: u5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(derive_mmio::Mmio)]
|
||||||
|
#[mmio(no_ctors)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Uart {
|
||||||
|
data: Data,
|
||||||
|
enable: Enable,
|
||||||
|
ctrl: Control,
|
||||||
|
clkscale: ClkScale,
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
rx_status: RxStatus,
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
tx_status: TxStatus,
|
||||||
|
#[mmio(Write)]
|
||||||
|
fifo_clr: FifoClear,
|
||||||
|
#[mmio(Write)]
|
||||||
|
txbreak: u32,
|
||||||
|
addr9: u32,
|
||||||
|
addr9mask: u32,
|
||||||
|
irq_enabled: InterruptControl,
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
irq_raw: InterruptStatus,
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
irq_status: InterruptStatus,
|
||||||
|
#[mmio(Write)]
|
||||||
|
irq_clr: InterruptClear,
|
||||||
|
rx_fifo_trigger: FifoTrigger,
|
||||||
|
tx_fifo_trigger: FifoTrigger,
|
||||||
|
rx_fifo_rts_trigger: u32,
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
state: State,
|
||||||
|
_reserved: [u32; 0x3ED],
|
||||||
|
/// Vorago 1x value: 0x0112_07E1. Vorago 4x value: 0x0212_07E9
|
||||||
|
#[mmio(PureRead)]
|
||||||
|
perid: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assertions::const_assert_eq!(core::mem::size_of::<Uart>(), 0x1000);
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
fn new_mmio_at(base: usize) -> MmioUart<'static> {
|
||||||
|
MmioUart {
|
||||||
|
ptr: base as *mut _,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_mmio(bank: Bank) -> MmioUart<'static> {
|
||||||
|
match bank {
|
||||||
|
Bank::Uart0 => Self::new_mmio_at(BASE_ADDR_0),
|
||||||
|
Bank::Uart1 => Self::new_mmio_at(BASE_ADDR_1),
|
||||||
|
#[cfg(feature = "vor4x")]
|
||||||
|
Bank::Uart2 => Self::new_mmio_at(BASE_ADDR_2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
437
vorago-shared-periphs/src/uart/rx_asynch.rs
Normal file
437
vorago-shared-periphs/src/uart/rx_asynch.rs
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
//! # Async UART reception functionality for the VA416xx family.
|
||||||
|
//!
|
||||||
|
//! This module provides the [RxAsync] and [RxAsyncOverwriting] struct which both implement the
|
||||||
|
//! [embedded_io_async::Read] trait.
|
||||||
|
//! This trait allows for asynchronous reception of data streams. Please note that this module does
|
||||||
|
//! not specify/declare the interrupt handlers which must be provided for async support to work.
|
||||||
|
//! However, it provides two interrupt handlers:
|
||||||
|
//!
|
||||||
|
//! - [on_interrupt_rx]
|
||||||
|
//! - [on_interrupt_rx_overwriting]
|
||||||
|
//!
|
||||||
|
//! The first two are used for the [RxAsync] struct, while the latter two are used with the
|
||||||
|
//! [RxAsyncOverwriting] struct. The later two will overwrite old values in the used ring buffer.
|
||||||
|
//!
|
||||||
|
//! Error handling is performed in the user interrupt handler by checking the [AsyncUartErrors]
|
||||||
|
//! structure returned by the interrupt handlers.
|
||||||
|
use core::{cell::RefCell, convert::Infallible, future::Future, sync::atomic::Ordering};
|
||||||
|
|
||||||
|
use arbitrary_int::Number;
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
use embedded_io::ErrorType;
|
||||||
|
use portable_atomic::AtomicBool;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Bank, Rx, UartErrors,
|
||||||
|
regs::{InterruptClear, MmioUart},
|
||||||
|
};
|
||||||
|
|
||||||
|
static UART_RX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
|
||||||
|
static RX_READ_ACTIVE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||||
|
static RX_HAS_DATA: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||||
|
|
||||||
|
struct RxFuture {
|
||||||
|
id: Bank,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxFuture {
|
||||||
|
pub fn new(rx: &mut Rx) -> Self {
|
||||||
|
RX_READ_ACTIVE[rx.id as usize].store(true, Ordering::Relaxed);
|
||||||
|
Self { id: rx.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for RxFuture {
|
||||||
|
type Output = Result<(), Infallible>;
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> core::task::Poll<Self::Output> {
|
||||||
|
UART_RX_WAKERS[self.id as usize].register(cx.waker());
|
||||||
|
if RX_HAS_DATA[self.id as usize].load(Ordering::Relaxed) {
|
||||||
|
return core::task::Poll::Ready(Ok(()));
|
||||||
|
}
|
||||||
|
core::task::Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct AsyncUartErrors {
|
||||||
|
/// Queue has overflowed, data might have been lost.
|
||||||
|
pub queue_overflow: bool,
|
||||||
|
/// UART errors.
|
||||||
|
pub uart_errors: UartErrors,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_interrupt_handle_rx_errors(uart: &mut MmioUart<'static>) -> Option<UartErrors> {
|
||||||
|
let rx_status = uart.read_rx_status();
|
||||||
|
if rx_status.overrun_error() || rx_status.framing_error() || rx_status.parity_error() {
|
||||||
|
let mut errors_val = UartErrors::default();
|
||||||
|
|
||||||
|
if rx_status.overrun_error() {
|
||||||
|
errors_val.overflow = true;
|
||||||
|
}
|
||||||
|
if rx_status.framing_error() {
|
||||||
|
errors_val.framing = true;
|
||||||
|
}
|
||||||
|
if rx_status.parity_error() {
|
||||||
|
errors_val.parity = true;
|
||||||
|
}
|
||||||
|
return Some(errors_val);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_interrupt_rx_common_post_processing(
|
||||||
|
id: Bank,
|
||||||
|
rx_enabled: bool,
|
||||||
|
read_some_data: bool,
|
||||||
|
) -> Option<UartErrors> {
|
||||||
|
let idx = id as usize;
|
||||||
|
if read_some_data {
|
||||||
|
RX_HAS_DATA[idx].store(true, Ordering::Relaxed);
|
||||||
|
if RX_READ_ACTIVE[idx].load(Ordering::Relaxed) {
|
||||||
|
UART_RX_WAKERS[idx].wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut errors = None;
|
||||||
|
let mut uart_regs = unsafe { id.steal_regs() };
|
||||||
|
// Check for RX errors
|
||||||
|
if rx_enabled {
|
||||||
|
errors = on_interrupt_handle_rx_errors(&mut uart_regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the interrupt status bits
|
||||||
|
uart_regs.write_irq_clr(
|
||||||
|
InterruptClear::builder()
|
||||||
|
.with_rx_overrun(true)
|
||||||
|
.with_tx_overrun(false)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler with overwriting behaviour when the ring buffer is full.
|
||||||
|
///
|
||||||
|
/// Should be called in the user interrupt handler to enable
|
||||||
|
/// asynchronous reception. This variant will overwrite old data in the ring buffer in case
|
||||||
|
/// the ring buffer is full.
|
||||||
|
pub fn on_interrupt_rx_overwriting<const N: usize>(
|
||||||
|
bank: Bank,
|
||||||
|
prod: &mut heapless::spsc::Producer<u8, N>,
|
||||||
|
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue_overwriting(bank, prod, shared_consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_interrupt_rx_async_heapless_queue_overwriting<const N: usize>(
|
||||||
|
bank: Bank,
|
||||||
|
prod: &mut heapless::spsc::Producer<u8, N>,
|
||||||
|
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
let uart_regs = unsafe { bank.steal_regs() };
|
||||||
|
let irq_status = uart_regs.read_irq_status();
|
||||||
|
let irq_enabled = uart_regs.read_irq_enabled();
|
||||||
|
let rx_enabled = irq_enabled.rx();
|
||||||
|
let mut read_some_data = false;
|
||||||
|
let mut queue_overflow = false;
|
||||||
|
|
||||||
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
|
if irq_status.rx() {
|
||||||
|
let available_bytes = uart_regs.read_rx_fifo_trigger().level().as_usize();
|
||||||
|
|
||||||
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
|
// Read everything as fast as possible
|
||||||
|
for _ in 0..available_bytes {
|
||||||
|
let byte = uart_regs.read_data().value();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut cons_ref = shared_consumer.borrow(cs).borrow_mut();
|
||||||
|
cons_ref.as_mut().unwrap().dequeue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prod.enqueue(byte).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout, empty the FIFO completely.
|
||||||
|
if irq_status.rx_timeout() {
|
||||||
|
while uart_regs.read_rx_status().data_available() {
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
let byte = uart_regs.read_data().value();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut cons_ref = shared_consumer.borrow(cs).borrow_mut();
|
||||||
|
cons_ref.as_mut().unwrap().dequeue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prod.enqueue(byte).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uart_errors = on_interrupt_rx_common_post_processing(bank, rx_enabled, read_some_data);
|
||||||
|
if uart_errors.is_some() || queue_overflow {
|
||||||
|
return Err(AsyncUartErrors {
|
||||||
|
queue_overflow,
|
||||||
|
uart_errors: uart_errors.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler for asynchronous RX operations.
|
||||||
|
///
|
||||||
|
/// Should be called in the user interrupt handler to enable asynchronous reception.
|
||||||
|
pub fn on_interrupt_rx<const N: usize>(
|
||||||
|
bank: Bank,
|
||||||
|
prod: &mut heapless::spsc::Producer<'_, u8, N>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue(bank, prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_interrupt_rx_async_heapless_queue<const N: usize>(
|
||||||
|
bank: Bank,
|
||||||
|
prod: &mut heapless::spsc::Producer<'_, u8, N>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
let uart_regs = unsafe { bank.steal_regs() };
|
||||||
|
let irq_status = uart_regs.read_irq_status();
|
||||||
|
let irq_enabled = uart_regs.read_irq_enabled();
|
||||||
|
let rx_enabled = irq_enabled.rx();
|
||||||
|
let mut read_some_data = false;
|
||||||
|
let mut queue_overflow = false;
|
||||||
|
|
||||||
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
|
if irq_status.rx() {
|
||||||
|
let available_bytes = uart_regs.read_rx_fifo_trigger().level().as_usize();
|
||||||
|
|
||||||
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
|
// Read everything as fast as possible
|
||||||
|
for _ in 0..available_bytes {
|
||||||
|
let byte = uart_regs.read_data().value();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
}
|
||||||
|
prod.enqueue(byte).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout, empty the FIFO completely.
|
||||||
|
if irq_status.rx_timeout() {
|
||||||
|
while uart_regs.read_rx_status().data_available() {
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
let byte = uart_regs.read_data().value();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
}
|
||||||
|
prod.enqueue(byte).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uart_errors = on_interrupt_rx_common_post_processing(bank, rx_enabled, read_some_data);
|
||||||
|
if uart_errors.is_some() || queue_overflow {
|
||||||
|
return Err(AsyncUartErrors {
|
||||||
|
queue_overflow,
|
||||||
|
uart_errors: uart_errors.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ActiveReadGuard(usize);
|
||||||
|
|
||||||
|
impl Drop for ActiveReadGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
RX_READ_ACTIVE[self.0].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RxAsyncInner<const N: usize> {
|
||||||
|
rx: Rx,
|
||||||
|
pub queue: heapless::spsc::Consumer<'static, u8, N>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Core data structure to allow asynchronous UART reception.
|
||||||
|
///
|
||||||
|
/// If the ring buffer becomes full, data will be lost.
|
||||||
|
pub struct RxAsync<const N: usize>(Option<RxAsyncInner<N>>);
|
||||||
|
|
||||||
|
impl<const N: usize> ErrorType for RxAsync<N> {
|
||||||
|
/// Error reporting is done using the result of the interrupt functions.
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_async_rx(rx: &mut Rx) {
|
||||||
|
rx.disable_interrupts();
|
||||||
|
rx.disable();
|
||||||
|
rx.clear_fifo();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> RxAsync<N> {
|
||||||
|
/// Create a new asynchronous receiver.
|
||||||
|
///
|
||||||
|
/// The passed [heapless::spsc::Consumer] will be used to asynchronously receive data which
|
||||||
|
/// is filled by the interrupt handler [on_interrupt_rx].
|
||||||
|
pub fn new(mut rx: Rx, queue: heapless::spsc::Consumer<'static, u8, N>) -> Self {
|
||||||
|
rx.disable_interrupts();
|
||||||
|
rx.disable();
|
||||||
|
rx.clear_fifo();
|
||||||
|
// Enable those together.
|
||||||
|
critical_section::with(|_| {
|
||||||
|
rx.enable_interrupts(true);
|
||||||
|
rx.enable();
|
||||||
|
});
|
||||||
|
Self(Some(RxAsyncInner { rx, queue }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
stop_async_rx(&mut self.0.as_mut().unwrap().rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(mut self) -> (Rx, heapless::spsc::Consumer<'static, u8, N>) {
|
||||||
|
self.stop();
|
||||||
|
let inner = self.0.take().unwrap();
|
||||||
|
(inner.rx, inner.queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Drop for RxAsync<N> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> embedded_io_async::Read for RxAsync<N> {
|
||||||
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
let inner = self.0.as_ref().unwrap();
|
||||||
|
// Need to wait for the IRQ to read data and set this flag. If the queue is not
|
||||||
|
// empty, we can read data immediately.
|
||||||
|
if inner.queue.len() == 0 {
|
||||||
|
RX_HAS_DATA[inner.rx.id as usize].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
let _guard = ActiveReadGuard(inner.rx.id as usize);
|
||||||
|
let mut handle_data_in_queue = |consumer: &mut heapless::spsc::Consumer<'static, u8, N>| {
|
||||||
|
let data_to_read = consumer.len().min(buf.len());
|
||||||
|
for byte in buf.iter_mut().take(data_to_read) {
|
||||||
|
// We own the consumer and we checked that the amount of data is guaranteed to be available.
|
||||||
|
*byte = unsafe { consumer.dequeue_unchecked() };
|
||||||
|
}
|
||||||
|
data_to_read
|
||||||
|
};
|
||||||
|
let mut_ref = self.0.as_mut().unwrap();
|
||||||
|
let fut = RxFuture::new(&mut mut_ref.rx);
|
||||||
|
// Data is available, so read that data immediately.
|
||||||
|
let read_data = handle_data_in_queue(&mut mut_ref.queue);
|
||||||
|
if read_data > 0 {
|
||||||
|
return Ok(read_data);
|
||||||
|
}
|
||||||
|
// Await data.
|
||||||
|
let _ = fut.await;
|
||||||
|
Ok(handle_data_in_queue(&mut mut_ref.queue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RxAsyncOverwritingInner<const N: usize> {
|
||||||
|
rx: Rx,
|
||||||
|
pub shared_consumer: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Core data structure to allow asynchronous UART reception.
|
||||||
|
///
|
||||||
|
/// If the ring buffer becomes full, the oldest data will be overwritten when using the
|
||||||
|
/// [on_interrupt_rx_overwriting] interrupt handlers.
|
||||||
|
pub struct RxAsyncOverwriting<const N: usize>(Option<RxAsyncOverwritingInner<N>>);
|
||||||
|
|
||||||
|
impl<const N: usize> ErrorType for RxAsyncOverwriting<N> {
|
||||||
|
/// Error reporting is done using the result of the interrupt functions.
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> RxAsyncOverwriting<N> {
|
||||||
|
/// Create a new asynchronous receiver.
|
||||||
|
///
|
||||||
|
/// The passed shared [heapless::spsc::Consumer] will be used to asynchronously receive data
|
||||||
|
/// which is filled by the interrupt handler. The shared property allows using it in the
|
||||||
|
/// interrupt handler to overwrite old data.
|
||||||
|
pub fn new(
|
||||||
|
mut rx: Rx,
|
||||||
|
shared_consumer: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Self {
|
||||||
|
rx.disable_interrupts();
|
||||||
|
rx.disable();
|
||||||
|
rx.clear_fifo();
|
||||||
|
// Enable those together.
|
||||||
|
critical_section::with(|_| {
|
||||||
|
rx.enable_interrupts(true);
|
||||||
|
rx.enable();
|
||||||
|
});
|
||||||
|
Self(Some(RxAsyncOverwritingInner {
|
||||||
|
rx,
|
||||||
|
shared_consumer,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
stop_async_rx(&mut self.0.as_mut().unwrap().rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(mut self) -> Rx {
|
||||||
|
self.stop();
|
||||||
|
let inner = self.0.take().unwrap();
|
||||||
|
inner.rx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Drop for RxAsyncOverwriting<N> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> embedded_io_async::Read for RxAsyncOverwriting<N> {
|
||||||
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
let inner = self.0.as_ref().unwrap();
|
||||||
|
let id = inner.rx.id as usize;
|
||||||
|
// Need to wait for the IRQ to read data and set this flag. If the queue is not
|
||||||
|
// empty, we can read data immediately.
|
||||||
|
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let queue = inner.shared_consumer.borrow(cs);
|
||||||
|
if queue.borrow().as_ref().unwrap().len() == 0 {
|
||||||
|
RX_HAS_DATA[id].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _guard = ActiveReadGuard(id);
|
||||||
|
let mut handle_data_in_queue = |inner: &mut RxAsyncOverwritingInner<N>| {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut consumer_ref = inner.shared_consumer.borrow(cs).borrow_mut();
|
||||||
|
let consumer = consumer_ref.as_mut().unwrap();
|
||||||
|
let data_to_read = consumer.len().min(buf.len());
|
||||||
|
for byte in buf.iter_mut().take(data_to_read) {
|
||||||
|
// We own the consumer and we checked that the amount of data is guaranteed to be available.
|
||||||
|
*byte = unsafe { consumer.dequeue_unchecked() };
|
||||||
|
}
|
||||||
|
data_to_read
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let fut = RxFuture::new(&mut self.0.as_mut().unwrap().rx);
|
||||||
|
// Data is available, so read that data immediately.
|
||||||
|
let read_data = handle_data_in_queue(self.0.as_mut().unwrap());
|
||||||
|
if read_data > 0 {
|
||||||
|
return Ok(read_data);
|
||||||
|
}
|
||||||
|
// Await data.
|
||||||
|
let _ = fut.await;
|
||||||
|
let read_data = handle_data_in_queue(self.0.as_mut().unwrap());
|
||||||
|
Ok(read_data)
|
||||||
|
}
|
||||||
|
}
|
205
vorago-shared-periphs/src/uart/tx_asynch.rs
Normal file
205
vorago-shared-periphs/src/uart/tx_asynch.rs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
//! # Async UART transmission functionality for the VA108xx family.
|
||||||
|
//!
|
||||||
|
//! This module provides the [TxAsync] struct which implements the [embedded_io_async::Write] trait.
|
||||||
|
//! This trait allows for asynchronous sending of data streams. Please note that this module does
|
||||||
|
//! not specify/declare the interrupt handlers which must be provided for async support to work.
|
||||||
|
//! However, it the [on_interrupt_tx] interrupt handler.
|
||||||
|
//!
|
||||||
|
//! This handler should be called in ALL user interrupt handlers which handle UART TX interrupts
|
||||||
|
//! for a given UART bank.
|
||||||
|
use core::{cell::RefCell, future::Future};
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
use embedded_io_async::Write;
|
||||||
|
use portable_atomic::AtomicBool;
|
||||||
|
use raw_slice::RawBufSlice;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
static UART_TX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
|
||||||
|
static TX_CONTEXTS: [Mutex<RefCell<TxContext>>; 2] =
|
||||||
|
[const { Mutex::new(RefCell::new(TxContext::new())) }; 2];
|
||||||
|
// Completion flag. Kept outside of the context structure as an atomic to avoid
|
||||||
|
// critical section.
|
||||||
|
static TX_DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||||
|
|
||||||
|
/// This is a generic interrupt handler to handle asynchronous UART TX operations for a given
|
||||||
|
/// UART bank.
|
||||||
|
///
|
||||||
|
/// The user has to call this once in the interrupt handler responsible for the TX interrupts on
|
||||||
|
/// the given UART bank.
|
||||||
|
pub fn on_interrupt_tx(bank: Bank) {
|
||||||
|
let mut uart = unsafe { bank.steal_regs() };
|
||||||
|
let idx = bank as usize;
|
||||||
|
let irq_enabled = uart.read_irq_enabled();
|
||||||
|
// IRQ is not related to TX.
|
||||||
|
if !irq_enabled.tx() && !irq_enabled.tx_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx_status = uart.read_tx_status();
|
||||||
|
let unexpected_overrun = tx_status.wr_lost();
|
||||||
|
let mut context = critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[idx].borrow(cs);
|
||||||
|
*context_ref.borrow()
|
||||||
|
});
|
||||||
|
context.tx_overrun = unexpected_overrun;
|
||||||
|
// Safety: We documented that the user provided slice must outlive the future, so we convert
|
||||||
|
// the raw pointer back to the slice here.
|
||||||
|
let slice = unsafe { context.slice.get().unwrap() };
|
||||||
|
if context.progress >= slice.len() && !tx_status.tx_busy() {
|
||||||
|
uart.modify_irq_enabled(|mut value| {
|
||||||
|
value.set_tx(false);
|
||||||
|
value.set_tx_empty(false);
|
||||||
|
value.set_tx_status(false);
|
||||||
|
value
|
||||||
|
});
|
||||||
|
uart.modify_enable(|mut value| {
|
||||||
|
value.set_tx(false);
|
||||||
|
value
|
||||||
|
});
|
||||||
|
// Write back updated context structure.
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[idx].borrow(cs);
|
||||||
|
*context_ref.borrow_mut() = context;
|
||||||
|
});
|
||||||
|
// Transfer is done.
|
||||||
|
TX_DONE[idx].store(true, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
UART_TX_WAKERS[idx].wake();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while context.progress < slice.len() {
|
||||||
|
if uart.read_tx_status().ready() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Safety: TX structure is owned by the future which does not write into the the data
|
||||||
|
// register, so we can assume we are the only one writing to the data register.
|
||||||
|
uart.write_data(Data::new_with_raw_value(slice[context.progress] as u32));
|
||||||
|
context.progress += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back updated context structure.
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[idx].borrow(cs);
|
||||||
|
*context_ref.borrow_mut() = context;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct TxContext {
|
||||||
|
progress: usize,
|
||||||
|
tx_overrun: bool,
|
||||||
|
slice: RawBufSlice,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
impl TxContext {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
progress: 0,
|
||||||
|
tx_overrun: false,
|
||||||
|
slice: RawBufSlice::new_nulled(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxFuture {
|
||||||
|
id: Bank,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxFuture {
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function stores the raw pointer of the passed data slice. The user MUST ensure
|
||||||
|
/// that the slice outlives the data structure.
|
||||||
|
pub unsafe fn new(tx: &mut Tx, data: &[u8]) -> Self {
|
||||||
|
TX_DONE[tx.id as usize].store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
tx.disable_interrupts();
|
||||||
|
tx.disable();
|
||||||
|
tx.clear_fifo();
|
||||||
|
|
||||||
|
let init_fill_count = core::cmp::min(data.len(), 16);
|
||||||
|
// We fill the FIFO.
|
||||||
|
for data in data.iter().take(init_fill_count) {
|
||||||
|
tx.regs.write_data(Data::new_with_raw_value(*data as u32));
|
||||||
|
}
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[tx.id as usize].borrow(cs);
|
||||||
|
let mut context = context_ref.borrow_mut();
|
||||||
|
unsafe { context.slice.set(data) };
|
||||||
|
context.progress = init_fill_count;
|
||||||
|
|
||||||
|
// Ensure those are enabled inside a critical section at the same time. Can lead to
|
||||||
|
// weird glitches otherwise.
|
||||||
|
tx.enable_interrupts();
|
||||||
|
tx.enable();
|
||||||
|
});
|
||||||
|
Self { id: tx.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for TxFuture {
|
||||||
|
type Output = Result<usize, TxOverrunError>;
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> core::task::Poll<Self::Output> {
|
||||||
|
UART_TX_WAKERS[self.id as usize].register(cx.waker());
|
||||||
|
if TX_DONE[self.id as usize].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||||
|
let progress = critical_section::with(|cs| {
|
||||||
|
TX_CONTEXTS[self.id as usize].borrow(cs).borrow().progress
|
||||||
|
});
|
||||||
|
return core::task::Poll::Ready(Ok(progress));
|
||||||
|
}
|
||||||
|
core::task::Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TxFuture {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut reg_block = unsafe { self.id.steal_regs() };
|
||||||
|
|
||||||
|
disable_tx_interrupts(&mut reg_block);
|
||||||
|
disable_tx(&mut reg_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxAsync(Tx);
|
||||||
|
|
||||||
|
impl TxAsync {
|
||||||
|
pub fn new(tx: Tx) -> Self {
|
||||||
|
Self(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> Tx {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[error("TX overrun error")]
|
||||||
|
pub struct TxOverrunError;
|
||||||
|
|
||||||
|
impl embedded_io_async::Error for TxOverrunError {
|
||||||
|
fn kind(&self) -> embedded_io_async::ErrorKind {
|
||||||
|
embedded_io_async::ErrorKind::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io::ErrorType for TxAsync {
|
||||||
|
type Error = TxOverrunError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for TxAsync {
|
||||||
|
/// Write a buffer asynchronously.
|
||||||
|
///
|
||||||
|
/// This implementation is not side effect free, and a started future might have already
|
||||||
|
/// written part of the passed buffer.
|
||||||
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
let fut = unsafe { TxFuture::new(&mut self.0, buf) };
|
||||||
|
fut.await
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user