UART reception and echo reply now working
All checks were successful
Rust/va108xx-hal/pipeline/head This commit looks good
All checks were successful
Rust/va108xx-hal/pipeline/head This commit looks good
- Important bugfix in UART: use `modify` instead of `write` when enabling or disabling TX or RX - Extend RTIC example application. Reply handling is dispatched to lower priority interrupt
This commit is contained in:
parent
d458a81635
commit
a8b484d66f
@ -28,6 +28,7 @@ rt = ["va108xx/rt"]
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cortex-m-rtic = "0.6.0-rc.4"
|
cortex-m-rtic = "0.6.0-rc.4"
|
||||||
|
arrayvec = { version = "0.7.2", default-features = false }
|
||||||
panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
|
panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
|
||||||
rtt-target = { version = "0.3", features = ["cortex-m"] }
|
rtt-target = { version = "0.3", features = ["cortex-m"] }
|
||||||
panic-halt = "0.2"
|
panic-halt = "0.2"
|
||||||
|
@ -11,7 +11,7 @@ use cortex_m_rt::entry;
|
|||||||
use panic_rtt_target as _;
|
use panic_rtt_target as _;
|
||||||
use rtt_target::{rprintln, rtt_init_print};
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
use va108xx_hal::{
|
use va108xx_hal::{
|
||||||
pac::{self, Interrupt, TIM4, TIM5},
|
pac::{self, interrupt, TIM4, TIM5},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{
|
timer::{
|
||||||
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
|
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
|
||||||
|
@ -3,40 +3,52 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[rtic::app(device = pac)]
|
#[rtic::app(device = pac, dispatchers = [OC4])]
|
||||||
mod app {
|
mod app {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use panic_rtt_target as _;
|
use panic_rtt_target as _;
|
||||||
use rtt_target::{rprintln, rtt_init_print};
|
use rtt_target::{rprintln, rtt_init_default, set_print_channel};
|
||||||
use va108xx_hal::{gpio::PinsB, pac, prelude::*, uart};
|
use va108xx_hal::{
|
||||||
|
gpio::PinsB,
|
||||||
|
pac,
|
||||||
|
prelude::*,
|
||||||
|
uart::{self, IrqCfg, IrqResult, UartWithIrqBase},
|
||||||
|
};
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {}
|
struct Local {}
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {}
|
struct Shared {
|
||||||
|
irq_uart: UartWithIrqBase<pac::UARTB>,
|
||||||
|
rx_buf: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_ctx: init::Context) -> (Shared, Local, init::Monotonics) {
|
fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||||
rtt_init_print!();
|
let channels = rtt_init_default!();
|
||||||
rprintln!("-- VA108xx UART example application--");
|
set_print_channel(channels.up.0);
|
||||||
|
rprintln!("-- VA108xx UART IRQ example application--");
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = ctx.device;
|
||||||
|
|
||||||
let gpiob = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
let gpiob = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
||||||
let tx = gpiob.pb21.into_funsel_1();
|
let tx = gpiob.pb21.into_funsel_1();
|
||||||
let rx = gpiob.pb20.into_funsel_1();
|
let rx = gpiob.pb20.into_funsel_1();
|
||||||
|
|
||||||
let uartb = uart::Uart::uartb(
|
let irq_cfg = IrqCfg::new(pac::interrupt::OC3, true, true);
|
||||||
|
let (mut irq_uart, _) = uart::Uart::uartb(
|
||||||
dp.UARTB,
|
dp.UARTB,
|
||||||
(tx, rx),
|
(tx, rx),
|
||||||
115200.bps(),
|
115200.bps(),
|
||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
50.mhz(),
|
50.mhz(),
|
||||||
);
|
)
|
||||||
let (mut tx, mut _rx) = uartb.split();
|
.into_uart_with_irq(irq_cfg, Some(&mut dp.SYSCONFIG), Some(&mut dp.IRQSEL))
|
||||||
writeln!(tx, "Hello World\r").unwrap();
|
.downgrade();
|
||||||
(Shared {}, Local {}, init::Monotonics())
|
irq_uart
|
||||||
|
.read_fixed_len_using_irq(64, true)
|
||||||
|
.expect("Read initialization failed");
|
||||||
|
let rx_buf: [u8; 64] = [0; 64];
|
||||||
|
(Shared { irq_uart, rx_buf }, Local {}, init::Monotonics())
|
||||||
}
|
}
|
||||||
|
|
||||||
// `shared` cannot be accessed from this context
|
// `shared` cannot be accessed from this context
|
||||||
@ -44,21 +56,64 @@ mod app {
|
|||||||
fn idle(_cx: idle::Context) -> ! {
|
fn idle(_cx: idle::Context) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[task(
|
||||||
|
binds = OC3,
|
||||||
|
shared = [irq_uart, rx_buf],
|
||||||
|
local = [cnt: u32 = 0, result: IrqResult = IrqResult::new()],
|
||||||
|
priority = 4
|
||||||
|
)]
|
||||||
|
fn reception_task(cx: reception_task::Context) {
|
||||||
|
let result = cx.local.result;
|
||||||
|
let cnt: &mut u32 = cx.local.cnt;
|
||||||
|
let irq_uart = cx.shared.irq_uart;
|
||||||
|
let rx_buf = cx.shared.rx_buf;
|
||||||
|
let (completed, end_idx) = (irq_uart, rx_buf).lock(|irq_uart, rx_buf| {
|
||||||
|
match irq_uart.irq_handler(result, rx_buf) {
|
||||||
|
Ok(_) => {
|
||||||
|
if result.complete() {
|
||||||
|
// Initiate next transfer immediately
|
||||||
|
irq_uart
|
||||||
|
.read_fixed_len_using_irq(64, true)
|
||||||
|
.expect("Read operation init failed");
|
||||||
|
|
||||||
|
let mut end_idx = 0;
|
||||||
|
for idx in 0..rx_buf.len() {
|
||||||
|
if (rx_buf[idx] as char) == '\n' {
|
||||||
|
end_idx = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true, end_idx)
|
||||||
|
} else {
|
||||||
|
(false, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
rprintln!("Reception Error {:?}", e);
|
||||||
|
(false, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if completed {
|
||||||
|
rprintln!("Counter: {}", cnt);
|
||||||
|
reply_handler::spawn(result.bytes_read, end_idx, result.timeout()).unwrap();
|
||||||
|
}
|
||||||
|
*cnt += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [irq_uart, rx_buf], priority = 3)]
|
||||||
|
fn reply_handler(cx: reply_handler::Context, bytes_read: usize, end_idx: usize, timeout: bool) {
|
||||||
|
let irq_uart = cx.shared.irq_uart;
|
||||||
|
let rx_buf = cx.shared.rx_buf;
|
||||||
|
(irq_uart, rx_buf).lock(|irq_uart, rx_buf| {
|
||||||
|
rprintln!("Reception success, {} bytes read", bytes_read);
|
||||||
|
if timeout {
|
||||||
|
rprintln!("Timeout occured");
|
||||||
|
}
|
||||||
|
let string = core::str::from_utf8(&rx_buf[0..end_idx]).expect("Invalid string format");
|
||||||
|
rprintln!("Read string: {}", string);
|
||||||
|
writeln!(irq_uart.uart, "{}", string).expect("Sending reply failed");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[entry]
|
|
||||||
// fn main() -> ! {
|
|
||||||
|
|
||||||
// loop {
|
|
||||||
// // Echo what is received on the serial link.
|
|
||||||
// match rx.read() {
|
|
||||||
// Ok(recv) => {
|
|
||||||
// nb::block!(tx.write(recv)).expect("TX send error");
|
|
||||||
// }
|
|
||||||
// Err(nb::Error::WouldBlock) => (),
|
|
||||||
// Err(nb::Error::Other(uart_error)) => {
|
|
||||||
// rprintln!("UART receive error {:?}", uart_error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
412
src/uart.rs
412
src/uart.rs
@ -7,10 +7,9 @@ use core::{convert::Infallible, ptr};
|
|||||||
use core::{marker::PhantomData, ops::Deref};
|
use core::{marker::PhantomData, ops::Deref};
|
||||||
use libm::floorf;
|
use libm::floorf;
|
||||||
|
|
||||||
use crate::clock::enable_peripheral_clock;
|
|
||||||
pub use crate::utility::IrqCfg;
|
pub use crate::utility::IrqCfg;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock,
|
clock::{self, enable_peripheral_clock, PeripheralClocks},
|
||||||
gpio::pins::{
|
gpio::pins::{
|
||||||
AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30,
|
AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30,
|
||||||
PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9,
|
PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9,
|
||||||
@ -56,6 +55,8 @@ pub enum Error {
|
|||||||
BreakCondition,
|
BreakCondition,
|
||||||
TransferPending,
|
TransferPending,
|
||||||
BufferTooShort,
|
BufferTooShort,
|
||||||
|
/// Can be a combination of overrun, framing or parity error
|
||||||
|
IrqError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
@ -191,12 +192,25 @@ pub enum IrqResultMask {
|
|||||||
Break = 4,
|
Break = 4,
|
||||||
Timeout = 5,
|
Timeout = 5,
|
||||||
Addr9 = 6,
|
Addr9 = 6,
|
||||||
|
/// Should not happen
|
||||||
|
Unknown = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct IrqResult {
|
pub struct IrqResult {
|
||||||
raw_res: u32,
|
raw_res: u32,
|
||||||
pub bytes_read: usize,
|
pub bytes_read: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IrqResult {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
IrqResult {
|
||||||
|
raw_res: 0,
|
||||||
|
bytes_read: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IrqResult {
|
impl IrqResult {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn raw_result(&self) -> u32 {
|
pub fn raw_result(&self) -> u32 {
|
||||||
@ -214,7 +228,7 @@ impl IrqResult {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn complete(&self) -> bool {
|
pub fn complete(&self) -> bool {
|
||||||
if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x00 {
|
if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x01 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -272,16 +286,24 @@ pub enum IrqReceptionMode {
|
|||||||
// UART implementation
|
// UART implementation
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Serial abstraction
|
pub struct UartBase<UART> {
|
||||||
pub struct Uart<UART, PINS> {
|
|
||||||
uart: UART,
|
uart: UART,
|
||||||
pins: PINS,
|
|
||||||
tx: Tx<UART>,
|
tx: Tx<UART>,
|
||||||
rx: Rx<UART>,
|
rx: Rx<UART>,
|
||||||
}
|
}
|
||||||
|
/// Serial abstraction
|
||||||
|
pub struct Uart<UART, PINS> {
|
||||||
|
uart_base: UartBase<UART>,
|
||||||
|
pins: PINS,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UartWithIrq<UART, PINS> {
|
pub struct UartWithIrq<UART, PINS> {
|
||||||
uart_base: Uart<UART, PINS>,
|
irq_base: UartWithIrqBase<UART>,
|
||||||
|
pins: PINS,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UartWithIrqBase<UART> {
|
||||||
|
pub uart: UartBase<UART>,
|
||||||
irq_info: IrqInfo,
|
irq_info: IrqInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,12 +335,10 @@ impl<UART> Tx<UART> {
|
|||||||
|
|
||||||
pub trait Instance: Deref<Target = uart_base::RegisterBlock> {
|
pub trait Instance: Deref<Target = uart_base::RegisterBlock> {
|
||||||
fn ptr() -> *const uart_base::RegisterBlock;
|
fn ptr() -> *const uart_base::RegisterBlock;
|
||||||
|
const IDX: u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UART, PINS> Uart<UART, PINS>
|
impl<UART: Instance> UartBase<UART> {
|
||||||
where
|
|
||||||
UART: Instance,
|
|
||||||
{
|
|
||||||
/// This function assumes that the peripheral clock was alredy enabled
|
/// This function assumes that the peripheral clock was alredy enabled
|
||||||
/// in the SYSCONFIG register
|
/// in the SYSCONFIG register
|
||||||
fn init(self, config: Config, sys_clk: Hertz) -> Self {
|
fn init(self, config: Config, sys_clk: Hertz) -> Self {
|
||||||
@ -366,22 +386,22 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable_rx(&mut self) {
|
pub fn enable_rx(&mut self) {
|
||||||
self.uart.enable.write(|w| w.rxenable().set_bit());
|
self.uart.enable.modify(|_, w| w.rxenable().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_rx(&mut self) {
|
pub fn disable_rx(&mut self) {
|
||||||
self.uart.enable.write(|w| w.rxenable().set_bit());
|
self.uart.enable.modify(|_, w| w.rxenable().clear_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable_tx(&mut self) {
|
pub fn enable_tx(&mut self) {
|
||||||
self.uart.enable.write(|w| w.txenable().set_bit());
|
self.uart.enable.modify(|_, w| w.txenable().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_tx(&mut self) {
|
pub fn disable_tx(&mut self) {
|
||||||
self.uart.enable.write(|w| w.txenable().set_bit());
|
self.uart.enable.modify(|_, w| w.txenable().clear_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -404,7 +424,7 @@ where
|
|||||||
self.uart.fifo_clr.write(|w| w.txsts().set_bit());
|
self.uart.fifo_clr.write(|w| w.txsts().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen(self, event: Event) -> Self {
|
pub fn listen(&self, event: Event) {
|
||||||
self.uart.irq_enb.modify(|_, w| match event {
|
self.uart.irq_enb.modify(|_, w| match event {
|
||||||
Event::RxError => w.irq_rx_status().set_bit(),
|
Event::RxError => w.irq_rx_status().set_bit(),
|
||||||
Event::RxFifoHalfFull => w.irq_rx().set_bit(),
|
Event::RxFifoHalfFull => w.irq_rx().set_bit(),
|
||||||
@ -414,10 +434,9 @@ where
|
|||||||
Event::TxFifoHalfFull => w.irq_tx().set_bit(),
|
Event::TxFifoHalfFull => w.irq_tx().set_bit(),
|
||||||
Event::TxCts => w.irq_tx_cts().set_bit(),
|
Event::TxCts => w.irq_tx_cts().set_bit(),
|
||||||
});
|
});
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlisten(self, event: Event) -> Self {
|
pub fn unlisten(&self, event: Event) {
|
||||||
self.uart.irq_enb.modify(|_, w| match event {
|
self.uart.irq_enb.modify(|_, w| match event {
|
||||||
Event::RxError => w.irq_rx_status().clear_bit(),
|
Event::RxError => w.irq_rx_status().clear_bit(),
|
||||||
Event::RxFifoHalfFull => w.irq_rx().clear_bit(),
|
Event::RxFifoHalfFull => w.irq_rx().clear_bit(),
|
||||||
@ -427,10 +446,9 @@ where
|
|||||||
Event::TxFifoHalfFull => w.irq_tx().clear_bit(),
|
Event::TxFifoHalfFull => w.irq_tx().clear_bit(),
|
||||||
Event::TxCts => w.irq_tx_cts().clear_bit(),
|
Event::TxCts => w.irq_tx_cts().clear_bit(),
|
||||||
});
|
});
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) -> (UART, PINS) {
|
pub fn release(self) -> UART {
|
||||||
// Clear the FIFO
|
// Clear the FIFO
|
||||||
self.uart.fifo_clr.write(|w| {
|
self.uart.fifo_clr.write(|w| {
|
||||||
w.rxfifo().set_bit();
|
w.rxfifo().set_bit();
|
||||||
@ -440,7 +458,7 @@ where
|
|||||||
w.rxenable().clear_bit();
|
w.rxenable().clear_bit();
|
||||||
w.txenable().clear_bit()
|
w.txenable().clear_bit()
|
||||||
});
|
});
|
||||||
(self.uart, self.pins)
|
self.uart
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
|
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
|
||||||
@ -448,14 +466,130 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<UART, PINS> Uart<UART, PINS>
|
||||||
|
where
|
||||||
|
UART: Instance,
|
||||||
|
{
|
||||||
|
/// This function assumes that the peripheral clock was alredy enabled
|
||||||
|
/// in the SYSCONFIG register
|
||||||
|
fn init(mut self, config: Config, sys_clk: Hertz) -> Self {
|
||||||
|
self.uart_base = self.uart_base.init(config, sys_clk);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_uart_with_irq(
|
||||||
|
self,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
|
sys_cfg: Option<&mut SYSCONFIG>,
|
||||||
|
irq_sel: Option<&mut IRQSEL>,
|
||||||
|
) -> UartWithIrq<UART, PINS> {
|
||||||
|
let (uart, pins) = self.downgrade_internal();
|
||||||
|
UartWithIrq {
|
||||||
|
pins,
|
||||||
|
irq_base: UartWithIrqBase {
|
||||||
|
uart,
|
||||||
|
irq_info: IrqInfo {
|
||||||
|
rx_len: 0,
|
||||||
|
rx_idx: 0,
|
||||||
|
irq_cfg,
|
||||||
|
mode: IrqReceptionMode::Idle,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.init(sys_cfg, irq_sel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_rx(&mut self) {
|
||||||
|
self.uart_base.enable_rx();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_rx(&mut self) {
|
||||||
|
self.uart_base.enable_rx();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_tx(&mut self) {
|
||||||
|
self.uart_base.enable_tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_tx(&mut self) {
|
||||||
|
self.uart_base.disable_tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_fifo(&mut self) {
|
||||||
|
self.uart_base.clear_rx_fifo();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_fifo(&mut self) {
|
||||||
|
self.uart_base.clear_tx_fifo();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_status(&mut self) {
|
||||||
|
self.uart_base.clear_rx_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_status(&mut self) {
|
||||||
|
self.uart_base.clear_tx_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(&self, event: Event) {
|
||||||
|
self.uart_base.listen(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlisten(&self, event: Event) {
|
||||||
|
self.uart_base.unlisten(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> (UART, PINS) {
|
||||||
|
(self.uart_base.release(), self.pins)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downgrade_internal(self) -> (UartBase<UART>, PINS) {
|
||||||
|
let base = UartBase {
|
||||||
|
uart: self.uart_base.uart,
|
||||||
|
tx: self.uart_base.tx,
|
||||||
|
rx: self.uart_base.rx,
|
||||||
|
};
|
||||||
|
(base, self.pins)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade(self) -> UartBase<UART> {
|
||||||
|
UartBase {
|
||||||
|
uart: self.uart_base.uart,
|
||||||
|
tx: self.uart_base.tx,
|
||||||
|
rx: self.uart_base.rx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
|
||||||
|
self.uart_base.split()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for UARTA {
|
||||||
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
|
UARTA::ptr() as *const _
|
||||||
|
}
|
||||||
|
const IDX: u8 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for UARTB {
|
||||||
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
|
UARTB::ptr() as *const _
|
||||||
|
}
|
||||||
|
const IDX: u8 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! uart_impl {
|
macro_rules! uart_impl {
|
||||||
($($UARTX:ident: ($uartx:ident, $clk_enb_enum:path),)+) => {
|
($($UARTX:ident: ($uartx:ident, $clk_enb_enum:path),)+) => {
|
||||||
$(
|
$(
|
||||||
impl Instance for $UARTX {
|
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
|
||||||
$UARTX::ptr() as *const _
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<PINS: Pins<$UARTX>> Uart<$UARTX, PINS> {
|
impl<PINS: Pins<$UARTX>> Uart<$UARTX, PINS> {
|
||||||
pub fn $uartx(
|
pub fn $uartx(
|
||||||
@ -467,47 +601,49 @@ macro_rules! uart_impl {
|
|||||||
) -> Self
|
) -> Self
|
||||||
{
|
{
|
||||||
enable_peripheral_clock(syscfg, $clk_enb_enum);
|
enable_peripheral_clock(syscfg, $clk_enb_enum);
|
||||||
Uart { uart, pins, tx: Tx::new(), rx: Rx::new() }.init(
|
Uart {
|
||||||
config.into(), sys_clk.into()
|
uart_base: UartBase {
|
||||||
)
|
uart,
|
||||||
|
tx: Tx::new(),
|
||||||
|
rx: Rx::new(),
|
||||||
|
},
|
||||||
|
pins,
|
||||||
|
}
|
||||||
|
.init(config.into(), sys_clk.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<PINS> Uart<UARTA, PINS> {
|
impl<UART: Instance> UartWithIrqBase<UART> {
|
||||||
pub fn into_uart_with_irq(self, irq_cfg: IrqCfg) -> UartWithIrq<UARTA, PINS> {
|
fn init(self, sys_cfg: Option<&mut SYSCONFIG>, irq_sel: Option<&mut IRQSEL>) -> Self {
|
||||||
UartWithIrq {
|
if let Some(sys_cfg) = sys_cfg {
|
||||||
uart_base: self,
|
enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel)
|
||||||
irq_info: IrqInfo {
|
}
|
||||||
rx_len: 0,
|
if let Some(irq_sel) = irq_sel {
|
||||||
rx_idx: 0,
|
if self.irq_info.irq_cfg.route {
|
||||||
irq_cfg,
|
irq_sel.uart[UART::IDX as usize]
|
||||||
mode: IrqReceptionMode::Idle,
|
.write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) });
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
self
|
||||||
|
}
|
||||||
|
|
||||||
impl<PINS> UartWithIrq<UARTA, PINS> {
|
|
||||||
pub fn read_fixed_len_using_irq(
|
pub fn read_fixed_len_using_irq(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
enb_timeout_irq: bool,
|
enb_timeout_irq: bool,
|
||||||
irqsel: Option<&mut IRQSEL>,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if self.irq_info.mode != IrqReceptionMode::Idle {
|
if self.irq_info.mode != IrqReceptionMode::Idle {
|
||||||
return Err(Error::TransferPending);
|
return Err(Error::TransferPending);
|
||||||
}
|
}
|
||||||
self.irq_info.rx_idx = 0;
|
self.irq_info.rx_idx = 0;
|
||||||
self.irq_info.rx_len = max_len;
|
self.irq_info.rx_len = max_len;
|
||||||
|
self.uart.enable_rx();
|
||||||
|
self.uart.enable_tx();
|
||||||
self.enable_rx_irq_sources(enb_timeout_irq);
|
self.enable_rx_irq_sources(enb_timeout_irq);
|
||||||
if let Some(irqsel) = irqsel {
|
|
||||||
if self.irq_info.irq_cfg.route {
|
|
||||||
irqsel.uart[0].write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.irq_info.irq_cfg.enable {
|
if self.irq_info.irq_cfg.enable {
|
||||||
unmask_irq(self.irq_info.irq_cfg.irq);
|
unmask_irq(self.irq_info.irq_cfg.irq);
|
||||||
}
|
}
|
||||||
@ -516,7 +652,7 @@ impl<PINS> UartWithIrq<UARTA, PINS> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn enable_rx_irq_sources(&mut self, timeout: bool) {
|
fn enable_rx_irq_sources(&mut self, timeout: bool) {
|
||||||
self.uart_base.uart.irq_enb.modify(|_, w| {
|
self.uart.uart.irq_enb.modify(|_, w| {
|
||||||
if timeout {
|
if timeout {
|
||||||
w.irq_rx_to().set_bit();
|
w.irq_rx_to().set_bit();
|
||||||
}
|
}
|
||||||
@ -527,18 +663,28 @@ impl<PINS> UartWithIrq<UARTA, PINS> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn disable_rx_irq_sources(&mut self) {
|
fn disable_rx_irq_sources(&mut self) {
|
||||||
self.uart_base.uart.irq_enb.modify(|_, w| {
|
self.uart.uart.irq_enb.modify(|_, w| {
|
||||||
w.irq_rx_to().clear_bit();
|
w.irq_rx_to().clear_bit();
|
||||||
w.irq_rx_status().clear_bit();
|
w.irq_rx_status().clear_bit();
|
||||||
w.irq_rx().clear_bit()
|
w.irq_rx().clear_bit()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_tx(&mut self) {
|
||||||
|
self.uart.enable_tx()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_tx(&mut self) {
|
||||||
|
self.uart.disable_tx()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cancel_transfer(&mut self) {
|
pub fn cancel_transfer(&mut self) {
|
||||||
// Disable IRQ
|
// Disable IRQ
|
||||||
cortex_m::peripheral::NVIC::mask(self.irq_info.irq_cfg.irq);
|
cortex_m::peripheral::NVIC::mask(self.irq_info.irq_cfg.irq);
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
self.uart_base.clear_tx_fifo();
|
self.uart.clear_tx_fifo();
|
||||||
self.irq_info.rx_idx = 0;
|
self.irq_info.rx_idx = 0;
|
||||||
self.irq_info.rx_len = 0;
|
self.irq_info.rx_len = 0;
|
||||||
}
|
}
|
||||||
@ -548,36 +694,68 @@ impl<PINS> UartWithIrq<UARTA, PINS> {
|
|||||||
return Err(Error::BufferTooShort);
|
return Err(Error::BufferTooShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rx_status = self.uart_base.uart.rxstatus.read();
|
let irq_end = self.uart.uart.irq_end.read();
|
||||||
let _tx_status = self.uart_base.uart.txstatus.read();
|
let enb_status = self.uart.uart.enable.read();
|
||||||
let irq_end = self.uart_base.uart.irq_end.read();
|
|
||||||
|
|
||||||
let enb_status = self.uart_base.uart.enable.read();
|
|
||||||
let rx_enabled = enb_status.rxenable().bit_is_set();
|
let rx_enabled = enb_status.rxenable().bit_is_set();
|
||||||
let _tx_enabled = enb_status.txenable().bit_is_set();
|
let _tx_enabled = enb_status.txenable().bit_is_set();
|
||||||
res.clear_result();
|
let read_handler =
|
||||||
if irq_end.irq_rx().bit_is_set() && rx_status.rdavl().bit_is_set() {
|
|res: &mut IrqResult, read_res: nb::Result<u8, Error>| -> Result<Option<u8>, Error> {
|
||||||
let mut rd_avl = rx_status.rdavl();
|
match read_res {
|
||||||
// While there is data in the FIFO, write it into the reception buffer
|
Ok(byte) => return Ok(Some(byte)),
|
||||||
while self.irq_info.rx_idx < self.irq_info.rx_len && rd_avl.bit_is_set() {
|
Err(nb::Error::WouldBlock) => {
|
||||||
buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap();
|
return Ok(None);
|
||||||
rd_avl = self.uart_base.uart.rxstatus.read().rdavl();
|
}
|
||||||
|
Err(nb::Error::Other(e)) => match e {
|
||||||
|
Error::Overrun => {
|
||||||
|
res.set_result(IrqResultMask::Overflow);
|
||||||
|
return Err(Error::IrqError);
|
||||||
|
}
|
||||||
|
Error::FramingError => {
|
||||||
|
res.set_result(IrqResultMask::FramingError);
|
||||||
|
return Err(Error::IrqError);
|
||||||
|
}
|
||||||
|
Error::ParityError => {
|
||||||
|
res.set_result(IrqResultMask::ParityError);
|
||||||
|
return Err(Error::IrqError);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
res.set_result(IrqResultMask::Unknown);
|
||||||
|
return Err(Error::IrqError);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if irq_end.irq_rx().bit_is_set() {
|
||||||
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
|
// Read everything as fast as possible
|
||||||
|
for _ in 0..core::cmp::min(
|
||||||
|
self.uart.uart.rxfifoirqtrg.read().bits() as usize,
|
||||||
|
self.irq_info.rx_len,
|
||||||
|
) {
|
||||||
|
buf[self.irq_info.rx_idx] = (self.uart.uart.data.read().bits() & 0xff) as u8;
|
||||||
self.irq_info.rx_idx += 1;
|
self.irq_info.rx_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
loop {
|
||||||
if self.irq_info.rx_idx == self.irq_info.rx_len {
|
if self.irq_info.rx_idx == self.irq_info.rx_len {
|
||||||
self.disable_rx_irq_sources();
|
self.irq_completion_handler(res);
|
||||||
res.bytes_read = self.irq_info.rx_len;
|
|
||||||
res.set_result(IrqResultMask::Complete);
|
|
||||||
self.irq_info.rx_idx = 0;
|
|
||||||
self.irq_info.rx_len = 0;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if let Some(byte) = read_handler(res, self.uart.read())? {
|
||||||
|
buf[self.irq_info.rx_idx] = byte;
|
||||||
|
self.irq_info.rx_idx += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RX transfer not complete, check for RX errors
|
// RX transfer not complete, check for RX errors
|
||||||
if (self.irq_info.rx_idx < self.irq_info.rx_len) && rx_enabled {
|
if (self.irq_info.rx_idx < self.irq_info.rx_len) && rx_enabled {
|
||||||
// Read status register again, might have changed since reading received data
|
// Read status register again, might have changed since reading received data
|
||||||
rx_status = self.uart_base.uart.rxstatus.read();
|
let rx_status = self.uart.uart.rxstatus.read();
|
||||||
|
res.clear_result();
|
||||||
if rx_status.rxovr().bit_is_set() {
|
if rx_status.rxovr().bit_is_set() {
|
||||||
res.set_result(IrqResultMask::Overflow);
|
res.set_result(IrqResultMask::Overflow);
|
||||||
}
|
}
|
||||||
@ -593,27 +771,74 @@ impl<PINS> UartWithIrq<UARTA, PINS> {
|
|||||||
if rx_status.rxto().bit_is_set() {
|
if rx_status.rxto().bit_is_set() {
|
||||||
// A timeout has occured but there might be some leftover data in the FIFO,
|
// A timeout has occured but there might be some leftover data in the FIFO,
|
||||||
// so read that data as well
|
// so read that data as well
|
||||||
while self.irq_info.rx_idx < self.irq_info.rx_len && rx_status.rdavl().bit_is_set()
|
loop {
|
||||||
{
|
if let Some(byte) = read_handler(res, self.uart.read())? {
|
||||||
buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap();
|
buf[self.irq_info.rx_idx] = byte;
|
||||||
self.irq_info.rx_idx += 1;
|
self.irq_info.rx_idx += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
res.bytes_read = self.irq_info.rx_idx;
|
}
|
||||||
|
self.irq_completion_handler(res);
|
||||||
res.set_result(IrqResultMask::Timeout);
|
res.set_result(IrqResultMask::Timeout);
|
||||||
res.set_result(IrqResultMask::Complete);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it is not a timeout, it's an error
|
||||||
if res.raw_res != 0 {
|
if res.raw_res != 0 {
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
|
return Err(Error::IrqError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.uart_base
|
// Clear the interrupt status bits
|
||||||
|
self.uart
|
||||||
.uart
|
.uart
|
||||||
.irq_clr
|
.irq_clr
|
||||||
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn irq_completion_handler(&mut self, res: &mut IrqResult) {
|
||||||
|
self.disable_rx_irq_sources();
|
||||||
|
self.uart.disable_rx();
|
||||||
|
res.bytes_read = self.irq_info.rx_idx;
|
||||||
|
res.clear_result();
|
||||||
|
res.set_result(IrqResultMask::Complete);
|
||||||
|
self.irq_info.rx_idx = 0;
|
||||||
|
self.irq_info.rx_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> UART {
|
||||||
|
self.uart.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<UART: Instance, PINS> UartWithIrq<UART, PINS> {
|
||||||
|
pub fn read_fixed_len_using_irq(
|
||||||
|
&mut self,
|
||||||
|
max_len: usize,
|
||||||
|
enb_timeout_irq: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.irq_base
|
||||||
|
.read_fixed_len_using_irq(max_len, enb_timeout_irq)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cancel_transfer(&mut self) {
|
||||||
|
self.irq_base.cancel_transfer()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq_handler(&mut self, res: &mut IrqResult, buf: &mut [u8]) -> Result<(), Error> {
|
||||||
|
self.irq_base.irq_handler(res, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> (UART, PINS) {
|
||||||
|
(self.irq_base.release(), self.pins)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade(self) -> (UartWithIrqBase<UART>, PINS) {
|
||||||
|
(self.irq_base, self.pins)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_impl! {
|
uart_impl! {
|
||||||
@ -623,10 +848,7 @@ uart_impl! {
|
|||||||
|
|
||||||
impl<UART> Tx<UART> where UART: Instance {}
|
impl<UART> Tx<UART> where UART: Instance {}
|
||||||
|
|
||||||
impl<UART, PINS> serial::Write<u8> for Uart<UART, PINS>
|
impl<UART: Instance> serial::Write<u8> for UartBase<UART> {
|
||||||
where
|
|
||||||
UART: Instance,
|
|
||||||
{
|
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.tx.write(word)
|
self.tx.write(word)
|
||||||
@ -636,6 +858,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<UART, PINS> serial::Write<u8> for Uart<UART, PINS>
|
||||||
|
where
|
||||||
|
UART: Instance,
|
||||||
|
{
|
||||||
|
type Error = Infallible;
|
||||||
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
self.uart_base.write(word)
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
|
self.uart_base.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<UART: Instance, PINS> blocking::serial::write::Default<u8> for Uart<UART, PINS> {}
|
impl<UART: Instance, PINS> blocking::serial::write::Default<u8> for Uart<UART, PINS> {}
|
||||||
|
|
||||||
impl<UART: Instance> serial::Write<u8> for Tx<UART> {
|
impl<UART: Instance> serial::Write<u8> for Tx<UART> {
|
||||||
@ -667,7 +902,7 @@ impl<UART: Instance> serial::Write<u8> for Tx<UART> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UART: Instance, PINS> serial::Read<u8> for Uart<UART, PINS> {
|
impl<UART: Instance> serial::Read<u8> for UartBase<UART> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> nb::Result<u8, Error> {
|
fn read(&mut self) -> nb::Result<u8, Error> {
|
||||||
@ -675,6 +910,14 @@ impl<UART: Instance, PINS> serial::Read<u8> for Uart<UART, PINS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<UART: Instance, PINS> serial::Read<u8> for Uart<UART, PINS> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn read(&mut self) -> nb::Result<u8, Error> {
|
||||||
|
self.uart_base.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<UART: Instance> serial::Read<u8> for Rx<UART> {
|
impl<UART: Instance> serial::Read<u8> for Rx<UART> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
@ -706,7 +949,7 @@ impl<UART: Instance> serial::Read<u8> for Rx<UART> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UART> core::fmt::Write for Tx<UART>
|
impl<UART: Instance> core::fmt::Write for Tx<UART>
|
||||||
where
|
where
|
||||||
Tx<UART>: embedded_hal::serial::Write<u8>,
|
Tx<UART>: embedded_hal::serial::Write<u8>,
|
||||||
{
|
{
|
||||||
@ -717,3 +960,12 @@ where
|
|||||||
.map_err(|_| core::fmt::Error)
|
.map_err(|_| core::fmt::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<UART: Instance> core::fmt::Write for UartBase<UART>
|
||||||
|
where
|
||||||
|
UartBase<UART>: embedded_hal::serial::Write<u8>,
|
||||||
|
{
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
self.tx.write_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user