Major refactoring
Some checks failed
Rust/va108xx-hal/pipeline/head There was a failure building this commit
Some checks failed
Rust/va108xx-hal/pipeline/head There was a failure building this commit
- Improved IRQ handling, which makes most unsafe unmask operations in user code absolete - Add first UART RX handlers which use an IRQ
This commit is contained in:
parent
dc2426a905
commit
f376a43f41
16
Cargo.toml
16
Cargo.toml
@ -45,19 +45,3 @@ opt-level = "s"
|
|||||||
# [profile.release-lto]
|
# [profile.release-lto]
|
||||||
# inherits = "release"
|
# inherits = "release"
|
||||||
# lto = true
|
# lto = true
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "timer-ticks"
|
|
||||||
required-features = ["rt"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "tests"
|
|
||||||
required-features = ["rt"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "pwm"
|
|
||||||
required-features = ["rt"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "cascade"
|
|
||||||
required-features = ["rt"]
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use embedded_hal::digital::v2::ToggleableOutputPin;
|
use embedded_hal::digital::v2::ToggleableOutputPin;
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::set_up_ms_timer};
|
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountDownTimer};
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
@ -18,13 +18,7 @@ fn main() -> ! {
|
|||||||
let mut led1 = porta.pa10.into_push_pull_output();
|
let mut led1 = porta.pa10.into_push_pull_output();
|
||||||
let mut led2 = porta.pa7.into_push_pull_output();
|
let mut led2 = porta.pa7.into_push_pull_output();
|
||||||
let mut led3 = porta.pa6.into_push_pull_output();
|
let mut led3 = porta.pa6.into_push_pull_output();
|
||||||
let mut delay = set_up_ms_timer(
|
let mut delay = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
|
||||||
&mut dp.SYSCONFIG,
|
|
||||||
&mut dp.IRQSEL,
|
|
||||||
50.mhz().into(),
|
|
||||||
dp.TIM0,
|
|
||||||
pac::Interrupt::OC0,
|
|
||||||
);
|
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
led1.set_low().ok();
|
led1.set_low().ok();
|
||||||
led2.set_low().ok();
|
led2.set_low().ok();
|
||||||
|
@ -14,8 +14,8 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt, TIM4, TIM5},
|
pac::{self, interrupt, TIM4, TIM5},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{
|
timer::{
|
||||||
default_ms_irq_handler, set_up_ms_timer, CascadeCtrl, CascadeSource, CountDownTimer, Delay,
|
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
|
||||||
Event,
|
CountDownTimer, Event, IrqCfg,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,23 +28,16 @@ fn main() -> ! {
|
|||||||
rprintln!("-- VA108xx Cascade example application--");
|
rprintln!("-- VA108xx Cascade example application--");
|
||||||
|
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let timer = set_up_ms_timer(
|
let mut delay = set_up_ms_delay_provider(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
|
||||||
&mut dp.SYSCONFIG,
|
|
||||||
&mut dp.IRQSEL,
|
|
||||||
50.mhz().into(),
|
|
||||||
dp.TIM0,
|
|
||||||
pac::Interrupt::OC0,
|
|
||||||
);
|
|
||||||
let mut delay = Delay::new(timer);
|
|
||||||
|
|
||||||
// Will be started periodically to trigger a cascade
|
// Will be started periodically to trigger a cascade
|
||||||
let mut cascade_triggerer =
|
let mut cascade_triggerer =
|
||||||
CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM3).auto_disable(true);
|
CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM3).auto_disable(true);
|
||||||
cascade_triggerer.listen(
|
cascade_triggerer.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
&mut dp.SYSCONFIG,
|
IrqCfg::new(va108xx::Interrupt::OC1, true, false),
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
va108xx::Interrupt::OC1,
|
Some(&mut dp.SYSCONFIG),
|
||||||
);
|
);
|
||||||
|
|
||||||
// First target for cascade
|
// First target for cascade
|
||||||
@ -63,9 +56,9 @@ fn main() -> ! {
|
|||||||
// the timer expires
|
// the timer expires
|
||||||
cascade_target_1.listen(
|
cascade_target_1.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
&mut dp.SYSCONFIG,
|
IrqCfg::new(va108xx::Interrupt::OC2, true, false),
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
va108xx::Interrupt::OC2,
|
Some(&mut dp.SYSCONFIG),
|
||||||
);
|
);
|
||||||
// The counter will only activate when the cascade signal is coming in so
|
// The counter will only activate when the cascade signal is coming in so
|
||||||
// it is okay to call start here to set the reset value
|
// it is okay to call start here to set the reset value
|
||||||
@ -89,9 +82,9 @@ fn main() -> ! {
|
|||||||
// the timer expires
|
// the timer expires
|
||||||
cascade_target_2.listen(
|
cascade_target_2.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
&mut dp.SYSCONFIG,
|
IrqCfg::new(va108xx::Interrupt::OC3, true, false),
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
va108xx::Interrupt::OC3,
|
Some(&mut dp.SYSCONFIG),
|
||||||
);
|
);
|
||||||
// The counter will only activate when the cascade signal is coming in so
|
// The counter will only activate when the cascade signal is coming in so
|
||||||
// it is okay to call start here to set the reset value
|
// it is okay to call start here to set the reset value
|
||||||
@ -112,7 +105,7 @@ fn main() -> ! {
|
|||||||
loop {
|
loop {
|
||||||
rprintln!("-- Triggering cascade in 0.5 seconds --");
|
rprintln!("-- Triggering cascade in 0.5 seconds --");
|
||||||
cascade_triggerer.start(2.hz());
|
cascade_triggerer.start(2.hz());
|
||||||
delay.delay_ms(5000);
|
delay.delay_ms(5000_u16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,10 @@ 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::{
|
||||||
gpio::PinsA,
|
gpio::PinsA,
|
||||||
pac::{self, interrupt},
|
pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
pwm::{self, get_duty_from_percent, ReducedPwmPin, PWMA, PWMB},
|
pwm::{self, get_duty_from_percent, ReducedPwmPin, PWMA, PWMB},
|
||||||
timer::{default_ms_irq_handler, set_up_ms_timer, Delay},
|
timer::set_up_ms_delay_provider,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
@ -26,17 +26,7 @@ fn main() -> ! {
|
|||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
10.hz(),
|
10.hz(),
|
||||||
);
|
);
|
||||||
let timer = set_up_ms_timer(
|
let mut delay = set_up_ms_delay_provider(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM0);
|
||||||
&mut dp.SYSCONFIG,
|
|
||||||
&mut dp.IRQSEL,
|
|
||||||
50.mhz().into(),
|
|
||||||
dp.TIM0,
|
|
||||||
pac::Interrupt::OC0,
|
|
||||||
);
|
|
||||||
let mut delay = Delay::new(timer);
|
|
||||||
unsafe {
|
|
||||||
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
|
|
||||||
}
|
|
||||||
let mut current_duty_cycle = 0.0;
|
let mut current_duty_cycle = 0.0;
|
||||||
PwmPin::set_duty(&mut pwm, get_duty_from_percent(current_duty_cycle));
|
PwmPin::set_duty(&mut pwm, get_duty_from_percent(current_duty_cycle));
|
||||||
PwmPin::enable(&mut pwm);
|
PwmPin::enable(&mut pwm);
|
||||||
@ -46,7 +36,7 @@ fn main() -> ! {
|
|||||||
loop {
|
loop {
|
||||||
// Increase duty cycle continuously
|
// Increase duty cycle continuously
|
||||||
while current_duty_cycle < 1.0 {
|
while current_duty_cycle < 1.0 {
|
||||||
delay.delay_ms(200);
|
delay.delay_ms(200_u16);
|
||||||
current_duty_cycle += 0.02;
|
current_duty_cycle += 0.02;
|
||||||
PwmPin::set_duty(&mut reduced_pin, get_duty_from_percent(current_duty_cycle));
|
PwmPin::set_duty(&mut reduced_pin, get_duty_from_percent(current_duty_cycle));
|
||||||
}
|
}
|
||||||
@ -60,7 +50,7 @@ fn main() -> ! {
|
|||||||
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
||||||
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
|
pwmb.set_pwmb_upper_limit(get_duty_from_percent(upper_limit));
|
||||||
while lower_limit < 0.5 {
|
while lower_limit < 0.5 {
|
||||||
delay.delay_ms(200);
|
delay.delay_ms(200_u16);
|
||||||
lower_limit += 0.01;
|
lower_limit += 0.01;
|
||||||
upper_limit -= 0.01;
|
upper_limit -= 0.01;
|
||||||
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
pwmb.set_pwmb_lower_limit(get_duty_from_percent(lower_limit));
|
||||||
@ -71,8 +61,3 @@ fn main() -> ! {
|
|||||||
reduced_pin = ReducedPwmPin::<PWMA>::from(pwmb);
|
reduced_pin = ReducedPwmPin::<PWMA>::from(pwmb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
fn OC0() {
|
|
||||||
default_ms_irq_handler()
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,7 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Delay},
|
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Delay, IrqCfg},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -146,15 +146,12 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
TestCase::DelayMs => {
|
TestCase::DelayMs => {
|
||||||
let ms_timer = set_up_ms_timer(
|
let ms_timer = set_up_ms_timer(
|
||||||
|
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
50.mhz().into(),
|
50.mhz(),
|
||||||
dp.TIM0,
|
dp.TIM0,
|
||||||
pac::Interrupt::OC0,
|
|
||||||
);
|
);
|
||||||
unsafe {
|
|
||||||
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
|
|
||||||
}
|
|
||||||
let mut delay = Delay::new(ms_timer);
|
let mut delay = Delay::new(ms_timer);
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
led1.toggle().ok();
|
led1.toggle().ok();
|
||||||
@ -163,7 +160,7 @@ fn main() -> ! {
|
|||||||
delay.delay_ms(500);
|
delay.delay_ms(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut delay_timer = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
|
let mut delay_timer = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz(), dp.TIM1);
|
||||||
let mut pa0 = pinsa.pa0.into_push_pull_output();
|
let mut pa0 = pinsa.pa0.into_push_pull_output();
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
led1.toggle().ok();
|
led1.toggle().ok();
|
||||||
|
@ -12,7 +12,7 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Event, MS_COUNTER},
|
timer::{default_ms_irq_handler, set_up_ms_timer, CountDownTimer, Event, IrqCfg, MS_COUNTER},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -65,22 +65,21 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
LibType::Hal => {
|
LibType::Hal => {
|
||||||
set_up_ms_timer(
|
set_up_ms_timer(
|
||||||
|
IrqCfg::new(interrupt::OC0, true, true),
|
||||||
&mut dp.SYSCONFIG,
|
&mut dp.SYSCONFIG,
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
50.mhz().into(),
|
50.mhz(),
|
||||||
dp.TIM0,
|
dp.TIM0,
|
||||||
interrupt::OC0,
|
|
||||||
);
|
);
|
||||||
let mut second_timer =
|
let mut second_timer =
|
||||||
CountDownTimer::new(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1);
|
CountDownTimer::new(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1);
|
||||||
second_timer.listen(
|
second_timer.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
&mut dp.SYSCONFIG,
|
IrqCfg::new(interrupt::OC1, true, true),
|
||||||
&mut dp.IRQSEL,
|
Some(&mut dp.IRQSEL),
|
||||||
interrupt::OC1,
|
Some(&mut dp.SYSCONFIG),
|
||||||
);
|
);
|
||||||
second_timer.start(1.hz());
|
second_timer.start(1.hz());
|
||||||
unmask_irqs();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
|
44
examples/uart-irq.rs
Normal file
44
examples/uart-irq.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
//! UART example application. Sends a test string over a UART and then enters
|
||||||
|
//! echo mode
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use va108xx_hal::{gpio::PinsB, pac, prelude::*, uart};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA108xx UART example application--");
|
||||||
|
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
let gpiob = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB);
|
||||||
|
let tx = gpiob.pb21.into_funsel_1();
|
||||||
|
let rx = gpiob.pb20.into_funsel_1();
|
||||||
|
|
||||||
|
let uartb = uart::Uart::uartb(
|
||||||
|
dp.UARTB,
|
||||||
|
(tx, rx),
|
||||||
|
115200.bps(),
|
||||||
|
&mut dp.SYSCONFIG,
|
||||||
|
50.mhz(),
|
||||||
|
);
|
||||||
|
let (mut tx, mut rx) = uartb.split();
|
||||||
|
writeln!(tx, "Hello World\r").unwrap();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -66,8 +66,8 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::FilterClkSel,
|
clock::FilterClkSel,
|
||||||
pac::{self, IRQSEL, SYSCONFIG},
|
pac::{IRQSEL, SYSCONFIG},
|
||||||
utility::Funsel,
|
utility::{IrqCfg, Funsel},
|
||||||
};
|
};
|
||||||
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
use embedded_hal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
@ -344,14 +344,14 @@ impl DynPin {
|
|||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
mut self,
|
mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Result<Self, PinError> {
|
) -> Result<Self, PinError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
_ => Err(PinError::InvalidPinType),
|
_ => Err(PinError::InvalidPinType),
|
||||||
@ -361,14 +361,14 @@ impl DynPin {
|
|||||||
pub fn interrupt_level(
|
pub fn interrupt_level(
|
||||||
mut self,
|
mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: crate::pac::Interrupt,
|
|
||||||
) -> Result<Self, PinError> {
|
) -> Result<Self, PinError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
_ => Err(PinError::InvalidPinType),
|
_ => Err(PinError::InvalidPinType),
|
||||||
|
@ -92,9 +92,10 @@
|
|||||||
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
use super::dynpins::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode};
|
||||||
use super::reg::RegisterInterface;
|
use super::reg::RegisterInterface;
|
||||||
use crate::{
|
use crate::{
|
||||||
pac::{self, IOCONFIG, IRQSEL, PORTA, PORTB, SYSCONFIG},
|
pac::{IOCONFIG, IRQSEL, PORTA, PORTB, SYSCONFIG},
|
||||||
typelevel::Is,
|
typelevel::Is,
|
||||||
Sealed,
|
Sealed,
|
||||||
|
utility::IrqCfg
|
||||||
};
|
};
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
@ -360,6 +361,7 @@ impl<I: PinId, M: PinMode> AnyPin for Pin<I, M> {
|
|||||||
macro_rules! common_reg_if_functions {
|
macro_rules! common_reg_if_functions {
|
||||||
() => {
|
() => {
|
||||||
paste!(
|
paste!(
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn datamask(&self) -> bool {
|
pub fn datamask(&self) -> bool {
|
||||||
self.regs.datamask()
|
self.regs.datamask()
|
||||||
@ -397,11 +399,11 @@ macro_rules! common_reg_if_functions {
|
|||||||
self.regs.write_pin_masked(false)
|
self.regs.write_pin_masked(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _irq_enb(
|
fn irq_enb(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
irq_cfg: crate::utility::IrqCfg,
|
||||||
syscfg: Option<&mut va108xx::SYSCONFIG>,
|
syscfg: Option<&mut va108xx::SYSCONFIG>,
|
||||||
irqsel: &mut va108xx::IRQSEL,
|
irqsel: Option<&mut va108xx::IRQSEL>
|
||||||
interrupt: va108xx::Interrupt,
|
|
||||||
) {
|
) {
|
||||||
if syscfg.is_some() {
|
if syscfg.is_some() {
|
||||||
crate::clock::enable_peripheral_clock(
|
crate::clock::enable_peripheral_clock(
|
||||||
@ -410,15 +412,19 @@ macro_rules! common_reg_if_functions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.regs.enable_irq();
|
self.regs.enable_irq();
|
||||||
|
if let Some(irqsel) = irqsel {
|
||||||
|
if irq_cfg.route {
|
||||||
match self.regs.id().group {
|
match self.regs.id().group {
|
||||||
// Set the correct interrupt number in the IRQSEL register
|
// Set the correct interrupt number in the IRQSEL register
|
||||||
DynGroup::A => {
|
DynGroup::A => {
|
||||||
irqsel.porta[self.regs.id().num as usize]
|
irqsel.porta[self.regs.id().num as usize]
|
||||||
.write(|w| unsafe { w.bits(interrupt as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
||||||
}
|
}
|
||||||
DynGroup::B => {
|
DynGroup::B => {
|
||||||
irqsel.portb[self.regs.id().num as usize]
|
irqsel.portb[self.regs.id().num as usize]
|
||||||
.write(|w| unsafe { w.bits(interrupt as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,24 +583,24 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
mut self,
|
mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn interrupt_level(
|
||||||
mut self,
|
mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,24 +628,24 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
mut self,
|
mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.interrupt_edge(edge_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn interrupt_level(
|
||||||
mut self,
|
mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
syscfg: Option<&mut SYSCONFIG>,
|
syscfg: Option<&mut SYSCONFIG>,
|
||||||
irqsel: &mut IRQSEL,
|
irqsel: Option<&mut IRQSEL>
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self._irq_enb(syscfg, irqsel, interrupt);
|
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.interrupt_level(level_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
src/timer.rs
66
src/timer.rs
@ -4,8 +4,10 @@
|
|||||||
//!
|
//!
|
||||||
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/timer-ticks.rs)
|
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/timer-ticks.rs)
|
||||||
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs)
|
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs)
|
||||||
|
pub use crate::utility::IrqCfg;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||||
|
utility::unmask_irq,
|
||||||
gpio::{
|
gpio::{
|
||||||
AltFunc1, AltFunc2, AltFunc3, DynPinId, Pin, PinId, PA0, PA1, PA10, PA11, PA12, PA13, PA14,
|
AltFunc1, AltFunc2, AltFunc3, DynPinId, Pin, PinId, PA0, PA1, PA10, PA11, PA12, PA13, PA14,
|
||||||
PA15, PA2, PA24, PA25, PA26, PA27, PA28, PA29, PA3, PA30, PA31, PA4, PA5, PA6, PA7, PA8,
|
PA15, PA2, PA24, PA25, PA26, PA27, PA28, PA29, PA3, PA30, PA31, PA4, PA5, PA6, PA7, PA8,
|
||||||
@ -27,7 +29,7 @@ use embedded_hal::{
|
|||||||
blocking::delay,
|
blocking::delay,
|
||||||
timer::{Cancel, CountDown, Periodic},
|
timer::{Cancel, CountDown, Periodic},
|
||||||
};
|
};
|
||||||
use va108xx::{Interrupt, IRQSEL, SYSCONFIG};
|
use va108xx::{IRQSEL, SYSCONFIG};
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
const IRQ_DST_NONE: u32 = 0xffffffff;
|
const IRQ_DST_NONE: u32 = 0xffffffff;
|
||||||
@ -386,6 +388,7 @@ unsafe impl TimPinInterface for TimDynRegister {
|
|||||||
pub struct CountDownTimer<TIM: ValidTim> {
|
pub struct CountDownTimer<TIM: ValidTim> {
|
||||||
tim: TimRegister<TIM>,
|
tim: TimRegister<TIM>,
|
||||||
curr_freq: Hertz,
|
curr_freq: Hertz,
|
||||||
|
irq_cfg: Option<IrqCfg>,
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
rst_val: u32,
|
rst_val: u32,
|
||||||
last_cnt: u32,
|
last_cnt: u32,
|
||||||
@ -482,6 +485,7 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
|||||||
let cd_timer = CountDownTimer {
|
let cd_timer = CountDownTimer {
|
||||||
tim: unsafe { TimRegister::new(tim) },
|
tim: unsafe { TimRegister::new(tim) },
|
||||||
sys_clk: sys_clk.into(),
|
sys_clk: sys_clk.into(),
|
||||||
|
irq_cfg: None,
|
||||||
rst_val: 0,
|
rst_val: 0,
|
||||||
curr_freq: 0.hz(),
|
curr_freq: 0.hz(),
|
||||||
listening: false,
|
listening: false,
|
||||||
@ -491,21 +495,28 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
|||||||
cd_timer
|
cd_timer
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listen for events. This also actives the IRQ in the IRQSEL register
|
/// Listen for events. Depending on the IRQ configuration, this also activates the IRQ in the
|
||||||
/// for the provided interrupt. It also actives the peripheral clock for
|
/// IRQSEL peripheral for the provided interrupt and unmasks the interrupt
|
||||||
/// IRQSEL
|
|
||||||
pub fn listen(
|
pub fn listen(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: Event,
|
event: Event,
|
||||||
syscfg: &mut SYSCONFIG,
|
irq_cfg: IrqCfg,
|
||||||
irqsel: &mut IRQSEL,
|
irq_sel: Option<&mut IRQSEL>,
|
||||||
interrupt: Interrupt,
|
sys_cfg: Option<&mut SYSCONFIG>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
Event::TimeOut => {
|
Event::TimeOut => {
|
||||||
enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel);
|
cortex_m::peripheral::NVIC::mask(irq_cfg.irq);
|
||||||
irqsel.tim[TIM::TIM_ID as usize].write(|w| unsafe { w.bits(interrupt as u32) });
|
self.irq_cfg = Some(irq_cfg);
|
||||||
self.enable_interrupt();
|
if irq_cfg.route {
|
||||||
|
if let Some(sys_cfg) = sys_cfg {
|
||||||
|
enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel);
|
||||||
|
}
|
||||||
|
if let Some(irq_sel) = irq_sel {
|
||||||
|
irq_sel.tim[TIM::TIM_ID as usize]
|
||||||
|
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
||||||
|
}
|
||||||
|
}
|
||||||
self.listening = true;
|
self.listening = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,6 +565,12 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
|
self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
|
||||||
|
if let Some(irq_cfg) = self.irq_cfg {
|
||||||
|
self.enable_interrupt();
|
||||||
|
if irq_cfg.enable {
|
||||||
|
unmask_irq(irq_cfg.irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -720,19 +737,29 @@ impl<TIM: ValidTim> embedded_hal::blocking::delay::DelayMs<u8> for CountDownTime
|
|||||||
|
|
||||||
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
|
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
|
||||||
// and provide an IRQ handler yourself
|
// and provide an IRQ handler yourself
|
||||||
pub fn set_up_ms_timer(
|
pub fn set_up_ms_timer<TIM: ValidTim>(
|
||||||
syscfg: &mut pac::SYSCONFIG,
|
irq_cfg: IrqCfg,
|
||||||
irqsel: &mut pac::IRQSEL,
|
sys_cfg: &mut pac::SYSCONFIG,
|
||||||
sys_clk: Hertz,
|
irq_sel: Option<&mut pac::IRQSEL>,
|
||||||
tim0: TIM0,
|
sys_clk: impl Into<Hertz>,
|
||||||
irq: pac::Interrupt,
|
tim0: TIM,
|
||||||
) -> CountDownTimer<TIM0> {
|
) -> CountDownTimer<TIM> {
|
||||||
let mut ms_timer = CountDownTimer::new(syscfg, sys_clk, tim0);
|
let mut ms_timer = CountDownTimer::new(sys_cfg, sys_clk, tim0);
|
||||||
ms_timer.listen(timer::Event::TimeOut, syscfg, irqsel, irq);
|
ms_timer.listen(timer::Event::TimeOut, irq_cfg, irq_sel, Some(sys_cfg));
|
||||||
ms_timer.start(1000.hz());
|
ms_timer.start(1000.hz());
|
||||||
ms_timer
|
ms_timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_up_ms_delay_provider<TIM: ValidTim>(
|
||||||
|
sys_cfg: &mut pac::SYSCONFIG,
|
||||||
|
sys_clk: impl Into<Hertz>,
|
||||||
|
tim: TIM,
|
||||||
|
) -> CountDownTimer<TIM> {
|
||||||
|
let mut provider = CountDownTimer::new(sys_cfg, sys_clk, tim);
|
||||||
|
provider.start(1000.hz());
|
||||||
|
provider
|
||||||
|
}
|
||||||
|
|
||||||
/// This function can be called in a specified interrupt handler to increment
|
/// This function can be called in a specified interrupt handler to increment
|
||||||
/// the MS counter
|
/// the MS counter
|
||||||
pub fn default_ms_irq_handler() {
|
pub fn default_ms_irq_handler() {
|
||||||
@ -763,6 +790,7 @@ impl Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This assumes that the user has already set up a MS tick timer in TIM0 as a system tick
|
/// This assumes that the user has already set up a MS tick timer in TIM0 as a system tick
|
||||||
|
/// with [`set_up_ms_delay_provider`]
|
||||||
impl embedded_hal::blocking::delay::DelayMs<u32> for Delay {
|
impl embedded_hal::blocking::delay::DelayMs<u32> for Delay {
|
||||||
fn delay_ms(&mut self, ms: u32) {
|
fn delay_ms(&mut self, ms: u32) {
|
||||||
if self.cd_tim.curr_freq() != 1000.hz() || !self.cd_tim.listening() {
|
if self.cd_tim.curr_freq() != 1000.hz() || !self.cd_tim.listening() {
|
||||||
|
299
src/uart.rs
299
src/uart.rs
@ -8,19 +8,25 @@ use core::{marker::PhantomData, ops::Deref};
|
|||||||
use libm::floorf;
|
use libm::floorf;
|
||||||
|
|
||||||
use crate::clock::enable_peripheral_clock;
|
use crate::clock::enable_peripheral_clock;
|
||||||
|
pub use crate::utility::IrqCfg;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock,
|
clock,
|
||||||
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,
|
||||||
},
|
},
|
||||||
pac::{uarta as uart_base, SYSCONFIG, UARTA, UARTB},
|
pac::{uarta as uart_base, IRQSEL, SYSCONFIG, UARTA, UARTB},
|
||||||
|
utility::unmask_irq,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::{Bps, Hertz},
|
time::{Bps, Hertz},
|
||||||
};
|
};
|
||||||
|
|
||||||
use embedded_hal::{blocking, serial};
|
use embedded_hal::{blocking, serial};
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Type-Level support
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
pub trait Pins<UART> {}
|
pub trait Pins<UART> {}
|
||||||
|
|
||||||
impl Pins<UARTA> for (Pin<PA9, AltFunc2>, Pin<PA8, AltFunc2>) {}
|
impl Pins<UARTA> for (Pin<PA9, AltFunc2>, Pin<PA8, AltFunc2>) {}
|
||||||
@ -38,12 +44,18 @@ impl Pins<UARTB> for (Pin<PB7, AltFunc1>, Pin<PB6, AltFunc1>) {}
|
|||||||
impl Pins<UARTB> for (Pin<PB19, AltFunc2>, Pin<PB18, AltFunc2>) {}
|
impl Pins<UARTB> for (Pin<PB19, AltFunc2>, Pin<PB18, AltFunc2>) {}
|
||||||
impl Pins<UARTB> for (Pin<PB21, AltFunc1>, Pin<PB20, AltFunc1>) {}
|
impl Pins<UARTB> for (Pin<PB21, AltFunc1>, Pin<PB20, AltFunc1>) {}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Regular Definitions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Overrun,
|
Overrun,
|
||||||
FramingError,
|
FramingError,
|
||||||
ParityError,
|
ParityError,
|
||||||
BreakCondition,
|
BreakCondition,
|
||||||
|
TransferPending,
|
||||||
|
BufferTooShort,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
@ -160,6 +172,106 @@ impl From<Bps> for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// IRQ Definitions
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
pub struct IrqInfo {
|
||||||
|
rx_len: usize,
|
||||||
|
rx_idx: usize,
|
||||||
|
irq_cfg: IrqCfg,
|
||||||
|
mode: IrqReceptionMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum IrqResultMask {
|
||||||
|
Complete = 0,
|
||||||
|
Overflow = 1,
|
||||||
|
FramingError = 2,
|
||||||
|
ParityError = 3,
|
||||||
|
Break = 4,
|
||||||
|
Timeout = 5,
|
||||||
|
Addr9 = 6,
|
||||||
|
}
|
||||||
|
pub struct IrqResult {
|
||||||
|
raw_res: u32,
|
||||||
|
pub bytes_read: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqResult {
|
||||||
|
#[inline]
|
||||||
|
pub fn raw_result(&self) -> u32 {
|
||||||
|
self.raw_res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn clear_result(&mut self) {
|
||||||
|
self.raw_res = 0;
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn set_result(&mut self, flag: IrqResultMask) {
|
||||||
|
self.raw_res |= 1 << flag as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn complete(&self) -> bool {
|
||||||
|
if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x00 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn error(&self) -> bool {
|
||||||
|
if self.overflow_error() || self.framing_error() || self.parity_error() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn overflow_error(&self) -> bool {
|
||||||
|
if ((self.raw_res >> IrqResultMask::Overflow as u32) & 0x01) == 0x01 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn framing_error(&self) -> bool {
|
||||||
|
if ((self.raw_res >> IrqResultMask::FramingError as u32) & 0x01) == 0x01 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn parity_error(&self) -> bool {
|
||||||
|
if ((self.raw_res >> IrqResultMask::ParityError as u32) & 0x01) == 0x01 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn timeout(&self) -> bool {
|
||||||
|
if ((self.raw_res >> IrqResultMask::Timeout as u32) & 0x01) == 0x01 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum IrqReceptionMode {
|
||||||
|
Idle,
|
||||||
|
FixedLen,
|
||||||
|
VarLen,
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// UART implementation
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
/// Serial abstraction
|
/// Serial abstraction
|
||||||
pub struct Uart<UART, PINS> {
|
pub struct Uart<UART, PINS> {
|
||||||
uart: UART,
|
uart: UART,
|
||||||
@ -168,6 +280,11 @@ pub struct Uart<UART, PINS> {
|
|||||||
rx: Rx<UART>,
|
rx: Rx<UART>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct UartWithIrq<UART, PINS> {
|
||||||
|
uart_base: Uart<UART, PINS>,
|
||||||
|
irq_info: IrqInfo,
|
||||||
|
}
|
||||||
|
|
||||||
/// Serial receiver
|
/// Serial receiver
|
||||||
pub struct Rx<UART> {
|
pub struct Rx<UART> {
|
||||||
_usart: PhantomData<UART>,
|
_usart: PhantomData<UART>,
|
||||||
@ -247,6 +364,46 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_rx(&mut self) {
|
||||||
|
self.uart.enable.write(|w| w.rxenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_rx(&mut self) {
|
||||||
|
self.uart.enable.write(|w| w.rxenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_tx(&mut self) {
|
||||||
|
self.uart.enable.write(|w| w.txenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_tx(&mut self) {
|
||||||
|
self.uart.enable.write(|w| w.txenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_fifo(&mut self) {
|
||||||
|
self.uart.fifo_clr.write(|w| w.rxfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_fifo(&mut self) {
|
||||||
|
self.uart.fifo_clr.write(|w| w.txfifo().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_rx_status(&mut self) {
|
||||||
|
self.uart.fifo_clr.write(|w| w.rxsts().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clear_tx_status(&mut self) {
|
||||||
|
self.uart.fifo_clr.write(|w| w.txsts().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn listen(self, event: Event) -> Self {
|
pub fn listen(self, event: Event) -> Self {
|
||||||
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(),
|
||||||
@ -319,6 +476,146 @@ macro_rules! uart_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<PINS> Uart<UARTA, PINS> {
|
||||||
|
pub fn into_uart_with_irq(self, irq_cfg: IrqCfg) -> UartWithIrq<UARTA, PINS> {
|
||||||
|
UartWithIrq {
|
||||||
|
uart_base: self,
|
||||||
|
irq_info: IrqInfo {
|
||||||
|
rx_len: 0,
|
||||||
|
rx_idx: 0,
|
||||||
|
irq_cfg,
|
||||||
|
mode: IrqReceptionMode::Idle,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<PINS> UartWithIrq<UARTA, PINS> {
|
||||||
|
pub fn read_fixed_len_using_irq(
|
||||||
|
&mut self,
|
||||||
|
max_len: usize,
|
||||||
|
enb_timeout_irq: bool,
|
||||||
|
irqsel: Option<&mut IRQSEL>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if self.irq_info.mode != IrqReceptionMode::Idle {
|
||||||
|
return Err(Error::TransferPending);
|
||||||
|
}
|
||||||
|
self.irq_info.rx_idx = 0;
|
||||||
|
self.irq_info.rx_len = max_len;
|
||||||
|
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 {
|
||||||
|
unmask_irq(self.irq_info.irq_cfg.irq);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn enable_rx_irq_sources(&mut self, timeout: bool) {
|
||||||
|
self.uart_base.uart.irq_enb.modify(|_, w| {
|
||||||
|
if timeout {
|
||||||
|
w.irq_rx_to().set_bit();
|
||||||
|
}
|
||||||
|
w.irq_rx_status().set_bit();
|
||||||
|
w.irq_rx().set_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn disable_rx_irq_sources(&mut self) {
|
||||||
|
self.uart_base.uart.irq_enb.modify(|_, w| {
|
||||||
|
w.irq_rx_to().clear_bit();
|
||||||
|
w.irq_rx_status().clear_bit();
|
||||||
|
w.irq_rx().clear_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cancel_transfer(&mut self) {
|
||||||
|
// Disable IRQ
|
||||||
|
cortex_m::peripheral::NVIC::mask(self.irq_info.irq_cfg.irq);
|
||||||
|
self.disable_rx_irq_sources();
|
||||||
|
self.uart_base.clear_tx_fifo();
|
||||||
|
self.irq_info.rx_idx = 0;
|
||||||
|
self.irq_info.rx_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn irq_handler(&mut self, res: &mut IrqResult, buf: &mut [u8]) -> Result<(), Error> {
|
||||||
|
if buf.len() < self.irq_info.rx_len {
|
||||||
|
return Err(Error::BufferTooShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rx_status = self.uart_base.uart.rxstatus.read();
|
||||||
|
let _tx_status = self.uart_base.uart.txstatus.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 _tx_enabled = enb_status.txenable().bit_is_set();
|
||||||
|
res.clear_result();
|
||||||
|
if irq_end.irq_rx().bit_is_set() && rx_status.rdavl().bit_is_set() {
|
||||||
|
let mut rd_avl = rx_status.rdavl();
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
while self.irq_info.rx_idx < self.irq_info.rx_len && rd_avl.bit_is_set() {
|
||||||
|
buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap();
|
||||||
|
rd_avl = self.uart_base.uart.rxstatus.read().rdavl();
|
||||||
|
self.irq_info.rx_idx += 1;
|
||||||
|
if self.irq_info.rx_idx == self.irq_info.rx_len {
|
||||||
|
self.disable_rx_irq_sources();
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RX transfer not complete, check for RX errors
|
||||||
|
if (self.irq_info.rx_idx < self.irq_info.rx_len) && rx_enabled {
|
||||||
|
// Read status register again, might have changed since reading received data
|
||||||
|
rx_status = self.uart_base.uart.rxstatus.read();
|
||||||
|
if rx_status.rxovr().bit_is_set() {
|
||||||
|
res.set_result(IrqResultMask::Overflow);
|
||||||
|
}
|
||||||
|
if rx_status.rxfrm().bit_is_set() {
|
||||||
|
res.set_result(IrqResultMask::FramingError);
|
||||||
|
}
|
||||||
|
if rx_status.rxpar().bit_is_set() {
|
||||||
|
res.set_result(IrqResultMask::ParityError);
|
||||||
|
}
|
||||||
|
if rx_status.rxbrk().bit_is_set() {
|
||||||
|
res.set_result(IrqResultMask::Break);
|
||||||
|
}
|
||||||
|
if rx_status.rxto().bit_is_set() {
|
||||||
|
// A timeout has occured but there might be some leftover data in the FIFO,
|
||||||
|
// so read that data as well
|
||||||
|
while self.irq_info.rx_idx < self.irq_info.rx_len && rx_status.rdavl().bit_is_set()
|
||||||
|
{
|
||||||
|
buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap();
|
||||||
|
self.irq_info.rx_idx += 1;
|
||||||
|
}
|
||||||
|
res.bytes_read = self.irq_info.rx_idx;
|
||||||
|
res.set_result(IrqResultMask::Timeout);
|
||||||
|
res.set_result(IrqResultMask::Complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.raw_res != 0 {
|
||||||
|
self.disable_rx_irq_sources();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.uart_base
|
||||||
|
.uart
|
||||||
|
.irq_clr
|
||||||
|
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uart_impl! {
|
uart_impl! {
|
||||||
UARTA: (uarta, clock::PeripheralClocks::Uart0),
|
UARTA: (uarta, clock::PeripheralClocks::Uart0),
|
||||||
UARTB: (uartb, clock::PeripheralClocks::Uart1),
|
UARTB: (uartb, clock::PeripheralClocks::Uart1),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! Some more information about the recommended scrub rates can be found on the
|
//! Some more information about the recommended scrub rates can be found on the
|
||||||
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the
|
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the
|
||||||
//! application note AN1212
|
//! application note AN1212
|
||||||
|
use crate::pac;
|
||||||
use va108xx::{IOCONFIG, SYSCONFIG};
|
use va108xx::{IOCONFIG, SYSCONFIG};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
@ -41,6 +42,26 @@ pub enum PeripheralSelect {
|
|||||||
Gpio = 24,
|
Gpio = 24,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generic IRQ config which can be used to specify whether the HAL driver will
|
||||||
|
/// use the IRQSEL register to route an interrupt, and whether the IRQ will be unmasked in the
|
||||||
|
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might perform
|
||||||
|
/// this steps themselves
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
pub struct IrqCfg {
|
||||||
|
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
|
||||||
|
pub irq: pac::Interrupt,
|
||||||
|
/// Specfiy whether IRQ should be routed to an IRQ vector using the IRQSEL peripheral
|
||||||
|
pub route: bool,
|
||||||
|
/// Specify whether the IRQ is unmasked in the Cortex-M NVIC
|
||||||
|
pub enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqCfg {
|
||||||
|
pub fn new(irq: pac::Interrupt, route: bool, enable: bool) -> Self {
|
||||||
|
IrqCfg { irq, route, enable }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Enable scrubbing for the ROM
|
/// Enable scrubbing for the ROM
|
||||||
///
|
///
|
||||||
/// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0
|
/// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0
|
||||||
@ -111,3 +132,13 @@ pub fn port_mux(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unmask and enable an IRQ with the given interrupt number
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// The unmask function can break mask-based critical sections
|
||||||
|
#[inline]
|
||||||
|
pub (crate) fn unmask_irq(irq: pac::Interrupt) {
|
||||||
|
unsafe { cortex_m::peripheral::NVIC::unmask(irq) };
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user