Rework library structure

Changed:

- Move most library components to new [`vorago-shared-periphs`](https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs)
  which is mostly re-exported in this crate.
- Overhaul and simplification of several HAL APIs. The system configuration and IRQ router
  peripheral instance generally does not need to be passed to HAL API anymore.
- All HAL drivers are now type erased. The constructors will still expect and consume the PAC
  singleton component for resource management purposes, but are not cached anymore.
- Refactoring of GPIO library to be more inline with embassy GPIO API.

Added:

- I2C clock timeout feature support.
This commit is contained in:
2025-04-24 14:05:02 +02:00
parent d641f3943f
commit 935ee9dbb1
52 changed files with 602 additions and 9305 deletions

View File

@ -4,10 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
cfg-if = "1"
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
embedded-hal = "1"
cfg-if = "1"
embedded-io = "0.6"
embedded-hal-async = "1"
embedded-io-async = "0.6"
@ -18,7 +16,6 @@ defmt = "1"
panic-probe = { version = "1", features = ["defmt"] }
static_cell = "2"
critical-section = "1"
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
ringbuf = { version = "0.4", default-features = false }
embassy-sync = "0.6"
@ -29,11 +26,14 @@ embassy-executor = { version = "0.7", features = [
"executor-interrupt"
]}
va416xx-hal = { version = "0.5", features = ["defmt"] }
va416xx-embassy = { version = "0.1", default-features = false }
va416xx-hal = { version = "0.5", path = "../../va416xx-hal", features = ["defmt"] }
va416xx-embassy = { version = "0.1", path = "../../va416xx-embassy", default-features = false }
[features]
default = ["ticks-hz-1_000", "va416xx-embassy/irq-tim14-tim15"]
custom-irqs = []
ticks-hz-1_000 = ["embassy-time/tick-hz-1_000"]
ticks-hz-32_768 = ["embassy-time/tick-hz-32_768"]
[package.metadata.cargo-machete]
ignored = ["cortex-m-rt"]

View File

@ -5,6 +5,7 @@
//! [CHECK_XXX_TO_XXX] constants to true.
#![no_std]
#![no_main]
// Import panic provider.
use panic_probe as _;
// Import logger.
@ -16,23 +17,19 @@ use embassy_sync::channel::{Receiver, Sender};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
use embassy_time::{Duration, Instant, Timer};
use embedded_hal_async::digital::Wait;
use va416xx_hal::clock::ClkgenExt;
use va416xx_hal::gpio::{
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, PinsC, PinsD,
PinsE, PinsF, PinsG, Port,
};
use va416xx_hal::clock::ClockConfigurator;
use va416xx_hal::gpio::asynch::{on_interrupt_for_async_gpio_for_port, InputPinAsync};
use va416xx_hal::gpio::{Input, Output, PinState, Port};
use va416xx_hal::pac::{self, interrupt};
use va416xx_hal::pins::{PinsA, PinsB, PinsC, PinsD, PinsE, PinsF, PinsG};
use va416xx_hal::time::Hertz;
use va416xx_hal::{
gpio::{DynPin, PinsA},
pac::{self, interrupt},
};
const CHECK_PA0_TO_PA1: bool = true;
const CHECK_PB0_TO_PB1: bool = true;
const CHECK_PC14_TO_PC15: bool = true;
const CHECK_PD2_TO_PD3: bool = true;
const CHECK_PE0_TO_PE1: bool = true;
const CHECK_PF0_TO_PF1: bool = true;
const CHECK_PB0_TO_PB1: bool = false;
const CHECK_PC14_TO_PC15: bool = false;
const CHECK_PD2_TO_PD3: bool = false;
const CHECK_PE0_TO_PE1: bool = false;
const CHECK_PF0_TO_PF1: bool = false;
#[derive(Clone, Copy)]
pub struct GpioCmd {
@ -70,41 +67,30 @@ static CHANNEL_PF0_TO_PF1: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::ne
async fn main(spawner: Spawner) {
defmt::println!("-- VA416xx Async GPIO Demo --");
let mut dp = pac::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
let clocks = ClockConfigurator::new(dp.clkgen)
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut dp.sysconfig)
.freeze()
.unwrap();
// Safety: Only called once here.
unsafe {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim15,
dp.tim14,
&clocks,
)
};
va416xx_embassy::init(dp.tim15, dp.tim14, &clocks);
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
let portb = PinsB::new(&mut dp.sysconfig, dp.portb);
let portc = PinsC::new(&mut dp.sysconfig, dp.portc);
let portd = PinsD::new(&mut dp.sysconfig, dp.portd);
let porte = PinsE::new(&mut dp.sysconfig, dp.porte);
let portf = PinsF::new(&mut dp.sysconfig, dp.portf);
let porta = PinsA::new(dp.porta);
let portb = PinsB::new(dp.portb);
let portc = PinsC::new(dp.portc);
let portd = PinsD::new(dp.portd);
let porte = PinsE::new(dp.porte);
let portf = PinsF::new(dp.portf);
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output();
let portg = PinsG::new(dp.portg);
let mut led = Output::new(portg.pg5, PinState::Low);
if CHECK_PA0_TO_PA1 {
let out_pin = porta.pa0.into_readable_push_pull_output();
let in_pin = porta.pa1.into_floating_input();
let out_pin = out_pin.downgrade();
let out_pin = Output::new(porta.pa0, PinState::Low);
let in_pin = Input::new_floating(porta.pa1);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
@ -119,10 +105,9 @@ async fn main(spawner: Spawner) {
}
if CHECK_PB0_TO_PB1 {
let out_pin = portb.pb0.into_readable_push_pull_output();
let in_pin = portb.pb1.into_floating_input();
let out_pin = out_pin.downgrade();
let in_pin = InputDynPinAsync::new(in_pin.downgrade()).unwrap();
let out_pin = Output::new(portb.pb0, PinState::Low);
let in_pin = Input::new_floating(portb.pb1);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
.spawn(output_task(
@ -136,10 +121,9 @@ async fn main(spawner: Spawner) {
}
if CHECK_PC14_TO_PC15 {
let out_pin = portc.pc14.into_readable_push_pull_output();
let in_pin = portc.pc15.into_floating_input();
let out_pin = out_pin.downgrade();
let in_pin = InputDynPinAsync::new(in_pin.downgrade()).unwrap();
let out_pin = Output::new(portc.pc14, PinState::Low);
let in_pin = Input::new_floating(portc.pc15);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
.spawn(output_task(
"PC14 to PC15",
@ -152,10 +136,9 @@ async fn main(spawner: Spawner) {
}
if CHECK_PD2_TO_PD3 {
let out_pin = portd.pd2.into_readable_push_pull_output();
let in_pin = portd.pd3.into_floating_input();
let out_pin = out_pin.downgrade();
let in_pin = InputDynPinAsync::new(in_pin.downgrade()).unwrap();
let out_pin = Output::new(portd.pd2, PinState::Low);
let in_pin = Input::new_floating(portd.pd3);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
.spawn(output_task(
"PD2 to PD3",
@ -168,10 +151,9 @@ async fn main(spawner: Spawner) {
}
if CHECK_PE0_TO_PE1 {
let out_pin = porte.pe0.into_readable_push_pull_output();
let in_pin = porte.pe1.into_floating_input();
let out_pin = out_pin.downgrade();
let in_pin = InputDynPinAsync::new(in_pin.downgrade()).unwrap();
let out_pin = Output::new(porte.pe0, PinState::Low);
let in_pin = Input::new_floating(porte.pe1);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
.spawn(output_task(
"PE0 to PE1",
@ -184,10 +166,9 @@ async fn main(spawner: Spawner) {
}
if CHECK_PF0_TO_PF1 {
let out_pin = portf.pf0.into_readable_push_pull_output();
let in_pin = portf.pf1.into_floating_input();
let out_pin = out_pin.downgrade();
let in_pin = InputDynPinAsync::new(in_pin.downgrade()).unwrap();
let out_pin = Output::new(portf.pf0, PinState::Low);
let in_pin = Input::new_floating(portf.pf1);
let in_pin = InputPinAsync::new(in_pin).unwrap();
spawner
.spawn(output_task(
"PF0 to PF1",
@ -298,7 +279,7 @@ async fn check_pin_to_pin_async_ops(
#[embassy_executor::task(pool_size = 8)]
async fn output_task(
ctx: &'static str,
mut out: DynPin,
mut out: Output,
receiver: Receiver<'static, ThreadModeRawMutex, GpioCmd, 3>,
) {
loop {
@ -307,25 +288,25 @@ async fn output_task(
match next_cmd.cmd_type {
GpioCmdType::SetHigh => {
defmt::info!("{}: Set output high", ctx);
out.set_high().unwrap();
out.set_high();
}
GpioCmdType::SetLow => {
defmt::info!("{}: Set output low", ctx);
out.set_low().unwrap();
out.set_low();
}
GpioCmdType::RisingEdge => {
defmt::info!("{}: Rising edge", ctx);
if !out.is_low().unwrap() {
out.set_low().unwrap();
if !out.is_set_low() {
out.set_low();
}
out.set_high().unwrap();
out.set_high();
}
GpioCmdType::FallingEdge => {
defmt::info!("{}: Falling edge", ctx);
if !out.is_high().unwrap() {
out.set_high().unwrap();
if !out.is_set_high() {
out.set_high();
}
out.set_low().unwrap();
out.set_low();
}
GpioCmdType::CloseTask => {
defmt::info!("{}: Closing task", ctx);

View File

@ -27,8 +27,10 @@ use embedded_io::Write;
use embedded_io_async::Read;
use heapless::spsc::{Producer, Queue};
use va416xx_hal::{
gpio::PinsG,
clock::ClockConfigurator,
gpio::{Output, PinState},
pac::{self, interrupt},
pins::PinsG,
prelude::*,
time::Hertz,
uart::{
@ -46,34 +48,22 @@ static PRODUCER_UART_A: Mutex<RefCell<Option<Producer<u8, 256>>>> = Mutex::new(R
async fn main(_spawner: Spawner) {
defmt::println!("-- VA108xx Async UART RX Demo --");
let mut dp = pac::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
let clocks = ClockConfigurator::new(dp.clkgen)
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut dp.sysconfig)
.freeze()
.unwrap();
// Safety: Only called once here.
unsafe {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim15,
dp.tim14,
&clocks,
);
}
va416xx_embassy::init(dp.tim15, dp.tim14, &clocks);
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output();
let portg = PinsG::new(dp.portg);
let mut led = Output::new(portg.pg5, PinState::Low);
let tx = portg.pg0.into_funsel_1();
let rx = portg.pg1.into_funsel_1();
let uarta = uart::Uart::new(&mut dp.sysconfig, dp.uart0, (tx, rx), 115200.Hz(), &clocks);
let uarta =
uart::Uart::new(dp.uart0, portg.pg0, portg.pg1, &clocks, 115200.Hz().into()).unwrap();
let (mut tx_uart_a, rx_uart_a) = uarta.split();
let (prod_uart_a, cons_uart_a) = QUEUE_UART_A.take().split();

View File

@ -21,8 +21,10 @@ use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker};
use embedded_io_async::Write;
use va416xx_hal::{
gpio::PinsG,
clock::ClockConfigurator,
gpio::{Output, PinState},
pac::{self, interrupt},
pins::PinsG,
prelude::*,
time::Hertz,
uart::{
@ -44,34 +46,22 @@ const STR_LIST: &[&str] = &[
async fn main(_spawner: Spawner) {
defmt::println!("-- VA108xx Async UART TX Demo --");
let mut dp = pac::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
let clocks = ClockConfigurator::new(dp.clkgen)
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut dp.sysconfig)
.freeze()
.unwrap();
// Safety: Only called once here.
unsafe {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim15,
dp.tim14,
&clocks,
);
}
va416xx_embassy::init(dp.tim15, dp.tim14, &clocks);
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output();
let pinsg = PinsG::new(dp.portg);
let mut led = Output::new(pinsg.pg5, PinState::Low);
let tx = portg.pg0.into_funsel_1();
let rx = portg.pg1.into_funsel_1();
let uarta = uart::Uart::new(&mut dp.sysconfig, dp.uart0, (tx, rx), 115200.Hz(), &clocks);
let uarta =
uart::Uart::new(dp.uart0, pinsg.pg0, pinsg.pg1, &clocks, 115200.Hz().into()).unwrap();
let (tx, _rx) = uarta.split();
let mut async_tx = TxAsync::new(tx);
let mut ticker = Ticker::every(Duration::from_secs(1));

View File

@ -27,15 +27,15 @@ use ringbuf::{
StaticRb,
};
use va416xx_hal::{
gpio::{OutputReadablePushPull, Pin, PinsG, PG5},
clock::ClockConfigurator,
gpio::{Output, PinState},
pac::{self, interrupt},
prelude::*,
pins::PinsG,
time::Hertz,
uart,
};
pub type SharedUart =
Mutex<CriticalSectionRawMutex, RefCell<Option<uart::RxWithInterrupt<pac::Uart0>>>>;
pub type SharedUart = Mutex<CriticalSectionRawMutex, RefCell<Option<uart::RxWithInterrupt>>>;
static RX: SharedUart = Mutex::new(RefCell::new(None));
const BAUDRATE: u32 = 115200;
@ -54,39 +54,27 @@ static RINGBUF: SharedRingBuf = Mutex::new(RefCell::new(None));
async fn main(spawner: Spawner) {
defmt::println!("VA416xx UART-Embassy Example");
let mut dp = pac::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
let clocks = ClockConfigurator::new(dp.clkgen)
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut dp.sysconfig)
.freeze()
.unwrap();
// Safety: Only called once here.
unsafe {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim15,
dp.tim14,
&clocks,
)
};
va416xx_embassy::init(dp.tim15, dp.tim14, &clocks);
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let tx = portg.pg0.into_funsel_1();
let rx = portg.pg1.into_funsel_1();
let portg = PinsG::new(dp.portg);
let uart0 = uart::Uart::new(
&mut dp.sysconfig,
dp.uart0,
(tx, rx),
Hertz::from_raw(BAUDRATE),
portg.pg0,
portg.pg1,
&clocks,
);
Hertz::from_raw(BAUDRATE).into(),
)
.unwrap();
let (mut tx, rx) = uart0.split();
let mut rx = rx.into_rx_with_irq();
rx.start();
@ -97,7 +85,7 @@ async fn main(spawner: Spawner) {
static_rb.borrow_mut().replace(StaticRb::default());
});
let led = portg.pg5.into_readable_push_pull_output();
let led = Output::new(portg.pg5, PinState::Low);
let mut ticker = Ticker::every(Duration::from_millis(50));
let mut processing_buf: [u8; RING_BUF_SIZE] = [0; RING_BUF_SIZE];
let mut read_bytes = 0;
@ -117,7 +105,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn blinky(mut led: Pin<PG5, OutputReadablePushPull>) {
async fn blinky(mut led: Output) {
let mut ticker = Ticker::every(Duration::from_millis(500));
loop {
led.toggle();

View File

@ -8,7 +8,13 @@ use defmt_rtt as _;
use embassy_example::EXTCLK_FREQ;
use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker};
use va416xx_hal::{gpio::PinsG, pac, prelude::*, time::Hertz};
use va416xx_hal::{
clock::ClockConfigurator,
gpio::{Output, PinState},
pac,
pins::PinsG,
time::Hertz,
};
cfg_if::cfg_if! {
if #[cfg(feature = "custom-irqs")] {
@ -22,40 +28,32 @@ cfg_if::cfg_if! {
async fn main(_spawner: Spawner) {
defmt::println!("VA416xx Embassy Demo");
let mut dp = pac::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = dp
.clkgen
.constrain()
let clocks = ClockConfigurator::new(dp.clkgen)
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut dp.sysconfig)
.freeze()
.unwrap();
// Safety: Only called once here.
unsafe {
cfg_if::cfg_if! {
if #[cfg(not(feature = "custom-irqs"))] {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim15,
dp.tim14,
&clocks
);
} else {
va416xx_embassy::init(
&mut dp.sysconfig,
&dp.irq_router,
dp.tim12,
dp.tim11,
&clocks
);
}
cfg_if::cfg_if! {
if #[cfg(not(feature = "custom-irqs"))] {
va416xx_embassy::init(
dp.tim15,
dp.tim14,
&clocks
);
} else {
va416xx_embassy::init(
dp.tim12,
dp.tim11,
&clocks
);
}
}
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
let mut led = portg.pg5.into_readable_push_pull_output();
let pinsg = PinsG::new(dp.portg);
let mut led = Output::new(pinsg.pg5, PinState::Low);
let mut ticker = Ticker::every(Duration::from_secs(1));
loop {
ticker.next().await;