Async UART TX support
This commit is contained in:
parent
4edba63b02
commit
6e0d417a5c
@ -17,7 +17,7 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, IrqCfg},
|
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, InterruptConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -155,7 +155,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
TestCase::DelayMs => {
|
TestCase::DelayMs => {
|
||||||
let mut ms_timer = set_up_ms_tick(
|
let mut ms_timer = set_up_ms_tick(
|
||||||
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
|
@ -9,6 +9,7 @@ cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
|||||||
cortex-m-rt = "0.7"
|
cortex-m-rt = "0.7"
|
||||||
embedded-hal = "1"
|
embedded-hal = "1"
|
||||||
embedded-hal-async = "1"
|
embedded-hal-async = "1"
|
||||||
|
embedded-io-async = "0.6"
|
||||||
|
|
||||||
rtt-target = "0.6"
|
rtt-target = "0.6"
|
||||||
panic-rtt-target = "0.2"
|
panic-rtt-target = "0.2"
|
||||||
|
@ -14,7 +14,7 @@ use embedded_hal_async::digital::Wait;
|
|||||||
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_embassy::embassy;
|
use va108xx_embassy::embassy;
|
||||||
use va108xx_hal::gpio::{handle_interrupt_for_async_gpio, InputDynPinAsync, InputPinAsync, PinsB};
|
use va108xx_hal::gpio::{on_interrupt_for_asynch_gpio, InputDynPinAsync, InputPinAsync, PinsB};
|
||||||
use va108xx_hal::{
|
use va108xx_hal::{
|
||||||
gpio::{DynPin, PinsA},
|
gpio::{DynPin, PinsA},
|
||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
@ -248,11 +248,11 @@ async fn output_task(
|
|||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn OC10() {
|
fn OC10() {
|
||||||
handle_interrupt_for_async_gpio();
|
on_interrupt_for_asynch_gpio();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn OC11() {
|
fn OC11() {
|
||||||
handle_interrupt_for_async_gpio();
|
on_interrupt_for_asynch_gpio();
|
||||||
}
|
}
|
||||||
|
87
examples/embassy/src/bin/async-uart.rs
Normal file
87
examples/embassy/src/bin/async-uart.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_time::{Duration, Instant, Ticker};
|
||||||
|
use embedded_hal::digital::StatefulOutputPin;
|
||||||
|
use embedded_io_async::Write;
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use va108xx_embassy::embassy;
|
||||||
|
use va108xx_hal::{
|
||||||
|
gpio::PinsA,
|
||||||
|
pac::{self, interrupt},
|
||||||
|
prelude::*,
|
||||||
|
uart::{self, on_interrupt_uart_a_tx, TxAsync},
|
||||||
|
InterruptConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
|
||||||
|
|
||||||
|
const STR_LIST: &[&str] = &[
|
||||||
|
"Hello World\r\n",
|
||||||
|
"Smoll\r\n",
|
||||||
|
"A string which is larger than the FIFO size\r\n",
|
||||||
|
"A really large string which is significantly larger than the FIFO size\r\n",
|
||||||
|
];
|
||||||
|
|
||||||
|
// main is itself an async function.
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA108xx Embassy Demo --");
|
||||||
|
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Safety: Only called once here.
|
||||||
|
unsafe {
|
||||||
|
embassy::init(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
&dp.irqsel,
|
||||||
|
SYSCLK_FREQ,
|
||||||
|
dp.tim23,
|
||||||
|
dp.tim22,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
|
let mut led0 = porta.pa10.into_readable_push_pull_output();
|
||||||
|
let mut led1 = porta.pa7.into_readable_push_pull_output();
|
||||||
|
let mut led2 = porta.pa6.into_readable_push_pull_output();
|
||||||
|
|
||||||
|
let tx = porta.pa9.into_funsel_2();
|
||||||
|
let rx = porta.pa8.into_funsel_2();
|
||||||
|
|
||||||
|
let uarta = uart::Uart::new_with_interrupt(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
50.MHz(),
|
||||||
|
dp.uarta,
|
||||||
|
(tx, rx),
|
||||||
|
115200.Hz(),
|
||||||
|
InterruptConfig::new(pac::Interrupt::OC2, true, true),
|
||||||
|
);
|
||||||
|
let (tx, _rx) = uarta.split();
|
||||||
|
let mut async_tx = TxAsync::new(tx);
|
||||||
|
let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||||
|
let mut idx = 0;
|
||||||
|
loop {
|
||||||
|
rprintln!("Current time: {}", Instant::now().as_secs());
|
||||||
|
led0.toggle().ok();
|
||||||
|
led1.toggle().ok();
|
||||||
|
led2.toggle().ok();
|
||||||
|
let _written = async_tx
|
||||||
|
.write(STR_LIST[idx].as_bytes())
|
||||||
|
.await
|
||||||
|
.expect("writing failed");
|
||||||
|
idx += 1;
|
||||||
|
if idx == STR_LIST.len() {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
ticker.next().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn OC2() {
|
||||||
|
on_interrupt_uart_a_tx();
|
||||||
|
}
|
@ -22,5 +22,5 @@ rtic-sync = { version = "1.3", features = ["defmt-03"] }
|
|||||||
once_cell = {version = "1", default-features = false, features = ["critical-section"]}
|
once_cell = {version = "1", default-features = false, features = ["critical-section"]}
|
||||||
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
|
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
|
||||||
|
|
||||||
va108xx-hal = "0.8"
|
va108xx-hal = { version = "0.8", path = "../../va108xx-hal" }
|
||||||
vorago-reb1 = { path = "../../vorago-reb1" }
|
vorago-reb1 = { path = "../../vorago-reb1" }
|
||||||
|
@ -12,7 +12,7 @@ mod app {
|
|||||||
gpio::{FilterType, InterruptEdge, PinsA},
|
gpio::{FilterType, InterruptEdge, PinsA},
|
||||||
pac,
|
pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, IrqCfg},
|
timer::{default_ms_irq_handler, set_up_ms_tick, InterruptConfig},
|
||||||
};
|
};
|
||||||
use vorago_reb1::button::Button;
|
use vorago_reb1::button::Button;
|
||||||
use vorago_reb1::leds::Leds;
|
use vorago_reb1::leds::Leds;
|
||||||
@ -61,23 +61,24 @@ mod app {
|
|||||||
rprintln!("Using {:?} mode", mode);
|
rprintln!("Using {:?} mode", mode);
|
||||||
|
|
||||||
let mut dp = cx.device;
|
let mut dp = cx.device;
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let edge_irq = match mode {
|
let edge_irq = match mode {
|
||||||
PressMode::Toggle => InterruptEdge::HighToLow,
|
PressMode::Toggle => InterruptEdge::HighToLow,
|
||||||
PressMode::Keep => InterruptEdge::BothEdges,
|
PressMode::Keep => InterruptEdge::BothEdges,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Configure an edge interrupt on the button and route it to interrupt vector 15
|
// Configure an edge interrupt on the button and route it to interrupt vector 15
|
||||||
let mut button = Button::new(pinsa.pa11.into_floating_input()).edge_irq(
|
let mut button = Button::new(pinsa.pa11.into_floating_input());
|
||||||
|
button.configure_edge_interrupt(
|
||||||
edge_irq,
|
edge_irq,
|
||||||
IrqCfg::new(pac::interrupt::OC15, true, true),
|
InterruptConfig::new(pac::interrupt::OC15, true, true),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
);
|
);
|
||||||
|
|
||||||
if mode == PressMode::Toggle {
|
if mode == PressMode::Toggle {
|
||||||
// This filter debounces the switch for edge based interrupts
|
// This filter debounces the switch for edge based interrupts
|
||||||
button = button.filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1);
|
button.configure_filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1);
|
||||||
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
|
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
|
||||||
}
|
}
|
||||||
let mut leds = Leds::new(
|
let mut leds = Leds::new(
|
||||||
@ -89,7 +90,7 @@ mod app {
|
|||||||
led.off();
|
led.off();
|
||||||
}
|
}
|
||||||
set_up_ms_tick(
|
set_up_ms_tick(
|
||||||
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
|
@ -23,12 +23,13 @@ mod app {
|
|||||||
gpio::PinsA,
|
gpio::PinsA,
|
||||||
pac,
|
pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
uart::{self, RxWithIrq, Tx},
|
uart::{self, RxWithInterrupt, Tx},
|
||||||
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
rx: RxWithIrq<pac::Uarta>,
|
rx: RxWithInterrupt<pac::Uarta>,
|
||||||
tx: Tx<pac::Uarta>,
|
tx: Tx<pac::Uarta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,19 +48,20 @@ mod app {
|
|||||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||||
|
|
||||||
let mut dp = cx.device;
|
let mut dp = cx.device;
|
||||||
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let tx = gpioa.pa9.into_funsel_2();
|
let tx = gpioa.pa9.into_funsel_2();
|
||||||
let rx = gpioa.pa8.into_funsel_2();
|
let rx = gpioa.pa8.into_funsel_2();
|
||||||
|
|
||||||
let irq_uart = uart::Uart::new(
|
let irq_uart = uart::Uart::new_with_interrupt(
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
SYSCLK_FREQ,
|
SYSCLK_FREQ,
|
||||||
dp.uarta,
|
dp.uarta,
|
||||||
(tx, rx),
|
(tx, rx),
|
||||||
115200.Hz(),
|
115200.Hz(),
|
||||||
|
InterruptConfig::new(pac::Interrupt::OC3, true, true),
|
||||||
);
|
);
|
||||||
let (tx, rx) = irq_uart.split();
|
let (tx, rx) = irq_uart.split();
|
||||||
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC3);
|
let mut rx = rx.into_rx_with_irq();
|
||||||
|
|
||||||
rx.start();
|
rx.start();
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ mod app {
|
|||||||
fn reception_task(mut cx: reception_task::Context) {
|
fn reception_task(mut cx: reception_task::Context) {
|
||||||
let mut buf: [u8; 16] = [0; 16];
|
let mut buf: [u8; 16] = [0; 16];
|
||||||
let mut ringbuf_full = false;
|
let mut ringbuf_full = false;
|
||||||
let result = cx.local.rx.irq_handler(&mut buf);
|
let result = cx.local.rx.on_interrupt(&mut buf);
|
||||||
if result.bytes_read > 0 && result.errors.is_none() {
|
if result.bytes_read > 0 && result.errors.is_none() {
|
||||||
cx.shared.rb.lock(|rb| {
|
cx.shared.rb.lock(|rb| {
|
||||||
if rb.vacant_len() < result.bytes_read {
|
if rb.vacant_len() < result.bytes_read {
|
||||||
|
@ -35,11 +35,7 @@ mod app {
|
|||||||
|
|
||||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||||
|
|
||||||
let porta = PinsA::new(
|
let porta = PinsA::new(&mut cx.device.sysconfig, cx.device.porta);
|
||||||
&mut cx.device.sysconfig,
|
|
||||||
Some(cx.device.ioconfig),
|
|
||||||
cx.device.porta,
|
|
||||||
);
|
|
||||||
let led0 = porta.pa10.into_readable_push_pull_output();
|
let led0 = porta.pa10.into_readable_push_pull_output();
|
||||||
let led1 = porta.pa7.into_readable_push_pull_output();
|
let led1 = porta.pa7.into_readable_push_pull_output();
|
||||||
let led2 = porta.pa6.into_readable_push_pull_output();
|
let led2 = porta.pa6.into_readable_push_pull_output();
|
||||||
|
@ -16,6 +16,7 @@ embedded-io = "0.6"
|
|||||||
cortex-m-semihosting = "0.5.0"
|
cortex-m-semihosting = "0.5.0"
|
||||||
|
|
||||||
[dependencies.va108xx-hal]
|
[dependencies.va108xx-hal]
|
||||||
|
path = "../../va108xx-hal"
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
features = ["rt", "defmt"]
|
features = ["rt", "defmt"]
|
||||||
|
|
||||||
|
@ -18,14 +18,14 @@ use va108xx_hal::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
timer::DelayMs,
|
timer::DelayMs,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer},
|
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer},
|
||||||
IrqCfg,
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let mut delay_ms = DelayMs::new(set_up_ms_tick(
|
let mut delay_ms = DelayMs::new(set_up_ms_tick(
|
||||||
IrqCfg::new(interrupt::OC0, true, true),
|
InterruptConfig::new(interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
@ -33,7 +33,7 @@ fn main() -> ! {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut delay_tim1 = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
|
let mut delay_tim1 = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
|
||||||
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let mut led1 = porta.pa10.into_readable_push_pull_output();
|
let mut led1 = porta.pa10.into_readable_push_pull_output();
|
||||||
let mut led2 = porta.pa7.into_readable_push_pull_output();
|
let mut led2 = porta.pa7.into_readable_push_pull_output();
|
||||||
let mut led3 = porta.pa6.into_readable_push_pull_output();
|
let mut led3 = porta.pa6.into_readable_push_pull_output();
|
||||||
|
@ -17,7 +17,7 @@ use va108xx_hal::{
|
|||||||
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,
|
||||||
CountdownTimer, Event, IrqCfg,
|
CountdownTimer, Event, InterruptConfig,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ fn main() -> ! {
|
|||||||
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,
|
||||||
IrqCfg::new(pac::Interrupt::OC1, true, false),
|
InterruptConfig::new(pac::Interrupt::OC1, true, false),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
);
|
);
|
||||||
@ -62,7 +62,7 @@ fn main() -> ! {
|
|||||||
// the timer expires
|
// the timer expires
|
||||||
cascade_target_1.listen(
|
cascade_target_1.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
IrqCfg::new(pac::Interrupt::OC2, true, false),
|
InterruptConfig::new(pac::Interrupt::OC2, true, false),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
);
|
);
|
||||||
@ -88,7 +88,7 @@ fn main() -> ! {
|
|||||||
// the timer expires
|
// the timer expires
|
||||||
cascade_target_2.listen(
|
cascade_target_2.listen(
|
||||||
Event::TimeOut,
|
Event::TimeOut,
|
||||||
IrqCfg::new(pac::Interrupt::OC3, true, false),
|
InterruptConfig::new(pac::Interrupt::OC3, true, false),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,7 @@ fn main() -> ! {
|
|||||||
rtt_init_print!();
|
rtt_init_print!();
|
||||||
rprintln!("-- VA108xx PWM example application--");
|
rprintln!("-- VA108xx PWM example application--");
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let mut pwm = pwm::PwmPin::new(
|
let mut pwm = pwm::PwmPin::new(
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
|
@ -17,7 +17,7 @@ use va108xx_hal::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
spi::{self, Spi, SpiBase, SpiClkConfig, TransferConfigWithHwcs},
|
spi::{self, Spi, SpiBase, SpiClkConfig, TransferConfigWithHwcs},
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick},
|
timer::{default_ms_irq_handler, set_up_ms_tick},
|
||||||
IrqCfg,
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
@ -47,7 +47,7 @@ fn main() -> ! {
|
|||||||
rprintln!("-- VA108xx SPI example application--");
|
rprintln!("-- VA108xx SPI example application--");
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let mut delay = set_up_ms_tick(
|
let mut delay = set_up_ms_tick(
|
||||||
IrqCfg::new(interrupt::OC0, true, true),
|
InterruptConfig::new(interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
@ -58,8 +58,8 @@ fn main() -> ! {
|
|||||||
.expect("creating SPI clock config failed");
|
.expect("creating SPI clock config failed");
|
||||||
let spia_ref: RefCell<Option<SpiBase<pac::Spia, u8>>> = RefCell::new(None);
|
let spia_ref: RefCell<Option<SpiBase<pac::Spia, u8>>> = RefCell::new(None);
|
||||||
let spib_ref: RefCell<Option<SpiBase<pac::Spib, u8>>> = RefCell::new(None);
|
let spib_ref: RefCell<Option<SpiBase<pac::Spib, u8>>> = RefCell::new(None);
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let pinsb = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb);
|
let pinsb = PinsB::new(&mut dp.sysconfig, dp.portb);
|
||||||
|
|
||||||
let mut spi_cfg = spi::SpiConfig::default();
|
let mut spi_cfg = spi::SpiConfig::default();
|
||||||
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
if EXAMPLE_SEL == ExampleSelect::Loopback {
|
||||||
|
@ -12,7 +12,9 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, Event, IrqCfg, MS_COUNTER},
|
timer::{
|
||||||
|
default_ms_irq_handler, set_up_ms_tick, CountdownTimer, Event, InterruptConfig, MS_COUNTER,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -65,7 +67,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
LibType::Hal => {
|
LibType::Hal => {
|
||||||
set_up_ms_tick(
|
set_up_ms_tick(
|
||||||
IrqCfg::new(interrupt::OC0, true, true),
|
InterruptConfig::new(interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
@ -75,7 +77,7 @@ fn main() -> ! {
|
|||||||
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,
|
||||||
IrqCfg::new(interrupt::OC1, true, true),
|
InterruptConfig::new(interrupt::OC1, true, true),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
);
|
);
|
||||||
|
@ -24,11 +24,17 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let tx = gpioa.pa9.into_funsel_2();
|
let tx = gpioa.pa9.into_funsel_2();
|
||||||
let rx = gpioa.pa8.into_funsel_2();
|
let rx = gpioa.pa8.into_funsel_2();
|
||||||
|
|
||||||
let uarta = uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uarta, (tx, rx), 115200.Hz());
|
let uarta = uart::Uart::new_without_interrupt(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
50.MHz(),
|
||||||
|
dp.uarta,
|
||||||
|
(tx, rx),
|
||||||
|
115200.Hz(),
|
||||||
|
);
|
||||||
let (mut tx, mut rx) = uarta.split();
|
let (mut tx, mut rx) = uarta.split();
|
||||||
writeln!(tx, "Hello World\r").unwrap();
|
writeln!(tx, "Hello World\r").unwrap();
|
||||||
loop {
|
loop {
|
||||||
|
@ -71,7 +71,7 @@ mod app {
|
|||||||
};
|
};
|
||||||
use va108xx_hal::gpio::PinsA;
|
use va108xx_hal::gpio::PinsA;
|
||||||
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
|
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
|
||||||
use va108xx_hal::{pac, uart};
|
use va108xx_hal::{pac, uart, InterruptConfig};
|
||||||
use vorago_reb1::m95m01::M95M01;
|
use vorago_reb1::m95m01::M95M01;
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
@ -84,7 +84,7 @@ mod app {
|
|||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
uart_rx: uart::RxWithIrq<pac::Uarta>,
|
uart_rx: uart::RxWithInterrupt<pac::Uarta>,
|
||||||
uart_tx: uart::Tx<pac::Uarta>,
|
uart_tx: uart::Tx<pac::Uarta>,
|
||||||
rx_context: IrqContextTimeoutOrMaxSize,
|
rx_context: IrqContextTimeoutOrMaxSize,
|
||||||
verif_reporter: VerificationReportCreator,
|
verif_reporter: VerificationReportCreator,
|
||||||
@ -114,15 +114,17 @@ mod app {
|
|||||||
let tx = gpioa.pa9.into_funsel_2();
|
let tx = gpioa.pa9.into_funsel_2();
|
||||||
let rx = gpioa.pa8.into_funsel_2();
|
let rx = gpioa.pa8.into_funsel_2();
|
||||||
|
|
||||||
let irq_uart = uart::Uart::new(
|
let irq_uart = uart::Uart::new_with_interrupt(
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
SYSCLK_FREQ,
|
SYSCLK_FREQ,
|
||||||
dp.uarta,
|
dp.uarta,
|
||||||
(tx, rx),
|
(tx, rx),
|
||||||
UART_BAUDRATE.Hz(),
|
UART_BAUDRATE.Hz(),
|
||||||
|
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||||
);
|
);
|
||||||
let (tx, rx) = irq_uart.split();
|
let (tx, rx) = irq_uart.split();
|
||||||
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC0);
|
// Unwrap is okay, we explicitely set the interrupt ID.
|
||||||
|
let mut rx = rx.into_rx_with_irq();
|
||||||
|
|
||||||
let verif_reporter = VerificationReportCreator::new(0).unwrap();
|
let verif_reporter = VerificationReportCreator::new(0).unwrap();
|
||||||
|
|
||||||
@ -175,7 +177,7 @@ mod app {
|
|||||||
match cx
|
match cx
|
||||||
.local
|
.local
|
||||||
.uart_rx
|
.uart_rx
|
||||||
.irq_handler_max_size_or_timeout_based(cx.local.rx_context, cx.local.rx_buf)
|
.on_interrupt_max_size_or_timeout_based(cx.local.rx_context, cx.local.rx_buf)
|
||||||
{
|
{
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if RX_DEBUGGING {
|
if RX_DEBUGGING {
|
||||||
|
@ -43,7 +43,7 @@ use once_cell::sync::OnceCell;
|
|||||||
use va108xx_hal::pac::interrupt;
|
use va108xx_hal::pac::interrupt;
|
||||||
use va108xx_hal::{
|
use va108xx_hal::{
|
||||||
clock::enable_peripheral_clock,
|
clock::enable_peripheral_clock,
|
||||||
enable_interrupt, pac,
|
enable_nvic_interrupt, pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{enable_tim_clk, get_tim_raw, TimRegInterface},
|
timer::{enable_tim_clk, get_tim_raw, TimRegInterface},
|
||||||
PeripheralSelect,
|
PeripheralSelect,
|
||||||
@ -221,7 +221,7 @@ impl TimerDriver {
|
|||||||
.tim0(timekeeper_tim.tim_id() as usize)
|
.tim0(timekeeper_tim.tim_id() as usize)
|
||||||
.write(|w| unsafe { w.bits(timekeeper_irq as u32) });
|
.write(|w| unsafe { w.bits(timekeeper_irq as u32) });
|
||||||
unsafe {
|
unsafe {
|
||||||
enable_interrupt(timekeeper_irq);
|
enable_nvic_interrupt(timekeeper_irq);
|
||||||
}
|
}
|
||||||
timekeeper_reg_block
|
timekeeper_reg_block
|
||||||
.ctrl()
|
.ctrl()
|
||||||
@ -239,7 +239,7 @@ impl TimerDriver {
|
|||||||
});
|
});
|
||||||
// Enable general interrupts. The IRQ enable of the peripheral remains cleared.
|
// Enable general interrupts. The IRQ enable of the peripheral remains cleared.
|
||||||
unsafe {
|
unsafe {
|
||||||
enable_interrupt(alarm_irq);
|
enable_nvic_interrupt(alarm_irq);
|
||||||
}
|
}
|
||||||
irqsel
|
irqsel
|
||||||
.tim0(alarm_tim.tim_id() as usize)
|
.tim0(alarm_tim.tim_id() as usize)
|
||||||
|
@ -24,12 +24,29 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- I2C `TimingCfg` constructor now returns explicit error instead of generic Error.
|
- I2C `TimingCfg` constructor now returns explicit error instead of generic Error.
|
||||||
Removed the timing configuration error type from the generic I2C error enumeration.
|
Removed the timing configuration error type from the generic I2C error enumeration.
|
||||||
- `PinsA` and `PinsB` constructor do not expect an optional `pac::Ioconfig` argument anymore.
|
- `PinsA` and `PinsB` constructor do not expect an optional `pac::Ioconfig` argument anymore.
|
||||||
|
- `IrqCfg` renamed to `InterruptConfig`, kept alias for old name.
|
||||||
|
- All library provided interrupt handlers now start with common prefix `on_interrupt_*`
|
||||||
|
- `RxWithIrq` renamed to `RxWithInterrupt`
|
||||||
|
- `Rx::into_rx_with_irq` does not expect any arguments any more.
|
||||||
|
- `filter_type` renamed to `configure_filter_type`.
|
||||||
|
- `level_irq` renamed to `configure_level_interrupt`.
|
||||||
|
- `edge_irq` renamed to `configure_edge_interrupt`.
|
||||||
|
- `PinsA` and `PinsB` constructor do not expect an optional IOCONFIG argument anymore.
|
||||||
|
- UART interrupt management is now handled by the main constructor instead of later stages to
|
||||||
|
statically ensure one interrupt vector for the UART peripheral. `Uart::new` expects an
|
||||||
|
optional `InterruptConfig` argument.
|
||||||
|
- `enable_interrupt` and `disable_interrupt` renamed to `enable_nvic_interrupt` and
|
||||||
|
`disable_nvic_interrupt` to distinguish them from peripheral interrupts more clearly.
|
||||||
|
- `port_mux` renamed to `port_function_select`
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Add `downgrade` method for `Pin` and `upgrade` method for `DynPin` as explicit conversion
|
- Add `downgrade` method for `Pin` and `upgrade` method for `DynPin` as explicit conversion
|
||||||
methods.
|
methods.
|
||||||
|
- Asynchronous GPIO support.
|
||||||
|
- Asynchronous UART TX support.
|
||||||
- Add new `get_tim_raw` unsafe method to retrieve TIM peripheral blocks.
|
- Add new `get_tim_raw` unsafe method to retrieve TIM peripheral blocks.
|
||||||
|
- `Uart::with_with_interrupt` and `Uart::new_without_interrupt`
|
||||||
|
|
||||||
## [v0.8.0] 2024-09-30
|
## [v0.8.0] 2024-09-30
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ embedded-hal = "1"
|
|||||||
embedded-hal-async = "1"
|
embedded-hal-async = "1"
|
||||||
embedded-hal-nb = "1"
|
embedded-hal-nb = "1"
|
||||||
embedded-io = "0.6"
|
embedded-io = "0.6"
|
||||||
|
embedded-io-async = "0.6"
|
||||||
fugit = "0.3"
|
fugit = "0.3"
|
||||||
typenum = "1"
|
typenum = "1"
|
||||||
critical-section = "1"
|
critical-section = "1"
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
//! on GPIO pins. Please note that this module does not specify/declare the interrupt handlers
|
//! on GPIO pins. Please note that this module does not specify/declare the interrupt handlers
|
||||||
//! which must be provided for async support to work. However, it provides one generic
|
//! which must be provided for async support to work. However, it provides one generic
|
||||||
//! [handler][handle_interrupt_for_async_gpio] which should be called in ALL user interrupt handlers
|
//! [handler][handle_interrupt_for_async_gpio] which should be called in ALL user interrupt handlers
|
||||||
//! for which handle GPIO interrupts.
|
//! which handle GPIO interrupts.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/async-gpio/examples/embassy/src/bin/async-gpio.rs)
|
//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs)
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -18,7 +18,7 @@ use embedded_hal_async::digital::Wait;
|
|||||||
use portable_atomic::AtomicBool;
|
use portable_atomic::AtomicBool;
|
||||||
use va108xx::{self as pac, Irqsel, Sysconfig};
|
use va108xx::{self as pac, Irqsel, Sysconfig};
|
||||||
|
|
||||||
use crate::IrqCfg;
|
use crate::InterruptConfig;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pin, DynGroup, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId,
|
pin, DynGroup, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId,
|
||||||
@ -44,7 +44,7 @@ fn pin_id_to_offset(dyn_pin_id: DynPinId) -> usize {
|
|||||||
/// complete async operations. The user should call this function in ALL interrupt handlers
|
/// complete async operations. The user should call this function in ALL interrupt handlers
|
||||||
/// which handle any GPIO interrupts.
|
/// which handle any GPIO interrupts.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle_interrupt_for_async_gpio() {
|
pub fn on_interrupt_for_asynch_gpio() {
|
||||||
let periphs = unsafe { pac::Peripherals::steal() };
|
let periphs = unsafe { pac::Peripherals::steal() };
|
||||||
|
|
||||||
handle_interrupt_for_gpio_and_port(
|
handle_interrupt_for_gpio_and_port(
|
||||||
@ -117,7 +117,7 @@ impl InputPinFuture {
|
|||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.interrupt_edge(
|
pin.interrupt_edge(
|
||||||
edge,
|
edge,
|
||||||
IrqCfg::new(irq, true, true),
|
InterruptConfig::new(irq, true, true),
|
||||||
Some(sys_cfg),
|
Some(sys_cfg),
|
||||||
Some(irq_sel),
|
Some(irq_sel),
|
||||||
)
|
)
|
||||||
@ -148,9 +148,9 @@ impl InputPinFuture {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.interrupt_edge(
|
pin.configure_edge_interrupt(
|
||||||
edge,
|
edge,
|
||||||
IrqCfg::new(irq, true, true),
|
InterruptConfig::new(irq, true, true),
|
||||||
Some(sys_cfg),
|
Some(sys_cfg),
|
||||||
Some(irq_sel),
|
Some(irq_sel),
|
||||||
);
|
);
|
||||||
|
@ -61,7 +61,7 @@ use super::{
|
|||||||
reg::RegisterInterface,
|
reg::RegisterInterface,
|
||||||
InputDynPinAsync,
|
InputDynPinAsync,
|
||||||
};
|
};
|
||||||
use crate::{clock::FilterClkSel, enable_interrupt, pac, FunSel, IrqCfg};
|
use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel, InterruptConfig};
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// DynPinMode configurations
|
// DynPinMode configurations
|
||||||
@ -351,7 +351,7 @@ impl DynPin {
|
|||||||
|
|
||||||
pub(crate) fn irq_enb(
|
pub(crate) fn irq_enb(
|
||||||
&mut self,
|
&mut self,
|
||||||
irq_cfg: crate::IrqCfg,
|
irq_cfg: crate::InterruptConfig,
|
||||||
syscfg: Option<&mut va108xx::Sysconfig>,
|
syscfg: Option<&mut va108xx::Sysconfig>,
|
||||||
irqsel: Option<&mut va108xx::Irqsel>,
|
irqsel: Option<&mut va108xx::Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -366,18 +366,18 @@ impl DynPin {
|
|||||||
DynGroup::A => {
|
DynGroup::A => {
|
||||||
irqsel
|
irqsel
|
||||||
.porta0(self.regs.id().num as usize)
|
.porta0(self.regs.id().num as usize)
|
||||||
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
}
|
}
|
||||||
DynGroup::B => {
|
DynGroup::B => {
|
||||||
irqsel
|
irqsel
|
||||||
.portb0(self.regs.id().num as usize)
|
.portb0(self.regs.id().num as usize)
|
||||||
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if irq_cfg.enable {
|
if irq_cfg.enable_in_nvic {
|
||||||
unsafe { enable_interrupt(irq_cfg.irq) };
|
unsafe { enable_nvic_interrupt(irq_cfg.id) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +435,7 @@ impl DynPin {
|
|||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut pac::Sysconfig>,
|
syscfg: Option<&mut pac::Sysconfig>,
|
||||||
irqsel: Option<&mut pac::Irqsel>,
|
irqsel: Option<&mut pac::Irqsel>,
|
||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
@ -453,7 +453,7 @@ impl DynPin {
|
|||||||
pub fn interrupt_level(
|
pub fn interrupt_level(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut pac::Sysconfig>,
|
syscfg: Option<&mut pac::Sysconfig>,
|
||||||
irqsel: Option<&mut pac::Irqsel>,
|
irqsel: Option<&mut pac::Irqsel>,
|
||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
|
@ -76,7 +76,7 @@ use super::{DynPin, InputPinAsync};
|
|||||||
use crate::{
|
use crate::{
|
||||||
pac::{Irqsel, Porta, Portb, Sysconfig},
|
pac::{Irqsel, Porta, Portb, Sysconfig},
|
||||||
typelevel::Sealed,
|
typelevel::Sealed,
|
||||||
IrqCfg,
|
InterruptConfig,
|
||||||
};
|
};
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
@ -454,7 +454,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
|
|
||||||
fn irq_enb(
|
fn irq_enb(
|
||||||
&mut self,
|
&mut self,
|
||||||
irq_cfg: crate::IrqCfg,
|
irq_cfg: crate::InterruptConfig,
|
||||||
syscfg: Option<&mut va108xx::Sysconfig>,
|
syscfg: Option<&mut va108xx::Sysconfig>,
|
||||||
irqsel: Option<&mut va108xx::Irqsel>,
|
irqsel: Option<&mut va108xx::Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -581,10 +581,10 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
InputPinAsync::new(self, irq)
|
InputPinAsync::new(self, irq)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_edge(
|
pub fn configure_edge_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -592,10 +592,10 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn configure_level_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -631,7 +631,7 @@ 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,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -642,7 +642,7 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
pub fn interrupt_level(
|
pub fn interrupt_level(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
@ -654,7 +654,7 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.inner.regs.filter_type(filter, clksel);
|
self.inner.regs.filter_type(filter, clksel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,14 @@ pub enum FunSel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PortSel {
|
pub enum PortSel {
|
||||||
PortA,
|
PortA,
|
||||||
PortB,
|
PortB,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PeripheralSelect {
|
pub enum PeripheralSelect {
|
||||||
PortA = 0,
|
PortA = 0,
|
||||||
PortB = 1,
|
PortB = 1,
|
||||||
@ -47,31 +49,38 @@ pub enum PeripheralSelect {
|
|||||||
Gpio = 24,
|
Gpio = 24,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic IRQ config which can be used to specify whether the HAL driver will
|
/// Generic interrupt 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
|
/// 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
|
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might perform
|
||||||
/// this steps themselves
|
/// this steps themselves
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct IrqCfg {
|
pub struct InterruptConfig {
|
||||||
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
|
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
|
||||||
pub irq: pac::Interrupt,
|
pub id: pac::Interrupt,
|
||||||
/// Specfiy whether IRQ should be routed to an IRQ vector using the IRQSEL peripheral
|
/// Specfiy whether IRQ should be routed to an IRQ vector using the IRQSEL peripheral.
|
||||||
pub route: bool,
|
pub route: bool,
|
||||||
/// Specify whether the IRQ is unmasked in the Cortex-M NVIC
|
/// Specify whether the IRQ is unmasked in the Cortex-M NVIC. If an interrupt is used for
|
||||||
pub enable: bool,
|
/// multiple purposes, the user can enable the interrupts themselves.
|
||||||
|
pub enable_in_nvic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqCfg {
|
impl InterruptConfig {
|
||||||
pub fn new(irq: pac::Interrupt, route: bool, enable: bool) -> Self {
|
pub fn new(id: pac::Interrupt, route: bool, enable_in_nvic: bool) -> Self {
|
||||||
IrqCfg { irq, route, enable }
|
InterruptConfig {
|
||||||
|
id,
|
||||||
|
route,
|
||||||
|
enable_in_nvic,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type IrqCfg = InterruptConfig;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct InvalidPin(pub(crate) ());
|
pub struct InvalidPin(pub(crate) ());
|
||||||
|
|
||||||
/// Can be used to manually manipulate the function select of port pins
|
/// Can be used to manually manipulate the function select of port pins
|
||||||
pub fn port_mux(
|
pub fn port_function_select(
|
||||||
ioconfig: &mut pac::Ioconfig,
|
ioconfig: &mut pac::Ioconfig,
|
||||||
port: PortSel,
|
port: PortSel,
|
||||||
pin: u8,
|
pin: u8,
|
||||||
@ -105,7 +114,7 @@ pub fn port_mux(
|
|||||||
///
|
///
|
||||||
/// This function is `unsafe` because it can break mask-based critical sections.
|
/// This function is `unsafe` because it can break mask-based critical sections.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn enable_interrupt(irq: pac::Interrupt) {
|
pub unsafe fn enable_nvic_interrupt(irq: pac::Interrupt) {
|
||||||
unsafe {
|
unsafe {
|
||||||
cortex_m::peripheral::NVIC::unmask(irq);
|
cortex_m::peripheral::NVIC::unmask(irq);
|
||||||
}
|
}
|
||||||
@ -113,6 +122,6 @@ pub unsafe fn enable_interrupt(irq: pac::Interrupt) {
|
|||||||
|
|
||||||
/// Disable a specific interrupt using the NVIC peripheral.
|
/// Disable a specific interrupt using the NVIC peripheral.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable_interrupt(irq: pac::Interrupt) {
|
pub fn disable_nvic_interrupt(irq: pac::Interrupt) {
|
||||||
cortex_m::peripheral::NVIC::mask(irq);
|
cortex_m::peripheral::NVIC::mask(irq);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ where
|
|||||||
pin
|
pin
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reduce(self) -> ReducedPwmPin<Mode> {
|
pub fn downgrade(self) -> ReducedPwmPin<Mode> {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,6 +277,24 @@ impl<Mode> ReducedPwmPin<Mode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> From<PwmPin<Pin, Tim, PwmA>> for ReducedPwmPin<PwmA>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
fn from(value: PwmPin<Pin, Tim, PwmA>) -> Self {
|
||||||
|
value.downgrade()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Pin: TimPin, Tim: ValidTim> From<PwmPin<Pin, Tim, PwmB>> for ReducedPwmPin<PwmB>
|
||||||
|
where
|
||||||
|
(Pin, Tim): ValidTimAndPin<Pin, Tim>,
|
||||||
|
{
|
||||||
|
fn from(value: PwmPin<Pin, Tim, PwmB>) -> Self {
|
||||||
|
value.downgrade()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ReducedPwmPin<PwmA>> for ReducedPwmPin<PwmB> {
|
impl From<ReducedPwmPin<PwmA>> for ReducedPwmPin<PwmB> {
|
||||||
fn from(other: ReducedPwmPin<PwmA>) -> Self {
|
fn from(other: ReducedPwmPin<PwmA>) -> Self {
|
||||||
let mut pwmb = Self {
|
let mut pwmb = Self {
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
//!
|
//!
|
||||||
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/timer-ticks.rs)
|
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/timer-ticks.rs)
|
||||||
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/cascade.rs)
|
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/cascade.rs)
|
||||||
pub use crate::IrqCfg;
|
pub use crate::InterruptConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||||
enable_interrupt,
|
enable_nvic_interrupt,
|
||||||
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,
|
||||||
@ -362,7 +362,7 @@ unsafe impl TimRegInterface for TimDynRegister {
|
|||||||
pub struct CountdownTimer<Tim: ValidTim> {
|
pub struct CountdownTimer<Tim: ValidTim> {
|
||||||
tim: Tim,
|
tim: Tim,
|
||||||
curr_freq: Hertz,
|
curr_freq: Hertz,
|
||||||
irq_cfg: Option<IrqCfg>,
|
irq_cfg: Option<InterruptConfig>,
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
rst_val: u32,
|
rst_val: u32,
|
||||||
last_cnt: u32,
|
last_cnt: u32,
|
||||||
@ -415,13 +415,13 @@ impl<Tim: ValidTim> CountdownTimer<Tim> {
|
|||||||
pub fn listen(
|
pub fn listen(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: Event,
|
event: Event,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
irq_sel: Option<&mut pac::Irqsel>,
|
irq_sel: Option<&mut pac::Irqsel>,
|
||||||
sys_cfg: Option<&mut pac::Sysconfig>,
|
sys_cfg: Option<&mut pac::Sysconfig>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
Event::TimeOut => {
|
Event::TimeOut => {
|
||||||
cortex_m::peripheral::NVIC::mask(irq_cfg.irq);
|
cortex_m::peripheral::NVIC::mask(irq_cfg.id);
|
||||||
self.irq_cfg = Some(irq_cfg);
|
self.irq_cfg = Some(irq_cfg);
|
||||||
if irq_cfg.route {
|
if irq_cfg.route {
|
||||||
if let Some(sys_cfg) = sys_cfg {
|
if let Some(sys_cfg) = sys_cfg {
|
||||||
@ -430,7 +430,7 @@ impl<Tim: ValidTim> CountdownTimer<Tim> {
|
|||||||
if let Some(irq_sel) = irq_sel {
|
if let Some(irq_sel) = irq_sel {
|
||||||
irq_sel
|
irq_sel
|
||||||
.tim0(Tim::TIM_ID as usize)
|
.tim0(Tim::TIM_ID as usize)
|
||||||
.write(|w| unsafe { w.bits(irq_cfg.irq as u32) });
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.listening = true;
|
self.listening = true;
|
||||||
@ -520,8 +520,8 @@ impl<Tim: ValidTim> CountdownTimer<Tim> {
|
|||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
if let Some(irq_cfg) = self.irq_cfg {
|
if let Some(irq_cfg) = self.irq_cfg {
|
||||||
self.enable_interrupt();
|
self.enable_interrupt();
|
||||||
if irq_cfg.enable {
|
if irq_cfg.enable_in_nvic {
|
||||||
unsafe { enable_interrupt(irq_cfg.irq) };
|
unsafe { enable_nvic_interrupt(irq_cfg.id) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tim
|
self.tim
|
||||||
@ -719,7 +719,7 @@ impl<TIM: ValidTim> embedded_hal::delay::DelayNs for CountdownTimer<TIM> {
|
|||||||
// Set up a millisecond timer on TIM0. Please note that the user still has to provide an IRQ handler
|
// Set up a millisecond timer on TIM0. Please note that the user still has to provide an IRQ handler
|
||||||
// which should call [default_ms_irq_handler].
|
// which should call [default_ms_irq_handler].
|
||||||
pub fn set_up_ms_tick<TIM: ValidTim>(
|
pub fn set_up_ms_tick<TIM: ValidTim>(
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
sys_cfg: &mut pac::Sysconfig,
|
sys_cfg: &mut pac::Sysconfig,
|
||||||
irq_sel: Option<&mut pac::Irqsel>,
|
irq_sel: Option<&mut pac::Irqsel>,
|
||||||
sys_clk: impl Into<Hertz>,
|
sys_clk: impl Into<Hertz>,
|
||||||
|
264
va108xx-hal/src/uart/asynch.rs
Normal file
264
va108xx-hal/src/uart/asynch.rs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
//! # Async GPIO 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 provides two interrupt handlers:
|
||||||
|
//!
|
||||||
|
//! - [on_interrupt_uart_a_tx]
|
||||||
|
//! - [on_interrupt_uart_b_tx]
|
||||||
|
//!
|
||||||
|
//! Those should be called in ALL user interrupt handlers which handle UART TX interrupts,
|
||||||
|
//! depending on which UARTs are used.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! - [Async UART example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/async-gpio/examples/embassy/src/bin/async-uart.rs)
|
||||||
|
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 super::*;
|
||||||
|
|
||||||
|
static UART_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. The user
|
||||||
|
/// has to call this once in the interrupt handler responsible for UART A TX interrupts for
|
||||||
|
/// asynchronous operations to work.
|
||||||
|
pub fn on_interrupt_uart_a_tx() {
|
||||||
|
on_interrupt_uart_tx(unsafe { pac::Uarta::steal() });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a generic interrupt handler to handle asynchronous UART TX operations. The user
|
||||||
|
/// has to call this once in the interrupt handler responsible for UART B TX interrupts for
|
||||||
|
/// asynchronous operations to work.
|
||||||
|
pub fn on_interrupt_uart_b_tx() {
|
||||||
|
on_interrupt_uart_tx(unsafe { pac::Uartb::steal() });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_interrupt_uart_tx<Uart: Instance>(uart: Uart) {
|
||||||
|
let irq_enb = uart.irq_enb().read();
|
||||||
|
// IRQ is not related to TX.
|
||||||
|
if irq_enb.irq_tx().bit_is_clear() || irq_enb.irq_tx_empty().bit_is_clear() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx_status = uart.txstatus().read();
|
||||||
|
let unexpected_overrun = tx_status.wrlost().bit_is_set();
|
||||||
|
let mut context = critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs);
|
||||||
|
*context_ref.borrow()
|
||||||
|
});
|
||||||
|
context.tx_overrun = unexpected_overrun;
|
||||||
|
if context.progress >= context.slice.len && !tx_status.wrbusy().bit_is_set() {
|
||||||
|
uart.irq_enb().modify(|_, w| {
|
||||||
|
w.irq_tx().clear_bit();
|
||||||
|
w.irq_tx_empty().clear_bit();
|
||||||
|
w.irq_tx_status().clear_bit()
|
||||||
|
});
|
||||||
|
uart.enable().modify(|_, w| w.txenable().clear_bit());
|
||||||
|
// Write back updated context structure.
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs);
|
||||||
|
*context_ref.borrow_mut() = context;
|
||||||
|
});
|
||||||
|
// Transfer is done.
|
||||||
|
TX_DONE[Uart::IDX as usize].store(true, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
UART_WAKERS[Uart::IDX as usize].wake();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 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 { core::slice::from_raw_parts(context.slice.data, context.slice.len) };
|
||||||
|
while context.progress < context.slice.len {
|
||||||
|
let wrrdy = uart.txstatus().read().wrrdy().bit_is_set();
|
||||||
|
if !wrrdy {
|
||||||
|
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.data()
|
||||||
|
.write(|w| unsafe { w.bits(slice[context.progress] as u32) });
|
||||||
|
context.progress += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back updated context structure.
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[Uart::IDX as usize].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_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
struct RawBufSlice {
|
||||||
|
data: *const u8,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safety: This type MUST be used with mutex to ensure concurrent access is valid.
|
||||||
|
unsafe impl Send for RawBufSlice {}
|
||||||
|
|
||||||
|
impl RawBufSlice {
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function stores the raw pointer of the passed data slice. The user MUST ensure
|
||||||
|
/// that the slice outlives the data structure.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const unsafe fn new(data: &[u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
data: data.as_ptr(),
|
||||||
|
len: data.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn new_empty() -> Self {
|
||||||
|
Self {
|
||||||
|
data: core::ptr::null(),
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # 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 set(&mut self, data: &[u8]) {
|
||||||
|
self.data = data.as_ptr();
|
||||||
|
self.len = data.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxFuture {
|
||||||
|
uart_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Uart: Instance>(tx: &mut Tx<Uart>, data: &[u8]) -> Self {
|
||||||
|
TX_DONE[Uart::IDX as usize].store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
tx.disable_interrupts();
|
||||||
|
tx.disable();
|
||||||
|
tx.clear_fifo();
|
||||||
|
|
||||||
|
let uart_tx = unsafe { tx.uart() };
|
||||||
|
let init_fill_count = core::cmp::min(data.len(), 16);
|
||||||
|
// We fill the FIFO.
|
||||||
|
for data in data.iter().take(init_fill_count) {
|
||||||
|
uart_tx.data().write(|w| unsafe { w.bits(*data as u32) });
|
||||||
|
}
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs);
|
||||||
|
let mut context = context_ref.borrow_mut();
|
||||||
|
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 {
|
||||||
|
uart_idx: Uart::IDX as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_WAKERS[self.uart_idx].register(cx.waker());
|
||||||
|
if TX_DONE[self.uart_idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||||
|
let progress = critical_section::with(|cs| {
|
||||||
|
TX_CONTEXTS[self.uart_idx].borrow(cs).borrow().progress
|
||||||
|
});
|
||||||
|
return core::task::Poll::Ready(Ok(progress));
|
||||||
|
}
|
||||||
|
core::task::Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TxFuture {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let reg_block = match self.uart_idx {
|
||||||
|
0 => unsafe { pac::Uarta::reg_block() },
|
||||||
|
1 => unsafe { pac::Uartb::reg_block() },
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
disable_tx_interrupts(reg_block);
|
||||||
|
disable_tx(reg_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxAsync<Uart: Instance> {
|
||||||
|
tx: Tx<Uart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance> TxAsync<Uart> {
|
||||||
|
pub fn new(tx: Tx<Uart>) -> Self {
|
||||||
|
Self { tx }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(self) -> Tx<Uart> {
|
||||||
|
self.tx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<Uart: Instance> embedded_io::ErrorType for TxAsync<Uart> {
|
||||||
|
type Error = TxOverrunError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance> Write for TxAsync<Uart> {
|
||||||
|
/// 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.tx, buf) };
|
||||||
|
fut.await
|
||||||
|
}
|
||||||
|
}
|
@ -9,10 +9,10 @@ use core::{convert::Infallible, ops::Deref};
|
|||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
use va108xx::Uarta;
|
use va108xx::Uarta;
|
||||||
|
|
||||||
pub use crate::IrqCfg;
|
pub use crate::InterruptConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::enable_peripheral_clock,
|
clock::enable_peripheral_clock,
|
||||||
enable_interrupt,
|
enable_nvic_interrupt,
|
||||||
gpio::pin::{
|
gpio::pin::{
|
||||||
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,
|
||||||
@ -48,6 +48,11 @@ impl Pins<pac::Uartb> for (Pin<PB21, AltFunc1>, Pin<PB20, AltFunc1>) {}
|
|||||||
// Regular Definitions
|
// Regular Definitions
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[error("no interrupt ID was set")]
|
||||||
|
pub struct NoInterruptIdWasSet;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[error("transer is pending")]
|
#[error("transer is pending")]
|
||||||
@ -373,6 +378,16 @@ pub trait Instance: Deref<Target = uart_base::RegisterBlock> {
|
|||||||
/// This circumvents the safety guarantees of the HAL.
|
/// This circumvents the safety guarantees of the HAL.
|
||||||
unsafe fn steal() -> Self;
|
unsafe fn steal() -> Self;
|
||||||
fn ptr() -> *const uart_base::RegisterBlock;
|
fn ptr() -> *const uart_base::RegisterBlock;
|
||||||
|
|
||||||
|
/// Retrieve the type erased peripheral register block.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This circumvents the safety guarantees of the HAL.
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn reg_block() -> &'static uart_base::RegisterBlock {
|
||||||
|
unsafe { &(*Self::ptr()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance for pac::Uarta {
|
impl Instance for pac::Uarta {
|
||||||
@ -380,9 +395,11 @@ impl Instance for pac::Uarta {
|
|||||||
|
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
unsafe fn steal() -> Self {
|
unsafe fn steal() -> Self {
|
||||||
pac::Peripherals::steal().uarta
|
pac::Peripherals::steal().uarta
|
||||||
}
|
}
|
||||||
|
#[inline(always)]
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uarta::ptr() as *const _
|
Uarta::ptr() as *const _
|
||||||
}
|
}
|
||||||
@ -393,9 +410,11 @@ impl Instance for pac::Uartb {
|
|||||||
|
|
||||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
|
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
unsafe fn steal() -> Self {
|
unsafe fn steal() -> Self {
|
||||||
pac::Peripherals::steal().uartb
|
pac::Peripherals::steal().uartb
|
||||||
}
|
}
|
||||||
|
#[inline(always)]
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uarta::ptr() as *const _
|
Uarta::ptr() as *const _
|
||||||
}
|
}
|
||||||
@ -592,15 +611,51 @@ where
|
|||||||
UartInstance: Instance,
|
UartInstance: Instance,
|
||||||
PinsInstance: Pins<UartInstance>,
|
PinsInstance: Pins<UartInstance>,
|
||||||
{
|
{
|
||||||
pub fn new(
|
/// Calls [Self::new] with the interrupt configuration to some valid value.
|
||||||
|
pub fn new_with_interrupt(
|
||||||
|
syscfg: &mut va108xx::Sysconfig,
|
||||||
|
sys_clk: impl Into<Hertz>,
|
||||||
|
uart: UartInstance,
|
||||||
|
pins: PinsInstance,
|
||||||
|
config: impl Into<Config>,
|
||||||
|
irq_cfg: InterruptConfig,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(syscfg, sys_clk, uart, pins, config, Some(irq_cfg))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls [Self::new] with the interrupt configuration to [None].
|
||||||
|
pub fn new_without_interrupt(
|
||||||
syscfg: &mut va108xx::Sysconfig,
|
syscfg: &mut va108xx::Sysconfig,
|
||||||
sys_clk: impl Into<Hertz>,
|
sys_clk: impl Into<Hertz>,
|
||||||
uart: UartInstance,
|
uart: UartInstance,
|
||||||
pins: PinsInstance,
|
pins: PinsInstance,
|
||||||
config: impl Into<Config>,
|
config: impl Into<Config>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(syscfg, sys_clk, uart, pins, config, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new UART peripheral with an interrupt configuration.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `syscfg`: The system configuration register block
|
||||||
|
/// - `sys_clk`: The system clock frequency
|
||||||
|
/// - `uart`: The concrete UART peripheral instance.
|
||||||
|
/// - `pins`: UART TX and RX pin tuple.
|
||||||
|
/// - `config`: UART specific configuration parameters like baudrate.
|
||||||
|
/// - `irq_cfg`: Optional interrupt configuration. This should be a valid value if the plan
|
||||||
|
/// is to use TX or RX functionality relying on interrupts. If only the blocking API without
|
||||||
|
/// any interrupt support is used, this can be [None].
|
||||||
|
pub fn new(
|
||||||
|
syscfg: &mut va108xx::Sysconfig,
|
||||||
|
sys_clk: impl Into<Hertz>,
|
||||||
|
uart: UartInstance,
|
||||||
|
pins: PinsInstance,
|
||||||
|
config: impl Into<Config>,
|
||||||
|
opt_irq_cfg: Option<InterruptConfig>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
crate::clock::enable_peripheral_clock(syscfg, UartInstance::PERIPH_SEL);
|
crate::clock::enable_peripheral_clock(syscfg, UartInstance::PERIPH_SEL);
|
||||||
Uart {
|
let uart = Uart {
|
||||||
inner: UartBase {
|
inner: UartBase {
|
||||||
uart,
|
uart,
|
||||||
tx: Tx::new(unsafe { UartInstance::steal() }),
|
tx: Tx::new(unsafe { UartInstance::steal() }),
|
||||||
@ -608,7 +663,21 @@ where
|
|||||||
},
|
},
|
||||||
pins,
|
pins,
|
||||||
}
|
}
|
||||||
.init(config.into(), sys_clk.into())
|
.init(config.into(), sys_clk.into());
|
||||||
|
|
||||||
|
if let Some(irq_cfg) = opt_irq_cfg {
|
||||||
|
if irq_cfg.route {
|
||||||
|
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
|
||||||
|
unsafe { pac::Irqsel::steal() }
|
||||||
|
.uart0(UartInstance::IDX as usize)
|
||||||
|
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
|
||||||
|
}
|
||||||
|
if irq_cfg.enable_in_nvic {
|
||||||
|
// Safety: User has specifically configured this.
|
||||||
|
unsafe { enable_nvic_interrupt(irq_cfg.id) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uart
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function assumes that the peripheral clock was alredy enabled
|
/// This function assumes that the peripheral clock was alredy enabled
|
||||||
@ -686,11 +755,13 @@ where
|
|||||||
/// Serial receiver.
|
/// Serial receiver.
|
||||||
///
|
///
|
||||||
/// Can be created by using the [Uart::split] or [UartBase::split] API.
|
/// Can be created by using the [Uart::split] or [UartBase::split] API.
|
||||||
pub struct Rx<Uart>(Uart);
|
pub struct Rx<Uart> {
|
||||||
|
uart: Uart,
|
||||||
|
}
|
||||||
|
|
||||||
impl<Uart: Instance> Rx<Uart> {
|
impl<Uart: Instance> Rx<Uart> {
|
||||||
fn new(uart: Uart) -> Self {
|
fn new(uart: Uart) -> Self {
|
||||||
Self(uart)
|
Self { uart }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direct access to the peripheral structure.
|
/// Direct access to the peripheral structure.
|
||||||
@ -699,22 +770,22 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
///
|
///
|
||||||
/// You must ensure that only registers related to the operation of the RX side are used.
|
/// You must ensure that only registers related to the operation of the RX side are used.
|
||||||
pub unsafe fn uart(&self) -> &Uart {
|
pub unsafe fn uart(&self) -> &Uart {
|
||||||
&self.0
|
&self.uart
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_fifo(&self) {
|
pub fn clear_fifo(&self) {
|
||||||
self.0.fifo_clr().write(|w| w.rxfifo().set_bit());
|
self.uart.fifo_clr().write(|w| w.rxfifo().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
self.0.enable().modify(|_, w| w.rxenable().set_bit());
|
self.uart.enable().modify(|_, w| w.rxenable().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable(&mut self) {
|
pub fn disable(&mut self) {
|
||||||
self.0.enable().modify(|_, w| w.rxenable().clear_bit());
|
self.uart.enable().modify(|_, w| w.rxenable().clear_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low level function to read a word from the UART FIFO.
|
/// Low level function to read a word from the UART FIFO.
|
||||||
@ -725,7 +796,7 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
/// value if you use the manual parity mode. See chapter 4.6.2 for more information.
|
/// value if you use the manual parity mode. See chapter 4.6.2 for more information.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_fifo(&self) -> nb::Result<u32, Infallible> {
|
pub fn read_fifo(&self) -> nb::Result<u32, Infallible> {
|
||||||
if self.0.rxstatus().read().rdavl().bit_is_clear() {
|
if self.uart.rxstatus().read().rdavl().bit_is_clear() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
Ok(self.read_fifo_unchecked())
|
Ok(self.read_fifo_unchecked())
|
||||||
@ -741,20 +812,15 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
/// value if you use the manual parity mode. See chapter 4.6.2 for more information.
|
/// value if you use the manual parity mode. See chapter 4.6.2 for more information.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_fifo_unchecked(&self) -> u32 {
|
pub fn read_fifo_unchecked(&self) -> u32 {
|
||||||
self.0.data().read().bits()
|
self.uart.data().read().bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_rx_with_irq(
|
pub fn into_rx_with_irq(self) -> RxWithInterrupt<Uart> {
|
||||||
self,
|
RxWithInterrupt::new(self)
|
||||||
sysconfig: &mut pac::Sysconfig,
|
|
||||||
irqsel: &mut pac::Irqsel,
|
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> RxWithIrq<Uart> {
|
|
||||||
RxWithIrq::new(self, sysconfig, irqsel, interrupt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) -> Uart {
|
pub fn release(self) -> Uart {
|
||||||
self.0
|
self.uart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,14 +877,51 @@ impl<Uart: Instance> embedded_io::Read for Rx<Uart> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_tx(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.enable().modify(|_, w| w.txenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_tx(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.enable().modify(|_, w| w.txenable().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.irq_enb().modify(|_, w| {
|
||||||
|
w.irq_tx().set_bit();
|
||||||
|
w.irq_tx_status().set_bit();
|
||||||
|
w.irq_tx_empty().set_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.irq_enb().modify(|_, w| {
|
||||||
|
w.irq_tx().clear_bit();
|
||||||
|
w.irq_tx_status().clear_bit();
|
||||||
|
w.irq_tx_empty().clear_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Serial transmitter
|
/// Serial transmitter
|
||||||
///
|
///
|
||||||
/// Can be created by using the [Uart::split] or [UartBase::split] API.
|
/// Can be created by using the [Uart::split] or [UartBase::split] API.
|
||||||
pub struct Tx<Uart>(Uart);
|
pub struct Tx<Uart> {
|
||||||
|
uart: Uart,
|
||||||
|
}
|
||||||
|
|
||||||
impl<Uart: Instance> Tx<Uart> {
|
impl<Uart: Instance> Tx<Uart> {
|
||||||
|
/// Retrieve a TX pin without expecting an explicit UART structure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Circumvents the HAL safety guarantees.
|
||||||
|
pub unsafe fn steal() -> Self {
|
||||||
|
Self {
|
||||||
|
uart: Uart::steal(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn new(uart: Uart) -> Self {
|
fn new(uart: Uart) -> Self {
|
||||||
Self(uart)
|
Self { uart }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direct access to the peripheral structure.
|
/// Direct access to the peripheral structure.
|
||||||
@ -827,22 +930,45 @@ impl<Uart: Instance> Tx<Uart> {
|
|||||||
///
|
///
|
||||||
/// You must ensure that only registers related to the operation of the TX side are used.
|
/// You must ensure that only registers related to the operation of the TX side are used.
|
||||||
pub unsafe fn uart(&self) -> &Uart {
|
pub unsafe fn uart(&self) -> &Uart {
|
||||||
&self.0
|
&self.uart
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_fifo(&self) {
|
pub fn clear_fifo(&self) {
|
||||||
self.0.fifo_clr().write(|w| w.txfifo().set_bit());
|
self.uart.fifo_clr().write(|w| w.txfifo().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
self.0.enable().modify(|_, w| w.txenable().set_bit());
|
// Safety: We own the UART structure
|
||||||
|
enable_tx(unsafe { Uart::reg_block() });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable(&mut self) {
|
pub fn disable(&mut self) {
|
||||||
self.0.enable().modify(|_, w| w.txenable().clear_bit());
|
// Safety: We own the UART structure
|
||||||
|
disable_tx(unsafe { Uart::reg_block() });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts.
|
||||||
|
///
|
||||||
|
/// - The IRQ_TX interrupt is generated when the TX FIFO is at least half empty.
|
||||||
|
/// - The IRQ_TX_STATUS interrupt is generated when write data is lost due to a FIFO overflow
|
||||||
|
/// - The IRQ_TX_EMPTY interrupt is generated when the TX FIFO is empty and the TXBUSY signal
|
||||||
|
/// is 0
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_interrupts(&self) {
|
||||||
|
// Safety: We own the UART structure
|
||||||
|
enable_tx_interrupts(unsafe { Uart::reg_block() });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts.
|
||||||
|
///
|
||||||
|
/// [Self::enable_interrupts] documents the interrupts.
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_interrupts(&self) {
|
||||||
|
// Safety: We own the UART structure
|
||||||
|
disable_tx_interrupts(unsafe { Uart::reg_block() });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low level function to write a word to the UART FIFO.
|
/// Low level function to write a word to the UART FIFO.
|
||||||
@ -853,7 +979,7 @@ impl<Uart: Instance> Tx<Uart> {
|
|||||||
/// value if you use the manual parity mode. See chapter 11.4.1 for more information.
|
/// value if you use the manual parity mode. See chapter 11.4.1 for more information.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn write_fifo(&self, data: u32) -> nb::Result<(), Infallible> {
|
pub fn write_fifo(&self, data: u32) -> nb::Result<(), Infallible> {
|
||||||
if self.0.txstatus().read().wrrdy().bit_is_clear() {
|
if self.uart.txstatus().read().wrrdy().bit_is_clear() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
self.write_fifo_unchecked(data);
|
self.write_fifo_unchecked(data);
|
||||||
@ -868,7 +994,11 @@ impl<Uart: Instance> Tx<Uart> {
|
|||||||
/// API.
|
/// API.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn write_fifo_unchecked(&self, data: u32) {
|
pub fn write_fifo_unchecked(&self, data: u32) {
|
||||||
self.0.data().write(|w| unsafe { w.bits(data) });
|
self.uart.data().write(|w| unsafe { w.bits(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_async(self) -> TxAsync<Uart> {
|
||||||
|
TxAsync::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,36 +1061,23 @@ impl<Uart: Instance> embedded_io::Write for Tx<Uart> {
|
|||||||
/// then call the [Self::irq_handler_max_size_or_timeout_based] in the interrupt service
|
/// then call the [Self::irq_handler_max_size_or_timeout_based] in the interrupt service
|
||||||
/// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
|
/// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
|
||||||
/// start reading the next packet.
|
/// start reading the next packet.
|
||||||
pub struct RxWithIrq<Uart> {
|
pub struct RxWithInterrupt<Uart>(Rx<Uart>);
|
||||||
pub rx: Rx<Uart>,
|
|
||||||
pub interrupt: pac::Interrupt,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Uart: Instance> RxWithIrq<Uart> {
|
impl<Uart: Instance> RxWithInterrupt<Uart> {
|
||||||
pub fn new(
|
pub fn new(rx: Rx<Uart>) -> Self {
|
||||||
rx: Rx<Uart>,
|
Self(rx)
|
||||||
syscfg: &mut pac::Sysconfig,
|
|
||||||
irqsel: &mut pac::Irqsel,
|
|
||||||
interrupt: pac::Interrupt,
|
|
||||||
) -> Self {
|
|
||||||
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
|
|
||||||
irqsel
|
|
||||||
.uart0(Uart::IDX as usize)
|
|
||||||
.write(|w| unsafe { w.bits(interrupt as u32) });
|
|
||||||
Self { rx, interrupt }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function should be called once at initialization time if the regular
|
/// This function should be called once at initialization time if the regular
|
||||||
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
|
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.rx.enable();
|
self.0.enable();
|
||||||
self.enable_rx_irq_sources(true);
|
self.enable_rx_irq_sources(true);
|
||||||
unsafe { enable_interrupt(self.interrupt) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn uart(&self) -> &Uart {
|
pub fn uart(&self) -> &Uart {
|
||||||
&self.rx.0
|
&self.0.uart
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is used together with the [Self::irq_handler_max_size_or_timeout_based]
|
/// This function is used together with the [Self::irq_handler_max_size_or_timeout_based]
|
||||||
@ -1006,7 +1123,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
pub fn cancel_transfer(&mut self) {
|
pub fn cancel_transfer(&mut self) {
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
self.rx.clear_fifo();
|
self.0.clear_fifo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function should be called in the user provided UART interrupt handler.
|
/// This function should be called in the user provided UART interrupt handler.
|
||||||
@ -1017,7 +1134,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
/// This function will not disable the RX interrupts, so you don't need to call any other
|
/// This function will not disable the RX interrupts, so you don't need to call any other
|
||||||
/// API after calling this function to continue emptying the FIFO. RX errors are handled
|
/// API after calling this function to continue emptying the FIFO. RX errors are handled
|
||||||
/// as partial errors and are returned as part of the [IrqResult].
|
/// as partial errors and are returned as part of the [IrqResult].
|
||||||
pub fn irq_handler(&mut self, buf: &mut [u8; 16]) -> IrqResult {
|
pub fn on_interrupt(&mut self, buf: &mut [u8; 16]) -> IrqResult {
|
||||||
let mut result = IrqResult::default();
|
let mut result = IrqResult::default();
|
||||||
|
|
||||||
let irq_end = self.uart().irq_end().read();
|
let irq_end = self.uart().irq_end().read();
|
||||||
@ -1040,7 +1157,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
if irq_end.irq_rx_to().bit_is_set() {
|
if irq_end.irq_rx_to().bit_is_set() {
|
||||||
loop {
|
loop {
|
||||||
// While there is data in the FIFO, write it into the reception buffer
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
let read_result = self.rx.read();
|
let read_result = self.0.read();
|
||||||
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
||||||
buf[result.bytes_read] = byte;
|
buf[result.bytes_read] = byte;
|
||||||
result.bytes_read += 1;
|
result.bytes_read += 1;
|
||||||
@ -1074,7 +1191,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
/// If passed buffer is equal to or larger than the specified maximum length, an
|
/// If passed buffer is equal to or larger than the specified maximum length, an
|
||||||
/// [BufferTooShortError] will be returned. Other RX errors are treated as partial errors
|
/// [BufferTooShortError] will be returned. Other RX errors are treated as partial errors
|
||||||
/// and returned inside the [IrqResultMaxSizeOrTimeout] structure.
|
/// and returned inside the [IrqResultMaxSizeOrTimeout] structure.
|
||||||
pub fn irq_handler_max_size_or_timeout_based(
|
pub fn on_interrupt_max_size_or_timeout_based(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut IrqContextTimeoutOrMaxSize,
|
context: &mut IrqContextTimeoutOrMaxSize,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
@ -1123,7 +1240,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
if context.rx_idx == context.max_len {
|
if context.rx_idx == context.max_len {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let read_result = self.rx.read();
|
let read_result = self.0.read();
|
||||||
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
||||||
buf[context.rx_idx] = byte;
|
buf[context.rx_idx] = byte;
|
||||||
context.rx_idx += 1;
|
context.rx_idx += 1;
|
||||||
@ -1197,7 +1314,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
context: &mut IrqContextTimeoutOrMaxSize,
|
context: &mut IrqContextTimeoutOrMaxSize,
|
||||||
) {
|
) {
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
self.rx.disable();
|
self.0.disable();
|
||||||
res.bytes_read = context.rx_idx;
|
res.bytes_read = context.rx_idx;
|
||||||
res.complete = true;
|
res.complete = true;
|
||||||
context.mode = IrqReceptionMode::Idle;
|
context.mode = IrqReceptionMode::Idle;
|
||||||
@ -1210,6 +1327,9 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
/// The user must ensure that these instances are not used to create multiple overlapping
|
/// The user must ensure that these instances are not used to create multiple overlapping
|
||||||
/// UART drivers.
|
/// UART drivers.
|
||||||
pub unsafe fn release(self) -> Uart {
|
pub unsafe fn release(self) -> Uart {
|
||||||
self.rx.release()
|
self.0.release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod asynch;
|
||||||
|
pub use asynch::*;
|
@ -19,6 +19,7 @@ bitfield = ">=0.17, <=0.18"
|
|||||||
max116xx-10bit = "0.3"
|
max116xx-10bit = "0.3"
|
||||||
|
|
||||||
[dependencies.va108xx-hal]
|
[dependencies.va108xx-hal]
|
||||||
|
path = "../va108xx-hal"
|
||||||
version = ">=0.8, <0.9"
|
version = ">=0.8, <0.9"
|
||||||
features = ["rt"]
|
features = ["rt"]
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ fn main() -> ! {
|
|||||||
rprintln!("-- Vorago Accelerometer Example --");
|
rprintln!("-- Vorago Accelerometer Example --");
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
|
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let (sck, mosi, miso) = (
|
let (sck, mosi, miso) = (
|
||||||
pinsa.pa20.into_funsel_2(),
|
pinsa.pa20.into_funsel_2(),
|
||||||
pinsa.pa19.into_funsel_2(),
|
pinsa.pa19.into_funsel_2(),
|
||||||
|
@ -13,7 +13,7 @@ use va108xx_hal::{
|
|||||||
gpio::{FilterType, InterruptEdge, PinsA},
|
gpio::{FilterType, InterruptEdge, PinsA},
|
||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, IrqCfg},
|
timer::{default_ms_irq_handler, set_up_ms_tick, InterruptConfig},
|
||||||
};
|
};
|
||||||
use vorago_reb1::button::Button;
|
use vorago_reb1::button::Button;
|
||||||
use vorago_reb1::leds::Leds;
|
use vorago_reb1::leds::Leds;
|
||||||
@ -35,28 +35,29 @@ fn main() -> ! {
|
|||||||
rtt_init_print!();
|
rtt_init_print!();
|
||||||
rprintln!("-- Vorago Button IRQ Example --");
|
rprintln!("-- Vorago Button IRQ Example --");
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let edge_irq = match PRESS_MODE {
|
let edge_irq = match PRESS_MODE {
|
||||||
PressMode::Toggle => InterruptEdge::HighToLow,
|
PressMode::Toggle => InterruptEdge::HighToLow,
|
||||||
PressMode::Keep => InterruptEdge::BothEdges,
|
PressMode::Keep => InterruptEdge::BothEdges,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Configure an edge interrupt on the button and route it to interrupt vector 15
|
// Configure an edge interrupt on the button and route it to interrupt vector 15
|
||||||
let mut button = Button::new(pinsa.pa11.into_floating_input()).edge_irq(
|
let mut button = Button::new(pinsa.pa11.into_floating_input());
|
||||||
|
button.configure_edge_interrupt(
|
||||||
edge_irq,
|
edge_irq,
|
||||||
IrqCfg::new(pac::interrupt::OC15, true, true),
|
InterruptConfig::new(pac::interrupt::OC15, true, true),
|
||||||
Some(&mut dp.sysconfig),
|
Some(&mut dp.sysconfig),
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
);
|
);
|
||||||
|
|
||||||
if PRESS_MODE == PressMode::Toggle {
|
if PRESS_MODE == PressMode::Toggle {
|
||||||
// This filter debounces the switch for edge based interrupts
|
// This filter debounces the switch for edge based interrupts
|
||||||
button = button.filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1);
|
button.configure_filter_type(FilterType::FilterFourClockCycles, FilterClkSel::Clk1);
|
||||||
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
|
set_clk_div_register(&mut dp.sysconfig, FilterClkSel::Clk1, 50_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_up_ms_tick(
|
set_up_ms_tick(
|
||||||
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
|
@ -61,7 +61,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LibType::Hal => {
|
LibType::Hal => {
|
||||||
let pins = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let pins = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let mut led1 = pins.pa10.into_readable_push_pull_output();
|
let mut led1 = pins.pa10.into_readable_push_pull_output();
|
||||||
let mut led2 = pins.pa7.into_readable_push_pull_output();
|
let mut led2 = pins.pa7.into_readable_push_pull_output();
|
||||||
let mut led3 = pins.pa6.into_readable_push_pull_output();
|
let mut led3 = pins.pa6.into_readable_push_pull_output();
|
||||||
@ -87,27 +87,25 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LibType::Bsp => {
|
LibType::Bsp => {
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let mut leds = Leds::new(
|
let mut leds = Leds::new(
|
||||||
pinsa.pa10.into_push_pull_output(),
|
pinsa.pa10.into_push_pull_output(),
|
||||||
pinsa.pa7.into_push_pull_output(),
|
pinsa.pa7.into_push_pull_output(),
|
||||||
pinsa.pa6.into_push_pull_output(),
|
pinsa.pa6.into_push_pull_output(),
|
||||||
);
|
);
|
||||||
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
|
let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0);
|
||||||
loop {
|
for _ in 0..10 {
|
||||||
for _ in 0..10 {
|
// Blink all LEDs quickly
|
||||||
// Blink all LEDs quickly
|
for led in leds.iter_mut() {
|
||||||
for led in leds.iter_mut() {
|
led.toggle();
|
||||||
led.toggle();
|
|
||||||
}
|
|
||||||
delay.delay_ms(500);
|
|
||||||
}
|
}
|
||||||
// Now use a wave pattern
|
delay.delay_ms(500);
|
||||||
loop {
|
}
|
||||||
for led in leds.iter_mut() {
|
// Now use a wave pattern
|
||||||
led.toggle();
|
loop {
|
||||||
delay.delay_ms(200);
|
for led in leds.iter_mut() {
|
||||||
}
|
led.toggle();
|
||||||
|
delay.delay_ms(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ use va108xx_hal::{
|
|||||||
pac::{self, interrupt},
|
pac::{self, interrupt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
spi::{Spi, SpiBase, SpiConfig},
|
spi::{Spi, SpiBase, SpiConfig},
|
||||||
timer::{default_ms_irq_handler, set_up_ms_tick, DelayMs, IrqCfg},
|
timer::{default_ms_irq_handler, set_up_ms_tick, DelayMs, InterruptConfig},
|
||||||
};
|
};
|
||||||
use va108xx_hal::{port_mux, FunSel, PortSel};
|
use va108xx_hal::{port_function_select, FunSel, PortSel};
|
||||||
use vorago_reb1::max11619::{
|
use vorago_reb1::max11619::{
|
||||||
max11619_externally_clocked_no_wakeup, max11619_externally_clocked_with_wakeup,
|
max11619_externally_clocked_no_wakeup, max11619_externally_clocked_with_wakeup,
|
||||||
max11619_internally_clocked, EocPin, AN2_CHANNEL, POTENTIOMETER_CHANNEL,
|
max11619_internally_clocked, EocPin, AN2_CHANNEL, POTENTIOMETER_CHANNEL,
|
||||||
@ -112,7 +112,7 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
let tim0 = set_up_ms_tick(
|
let tim0 = set_up_ms_tick(
|
||||||
IrqCfg::new(pac::Interrupt::OC0, true, true),
|
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
Some(&mut dp.irqsel),
|
Some(&mut dp.irqsel),
|
||||||
SYS_CLK,
|
SYS_CLK,
|
||||||
@ -123,7 +123,7 @@ fn main() -> ! {
|
|||||||
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
|
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
|
let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let spi_cfg = SpiConfig::default()
|
let spi_cfg = SpiConfig::default()
|
||||||
.clk_cfg(SpiClkConfig::from_clk(SYS_CLK, 3.MHz()).unwrap())
|
.clk_cfg(SpiClkConfig::from_clk(SYS_CLK, 3.MHz()).unwrap())
|
||||||
.mode(MODE_0)
|
.mode(MODE_0)
|
||||||
@ -135,10 +135,10 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if MUX_MODE == MuxMode::PortB19to17 {
|
if MUX_MODE == MuxMode::PortB19to17 {
|
||||||
port_mux(&mut dp.ioconfig, PortSel::PortB, 19, FunSel::Sel1).ok();
|
port_function_select(&mut dp.ioconfig, PortSel::PortB, 19, FunSel::Sel1).ok();
|
||||||
port_mux(&mut dp.ioconfig, PortSel::PortB, 18, FunSel::Sel2).ok();
|
port_function_select(&mut dp.ioconfig, PortSel::PortB, 18, FunSel::Sel2).ok();
|
||||||
port_mux(&mut dp.ioconfig, PortSel::PortB, 17, FunSel::Sel1).ok();
|
port_function_select(&mut dp.ioconfig, PortSel::PortB, 17, FunSel::Sel1).ok();
|
||||||
port_mux(&mut dp.ioconfig, PortSel::PortB, 16, FunSel::Sel1).ok();
|
port_function_select(&mut dp.ioconfig, PortSel::PortB, 16, FunSel::Sel1).ok();
|
||||||
}
|
}
|
||||||
// Set the accelerometer chip select low in case the board slot is populated
|
// Set the accelerometer chip select low in case the board slot is populated
|
||||||
let mut accel_cs = pinsa.pa16.into_push_pull_output();
|
let mut accel_cs = pinsa.pa16.into_push_pull_output();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
use embedded_hal::digital::InputPin;
|
use embedded_hal::digital::InputPin;
|
||||||
use va108xx_hal::{
|
use va108xx_hal::{
|
||||||
gpio::{FilterClkSel, FilterType, InputFloating, InterruptEdge, InterruptLevel, Pin, PA11},
|
gpio::{FilterClkSel, FilterType, InputFloating, InterruptEdge, InterruptLevel, Pin, PA11},
|
||||||
pac, IrqCfg,
|
pac, InterruptConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
@ -30,37 +30,34 @@ impl Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configures an IRQ on edge.
|
/// Configures an IRQ on edge.
|
||||||
pub fn edge_irq(
|
pub fn configure_edge_interrupt(
|
||||||
mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut pac::Sysconfig>,
|
syscfg: Option<&mut pac::Sysconfig>,
|
||||||
irqsel: Option<&mut pac::Irqsel>,
|
irqsel: Option<&mut pac::Irqsel>,
|
||||||
) -> Self {
|
) {
|
||||||
self.button = self
|
self.button
|
||||||
.button
|
.configure_edge_interrupt(edge_type, irq_cfg, syscfg, irqsel);
|
||||||
.interrupt_edge(edge_type, irq_cfg, syscfg, irqsel);
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures an IRQ on level.
|
/// Configures an IRQ on level.
|
||||||
pub fn level_irq(
|
pub fn configure_level_interrupt(
|
||||||
mut self,
|
&mut self,
|
||||||
level: InterruptLevel,
|
level: InterruptLevel,
|
||||||
irq_cfg: IrqCfg,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut pac::Sysconfig>,
|
syscfg: Option<&mut pac::Sysconfig>,
|
||||||
irqsel: Option<&mut pac::Irqsel>,
|
irqsel: Option<&mut pac::Irqsel>,
|
||||||
) -> Self {
|
) {
|
||||||
self.button = self.button.interrupt_level(level, irq_cfg, syscfg, irqsel);
|
self.button
|
||||||
self
|
.configure_level_interrupt(level, irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures a filter on the button. This can be useful for debouncing the switch.
|
/// Configures a filter on the button. This can be useful for debouncing the switch.
|
||||||
///
|
///
|
||||||
/// Please note that you still have to set a clock divisor yourself using the
|
/// Please note that you still have to set a clock divisor yourself using the
|
||||||
/// [`va108xx_hal::clock::set_clk_div_register`] function in order for this to work.
|
/// [`va108xx_hal::clock::set_clk_div_register`] function in order for this to work.
|
||||||
pub fn filter_type(mut self, filter: FilterType, clksel: FilterClkSel) -> Self {
|
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.button = self.button.filter_type(filter, clksel);
|
self.button.configure_filter_type(filter, clksel);
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,8 +363,8 @@
|
|||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"device": "Cortex-M0",
|
"device": "Cortex-M0",
|
||||||
"svdFile": "./va108xx/svd/va108xx.svd.patched",
|
"svdFile": "./va108xx/svd/va108xx.svd.patched",
|
||||||
"preLaunchTask": "rust: cargo build uart irq",
|
"preLaunchTask": "uart-echo-rtic-example",
|
||||||
"executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/uart-rtic",
|
"executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/uart-echo-rtic",
|
||||||
"interface": "jtag",
|
"interface": "jtag",
|
||||||
"runToEntryPoint": "main",
|
"runToEntryPoint": "main",
|
||||||
"rttConfig": {
|
"rttConfig": {
|
||||||
@ -523,5 +523,29 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "cortex-debug",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Async UART",
|
||||||
|
"servertype": "jlink",
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"device": "Cortex-M0",
|
||||||
|
"svdFile": "./va108xx/svd/va108xx.svd.patched",
|
||||||
|
"preLaunchTask": "async-uart",
|
||||||
|
"executable": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/async-uart",
|
||||||
|
"interface": "jtag",
|
||||||
|
"runToEntryPoint": "main",
|
||||||
|
"rttConfig": {
|
||||||
|
"enabled": true,
|
||||||
|
"address": "auto",
|
||||||
|
"decoders": [
|
||||||
|
{
|
||||||
|
"port": 0,
|
||||||
|
"timestamp": true,
|
||||||
|
"type": "console"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -276,6 +276,16 @@
|
|||||||
"async-gpio"
|
"async-gpio"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "async-uart",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "~/.cargo/bin/cargo", // note: full path to the cargo
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin",
|
||||||
|
"async-uart"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "bootloader",
|
"label": "bootloader",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user