16 Commits

Author SHA1 Message Date
41f7f9d25b Merge pull request 'prep PAC v0.5.0' (#63) from prep-pac-v0.5.0 into main
Reviewed-on: #63
2025-02-17 20:05:21 +01:00
47e754433d prep PAC v0.5.0 2025-02-17 20:04:55 +01:00
e5e010a276 Merge pull request 'larger GPIO refactoring and Async UART update' (#62) from uart-gpio-update into main
Reviewed-on: #62
2025-02-17 10:56:21 +01:00
caf54e5a70 larger GPIO refactoring and Async UART update 2025-02-17 10:53:40 +01:00
31b25b0211 Merge pull request 'Adaption Async GPIO' (#59) from adaption-gpio-asynch into main
Reviewed-on: #59
2025-02-15 12:48:48 +01:00
8b55d0923f Bugfix and improvements for async GPIO 2025-02-15 12:46:10 +01:00
a65f4039ee Merge pull request 'minor CI update' (#58) from minor-ci-update into main
Reviewed-on: #58
2025-02-14 16:43:03 +01:00
97da2a0752 minor CI update 2025-02-14 16:40:58 +01:00
c43d1f8861 Merge pull request 'defmt in PAC is optional' (#57) from defmt-in-pac-optional into main
Reviewed-on: #57
2025-02-14 16:29:05 +01:00
181c2bdc7b defmt in PAC is optional 2025-02-14 16:26:27 +01:00
2bca96b5db Merge pull request 'HAL update' (#53) from hal-update into main
Reviewed-on: #53
2025-02-14 16:20:45 +01:00
bf41b59a24 HAL update 2025-02-14 16:18:59 +01:00
6cbba8414c Merge pull request 'bump version' (#55) from pac-update into main
Reviewed-on: #55
2025-02-14 16:14:05 +01:00
fe04a3e7cd bump version 2025-02-14 16:11:53 +01:00
e25fb20b08 Merge pull request 'PAC update' (#54) from pac-update into main
Reviewed-on: #54
2025-02-14 16:06:49 +01:00
67af1bb9b5 PAC update 2025-02-14 16:02:11 +01:00
127 changed files with 1274 additions and 1592 deletions

View File

@ -12,6 +12,8 @@ jobs:
targets: "thumbv6m-none-eabi" targets: "thumbv6m-none-eabi"
- run: cargo check --target thumbv6m-none-eabi - run: cargo check --target thumbv6m-none-eabi
- run: cargo check --target thumbv6m-none-eabi --examples - run: cargo check --target thumbv6m-none-eabi --examples
- run: cargo check -p va108xx --target thumbv6m-none-eabi --all-features
- run: cargo check -p va108xx-hal --target thumbv6m-none-eabi --features "defmt"
test: test:
name: Run Tests name: Run Tests
@ -39,8 +41,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@nightly
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx - run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx --all-features
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx-hal - run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx-hal --all-features
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-reb1 - run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-reb1
clippy: clippy:

View File

@ -6,10 +6,7 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::{ use embedded_hal::delay::DelayNs;
delay::DelayNs,
digital::{InputPin, OutputPin, StatefulOutputPin},
};
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
@ -67,35 +64,35 @@ fn main() -> ! {
TestCase::TestBasic => { TestCase::TestBasic => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let mut out = pinsa.pa0.into_readable_push_pull_output(); let mut out = pinsa.pa0.into_readable_push_pull_output();
let mut input = pinsa.pa1.into_floating_input(); let input = pinsa.pa1.into_floating_input();
out.set_high().unwrap(); out.set_high();
assert!(input.is_high().unwrap()); assert!(input.is_high());
out.set_low().unwrap(); out.set_low();
assert!(input.is_low().unwrap()); assert!(input.is_low());
} }
TestCase::TestPullup => { TestCase::TestPullup => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let mut input = pinsa.pa1.into_pull_up_input(); let input = pinsa.pa1.into_pull_up_input();
assert!(input.is_high().unwrap()); assert!(input.is_high());
let mut out = pinsa.pa0.into_readable_push_pull_output(); let mut out = pinsa.pa0.into_readable_push_pull_output();
out.set_low().unwrap(); out.set_low();
assert!(input.is_low().unwrap()); assert!(input.is_low());
out.set_high().unwrap(); out.set_high();
assert!(input.is_high().unwrap()); assert!(input.is_high());
out.into_floating_input(); out.into_floating_input();
assert!(input.is_high().unwrap()); assert!(input.is_high());
} }
TestCase::TestPulldown => { TestCase::TestPulldown => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let mut input = pinsa.pa1.into_pull_down_input(); let input = pinsa.pa1.into_pull_down_input();
assert!(input.is_low().unwrap()); assert!(input.is_low());
let mut out = pinsa.pa0.into_push_pull_output(); let mut out = pinsa.pa0.into_push_pull_output();
out.set_low().unwrap(); out.set_low();
assert!(input.is_low().unwrap()); assert!(input.is_low());
out.set_high().unwrap(); out.set_high();
assert!(input.is_high().unwrap()); assert!(input.is_high());
out.into_floating_input(); out.into_floating_input();
assert!(input.is_low().unwrap()); assert!(input.is_low());
} }
TestCase::TestMask => { TestCase::TestMask => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
@ -110,11 +107,11 @@ fn main() -> ! {
TestCase::PortB => { TestCase::PortB => {
// Tie PORTB[22] to PORTB[23] for these tests! // Tie PORTB[22] to PORTB[23] for these tests!
let mut out = pinsb.pb22.into_readable_push_pull_output(); let mut out = pinsb.pb22.into_readable_push_pull_output();
let mut input = pinsb.pb23.into_floating_input(); let input = pinsb.pb23.into_floating_input();
out.set_high().unwrap(); out.set_high();
assert!(input.is_high().unwrap()); assert!(input.is_high());
out.set_low().unwrap(); out.set_low();
assert!(input.is_low().unwrap()); assert!(input.is_low());
} }
TestCase::Perid => { TestCase::Perid => {
assert_eq!(PinsA::get_perid(), 0x004007e1); assert_eq!(PinsA::get_perid(), 0x004007e1);
@ -122,34 +119,31 @@ fn main() -> ! {
} }
TestCase::Pulse => { TestCase::Pulse => {
let mut output_pulsed = pinsa.pa0.into_push_pull_output(); let mut output_pulsed = pinsa.pa0.into_push_pull_output();
output_pulsed.pulse_mode(true, PinState::Low); output_pulsed.configure_pulse_mode(true, PinState::Low);
rprintln!("Pulsing high 10 times.."); rprintln!("Pulsing high 10 times..");
output_pulsed.set_low().unwrap(); output_pulsed.set_low();
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_high().unwrap(); output_pulsed.set_high();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
output_pulsed.pulse_mode(true, PinState::High); output_pulsed.configure_pulse_mode(true, PinState::High);
rprintln!("Pulsing low 10 times.."); rprintln!("Pulsing low 10 times..");
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_low().unwrap(); output_pulsed.set_low();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
} }
TestCase::DelayGpio => { TestCase::DelayGpio => {
let mut out_0 = pinsa let mut out_0 = pinsa.pa0.into_readable_push_pull_output();
.pa0 out_0.configure_delay(true, false);
.into_readable_push_pull_output() let mut out_1 = pinsa.pa1.into_readable_push_pull_output();
.delay(true, false); out_1.configure_delay(false, true);
let mut out_1 = pinsa let mut out_2 = pinsa.pa3.into_readable_push_pull_output();
.pa1 out_2.configure_delay(true, true);
.into_readable_push_pull_output()
.delay(false, true);
let mut out_2 = pinsa.pa3.into_readable_push_pull_output().delay(true, true);
for _ in 0..20 { for _ in 0..20 {
out_0.toggle().unwrap(); out_0.toggle();
out_1.toggle().unwrap(); out_1.toggle();
out_2.toggle().unwrap(); out_2.toggle();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
} }
@ -162,18 +156,18 @@ fn main() -> ! {
dp.tim0, dp.tim0,
); );
for _ in 0..5 { for _ in 0..5 {
led1.toggle().ok(); led1.toggle();
ms_timer.delay_ms(500); ms_timer.delay_ms(500);
led1.toggle().ok(); led1.toggle();
ms_timer.delay_ms(500); ms_timer.delay_ms(500);
} }
let mut delay_timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1); let mut delay_timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let mut pa0 = pinsa.pa0.into_readable_push_pull_output(); let mut pa0 = pinsa.pa0.into_readable_push_pull_output();
for _ in 0..5 { for _ in 0..5 {
led1.toggle().ok(); led1.toggle();
delay_timer.delay_ms(500); delay_timer.delay_ms(500);
led1.toggle().ok(); led1.toggle();
delay_timer.delay_ms(500); delay_timer.delay_ms(500);
} }
let ahb_freq: Hertz = 50.MHz(); let ahb_freq: Hertz = 50.MHz();
@ -181,13 +175,13 @@ fn main() -> ! {
// Test usecond delay using both TIM peripheral and SYST. Use the release image if you // Test usecond delay using both TIM peripheral and SYST. Use the release image if you
// want to verify the timings! // want to verify the timings!
loop { loop {
pa0.toggle().ok(); pa0.toggle();
delay_timer.delay_us(50); delay_timer.delay_us(50);
pa0.toggle().ok(); pa0.toggle();
delay_timer.delay_us(50); delay_timer.delay_us(50);
pa0.toggle_with_toggle_reg(); pa0.toggle();
syst_delay.delay_us(50); syst_delay.delay_us(50);
pa0.toggle_with_toggle_reg(); pa0.toggle();
syst_delay.delay_us(50); syst_delay.delay_us(50);
} }
} }
@ -195,7 +189,7 @@ fn main() -> ! {
rprintln!("Test success"); rprintln!("Test success");
loop { loop {
led1.toggle().ok(); led1.toggle();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
} }

View File

@ -27,8 +27,8 @@ embassy-executor = { version = "0.7", features = [
"executor-interrupt" "executor-interrupt"
]} ]}
va108xx-hal = "0.9" va108xx-hal = { version = "0.9", path = "../../va108xx-hal" }
va108xx-embassy = "0.1" va108xx-embassy = { version = "0.1", path = "../../va108xx-embassy" }
[features] [features]
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"] default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]

View File

@ -9,12 +9,13 @@ use embassy_executor::Spawner;
use embassy_sync::channel::{Receiver, Sender}; use embassy_sync::channel::{Receiver, Sender};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel}; use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
use embedded_hal_async::digital::Wait; 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::{on_interrupt_for_asynch_gpio, InputDynPinAsync, InputPinAsync, PinsB}; use va108xx_hal::gpio::{
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, Port,
};
use va108xx_hal::{ use va108xx_hal::{
gpio::{DynPin, PinsA}, gpio::{DynPin, PinsA},
pac::{self, interrupt}, pac::{self, interrupt},
@ -114,7 +115,7 @@ async fn main(spawner: Spawner) {
rprintln!("Example done, toggling LED0"); rprintln!("Example done, toggling LED0");
loop { loop {
led0.toggle().unwrap(); led0.toggle();
Timer::after(Duration::from_millis(500)).await; Timer::after(Duration::from_millis(500)).await;
} }
} }
@ -244,15 +245,16 @@ async fn output_task(
} }
// PB22 to PB23 can be handled by both OC10 and OC11 depending on configuration. // PB22 to PB23 can be handled by both OC10 and OC11 depending on configuration.
#[interrupt] #[interrupt]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn OC10() { fn OC10() {
on_interrupt_for_asynch_gpio(); on_interrupt_for_async_gpio_for_port(Port::A);
on_interrupt_for_async_gpio_for_port(Port::B);
} }
// This interrupt only handles PORT B interrupts.
#[interrupt] #[interrupt]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn OC11() { fn OC11() {
on_interrupt_for_asynch_gpio(); on_interrupt_for_async_gpio_for_port(Port::B);
} }

View File

@ -18,7 +18,6 @@ use core::cell::RefCell;
use critical_section::Mutex; use critical_section::Mutex;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_time::Instant; use embassy_time::Instant;
use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write; use embedded_io::Write;
use embedded_io_async::Read; use embedded_io_async::Read;
use heapless::spsc::{Consumer, Producer, Queue}; use heapless::spsc::{Consumer, Producer, Queue};
@ -30,9 +29,9 @@ use va108xx_hal::{
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
uart::{ uart::{
self, on_interrupt_uart_b_overwriting, self, on_interrupt_rx_overwriting,
rx_asynch::{on_interrupt_uart_a, RxAsync}, rx_asynch::{on_interrupt_rx, RxAsync},
RxAsyncSharedConsumer, Tx, Bank, RxAsyncOverwriting, Tx,
}, },
InterruptConfig, InterruptConfig,
}; };
@ -106,16 +105,16 @@ async fn main(spawner: Spawner) {
*CONSUMER_UART_B.borrow(cs).borrow_mut() = Some(cons_uart_b); *CONSUMER_UART_B.borrow(cs).borrow_mut() = Some(cons_uart_b);
}); });
let mut async_rx_uart_a = RxAsync::new(rx_uart_a, cons_uart_a); let mut async_rx_uart_a = RxAsync::new(rx_uart_a, cons_uart_a);
let async_rx_uart_b = RxAsyncSharedConsumer::new(rx_uart_b, &CONSUMER_UART_B); let async_rx_uart_b = RxAsyncOverwriting::new(rx_uart_b, &CONSUMER_UART_B);
spawner spawner
.spawn(uart_b_task(async_rx_uart_b, tx_uart_b)) .spawn(uart_b_task(async_rx_uart_b, tx_uart_b))
.unwrap(); .unwrap();
let mut buf = [0u8; 256]; let mut buf = [0u8; 256];
loop { loop {
rprintln!("Current time UART A: {}", Instant::now().as_secs()); rprintln!("Current time UART A: {}", Instant::now().as_secs());
led0.toggle().ok(); led0.toggle();
led1.toggle().ok(); led1.toggle();
led2.toggle().ok(); led2.toggle();
let read_bytes = async_rx_uart_a.read(&mut buf).await.unwrap(); let read_bytes = async_rx_uart_a.read(&mut buf).await.unwrap();
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap(); let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
rprintln!( rprintln!(
@ -128,7 +127,7 @@ async fn main(spawner: Spawner) {
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn uart_b_task(mut async_rx: RxAsyncSharedConsumer<pac::Uartb, 256>, mut tx: Tx<pac::Uartb>) { async fn uart_b_task(mut async_rx: RxAsyncOverwriting<pac::Uartb, 256>, mut tx: Tx<pac::Uartb>) {
let mut buf = [0u8; 256]; let mut buf = [0u8; 256];
loop { loop {
rprintln!("Current time UART B: {}", Instant::now().as_secs()); rprintln!("Current time UART B: {}", Instant::now().as_secs());
@ -149,7 +148,7 @@ async fn uart_b_task(mut async_rx: RxAsyncSharedConsumer<pac::Uartb, 256>, mut t
fn OC2() { fn OC2() {
let mut prod = let mut prod =
critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap()); critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap());
let errors = on_interrupt_uart_a(&mut prod); let errors = on_interrupt_rx(Bank::A, &mut prod);
critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod)); critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task. // In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors { if let Err(errors) = errors {
@ -162,7 +161,7 @@ fn OC2() {
fn OC3() { fn OC3() {
let mut prod = let mut prod =
critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap()); critical_section::with(|cs| PRODUCER_UART_B.borrow(cs).borrow_mut().take().unwrap());
let errors = on_interrupt_uart_b_overwriting(&mut prod, &CONSUMER_UART_B); let errors = on_interrupt_rx_overwriting(Bank::B, &mut prod, &CONSUMER_UART_B);
critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod)); critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task. // In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors { if let Err(errors) = errors {

View File

@ -12,7 +12,6 @@
#![no_main] #![no_main]
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker}; use embassy_time::{Duration, Instant, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use embedded_io_async::Write; use embedded_io_async::Write;
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
@ -21,7 +20,7 @@ use va108xx_hal::{
gpio::PinsA, gpio::PinsA,
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
uart::{self, on_interrupt_uart_a_tx, TxAsync}, uart::{self, on_interrupt_tx, Bank, TxAsync},
InterruptConfig, InterruptConfig,
}; };
@ -75,9 +74,9 @@ async fn main(_spawner: Spawner) {
let mut idx = 0; let mut idx = 0;
loop { loop {
rprintln!("Current time: {}", Instant::now().as_secs()); rprintln!("Current time: {}", Instant::now().as_secs());
led0.toggle().ok(); led0.toggle();
led1.toggle().ok(); led1.toggle();
led2.toggle().ok(); led2.toggle();
let _written = async_tx let _written = async_tx
.write(STR_LIST[idx].as_bytes()) .write(STR_LIST[idx].as_bytes())
.await .await
@ -93,5 +92,5 @@ async fn main(_spawner: Spawner) {
#[interrupt] #[interrupt]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn OC2() { fn OC2() {
on_interrupt_uart_a_tx(); on_interrupt_tx(Bank::A);
} }

View File

@ -2,7 +2,6 @@
#![no_main] #![no_main]
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker}; use embassy_time::{Duration, Instant, Ticker};
use embedded_hal::digital::StatefulOutputPin;
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;
@ -60,8 +59,8 @@ async fn main(_spawner: Spawner) {
loop { loop {
ticker.next().await; ticker.next().await;
rprintln!("Current time: {}", Instant::now().as_secs()); rprintln!("Current time: {}", Instant::now().as_secs());
led0.toggle().ok(); led0.toggle();
led1.toggle().ok(); led1.toggle();
led2.toggle().ok(); led2.toggle();
} }
} }

View File

@ -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.9" va108xx-hal = { version = "0.9", path = "../../va108xx-hal" }
vorago-reb1 = "0.7" vorago-reb1 = { version = "0.7", path = "../../vorago-reb1" }

View File

@ -69,18 +69,16 @@ mod app {
// 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()); let mut button = Button::new(pinsa.pa11.into_floating_input());
button.configure_edge_interrupt(
edge_irq,
InterruptConfig::new(pac::interrupt::OC15, true, true),
Some(&mut dp.sysconfig),
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.configure_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);
} }
button.configure_and_enable_edge_interrupt(
edge_irq,
InterruptConfig::new(pac::interrupt::OC15, true, true),
);
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(),

View File

@ -5,7 +5,6 @@
#[rtic::app(device = pac, dispatchers = [OC31, OC30, OC29])] #[rtic::app(device = pac, dispatchers = [OC31, OC30, OC29])]
mod app { mod app {
use cortex_m::asm; use cortex_m::asm;
use embedded_hal::digital::StatefulOutputPin;
use panic_rtt_target as _; use panic_rtt_target as _;
use rtic_example::SYSCLK_FREQ; use rtic_example::SYSCLK_FREQ;
use rtic_monotonics::systick::prelude::*; use rtic_monotonics::systick::prelude::*;
@ -58,9 +57,9 @@ mod app {
async fn blinky(cx: blinky::Context) { async fn blinky(cx: blinky::Context) {
loop { loop {
rprintln!("toggling LEDs"); rprintln!("toggling LEDs");
cx.local.led0.toggle().ok(); cx.local.led0.toggle();
cx.local.led1.toggle().ok(); cx.local.led1.toggle();
cx.local.led2.toggle().ok(); cx.local.led2.toggle();
Mono::delay(1000.millis()).await; Mono::delay(1000.millis()).await;
} }
} }

View File

@ -16,8 +16,10 @@ 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.9" version = "0.9"
features = ["rt", "defmt"] features = ["rt", "defmt"]
[dependencies.vorago-reb1] [dependencies.vorago-reb1]
path = "../../vorago-reb1"
version = "0.7" version = "0.7"

View File

@ -7,10 +7,7 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::{ use embedded_hal::delay::DelayNs;
delay::DelayNs,
digital::{OutputPin, StatefulOutputPin},
};
use panic_halt as _; use panic_halt as _;
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsA, gpio::PinsA,
@ -38,21 +35,21 @@ fn main() -> ! {
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();
for _ in 0..10 { for _ in 0..10 {
led1.set_low().ok(); led1.set_low();
led2.set_low().ok(); led2.set_low();
led3.set_low().ok(); led3.set_low();
delay_ms.delay_ms(200); delay_ms.delay_ms(200);
led1.set_high().ok(); led1.set_high();
led2.set_high().ok(); led2.set_high();
led3.set_high().ok(); led3.set_high();
delay_tim1.delay_ms(200); delay_tim1.delay_ms(200);
} }
loop { loop {
led1.toggle().ok(); led1.toggle();
delay_ms.delay_ms(200); delay_ms.delay_ms(200);
led2.toggle().ok(); led2.toggle();
delay_tim1.delay_ms(200); delay_tim1.delay_ms(200);
led3.toggle().ok(); led3.toggle();
delay_ms.delay_ms(200); delay_ms.delay_ms(200);
} }
} }

View File

@ -20,7 +20,7 @@ embassy-time-queue-utils = "0.1"
once_cell = { version = "1", default-features = false, features = ["critical-section"] } once_cell = { version = "1", default-features = false, features = ["critical-section"] }
va108xx-hal = "0.9" va108xx-hal = { version = "0.9", path = "../va108xx-hal" }
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies] [target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] } portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }

View File

@ -8,6 +8,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## [v0.10.0]
## Added
- A lot of missing `defmt::Format` implementations.
## Changed
- Larger refactoring of GPIO library. The edge and level interrupt configurator functions do not
enable interrupts anymore. Instead, there are explicit `enbable_interrupt` and
`disable_interrupt` methods
- Renamed GPIO `DynGroup` to `Port`
- Rename generic GPIO interrupt handler into `on_interrupt_for_asynch_gpio`
into `on_interrupt_for_async_gpio_for_port` which expects a Port argument
## Fixed
- Bug in async GPIO interrupt handler where all enabled interrupts, even the ones which might
be unrelated to the pin, were disabled.
## [v0.9.0] ## [v0.9.0]
## Fixed ## Fixed

View File

@ -29,7 +29,7 @@ static_cell = "2"
thiserror = { version = "2", default-features = false } thiserror = { version = "2", default-features = false }
void = { version = "1", default-features = false } void = { version = "1", default-features = false }
once_cell = {version = "1", default-features = false } once_cell = {version = "1", default-features = false }
va108xx = { version = "0.4", default-features = false, features = ["critical-section"] } va108xx = { version = "0.5", path = "../va108xx", default-features = false, features = ["critical-section", "defmt"] }
embassy-sync = "0.6" embassy-sync = "0.6"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
@ -42,7 +42,7 @@ portable-atomic = "1"
[features] [features]
default = ["rt"] default = ["rt"]
rt = ["va108xx/rt"] rt = ["va108xx/rt"]
defmt = ["dep:defmt", "fugit/defmt"] defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@ -3,9 +3,9 @@
//! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement //! This module provides the [InputPinAsync] and [InputDynPinAsync] which both implement
//! the [embedded_hal_async::digital::Wait] trait. These types allow for asynchronous waiting //! the [embedded_hal_async::digital::Wait] trait. These types allow for asynchronous waiting
//! 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 the
//! [handler][on_interrupt_for_asynch_gpio] which should be called in ALL user interrupt handlers //! [on_interrupt_for_async_gpio_for_port] generic interrupt handler. This should be called in all
//! which handle GPIO interrupts. //! IRQ functions which handle any GPIO interrupts with the corresponding [Port] argument.
//! //!
//! # Example //! # Example
//! //!
@ -13,68 +13,73 @@
use core::future::Future; use core::future::Future;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal::digital::InputPin;
use embedded_hal_async::digital::Wait; 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};
use crate::InterruptConfig; use crate::InterruptConfig;
use super::{ use super::{
pin, DynGroup, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId, pin, DynPin, DynPinId, InputConfig, InterruptEdge, InvalidPinTypeError, Pin, PinId, Port,
NUM_GPIO_PINS, NUM_PINS_PORT_A, NUM_PINS_PORT_A, NUM_PINS_PORT_B,
}; };
static WAKERS: [AtomicWaker; NUM_GPIO_PINS] = [const { AtomicWaker::new() }; NUM_GPIO_PINS]; static WAKERS_FOR_PORT_A: [AtomicWaker; NUM_PINS_PORT_A] =
static EDGE_DETECTION: [AtomicBool; NUM_GPIO_PINS] = [const { AtomicWaker::new() }; NUM_PINS_PORT_A];
[const { AtomicBool::new(false) }; NUM_GPIO_PINS]; static WAKERS_FOR_PORT_B: [AtomicWaker; NUM_PINS_PORT_B] =
[const { AtomicWaker::new() }; NUM_PINS_PORT_B];
static EDGE_DETECTION_PORT_A: [AtomicBool; NUM_PINS_PORT_A] =
[const { AtomicBool::new(false) }; NUM_PINS_PORT_A];
static EDGE_DETECTION_PORT_B: [AtomicBool; NUM_PINS_PORT_B] =
[const { AtomicBool::new(false) }; NUM_PINS_PORT_B];
#[inline] /// Generic interrupt handler for GPIO interrupts on a specific port to support async functionalities
fn pin_id_to_offset(dyn_pin_id: DynPinId) -> usize {
match dyn_pin_id.group {
DynGroup::A => dyn_pin_id.num as usize,
DynGroup::B => NUM_PINS_PORT_A + dyn_pin_id.num as usize,
}
}
/// Generic interrupt handler for GPIO interrupts to support the async functionalities.
/// ///
/// This handler will wake the correspoding wakers for the pins which triggered an interrupt /// This function should be called in all interrupt handlers which handle any GPIO interrupts
/// as well as updating the static edge detection structures. This allows the pin future to /// matching the [Port] argument.
/// complete async operations. The user should call this function in ALL interrupt handlers /// The handler will wake the corresponding wakers for the pins that triggered an interrupts
/// which handle any GPIO interrupts. /// as well as update the static edge detection structures. This allows the pin future tocomplete
#[inline] /// complete async operations.
pub fn on_interrupt_for_asynch_gpio() { pub fn on_interrupt_for_async_gpio_for_port(port: Port) {
let periphs = unsafe { pac::Peripherals::steal() }; let periphs = unsafe { pac::Peripherals::steal() };
handle_interrupt_for_gpio_and_port( let (irq_enb, edge_status, wakers, edge_detection) = match port {
periphs.porta.irq_enb().read().bits(), Port::A => (
periphs.porta.edge_status().read().bits(), periphs.porta.irq_enb().read().bits(),
0, periphs.porta.edge_status().read().bits(),
); WAKERS_FOR_PORT_A.as_ref(),
handle_interrupt_for_gpio_and_port( EDGE_DETECTION_PORT_A.as_ref(),
periphs.portb.irq_enb().read().bits(), ),
periphs.portb.edge_status().read().bits(), Port::B => (
NUM_PINS_PORT_A, periphs.portb.irq_enb().read().bits(),
); periphs.portb.edge_status().read().bits(),
WAKERS_FOR_PORT_B.as_ref(),
EDGE_DETECTION_PORT_B.as_ref(),
),
};
on_interrupt_for_port(irq_enb, edge_status, wakers, edge_detection);
} }
// Uses the enabled interrupt register and the persistent edge status to capture all GPIO events.
#[inline] #[inline]
fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_base_offset: usize) { fn on_interrupt_for_port(
mut irq_enb: u32,
edge_status: u32,
wakers: &'static [AtomicWaker],
edge_detection: &'static [AtomicBool],
) {
while irq_enb != 0 { while irq_enb != 0 {
let bit_pos = irq_enb.trailing_zeros() as usize; let bit_pos = irq_enb.trailing_zeros() as usize;
let bit_mask = 1 << bit_pos; let bit_mask = 1 << bit_pos;
WAKERS[pin_base_offset + bit_pos].wake(); wakers[bit_pos].wake();
if edge_status & bit_mask != 0 { if edge_status & bit_mask != 0 {
EDGE_DETECTION[pin_base_offset + bit_pos] edge_detection[bit_pos].store(true, core::sync::atomic::Ordering::Relaxed);
.store(true, core::sync::atomic::Ordering::Relaxed);
}
// Clear the processed bit // Clear the processed bit
irq_enb &= !bit_mask; irq_enb &= !bit_mask;
}
} }
} }
@ -85,93 +90,66 @@ fn handle_interrupt_for_gpio_and_port(mut irq_enb: u32, edge_status: u32, pin_ba
/// struture is granted to allow writing custom async structures. /// struture is granted to allow writing custom async structures.
pub struct InputPinFuture { pub struct InputPinFuture {
pin_id: DynPinId, pin_id: DynPinId,
waker_group: &'static [AtomicWaker],
edge_detection_group: &'static [AtomicBool],
} }
impl InputPinFuture { impl InputPinFuture {
/// # Safety #[inline]
/// pub fn pin_group_to_waker_and_edge_detection_group(
/// This calls [Self::new_with_dyn_pin] but uses [pac::Peripherals::steal] to get the system configuration group: Port,
/// and IRQ selection peripherals. Users must ensure that the registers and configuration ) -> (&'static [AtomicWaker], &'static [AtomicBool]) {
/// related to this input pin are not being used elsewhere concurrently. match group {
pub unsafe fn new_unchecked_with_dyn_pin( Port::A => (WAKERS_FOR_PORT_A.as_ref(), EDGE_DETECTION_PORT_A.as_ref()),
pin: &mut DynPin, Port::B => (WAKERS_FOR_PORT_B.as_ref(), EDGE_DETECTION_PORT_B.as_ref()),
irq: pac::Interrupt, }
edge: InterruptEdge,
) -> Result<Self, InvalidPinTypeError> {
let mut periphs = pac::Peripherals::steal();
Self::new_with_dyn_pin(pin, irq, edge, &mut periphs.sysconfig, &mut periphs.irqsel)
} }
pub fn new_with_dyn_pin( pub fn new_with_dyn_pin(
pin: &mut DynPin, pin: &mut DynPin,
irq: pac::Interrupt, irq: pac::Interrupt,
edge: InterruptEdge, edge: InterruptEdge,
sys_cfg: &mut Sysconfig,
irq_sel: &mut Irqsel,
) -> Result<Self, InvalidPinTypeError> { ) -> Result<Self, InvalidPinTypeError> {
if !pin.is_input_pin() { if !pin.is_input_pin() {
return Err(InvalidPinTypeError(pin.mode())); return Err(InvalidPinTypeError(pin.mode()));
} }
EDGE_DETECTION[pin_id_to_offset(pin.id())] let (waker_group, edge_detection_group) =
Self::pin_group_to_waker_and_edge_detection_group(pin.id().port());
edge_detection_group[pin.id().num() as usize]
.store(false, core::sync::atomic::Ordering::Relaxed); .store(false, core::sync::atomic::Ordering::Relaxed);
pin.interrupt_edge( pin.configure_edge_interrupt(edge).unwrap();
edge, pin.enable_interrupt(InterruptConfig::new(irq, true, true));
InterruptConfig::new(irq, true, true), Ok(Self {
Some(sys_cfg), pin_id: pin.id(),
Some(irq_sel), waker_group,
) edge_detection_group,
.unwrap(); })
Ok(Self { pin_id: pin.id() })
}
/// # Safety
///
/// This calls [Self::new_with_pin] but uses [pac::Peripherals::steal] to get the system configuration
/// and IRQ selection peripherals. Users must ensure that the registers and configuration
/// related to this input pin are not being used elsewhere concurrently.
pub unsafe fn new_unchecked_with_pin<I: PinId, C: InputConfig>(
pin: &mut Pin<I, pin::Input<C>>,
irq: pac::Interrupt,
edge: InterruptEdge,
) -> Self {
let mut periphs = pac::Peripherals::steal();
Self::new_with_pin(pin, irq, edge, &mut periphs.sysconfig, &mut periphs.irqsel)
} }
pub fn new_with_pin<I: PinId, C: InputConfig>( pub fn new_with_pin<I: PinId, C: InputConfig>(
pin: &mut Pin<I, pin::Input<C>>, pin: &mut Pin<I, pin::Input<C>>,
irq: pac::Interrupt, irq: pac::Interrupt,
edge: InterruptEdge, edge: InterruptEdge,
sys_cfg: &mut Sysconfig,
irq_sel: &mut Irqsel,
) -> Self { ) -> Self {
EDGE_DETECTION[pin_id_to_offset(pin.id())] let (waker_group, edge_detection_group) =
Self::pin_group_to_waker_and_edge_detection_group(pin.id().port());
edge_detection_group[pin.id().num() as usize]
.store(false, core::sync::atomic::Ordering::Relaxed); .store(false, core::sync::atomic::Ordering::Relaxed);
pin.configure_edge_interrupt( pin.configure_edge_interrupt(edge);
edge, pin.enable_interrupt(InterruptConfig::new(irq, true, true));
InterruptConfig::new(irq, true, true), Self {
Some(sys_cfg), pin_id: pin.id(),
Some(irq_sel), edge_detection_group,
); waker_group,
Self { pin_id: pin.id() } }
} }
} }
impl Drop for InputPinFuture { impl Drop for InputPinFuture {
fn drop(&mut self) { fn drop(&mut self) {
let periphs = unsafe { pac::Peripherals::steal() }; // The API ensures that we actually own the pin, so stealing it here is okay.
if self.pin_id.group == DynGroup::A { unsafe { DynPin::steal(self.pin_id) }.disable_interrupt(false);
periphs
.porta
.irq_enb()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id.num)) });
} else {
periphs
.porta
.irq_enb()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id.num)) });
}
} }
} }
@ -181,9 +159,9 @@ impl Future for InputPinFuture {
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> { ) -> core::task::Poll<Self::Output> {
let idx = pin_id_to_offset(self.pin_id); let idx = self.pin_id.num() as usize;
WAKERS[idx].register(cx.waker()); self.waker_group[idx].register(cx.waker());
if EDGE_DETECTION[idx].swap(false, core::sync::atomic::Ordering::Relaxed) { if self.edge_detection_group[idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
return core::task::Poll::Ready(()); return core::task::Poll::Ready(());
} }
core::task::Poll::Pending core::task::Poll::Pending
@ -200,8 +178,8 @@ impl InputDynPinAsync {
/// passed as well and is used to route and enable the interrupt. /// passed as well and is used to route and enable the interrupt.
/// ///
/// Please note that the interrupt handler itself must be provided by the user and the /// Please note that the interrupt handler itself must be provided by the user and the
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function
/// the asynchronous functionality to work. /// for the asynchronous functionality to work.
pub fn new(pin: DynPin, irq: pac::Interrupt) -> Result<Self, InvalidPinTypeError> { pub fn new(pin: DynPin, irq: pac::Interrupt) -> Result<Self, InvalidPinTypeError> {
if !pin.is_input_pin() { if !pin.is_input_pin() {
return Err(InvalidPinTypeError(pin.mode())); return Err(InvalidPinTypeError(pin.mode()));
@ -213,15 +191,10 @@ impl InputDynPinAsync {
/// ///
/// This returns immediately if the pin is already high. /// This returns immediately if the pin is already high.
pub async fn wait_for_high(&mut self) { pub async fn wait_for_high(&mut self) {
let fut = unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. let fut =
InputPinFuture::new_unchecked_with_dyn_pin( InputPinFuture::new_with_dyn_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh)
&mut self.pin, .unwrap();
self.irq,
InterruptEdge::LowToHigh,
)
.unwrap()
};
if self.pin.is_high().unwrap() { if self.pin.is_high().unwrap() {
return; return;
} }
@ -232,15 +205,10 @@ impl InputDynPinAsync {
/// ///
/// This returns immediately if the pin is already high. /// This returns immediately if the pin is already high.
pub async fn wait_for_low(&mut self) { pub async fn wait_for_low(&mut self) {
let fut = unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. let fut =
InputPinFuture::new_unchecked_with_dyn_pin( InputPinFuture::new_with_dyn_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow)
&mut self.pin, .unwrap();
self.irq,
InterruptEdge::HighToLow,
)
.unwrap()
};
if self.pin.is_low().unwrap() { if self.pin.is_low().unwrap() {
return; return;
} }
@ -249,44 +217,26 @@ impl InputDynPinAsync {
/// Asynchronously wait until the pin sees a falling edge. /// Asynchronously wait until the pin sees a falling edge.
pub async fn wait_for_falling_edge(&mut self) { pub async fn wait_for_falling_edge(&mut self) {
unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. InputPinFuture::new_with_dyn_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow)
InputPinFuture::new_unchecked_with_dyn_pin(
&mut self.pin,
self.irq,
InterruptEdge::HighToLow,
)
.unwrap() .unwrap()
} .await;
.await;
} }
/// Asynchronously wait until the pin sees a rising edge. /// Asynchronously wait until the pin sees a rising edge.
pub async fn wait_for_rising_edge(&mut self) { pub async fn wait_for_rising_edge(&mut self) {
unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. InputPinFuture::new_with_dyn_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh)
InputPinFuture::new_unchecked_with_dyn_pin(
&mut self.pin,
self.irq,
InterruptEdge::LowToHigh,
)
.unwrap() .unwrap()
} .await;
.await;
} }
/// Asynchronously wait until the pin sees any edge (either rising or falling). /// Asynchronously wait until the pin sees any edge (either rising or falling).
pub async fn wait_for_any_edge(&mut self) { pub async fn wait_for_any_edge(&mut self) {
unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. InputPinFuture::new_with_dyn_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges)
InputPinFuture::new_unchecked_with_dyn_pin(
&mut self.pin,
self.irq,
InterruptEdge::BothEdges,
)
.unwrap() .unwrap()
} .await;
.await;
} }
pub fn release(self) -> DynPin { pub fn release(self) -> DynPin {
@ -335,8 +285,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
/// passed as well and is used to route and enable the interrupt. /// passed as well and is used to route and enable the interrupt.
/// ///
/// Please note that the interrupt handler itself must be provided by the user and the /// Please note that the interrupt handler itself must be provided by the user and the
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for /// generic [on_interrupt_for_async_gpio_for_port] function must be called inside that function
/// the asynchronous functionality to work. /// for the asynchronous functionality to work.
pub fn new(pin: Pin<I, pin::Input<C>>, irq: pac::Interrupt) -> Self { pub fn new(pin: Pin<I, pin::Input<C>>, irq: pac::Interrupt) -> Self {
Self { pin, irq } Self { pin, irq }
} }
@ -345,14 +295,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
/// ///
/// This returns immediately if the pin is already high. /// This returns immediately if the pin is already high.
pub async fn wait_for_high(&mut self) { pub async fn wait_for_high(&mut self) {
let fut = unsafe { let fut = InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh);
InputPinFuture::new_unchecked_with_pin( if self.pin.is_high() {
&mut self.pin,
self.irq,
InterruptEdge::LowToHigh,
)
};
if self.pin.is_high().unwrap() {
return; return;
} }
fut.await; fut.await;
@ -362,14 +306,8 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
/// ///
/// This returns immediately if the pin is already high. /// This returns immediately if the pin is already high.
pub async fn wait_for_low(&mut self) { pub async fn wait_for_low(&mut self) {
let fut = unsafe { let fut = InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow);
InputPinFuture::new_unchecked_with_pin( if self.pin.is_low() {
&mut self.pin,
self.irq,
InterruptEdge::HighToLow,
)
};
if self.pin.is_low().unwrap() {
return; return;
} }
fut.await; fut.await;
@ -377,40 +315,19 @@ impl<I: PinId, C: InputConfig> InputPinAsync<I, C> {
/// Asynchronously wait until the pin sees falling edge. /// Asynchronously wait until the pin sees falling edge.
pub async fn wait_for_falling_edge(&mut self) { pub async fn wait_for_falling_edge(&mut self) {
unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::HighToLow).await;
InputPinFuture::new_unchecked_with_pin(
&mut self.pin,
self.irq,
InterruptEdge::HighToLow,
)
}
.await;
} }
/// Asynchronously wait until the pin sees rising edge. /// Asynchronously wait until the pin sees rising edge.
pub async fn wait_for_rising_edge(&mut self) { pub async fn wait_for_rising_edge(&mut self) {
unsafe { // Unwrap okay, checked pin in constructor.
// Unwrap okay, checked pin in constructor. InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::LowToHigh).await;
InputPinFuture::new_unchecked_with_pin(
&mut self.pin,
self.irq,
InterruptEdge::LowToHigh,
)
}
.await;
} }
/// Asynchronously wait until the pin sees any edge (either rising or falling). /// Asynchronously wait until the pin sees any edge (either rising or falling).
pub async fn wait_for_any_edge(&mut self) { pub async fn wait_for_any_edge(&mut self) {
unsafe { InputPinFuture::new_with_pin(&mut self.pin, self.irq, InterruptEdge::BothEdges).await;
InputPinFuture::new_unchecked_with_pin(
&mut self.pin,
self.irq,
InterruptEdge::BothEdges,
)
}
.await;
} }
pub fn release(self) -> Pin<I, pin::Input<C>> { pub fn release(self) -> Pin<I, pin::Input<C>> {

View File

@ -57,11 +57,10 @@
//! [InvalidPinTypeError]. //! [InvalidPinTypeError].
use super::{ use super::{
pin::{FilterType, InterruptEdge, InterruptLevel, Pin, PinId, PinMode, PinState}, pin::{FilterType, Pin, PinId, PinMode},
reg::RegisterInterface, InputDynPinAsync, InterruptEdge, InterruptLevel, IsMaskedError, PinState, Port,
InputDynPinAsync,
}; };
use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel, InterruptConfig}; use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel};
//================================================================================================== //==================================================================================================
// DynPinMode configurations // DynPinMode configurations
@ -156,55 +155,92 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
// DynGroup & DynPinId // DynGroup & DynPinId
//================================================================================================== //==================================================================================================
/// Value-level `enum` for pin groups pub type DynGroup = Port;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynGroup {
A,
B,
}
/// Value-level `struct` representing pin IDs
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DynPinId { pub struct DynPinId {
pub group: DynGroup, port: Port,
pub num: u8, num: u8,
} }
//================================================================================================== impl DynPinId {
// DynRegisters pub const fn new(port: Port, num: u8) -> Self {
//================================================================================================== DynPinId { port, num }
}
/// Provide a safe register interface for [`DynPin`]s pub const fn port(&self) -> Port {
/// self.port
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to }
/// access the corresponding regsiters. pub const fn num(&self) -> u8 {
#[derive(Debug)] self.num
pub(crate) struct DynRegisters(DynPinId);
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
// guarantees that each pin is a singleton, so this implementation is safe.
unsafe impl RegisterInterface for DynRegisters {
#[inline]
fn id(&self) -> DynPinId {
self.0
} }
} }
impl DynRegisters { //==================================================================================================
/// Create a new instance of [`DynRegisters`] // ModeFields
/// //==================================================================================================
/// # Safety
/// /// Collect all fields needed to set the [`PinMode`](super::PinMode)
/// Users must never create two simultaneous instances of this `struct` with #[derive(Default)]
/// the same [`DynPinId`] struct ModeFields {
dir: bool,
opendrn: bool,
pull_en: bool,
/// true for pullup, false for pulldown
pull_dir: bool,
funsel: u8,
enb_input: bool,
}
impl From<DynPinMode> for ModeFields {
#[inline] #[inline]
unsafe fn new(id: DynPinId) -> Self { fn from(mode: DynPinMode) -> Self {
DynRegisters(id) let mut fields = Self::default();
match mode {
DynPinMode::Input(config) => {
fields.dir = false;
fields.funsel = FunSel::Sel0 as u8;
match config {
DynInput::Floating => (),
DynInput::PullUp => {
fields.pull_en = true;
fields.pull_dir = true;
}
DynInput::PullDown => {
fields.pull_en = true;
}
}
}
DynPinMode::Output(config) => {
fields.dir = true;
fields.funsel = FunSel::Sel0 as u8;
match config {
DynOutput::PushPull => (),
DynOutput::OpenDrain => {
fields.opendrn = true;
}
DynOutput::ReadableOpenDrain => {
fields.enb_input = true;
fields.opendrn = true;
}
DynOutput::ReadablePushPull => {
fields.enb_input = true;
}
}
}
DynPinMode::Alternate(config) => {
fields.funsel = config as u8;
}
}
fields
} }
} }
/// Type definition to avoid confusion: These register blocks are identical
type PortRegisterBlock = pac::porta::RegisterBlock;
pub type PortReg = pac::ioconfig::Porta;
//================================================================================================== //==================================================================================================
// DynPin // DynPin
//================================================================================================== //==================================================================================================
@ -215,46 +251,59 @@ impl DynRegisters {
/// by the same type, and pins are tracked and distinguished at run-time. /// by the same type, and pins are tracked and distinguished at run-time.
#[derive(Debug)] #[derive(Debug)]
pub struct DynPin { pub struct DynPin {
pub(crate) regs: DynRegisters, id: DynPinId,
mode: DynPinMode, mode: DynPinMode,
} }
impl DynPin { impl DynPin {
/// Create a new [`DynPin`] /// Create a new [DynPin]
/// ///
/// # Safety /// # Safety
/// ///
/// Each [`DynPin`] must be a singleton. For a given [`DynPinId`], there /// Each [DynPin] must be a singleton. For a given [DynPinId], there
/// must be at most one corresponding [`DynPin`] in existence at any given /// must be at most one corresponding [`DynPin`] in existence at any given
/// time. Violating this requirement is `unsafe`. /// time. Violating this requirement is `unsafe`.
#[inline] #[inline]
pub(crate) unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self { pub(crate) const unsafe fn new(id: DynPinId, mode: DynPinMode) -> Self {
DynPin { id, mode }
}
/// Steals a new [DynPin].
///
/// This function will simply set the internal mode to [DYN_FLOATING_INPUT] pin without
/// modifying any registers related to the behaviour of the pin. The user should call
/// [Self::into_mode] to ensure the correct mode of the pin.
///
/// # Safety
///
/// Circumvents the HAL's safety guarantees. The caller must ensure that the pin is not
/// used cocurrently somewhere else. The caller might also want to call [Self::into_mode]
/// to ensure the correct desired state of the pin. It is recommended to create the pin using
/// [Pin::downgrade] instead.
pub const unsafe fn steal(id: DynPinId) -> Self {
DynPin { DynPin {
regs: DynRegisters::new(id), id,
mode, mode: DYN_FLOATING_INPUT,
} }
} }
/// Return a copy of the pin ID /// Return a copy of the pin ID
#[inline] #[inline]
pub fn id(&self) -> DynPinId { pub const fn id(&self) -> DynPinId {
self.regs.0 self.id
} }
/// Return a copy of the pin mode /// Return a copy of the pin mode
#[inline] #[inline]
pub fn mode(&self) -> DynPinMode { pub const fn mode(&self) -> DynPinMode {
self.mode self.mode
} }
/// Convert the pin to the requested [`DynPinMode`] /// Convert the pin to the requested [`DynPinMode`]
#[inline] #[inline]
pub fn into_mode(&mut self, mode: DynPinMode) { pub fn into_mode(&mut self, mode: DynPinMode) {
// Only modify registers if we are actually changing pin mode self.change_mode(mode);
if mode != self.mode { self.mode = mode;
self.regs.change_mode(mode);
self.mode = mode;
}
} }
#[inline] #[inline]
@ -262,6 +311,11 @@ impl DynPin {
matches!(self.mode, DynPinMode::Input(_)) matches!(self.mode, DynPinMode::Input(_))
} }
#[inline]
pub fn is_output_pin(&self) -> bool {
matches!(self.mode, DynPinMode::Output(_))
}
#[inline] #[inline]
pub fn into_funsel_1(&mut self) { pub fn into_funsel_1(&mut self) {
self.into_mode(DYN_ALT_FUNC_1); self.into_mode(DYN_ALT_FUNC_1);
@ -319,205 +373,60 @@ impl DynPin {
self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT); self.into_mode(DYN_RD_OPEN_DRAIN_OUTPUT);
} }
#[inline] #[inline(always)]
pub fn datamask(&self) -> bool { pub fn is_low(&self) -> Result<bool, InvalidPinTypeError> {
self.regs.datamask() self.read_internal().map(|v| !v)
} }
#[inline] #[inline(always)]
pub fn clear_datamask(&mut self) { pub fn is_high(&self) -> Result<bool, InvalidPinTypeError> {
self.regs.clear_datamask(); self.read_internal()
} }
#[inline] #[inline(always)]
pub fn set_datamask(&mut self) { pub fn set_low(&mut self) -> Result<(), InvalidPinTypeError> {
self.regs.set_datamask(); self.write_internal(false)
} }
#[inline] #[inline(always)]
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> { pub fn set_high(&mut self) -> Result<(), InvalidPinTypeError> {
self.regs.read_pin_masked() self.write_internal(true)
} }
#[inline] /// Toggle the logic level of an output pin
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> { #[inline(always)]
self.regs.read_pin_masked().map(|v| !v) pub fn toggle(&mut self) -> Result<(), InvalidPinTypeError> {
} if !self.is_output_pin() {
return Err(InvalidPinTypeError(self.mode));
#[inline]
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.regs.write_pin_masked(true)
}
#[inline]
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.regs.write_pin_masked(false)
}
pub(crate) fn irq_enb(
&mut self,
irq_cfg: crate::InterruptConfig,
syscfg: Option<&mut va108xx::Sysconfig>,
irqsel: Option<&mut va108xx::Irqsel>,
) {
if let Some(syscfg) = syscfg {
crate::clock::enable_peripheral_clock(syscfg, crate::clock::PeripheralClocks::Irqsel);
} }
self.regs.enable_irq(); // Safety: TOGOUT is a "mask" register, and we only write the bit for
if let Some(irqsel) = irqsel { // this pin ID
if irq_cfg.route { unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) };
match self.regs.id().group { Ok(())
// Set the correct interrupt number in the IRQSEL register }
DynGroup::A => {
irqsel pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) {
.porta0(self.regs.id().num as usize) if irq_cfg.route {
.write(|w| unsafe { w.bits(irq_cfg.id as u32) }); self.configure_irqsel(irq_cfg.id);
}
DynGroup::B => {
irqsel
.portb0(self.regs.id().num as usize)
.write(|w| unsafe { w.bits(irq_cfg.id as u32) });
}
}
}
} }
if irq_cfg.enable_in_nvic { if irq_cfg.enable_in_nvic {
unsafe { enable_nvic_interrupt(irq_cfg.id) }; unsafe { enable_nvic_interrupt(irq_cfg.id) };
} }
// We only manipulate our own bit.
self.port_reg()
.irq_enb()
.modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) });
} }
/// See p.53 of the programmers guide for more information. pub fn disable_interrupt(&mut self, reset_irqsel: bool) {
/// Possible delays in clock cycles: if reset_irqsel {
/// - Delay 1: 1 self.reset_irqsel();
/// - Delay 2: 2
/// - Delay 1 + Delay 2: 3
#[inline]
pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.regs.delay(delay_1, delay_2);
Ok(self)
}
_ => Err(InvalidPinTypeError(self.mode)),
} }
} // We only manipulate our own bit.
self.port_reg()
/// See p.52 of the programmers guide for more information. .irq_enb()
/// When configured for pulse mode, a given pin will set the non-default state for exactly .modify(|r, w| unsafe { w.bits(r.bits() & !self.mask_32()) });
/// one clock cycle before returning to the configured default state
#[inline]
pub fn pulse_mode(
&mut self,
enable: bool,
default_state: PinState,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.regs.pulse_mode(enable, default_state);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
/// See p.37 and p.38 of the programmers guide for more information.
#[inline]
pub fn filter_type(
&mut self,
filter: FilterType,
clksel: FilterClkSel,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) => {
self.regs.filter_type(filter, clksel);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
pub fn interrupt_edge(
&mut self,
edge_type: InterruptEdge,
irq_cfg: InterruptConfig,
syscfg: Option<&mut pac::Sysconfig>,
irqsel: Option<&mut pac::Irqsel>,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
pub fn interrupt_level(
&mut self,
level_type: InterruptLevel,
irq_cfg: InterruptConfig,
syscfg: Option<&mut pac::Sysconfig>,
irqsel: Option<&mut pac::Irqsel>,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
pub fn toggle_with_toggle_reg(&mut self) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.regs.toggle();
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
fn _read(&self) -> Result<bool, InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
Ok(self.regs.read_pin())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
fn _write(&mut self, bit: bool) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.regs.write_pin(bit);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
fn _is_low(&self) -> Result<bool, InvalidPinTypeError> {
self._read().map(|v| !v)
}
#[inline]
fn _is_high(&self) -> Result<bool, InvalidPinTypeError> {
self._read()
}
#[inline]
fn _set_low(&mut self) -> Result<(), InvalidPinTypeError> {
self._write(false)
}
#[inline]
fn _set_high(&mut self) -> Result<(), InvalidPinTypeError> {
self._write(true)
} }
/// Try to recreate a type-level [`Pin`] from a value-level [`DynPin`] /// Try to recreate a type-level [`Pin`] from a value-level [`DynPin`]
@ -527,7 +436,7 @@ impl DynPin {
/// or refuse to perform it. /// or refuse to perform it.
#[inline] #[inline]
pub fn upgrade<I: PinId, M: PinMode>(self) -> Result<Pin<I, M>, InvalidPinTypeError> { pub fn upgrade<I: PinId, M: PinMode>(self) -> Result<Pin<I, M>, InvalidPinTypeError> {
if self.regs.0 == I::DYN && self.mode == M::DYN { if self.id == I::DYN && self.mode == M::DYN {
// The `DynPin` is consumed, so it is safe to replace it with the // The `DynPin` is consumed, so it is safe to replace it with the
// corresponding `Pin` // corresponding `Pin`
return Ok(unsafe { Pin::new() }); return Ok(unsafe { Pin::new() });
@ -543,6 +452,424 @@ impl DynPin {
) -> Result<InputDynPinAsync, InvalidPinTypeError> { ) -> Result<InputDynPinAsync, InvalidPinTypeError> {
InputDynPinAsync::new(self, irq) InputDynPinAsync::new(self, irq)
} }
/// Configure the IRQSEL peripheral for this particular pin with the given interrupt ID.
pub fn configure_irqsel(&mut self, id: pac::Interrupt) {
let mut syscfg = unsafe { pac::Sysconfig::steal() };
let irqsel = unsafe { pac::Irqsel::steal() };
crate::clock::enable_peripheral_clock(&mut syscfg, crate::clock::PeripheralClocks::Irqsel);
match self.id().port() {
// Set the correct interrupt number in the IRQSEL register
super::Port::A => {
irqsel
.porta0(self.id().num() as usize)
.write(|w| unsafe { w.bits(id as u32) });
}
super::Port::B => {
irqsel
.portb0(self.id().num as usize)
.write(|w| unsafe { w.bits(id as u32) });
}
}
}
/// Reset the IRQSEL peripheral value for this particular pin.
pub fn reset_irqsel(&mut self) {
let mut syscfg = unsafe { pac::Sysconfig::steal() };
let irqsel = unsafe { pac::Irqsel::steal() };
crate::clock::enable_peripheral_clock(&mut syscfg, crate::clock::PeripheralClocks::Irqsel);
match self.id().port() {
// Set the correct interrupt number in the IRQSEL register
super::Port::A => {
irqsel
.porta0(self.id().num() as usize)
.write(|w| unsafe { w.bits(u32::MAX) });
}
super::Port::B => {
irqsel
.portb0(self.id().num as usize)
.write(|w| unsafe { w.bits(u32::MAX) });
}
}
}
// Get DATAMASK bit for this particular pin
#[inline(always)]
pub fn datamask(&self) -> bool {
(self.port_reg().datamask().read().bits() >> self.id().num) == 1
}
/// Clear DATAMASK bit for this particular pin. This prevents access
/// of the corresponding bit for output and input operations
#[inline(always)]
pub fn clear_datamask(&self) {
self.port_reg()
.datamask()
.modify(|r, w| unsafe { w.bits(r.bits() & !self.mask_32()) });
}
/// Set DATAMASK bit for this particular pin. 1 is the default
/// state of the bit and allows access of the corresponding bit
#[inline(always)]
pub fn set_datamask(&self) {
self.port_reg()
.datamask()
.modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) });
}
#[inline]
pub fn is_high_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
self.read_pin_masked()
}
#[inline]
pub fn is_low_masked(&self) -> Result<bool, crate::gpio::IsMaskedError> {
self.read_pin_masked().map(|v| !v)
}
#[inline]
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.write_pin_masked(true)
}
#[inline]
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.write_pin_masked(false)
}
/// Possible delays in clock cycles:
/// - Delay 1: 1
/// - Delay 2: 2
/// - Delay 1 + Delay 2: 3
#[inline]
pub fn configure_delay(
&mut self,
delay_1: bool,
delay_2: bool,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.configure_delay_internal(delay_1, delay_2);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
/// When configured for pulse mode, a given pin will set the non-default state for exactly
/// one clock cycle before returning to the configured default state
#[inline]
pub fn configure_pulse_mode(
&mut self,
enable: bool,
default_state: PinState,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.configure_pulse_mode_internal(enable, default_state);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
/// See p.37 and p.38 of the programmers guide for more information.
#[inline]
pub fn configure_filter_type(
&mut self,
filter: FilterType,
clksel: FilterClkSel,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) => {
self.configure_filter_type_internal(filter, clksel);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
pub fn configure_edge_interrupt(
&mut self,
edge_type: InterruptEdge,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.configure_edge_interrupt_internal(edge_type);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
pub fn configure_level_interrupt(
&mut self,
level_type: InterruptLevel,
) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DynPinMode::Output(_) => {
self.configure_level_interrupt_internal(level_type);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
/// Change the pin mode
#[inline]
pub(crate) fn change_mode(&mut self, mode: DynPinMode) {
let ModeFields {
dir,
funsel,
opendrn,
pull_dir,
pull_en,
enb_input,
} = mode.into();
let (portreg, iocfg) = (self.port_reg(), self.iocfg_port());
iocfg.write(|w| {
w.opendrn().bit(opendrn);
w.pen().bit(pull_en);
w.plevel().bit(pull_dir);
w.iewo().bit(enb_input);
unsafe { w.funsel().bits(funsel) }
});
let mask = self.mask_32();
unsafe {
if dir {
portreg.dir().modify(|r, w| w.bits(r.bits() | mask));
// Clear output
portreg.clrout().write(|w| w.bits(mask));
} else {
portreg.dir().modify(|r, w| w.bits(r.bits() & !mask));
}
}
}
#[inline]
const fn port_reg(&self) -> &PortRegisterBlock {
match self.id().port() {
Port::A => unsafe { &(*pac::Porta::ptr()) },
Port::B => unsafe { &(*pac::Portb::ptr()) },
}
}
#[inline]
const fn iocfg_port(&self) -> &PortReg {
let ioconfig = unsafe { va108xx::Ioconfig::ptr().as_ref().unwrap() };
match self.id().port() {
Port::A => ioconfig.porta(self.id().num() as usize),
Port::B => ioconfig.portb0(self.id().num() as usize),
}
}
#[inline(always)]
fn read_internal(&self) -> Result<bool, InvalidPinTypeError> {
match self.mode {
DynPinMode::Input(_) | DYN_RD_OPEN_DRAIN_OUTPUT | DYN_RD_PUSH_PULL_OUTPUT => {
Ok(self.read_pin())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline(always)]
fn write_internal(&mut self, bit: bool) -> Result<(), InvalidPinTypeError> {
match self.mode {
DynPinMode::Output(_) => {
self.write_pin(bit);
Ok(())
}
_ => Err(InvalidPinTypeError(self.mode)),
}
}
#[inline]
/// Read the logic level of an output pin
pub(crate) fn read_pin(&self) -> bool {
let portreg = self.port_reg();
((portreg.datainraw().read().bits() >> self.id().num) & 0x01) == 1
}
/// Read a pin but use the masked version but check whether the datamask for the pin is
/// cleared as well
#[inline(always)]
fn read_pin_masked(&self) -> Result<bool, IsMaskedError> {
if !self.datamask() {
Err(IsMaskedError)
} else {
Ok(((self.port_reg().datain().read().bits() >> self.id().num) & 0x01) == 1)
}
}
/// Write the logic level of an output pin
#[inline(always)]
pub(crate) fn write_pin(&mut self, bit: bool) {
// Safety: SETOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe {
if bit {
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
} else {
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
}
}
}
/// Write the logic level of an output pin but check whether the datamask for the pin is
/// cleared as well
#[inline]
fn write_pin_masked(&mut self, bit: bool) -> Result<(), IsMaskedError> {
if !self.datamask() {
Err(IsMaskedError)
} else {
// Safety: SETOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe {
if bit {
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
} else {
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
}
Ok(())
}
}
}
/// Toggle the logic level of an output pin
#[inline(always)]
pub fn toggle_with_togout_reg(&mut self) {
// Safety: TOGOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) };
}
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
/// When using edge mode, it is possible to generate interrupts on both edges as well
#[inline]
fn configure_edge_interrupt_internal(&mut self, edge_type: InterruptEdge) {
unsafe {
self.port_reg()
.irq_sen()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
match edge_type {
InterruptEdge::HighToLow => {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
InterruptEdge::LowToHigh => {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
InterruptEdge::BothEdges => {
self.port_reg()
.irq_edge()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
}
/// Configure which edge or level type triggers an interrupt
#[inline]
fn configure_level_interrupt_internal(&mut self, level: InterruptLevel) {
unsafe {
self.port_reg()
.irq_sen()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
if level == InterruptLevel::Low {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
} else {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
/// Only useful for input pins
#[inline]
fn configure_filter_type_internal(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.iocfg_port().modify(|_, w| {
// Safety: Only write to register for this Pin ID
unsafe {
w.flttype().bits(filter as u8);
w.fltclk().bits(clksel as u8)
}
});
}
#[inline]
fn configure_pulse_mode_internal(&mut self, enable: bool, default_state: PinState) {
let portreg = self.port_reg();
unsafe {
if enable {
portreg
.pulse()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.pulse()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
if default_state == PinState::Low {
portreg
.pulsebase()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
} else {
portreg
.pulsebase()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
/// Only useful for output pins
#[inline]
fn configure_delay_internal(&mut self, delay_1: bool, delay_2: bool) {
let portreg = self.port_reg();
unsafe {
if delay_1 {
portreg
.delay1()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.delay1()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
if delay_2 {
portreg
.delay2()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.delay2()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
}
}
// Only serves disambiguation purposes for the Embedded HAL impl
#[inline(always)]
fn is_low_mut(&mut self) -> Result<bool, InvalidPinTypeError> {
self.is_low()
}
// Only serves disambiguation purposes for the Embedded HAL impl
#[inline(always)]
fn is_high_mut(&mut self) -> Result<bool, InvalidPinTypeError> {
self.is_high()
}
#[inline(always)]
const fn mask_32(&self) -> u32 {
1 << self.id().num()
}
} }
//================================================================================================== //==================================================================================================
@ -583,33 +910,38 @@ impl embedded_hal::digital::ErrorType for DynPin {
impl embedded_hal::digital::OutputPin for DynPin { impl embedded_hal::digital::OutputPin for DynPin {
#[inline] #[inline]
fn set_high(&mut self) -> Result<(), Self::Error> { fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high() self.set_high()
} }
#[inline] #[inline]
fn set_low(&mut self) -> Result<(), Self::Error> { fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low() self.set_low()
} }
} }
impl embedded_hal::digital::InputPin for DynPin { impl embedded_hal::digital::InputPin for DynPin {
#[inline] #[inline]
fn is_high(&mut self) -> Result<bool, Self::Error> { fn is_high(&mut self) -> Result<bool, Self::Error> {
self._is_high() self.is_high_mut()
} }
#[inline] #[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> { fn is_low(&mut self) -> Result<bool, Self::Error> {
self._is_low() self.is_low_mut()
} }
} }
impl embedded_hal::digital::StatefulOutputPin for DynPin { impl embedded_hal::digital::StatefulOutputPin for DynPin {
#[inline] #[inline]
fn is_set_high(&mut self) -> Result<bool, Self::Error> { fn is_set_high(&mut self) -> Result<bool, Self::Error> {
self._is_high() self.is_high_mut()
} }
#[inline] #[inline]
fn is_set_low(&mut self) -> Result<bool, Self::Error> { fn is_set_low(&mut self) -> Result<bool, Self::Error> {
self._is_low() self.is_low_mut()
}
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self.toggle()
} }
} }

View File

@ -22,14 +22,47 @@
//! //!
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs) //! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
//==================================================================================================
// Errors, Definitions and Constants
//==================================================================================================
pub const NUM_PINS_PORT_A: usize = 32;
pub const NUM_PINS_PORT_B: usize = 24;
pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A + NUM_PINS_PORT_B;
#[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("The pin is masked")] #[error("The pin is masked")]
pub struct IsMaskedError; pub struct IsMaskedError;
pub const NUM_PINS_PORT_A: usize = 32; #[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub const NUM_PINS_PORT_B: usize = 24; #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub const NUM_GPIO_PINS: usize = NUM_PINS_PORT_A + NUM_PINS_PORT_B; pub enum Port {
A,
B,
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InterruptEdge {
HighToLow,
LowToHigh,
BothEdges,
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InterruptLevel {
Low = 0,
High = 1,
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PinState {
Low = 0,
High = 1,
}
pub mod dynpin; pub mod dynpin;
pub use dynpin::*; pub use dynpin::*;
@ -39,5 +72,3 @@ pub use pin::*;
pub mod asynch; pub mod asynch;
pub use asynch::*; pub use asynch::*;
mod reg;

View File

@ -68,45 +68,19 @@
//! # Embedded HAL traits //! # Embedded HAL traits
//! //!
//! This module implements all of the embedded HAL GPIO traits for each [`Pin`] //! This module implements all of the embedded HAL GPIO traits for each [`Pin`]
//! in the corresponding [`PinMode`]s, namely: [`InputPin`], [`OutputPin`], //! in the corresponding [`PinMode`]s, namely: [embedded_hal::digital::InputPin],
//! and [`StatefulOutputPin`]. //! [embedded_hal::digital::OutputPin] and [embedded_hal::digital::StatefulOutputPin].
use super::dynpin::{DynAlternate, DynGroup, DynInput, DynOutput, DynPinId, DynPinMode}; use super::dynpin::{DynAlternate, DynInput, DynOutput, DynPinId, DynPinMode};
use super::reg::RegisterInterface; use super::{DynPin, InputPinAsync, InterruptEdge, InterruptLevel, PinState, Port};
use super::{DynPin, InputPinAsync};
use crate::{ use crate::{
pac::{Irqsel, Porta, Portb, Sysconfig}, pac::{Porta, Portb},
typelevel::Sealed, typelevel::Sealed,
InterruptConfig,
}; };
use core::convert::Infallible; use core::convert::Infallible;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::transmute; use core::mem::transmute;
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
use paste::paste; use paste::paste;
//==================================================================================================
// Errors and Definitions
//==================================================================================================
#[derive(Debug, PartialEq, Eq)]
pub enum InterruptEdge {
HighToLow,
LowToHigh,
BothEdges,
}
#[derive(Debug, PartialEq, Eq)]
pub enum InterruptLevel {
Low = 0,
High = 1,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PinState {
Low = 0,
High = 1,
}
//================================================================================================== //==================================================================================================
// Input configuration // Input configuration
//================================================================================================== //==================================================================================================
@ -317,10 +291,7 @@ macro_rules! pin_id {
pub enum $Id {} pub enum $Id {}
impl Sealed for $Id {} impl Sealed for $Id {}
impl PinId for $Id { impl PinId for $Id {
const DYN: DynPinId = DynPinId { const DYN: DynPinId = DynPinId::new(Port::$Group, $NUM);
group: DynGroup::$Group,
num: $NUM,
};
} }
} }
}; };
@ -346,14 +317,15 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
/// at most one corresponding [Pin] in existence at any given time. /// at most one corresponding [Pin] in existence at any given time.
/// Violating this requirement is `unsafe`. /// Violating this requirement is `unsafe`.
#[inline] #[inline]
pub(crate) unsafe fn new() -> Pin<I, M> { pub(crate) const unsafe fn new() -> Pin<I, M> {
Pin { Pin {
inner: DynPin::new(I::DYN, M::DYN), inner: DynPin::new(I::DYN, M::DYN),
phantom: PhantomData, phantom: PhantomData,
} }
} }
pub fn id(&self) -> DynPinId { #[inline]
pub const fn id(&self) -> DynPinId {
self.inner.id() self.inner.id()
} }
@ -363,7 +335,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
// Only modify registers if we are actually changing pin mode // Only modify registers if we are actually changing pin mode
// This check should compile away // This check should compile away
if N::DYN != M::DYN { if N::DYN != M::DYN {
self.inner.regs.change_mode(N::DYN); self.inner.change_mode(N::DYN);
} }
// Safe because we drop the existing Pin // Safe because we drop the existing Pin
unsafe { Pin::new() } unsafe { Pin::new() }
@ -423,6 +395,16 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
self.into_mode() self.into_mode()
} }
#[inline]
pub fn is_low(&self) -> bool {
!self.inner.read_pin()
}
#[inline]
pub fn is_high(&self) -> bool {
self.inner.read_pin()
}
#[inline] #[inline]
pub fn datamask(&self) -> bool { pub fn datamask(&self) -> bool {
self.inner.datamask() self.inner.datamask()
@ -448,53 +430,41 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
self.inner.is_low_masked() self.inner.is_low_masked()
} }
#[inline]
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.inner.set_high_masked()
}
#[inline]
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.inner.set_low_masked()
}
#[inline] #[inline]
pub fn downgrade(self) -> DynPin { pub fn downgrade(self) -> DynPin {
self.inner self.inner
} }
fn irq_enb( // Those only serve for the embedded HAL implementations which have different mutability.
&mut self,
irq_cfg: crate::InterruptConfig, #[inline]
syscfg: Option<&mut va108xx::Sysconfig>, fn is_low_mut(&mut self) -> bool {
irqsel: Option<&mut va108xx::Irqsel>, self.is_low()
) {
self.inner.irq_enb(irq_cfg, syscfg, irqsel);
} }
#[inline] #[inline]
pub(crate) fn _set_high(&mut self) { fn is_high_mut(&mut self) -> bool {
self.inner.regs.write_pin(true) self.is_high()
} }
#[inline] #[inline]
pub(crate) fn _set_low(&mut self) { pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) {
self.inner.regs.write_pin(false) self.inner.enable_interrupt(irq_cfg);
} }
#[inline] #[inline]
pub(crate) fn _toggle_with_toggle_reg(&mut self) { pub fn disable_interrupt(&mut self, reset_irqsel: bool) {
self.inner.regs.toggle(); self.inner.disable_interrupt(reset_irqsel);
} }
#[inline] /// Configure the pin for an edge interrupt but does not enable the interrupt.
pub(crate) fn _is_low(&self) -> bool { pub fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
!self.inner.regs.read_pin() self.inner.configure_edge_interrupt(edge_type).unwrap();
} }
#[inline] /// Configure the pin for a level interrupt but does not enable the interrupt.
pub(crate) fn _is_high(&self) -> bool { pub fn configure_level_interrupt(&mut self, level_type: InterruptLevel) {
self.inner.regs.read_pin() self.inner.configure_level_interrupt(level_type).unwrap();
} }
} }
@ -591,74 +561,52 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
pub fn into_async_input(self, irq: crate::pac::Interrupt) -> InputPinAsync<I, C> { pub fn into_async_input(self, irq: crate::pac::Interrupt) -> InputPinAsync<I, C> {
InputPinAsync::new(self, irq) InputPinAsync::new(self, irq)
} }
pub fn configure_edge_interrupt(
&mut self,
edge_type: InterruptEdge,
irq_cfg: InterruptConfig,
syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>,
) {
self.inner.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
}
pub fn configure_level_interrupt(
&mut self,
level_type: InterruptLevel,
irq_cfg: InterruptConfig,
syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>,
) {
self.inner.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
}
} }
impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> { impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
#[inline]
pub fn set_high(&mut self) {
self.inner.write_pin(true)
}
#[inline]
pub fn set_low(&mut self) {
self.inner.write_pin(false)
}
#[inline]
pub fn toggle(&mut self) {
self.inner.toggle().unwrap()
}
#[inline]
pub fn set_high_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.inner.set_high_masked()
}
#[inline]
pub fn set_low_masked(&mut self) -> Result<(), crate::gpio::IsMaskedError> {
self.inner.set_low_masked()
}
/// See p.53 of the programmers guide for more information. /// See p.53 of the programmers guide for more information.
/// Possible delays in clock cycles: /// Possible delays in clock cycles:
/// - Delay 1: 1 /// - Delay 1: 1
/// - Delay 2: 2 /// - Delay 2: 2
/// - Delay 1 + Delay 2: 3 /// - Delay 1 + Delay 2: 3
#[inline] #[inline]
pub fn delay(self, delay_1: bool, delay_2: bool) -> Self { pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
self.inner.regs.delay(delay_1, delay_2); self.inner.configure_delay(delay_1, delay_2).unwrap();
self
}
#[inline]
pub fn toggle_with_toggle_reg(&mut self) {
self._toggle_with_toggle_reg()
} }
/// See p.52 of the programmers guide for more information. /// See p.52 of the programmers guide for more information.
///
/// When configured for pulse mode, a given pin will set the non-default state for exactly /// When configured for pulse mode, a given pin will set the non-default state for exactly
/// one clock cycle before returning to the configured default state /// one clock cycle before returning to the configured default state
pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) { pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
self.inner.regs.pulse_mode(enable, default_state); self.inner
} .configure_pulse_mode(enable, default_state)
.unwrap();
pub fn interrupt_edge(
&mut self,
edge_type: InterruptEdge,
irq_cfg: InterruptConfig,
syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>,
) {
self.inner.regs.interrupt_edge(edge_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
}
pub fn interrupt_level(
&mut self,
level_type: InterruptLevel,
irq_cfg: InterruptConfig,
syscfg: Option<&mut Sysconfig>,
irqsel: Option<&mut Irqsel>,
) {
self.inner.regs.interrupt_level(level_type);
self.irq_enb(irq_cfg, syscfg, irqsel);
} }
} }
@ -666,7 +614,7 @@ 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 configure_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.configure_filter_type(filter, clksel).unwrap();
} }
} }
@ -682,63 +630,53 @@ where
type Error = Infallible; type Error = Infallible;
} }
impl<I: PinId, C: OutputConfig> OutputPin for Pin<I, Output<C>> { impl<I: PinId, C: OutputConfig> embedded_hal::digital::OutputPin for Pin<I, Output<C>> {
#[inline] #[inline]
fn set_high(&mut self) -> Result<(), Self::Error> { fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high(); self.set_high();
Ok(()) Ok(())
} }
#[inline] #[inline]
fn set_low(&mut self) -> Result<(), Self::Error> { fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low(); self.set_low();
Ok(()) Ok(())
} }
} }
impl<I, C> InputPin for Pin<I, Input<C>> impl<I, C> embedded_hal::digital::InputPin for Pin<I, Input<C>>
where where
I: PinId, I: PinId,
C: InputConfig, C: InputConfig,
{ {
#[inline] #[inline]
fn is_high(&mut self) -> Result<bool, Self::Error> { fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_high()) Ok(self.is_high_mut())
} }
#[inline] #[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> { fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_low()) Ok(self.is_low_mut())
} }
} }
impl<I, C> StatefulOutputPin for Pin<I, Output<C>> impl<I, C> embedded_hal::digital::StatefulOutputPin for Pin<I, Output<C>>
where where
I: PinId, I: PinId,
C: OutputConfig + ReadableOutput, C: OutputConfig + ReadableOutput,
{ {
#[inline] #[inline]
fn is_set_high(&mut self) -> Result<bool, Self::Error> { fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_high()) Ok(self.is_high())
} }
#[inline] #[inline]
fn is_set_low(&mut self) -> Result<bool, Self::Error> { fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_low()) Ok(self.is_low())
}
}
impl<I, C> InputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig + ReadableOutput,
{
#[inline]
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_high())
} }
#[inline] #[inline]
fn is_low(&mut self) -> Result<bool, Self::Error> { fn toggle(&mut self) -> Result<(), Self::Error> {
Ok(self._is_low()) self.toggle();
Ok(())
} }
} }

View File

@ -1,375 +0,0 @@
use super::dynpin::{self, DynGroup, DynPinId, DynPinMode};
use super::pin::{FilterType, InterruptEdge, InterruptLevel, PinState};
use super::IsMaskedError;
use crate::clock::FilterClkSel;
use va108xx::{ioconfig, porta};
/// Type definition to avoid confusion: These register blocks are identical
type PortRegisterBlock = porta::RegisterBlock;
//==================================================================================================
// ModeFields
//==================================================================================================
/// Collect all fields needed to set the [`PinMode`](super::PinMode)
#[derive(Default)]
struct ModeFields {
dir: bool,
opendrn: bool,
pull_en: bool,
/// true for pullup, false for pulldown
pull_dir: bool,
funsel: u8,
enb_input: bool,
}
impl From<DynPinMode> for ModeFields {
#[inline]
fn from(mode: DynPinMode) -> Self {
let mut fields = Self::default();
use DynPinMode::*;
match mode {
Input(config) => {
use dynpin::DynInput::*;
fields.dir = false;
match config {
Floating => (),
PullUp => {
fields.pull_en = true;
fields.pull_dir = true;
}
PullDown => {
fields.pull_en = true;
}
}
}
Output(config) => {
use dynpin::DynOutput::*;
fields.dir = true;
match config {
PushPull => (),
OpenDrain => {
fields.opendrn = true;
}
ReadableOpenDrain => {
fields.enb_input = true;
fields.opendrn = true;
}
ReadablePushPull => {
fields.enb_input = true;
}
}
}
Alternate(config) => {
fields.funsel = config as u8;
}
}
fields
}
}
//==================================================================================================
// Register Interface
//==================================================================================================
pub type PortReg = ioconfig::Porta;
/// Provide a safe register interface for pin objects
///
/// [`PORTA`] and [`PORTB`], like every PAC `struct`, is [`Send`] but not [`Sync`], because it
/// points to a `RegisterBlock` of `VolatileCell`s. Unfortunately, such an
/// interface is quite restrictive. Instead, it would be ideal if we could split
/// the [`PORT`] into independent pins that are both [`Send`] and [`Sync`].
///
/// [`PORT`] is a single, zero-sized marker `struct` that provides access to
/// every [`PORT`] register. Instead, we would like to create zero-sized marker
/// `struct`s for every pin, where each pin is only allowed to control its own
/// registers. Furthermore, each pin `struct` should be a singleton, so that
/// exclusive access to the `struct` also guarantees exclusive access to the
/// corresponding registers. Finally, the pin `struct`s should not have any
/// interior mutability. Together, these requirements would allow the pin
/// `struct`s to be both [`Send`] and [`Sync`].
///
/// This trait creates a safe API for accomplishing these goals. Implementers
/// supply a pin ID through the [`id`] function. The remaining functions provide
/// a safe API for accessing the registers associated with that pin ID. Any
/// modification of the registers requires `&mut self`, which destroys interior
/// mutability.
///
/// # Safety
///
/// Users should only implement the [`id`] function. No default function
/// implementations should be overridden. The implementing type must also have
/// "control" over the corresponding pin ID, i.e. it must guarantee that a each
/// pin ID is a singleton.
///
/// [`id`]: Self::id
pub(super) unsafe trait RegisterInterface {
/// Provide a [`DynPinId`] identifying the set of registers controlled by
/// this type.
fn id(&self) -> DynPinId;
const PORTA: *const PortRegisterBlock = va108xx::Porta::ptr();
const PORTB: *const PortRegisterBlock = va108xx::Portb::ptr();
/// Change the pin mode
#[inline]
fn change_mode(&mut self, mode: DynPinMode) {
let ModeFields {
dir,
funsel,
opendrn,
pull_dir,
pull_en,
enb_input,
} = mode.into();
let (portreg, iocfg) = (self.port_reg(), self.iocfg_port());
iocfg.write(|w| {
w.opendrn().bit(opendrn);
w.pen().bit(pull_en);
w.plevel().bit(pull_dir);
w.iewo().bit(enb_input);
unsafe { w.funsel().bits(funsel) }
});
let mask = self.mask_32();
unsafe {
if dir {
portreg.dir().modify(|r, w| w.bits(r.bits() | mask));
// Clear output
portreg.clrout().write(|w| w.bits(mask));
} else {
portreg.dir().modify(|r, w| w.bits(r.bits() & !mask));
}
}
}
#[inline]
fn port_reg(&self) -> &PortRegisterBlock {
match self.id().group {
DynGroup::A => unsafe { &(*Self::PORTA) },
DynGroup::B => unsafe { &(*Self::PORTB) },
}
}
fn iocfg_port(&self) -> &PortReg {
let ioconfig = unsafe { va108xx::Ioconfig::ptr().as_ref().unwrap() };
match self.id().group {
DynGroup::A => ioconfig.porta(self.id().num as usize),
DynGroup::B => ioconfig.portb0(self.id().num as usize),
}
}
#[inline]
fn mask_32(&self) -> u32 {
1 << self.id().num
}
#[inline]
fn enable_irq(&self) {
self.port_reg()
.irq_enb()
.modify(|r, w| unsafe { w.bits(r.bits() | self.mask_32()) });
}
#[inline]
/// Read the logic level of an output pin
fn read_pin(&self) -> bool {
let portreg = self.port_reg();
((portreg.datainraw().read().bits() >> self.id().num) & 0x01) == 1
}
// Get DATAMASK bit for this particular pin
#[inline(always)]
fn datamask(&self) -> bool {
let portreg = self.port_reg();
(portreg.datamask().read().bits() >> self.id().num) == 1
}
/// Read a pin but use the masked version but check whether the datamask for the pin is
/// cleared as well
#[inline(always)]
fn read_pin_masked(&self) -> Result<bool, IsMaskedError> {
if !self.datamask() {
Err(IsMaskedError)
} else {
Ok(((self.port_reg().datain().read().bits() >> self.id().num) & 0x01) == 1)
}
}
/// Write the logic level of an output pin
#[inline(always)]
fn write_pin(&mut self, bit: bool) {
// Safety: SETOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe {
if bit {
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
} else {
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
}
}
}
/// Write the logic level of an output pin but check whether the datamask for the pin is
/// cleared as well
#[inline]
fn write_pin_masked(&mut self, bit: bool) -> Result<(), IsMaskedError> {
if !self.datamask() {
Err(IsMaskedError)
} else {
// Safety: SETOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe {
if bit {
self.port_reg().setout().write(|w| w.bits(self.mask_32()));
} else {
self.port_reg().clrout().write(|w| w.bits(self.mask_32()));
}
Ok(())
}
}
}
/// Toggle the logic level of an output pin
#[inline(always)]
fn toggle(&mut self) {
// Safety: TOGOUT is a "mask" register, and we only write the bit for
// this pin ID
unsafe { self.port_reg().togout().write(|w| w.bits(self.mask_32())) };
}
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
/// When using edge mode, it is possible to generate interrupts on both edges as well
#[inline]
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
unsafe {
self.port_reg()
.irq_sen()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
match edge_type {
InterruptEdge::HighToLow => {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
InterruptEdge::LowToHigh => {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
InterruptEdge::BothEdges => {
self.port_reg()
.irq_edge()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
}
/// Configure which edge or level type triggers an interrupt
#[inline]
fn interrupt_level(&mut self, level: InterruptLevel) {
unsafe {
self.port_reg()
.irq_sen()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
if level == InterruptLevel::Low {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
} else {
self.port_reg()
.irq_evt()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
/// Only useful for input pins
#[inline]
fn filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
self.iocfg_port().modify(|_, w| {
// Safety: Only write to register for this Pin ID
unsafe {
w.flttype().bits(filter as u8);
w.fltclk().bits(clksel as u8)
}
});
}
/// Set DATAMASK bit for this particular pin. 1 is the default
/// state of the bit and allows access of the corresponding bit
#[inline(always)]
fn set_datamask(&self) {
let portreg = self.port_reg();
unsafe {
portreg
.datamask()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
/// Clear DATAMASK bit for this particular pin. This prevents access
/// of the corresponding bit for output and input operations
#[inline(always)]
fn clear_datamask(&self) {
let portreg = self.port_reg();
unsafe {
portreg
.datamask()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
}
/// Only useful for output pins
/// See p.52 of the programmers guide for more information.
/// When configured for pulse mode, a given pin will set the non-default state for exactly
/// one clock cycle before returning to the configured default state
fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
let portreg = self.port_reg();
unsafe {
if enable {
portreg
.pulse()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.pulse()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
if default_state == PinState::Low {
portreg
.pulsebase()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
} else {
portreg
.pulsebase()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
}
}
}
/// Only useful for output pins
fn delay(&self, delay_1: bool, delay_2: bool) {
let portreg = self.port_reg();
unsafe {
if delay_1 {
portreg
.delay1()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.delay1()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
if delay_2 {
portreg
.delay2()
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
} else {
portreg
.delay2()
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
}
}
}
}

View File

@ -36,8 +36,6 @@ pub struct InvalidTimingParamsError;
#[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))]
pub enum Error { pub enum Error {
//#[error("Invalid timing parameters")]
//InvalidTimingParams,
#[error("arbitration lost")] #[error("arbitration lost")]
ArbitrationLost, ArbitrationLost,
#[error("nack address")] #[error("nack address")]
@ -82,6 +80,7 @@ impl embedded_hal::i2c::Error for Error {
} }
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum I2cCmd { enum I2cCmd {
Start = 0b00, Start = 0b00,
Stop = 0b10, Stop = 0b10,
@ -252,6 +251,8 @@ impl Default for MasterConfig {
impl Sealed for MasterConfig {} impl Sealed for MasterConfig {}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SlaveConfig { pub struct SlaveConfig {
pub tx_fe_mode: FifoEmptyMode, pub tx_fe_mode: FifoEmptyMode,
pub rx_fe_mode: FifoEmptyMode, pub rx_fe_mode: FifoEmptyMode,
@ -455,13 +456,6 @@ impl<I2c: Instance> I2cBase<I2c> {
} }
} }
// Unique mode to use the loopback functionality
// pub struct I2cLoopback<I2C> {
// i2c_base: I2cBase<I2C>,
// master_cfg: MasterConfig,
// slave_cfg: SlaveConfig,
// }
//================================================================================================== //==================================================================================================
// I2C Master // I2C Master
//================================================================================================== //==================================================================================================
@ -673,275 +667,6 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
} }
} }
/*
macro_rules! i2c_master {
($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => {
$(
impl<ADDR> I2cMaster<$I2CX, ADDR> {
pub fn $i2cx(
i2c: $I2CX,
cfg: MasterConfig,
sys_clk: impl Into<Hertz> + Copy,
speed_mode: I2cSpeed,
sys_cfg: Option<&mut pac::Sysconfig>,
) -> Self {
I2cMaster {
i2c_base: I2cBase::$i2cx(
i2c,
sys_clk,
speed_mode,
Some(&cfg),
None,
sys_cfg
),
_addr: PhantomData,
}
.enable_master()
}
#[inline]
pub fn cancel_transfer(&self) {
self.i2c_base
.i2c
.cmd()
.write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
}
#[inline]
pub fn clear_tx_fifo(&self) {
self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit());
}
#[inline]
pub fn clear_rx_fifo(&self) {
self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit());
}
#[inline]
pub fn enable_master(self) -> Self {
self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit());
self
}
#[inline]
pub fn disable_master(self) -> Self {
self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().clear_bit());
self
}
#[inline(always)]
fn load_fifo(&self, word: u8) {
self.i2c_base
.i2c
.data()
.write(|w| unsafe { w.bits(word as u32) });
}
#[inline(always)]
fn read_fifo(&self) -> u8 {
self.i2c_base.i2c.data().read().bits() as u8
}
fn error_handler_write(&mut self, init_cmd: &I2cCmd) {
self.clear_tx_fifo();
if *init_cmd == I2cCmd::Start {
self.i2c_base.stop_cmd()
}
}
fn write_base(
&mut self,
addr: I2cAddress,
init_cmd: I2cCmd,
bytes: impl IntoIterator<Item = u8>,
) -> Result<(), Error> {
let mut iter = bytes.into_iter();
// Load address
let (addr, addr_mode_bit) = I2cBase::<$I2CX>::unwrap_addr(addr);
self.i2c_base.i2c.address().write(|w| unsafe {
w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
});
self.i2c_base
.i2c
.cmd()
.write(|w| unsafe { w.bits(init_cmd as u32) });
let mut load_if_next_available = || {
if let Some(next_byte) = iter.next() {
self.load_fifo(next_byte);
}
};
loop {
let status_reader = self.i2c_base.i2c.status().read();
if status_reader.arblost().bit_is_set() {
self.error_handler_write(&init_cmd);
return Err(Error::ArbitrationLost);
} else if status_reader.nackaddr().bit_is_set() {
self.error_handler_write(&init_cmd);
return Err(Error::NackAddr);
} else if status_reader.nackdata().bit_is_set() {
self.error_handler_write(&init_cmd);
return Err(Error::NackData);
} else if status_reader.idle().bit_is_set() {
return Ok(());
} else {
while !status_reader.txnfull().bit_is_set() {
load_if_next_available();
}
}
}
}
fn write_from_buffer(
&mut self,
init_cmd: I2cCmd,
addr: I2cAddress,
output: &[u8],
) -> Result<(), Error> {
let len = output.len();
// It should theoretically possible to transfer larger data sizes by tracking
// the number of sent words and setting it to 0x7fe as soon as only that many
// bytes are remaining. However, large transfer like this are not common. This
// feature will therefore not be supported for now.
if len > 0x7fe {
return Err(Error::DataTooLarge);
}
// Load number of words
self.i2c_base
.i2c
.words()
.write(|w| unsafe { w.bits(len as u32) });
let mut bytes = output.iter();
// FIFO has a depth of 16. We load slightly above the trigger level
// but not all of it because the transaction might fail immediately
const FILL_DEPTH: usize = 12;
// load the FIFO
for _ in 0..core::cmp::min(FILL_DEPTH, len) {
self.load_fifo(*bytes.next().unwrap());
}
self.write_base(addr, init_cmd, output.iter().cloned())
}
fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> {
let len = buffer.len();
// It should theoretically possible to transfer larger data sizes by tracking
// the number of sent words and setting it to 0x7fe as soon as only that many
// bytes are remaining. However, large transfer like this are not common. This
// feature will therefore not be supported for now.
if len > 0x7fe {
return Err(Error::DataTooLarge);
}
// Clear the receive FIFO
self.clear_rx_fifo();
// Load number of words
self.i2c_base
.i2c
.words()
.write(|w| unsafe { w.bits(len as u32) });
let (addr, addr_mode_bit) = match addr {
I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
I2cAddress::TenBit(addr) => (addr, 1 << 15),
};
// Load address
self.i2c_base.i2c.address().write(|w| unsafe {
w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit)
});
let mut buf_iter = buffer.iter_mut();
let mut read_bytes = 0;
// Start receive transfer
self.i2c_base
.i2c
.cmd()
.write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
let mut read_if_next_available = || {
if let Some(next_byte) = buf_iter.next() {
*next_byte = self.read_fifo();
}
};
loop {
let status_reader = self.i2c_base.i2c.status().read();
if status_reader.arblost().bit_is_set() {
self.clear_rx_fifo();
return Err(Error::ArbitrationLost);
} else if status_reader.nackaddr().bit_is_set() {
self.clear_rx_fifo();
return Err(Error::NackAddr);
} else if status_reader.idle().bit_is_set() {
if read_bytes != len {
return Err(Error::InsufficientDataReceived);
}
return Ok(());
} else if status_reader.rxnempty().bit_is_set() {
read_if_next_available();
read_bytes += 1;
}
}
}
}
//======================================================================================
// Embedded HAL I2C implementations
//======================================================================================
impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, SevenBitAddress> {
type Error = Error;
}
impl embedded_hal::i2c::I2c for I2cMaster<$I2CX, SevenBitAddress> {
fn transaction(
&mut self,
address: SevenBitAddress,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
for operation in operations {
match operation {
Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?,
Operation::Write(buf) => self.write_from_buffer(
I2cCmd::StartWithStop,
I2cAddress::Regular(address),
buf,
)?,
}
}
Ok(())
}
}
impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, TenBitAddress> {
type Error = Error;
}
impl embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<$I2CX, TenBitAddress> {
fn transaction(
&mut self,
address: TenBitAddress,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
for operation in operations {
match operation {
Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?,
Operation::Write(buf) => self.write_from_buffer(
I2cCmd::StartWithStop,
I2cAddress::TenBit(address),
buf,
)?,
}
}
Ok(())
}
}
)+
}
}
i2c_master!(
pac::I2ca: (i2ca, PeripheralClocks::I2c0),
pac::I2cb: (i2cb, PeripheralClocks::I2c1),
);
*/
//====================================================================================== //======================================================================================
// Embedded HAL I2C implementations // Embedded HAL I2C implementations
//====================================================================================== //======================================================================================

View File

@ -1,6 +1,7 @@
#![no_std] #![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
use gpio::Port;
pub use va108xx; pub use va108xx;
pub use va108xx as pac; pub use va108xx as pac;
@ -19,6 +20,7 @@ pub mod uart;
#[derive(Debug, Eq, Copy, Clone, PartialEq)] #[derive(Debug, Eq, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FunSel { pub enum FunSel {
Sel0 = 0b00,
Sel1 = 0b01, Sel1 = 0b01,
Sel2 = 0b10, Sel2 = 0b10,
Sel3 = 0b11, Sel3 = 0b11,
@ -26,13 +28,6 @@ pub enum FunSel {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PortSel {
PortA,
PortB,
}
#[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,
@ -54,6 +49,7 @@ pub enum PeripheralSelect {
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to /// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
/// perform those steps themselves. /// perform those steps themselves.
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterruptConfig { 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 id: pac::Interrupt, pub id: pac::Interrupt,
@ -76,37 +72,33 @@ impl InterruptConfig {
pub type IrqCfg = InterruptConfig; pub type IrqCfg = InterruptConfig;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidPin(pub(crate) ()); #[error("invalid pin with number {0}")]
pub struct InvalidPinError(u8);
/// Can be used to manually manipulate the function select of port pins /// Can be used to manually manipulate the function select of port pins.
///
/// The function selection table can be found on p.36 of the programmers guide. Please note
/// that most of the structures and APIs in this library will automatically correctly configure
/// the pin or statically expect the correct pin type.
pub fn port_function_select( pub fn port_function_select(
ioconfig: &mut pac::Ioconfig, ioconfig: &mut pac::Ioconfig,
port: PortSel, port: Port,
pin: u8, pin: u8,
funsel: FunSel, funsel: FunSel,
) -> Result<(), InvalidPin> { ) -> Result<(), InvalidPinError> {
match port { if (port == Port::A && pin >= 32) || (port == Port::B && pin >= 24) {
PortSel::PortA => { return Err(InvalidPinError(pin));
if pin > 31 {
return Err(InvalidPin(()));
}
ioconfig
.porta(pin as usize)
.modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
PortSel::PortB => {
if pin > 23 {
return Err(InvalidPin(()));
}
ioconfig
.portb0(pin as usize)
.modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
}
} }
let reg_block = match port {
Port::A => ioconfig.porta(pin as usize),
Port::B => ioconfig.portb0(pin as usize),
};
reg_block.modify(|_, w| unsafe { w.funsel().bits(funsel as u8) });
Ok(())
} }
/// Enable a specific interrupt using the NVIC peripheral. /// Enable a specific interrupt using the NVIC peripheral.

View File

@ -33,6 +33,7 @@ use embedded_hal::spi::{Mode, MODE_0};
const FILL_DEPTH: usize = 12; const FILL_DEPTH: usize = 12;
pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31; pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
pub const BMSKIPDATA_MASK: u32 = 1 << 30;
pub const DEFAULT_CLK_DIV: u16 = 2; pub const DEFAULT_CLK_DIV: u16 = 2;
@ -288,6 +289,7 @@ pub trait TransferConfigProvider {
/// This struct contains all configuration parameter which are transfer specific /// This struct contains all configuration parameter which are transfer specific
/// and might change for transfers to different SPI slaves /// and might change for transfers to different SPI slaves
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferConfigWithHwcs<HwCs> { pub struct TransferConfigWithHwcs<HwCs> {
pub hw_cs: Option<HwCs>, pub hw_cs: Option<HwCs>,
pub cfg: TransferConfig, pub cfg: TransferConfig,
@ -296,6 +298,7 @@ pub struct TransferConfigWithHwcs<HwCs> {
/// Type erased variant of the transfer configuration. This is required to avoid generics in /// Type erased variant of the transfer configuration. This is required to avoid generics in
/// the SPI constructor. /// the SPI constructor.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferConfig { pub struct TransferConfig {
pub clk_cfg: Option<SpiClkConfig>, pub clk_cfg: Option<SpiClkConfig>,
pub mode: Option<Mode>, pub mode: Option<Mode>,
@ -383,6 +386,8 @@ impl<HwCs: HwCsProvider> TransferConfigProvider for TransferConfigWithHwcs<HwCs>
} }
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details /// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SpiConfig { pub struct SpiConfig {
clk: SpiClkConfig, clk: SpiClkConfig,
// SPI mode configuration // SPI mode configuration
@ -532,6 +537,7 @@ pub struct Spi<SpiInstance, Pins, Word = u8> {
pins: Pins, pins: Pins,
} }
#[inline(always)]
pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) { pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
match mode { match mode {
embedded_hal::spi::MODE_0 => (false, false), embedded_hal::spi::MODE_0 => (false, false),
@ -575,6 +581,7 @@ impl SpiClkConfig {
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiClkConfigError { pub enum SpiClkConfigError {
#[error("division by zero")] #[error("division by zero")]
DivIsZero, DivIsZero,

View File

@ -22,7 +22,7 @@ use crate::{
}; };
use embedded_hal_nb::serial::Read; use embedded_hal_nb::serial::Read;
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Bank { pub enum Bank {
A = 0, A = 0,
@ -381,6 +381,7 @@ pub struct BufferTooShortError {
pub trait Instance: Deref<Target = uart_base::RegisterBlock> { pub trait Instance: Deref<Target = uart_base::RegisterBlock> {
const IDX: u8; const IDX: u8;
const PERIPH_SEL: PeripheralSelect; const PERIPH_SEL: PeripheralSelect;
const PTR: *const uart_base::RegisterBlock;
/// Retrieve the peripheral structure. /// Retrieve the peripheral structure.
/// ///
@ -388,7 +389,11 @@ 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;
#[inline(always)]
fn ptr() -> *const uart_base::RegisterBlock {
Self::PTR
}
/// Retrieve the type erased peripheral register block. /// Retrieve the type erased peripheral register block.
/// ///
@ -405,14 +410,11 @@ impl Instance for pac::Uarta {
const IDX: u8 = 0; const IDX: u8 = 0;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0;
const PTR: *const uart_base::RegisterBlock = Self::PTR;
#[inline(always)] #[inline(always)]
unsafe fn steal() -> Self { unsafe fn steal() -> Self {
pac::Peripherals::steal().uarta Self::steal()
}
#[inline(always)]
fn ptr() -> *const uart_base::RegisterBlock {
Self::ptr() as *const _
} }
} }
@ -420,14 +422,25 @@ impl Instance for pac::Uartb {
const IDX: u8 = 1; const IDX: u8 = 1;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1; const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
const PTR: *const uart_base::RegisterBlock = Self::PTR;
#[inline(always)] #[inline(always)]
unsafe fn steal() -> Self { unsafe fn steal() -> Self {
pac::Peripherals::steal().uartb Self::steal()
} }
#[inline(always)] }
fn ptr() -> *const uart_base::RegisterBlock {
Self::ptr() as *const _ impl Bank {
/// Retrieve the peripheral register block.
///
/// # Safety
///
/// Circumvents the HAL safety guarantees.
pub unsafe fn reg_block(&self) -> &'static uart_base::RegisterBlock {
match self {
Bank::A => unsafe { pac::Uarta::reg_block() },
Bank::B => unsafe { pac::Uartb::reg_block() },
}
} }
} }
@ -794,14 +807,12 @@ pub fn disable_rx_interrupts(uart: &uart_base::RegisterBlock) {
/// 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> { pub struct Rx<Uart>(Uart);
uart: Uart,
}
impl<Uart: Instance> Rx<Uart> { impl<Uart: Instance> Rx<Uart> {
#[inline(always)] #[inline(always)]
fn new(uart: Uart) -> Self { const fn new(uart: Uart) -> Self {
Self { uart } Self(uart)
} }
/// Direct access to the peripheral structure. /// Direct access to the peripheral structure.
@ -810,13 +821,13 @@ 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.
#[inline(always)] #[inline(always)]
pub unsafe fn uart(&self) -> &Uart { pub const unsafe fn uart(&self) -> &Uart {
&self.uart &self.0
} }
#[inline] #[inline]
pub fn clear_fifo(&self) { pub fn clear_fifo(&self) {
self.uart.fifo_clr().write(|w| w.rxfifo().set_bit()); self.0.fifo_clr().write(|w| w.rxfifo().set_bit());
} }
#[inline] #[inline]
@ -846,7 +857,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.uart.rxstatus().read().rdavl().bit_is_clear() { if self.0.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())
@ -862,7 +873,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_unchecked(&self) -> u32 { pub fn read_fifo_unchecked(&self) -> u32 {
self.uart.data().read().bits() self.0.data().read().bits()
} }
pub fn into_rx_with_irq(self) -> RxWithInterrupt<Uart> { pub fn into_rx_with_irq(self) -> RxWithInterrupt<Uart> {
@ -871,7 +882,7 @@ impl<Uart: Instance> Rx<Uart> {
#[inline(always)] #[inline(always)]
pub fn release(self) -> Uart { pub fn release(self) -> Uart {
self.uart self.0
} }
} }
@ -959,9 +970,7 @@ pub fn disable_tx_interrupts(uart: &uart_base::RegisterBlock) {
/// 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> { pub struct Tx<Uart>(Uart);
uart: Uart,
}
impl<Uart: Instance> Tx<Uart> { impl<Uart: Instance> Tx<Uart> {
/// Retrieve a TX pin without expecting an explicit UART structure /// Retrieve a TX pin without expecting an explicit UART structure
@ -971,14 +980,12 @@ impl<Uart: Instance> Tx<Uart> {
/// Circumvents the HAL safety guarantees. /// Circumvents the HAL safety guarantees.
#[inline(always)] #[inline(always)]
pub unsafe fn steal() -> Self { pub unsafe fn steal() -> Self {
Self { Self(Uart::steal())
uart: Uart::steal(),
}
} }
#[inline(always)] #[inline(always)]
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.
@ -987,25 +994,23 @@ 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.
#[inline(always)] #[inline(always)]
pub unsafe fn uart(&self) -> &Uart { pub const unsafe fn uart(&self) -> &Uart {
&self.uart &self.0
} }
#[inline] #[inline]
pub fn clear_fifo(&self) { pub fn clear_fifo(&self) {
self.uart.fifo_clr().write(|w| w.txfifo().set_bit()); self.0.fifo_clr().write(|w| w.txfifo().set_bit());
} }
#[inline] #[inline]
pub fn enable(&mut self) { pub fn enable(&mut self) {
// Safety: We own the UART structure self.0.enable().modify(|_, w| w.txenable().set_bit());
enable_tx(unsafe { Uart::reg_block() });
} }
#[inline] #[inline]
pub fn disable(&mut self) { pub fn disable(&mut self) {
// Safety: We own the UART structure self.0.enable().modify(|_, w| w.txenable().clear_bit());
disable_tx(unsafe { Uart::reg_block() });
} }
/// Enables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts. /// Enables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts.
@ -1037,7 +1042,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.uart.txstatus().read().wrrdy().bit_is_clear() { if self.0.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);
@ -1052,7 +1057,7 @@ 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.uart.data().write(|w| unsafe { w.bits(data) }); self.0.data().write(|w| unsafe { w.bits(data) });
} }
pub fn into_async(self) -> TxAsync<Uart> { pub fn into_async(self) -> TxAsync<Uart> {
@ -1135,7 +1140,7 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
#[inline(always)] #[inline(always)]
pub fn uart(&self) -> &Uart { pub fn uart(&self) -> &Uart {
&self.0.uart &self.0 .0
} }
/// This function is used together with the [Self::on_interrupt_max_size_or_timeout_based] /// This function is used together with the [Self::on_interrupt_max_size_or_timeout_based]

View File

@ -1,18 +1,16 @@
//! # Async UART reception functionality for the VA108xx family. //! # Async UART reception functionality for the VA416xx family.
//! //!
//! This module provides the [RxAsync] and [RxAsyncSharedConsumer] struct which both implement the //! This module provides the [RxAsync] and [RxAsyncOverwriting] struct which both implement the
//! [embedded_io_async::Read] trait. //! [embedded_io_async::Read] trait.
//! This trait allows for asynchronous reception of data streams. Please note that this module does //! This trait allows for asynchronous reception of data streams. Please note that this module does
//! not specify/declare the interrupt handlers which must be provided for async support to work. //! not specify/declare the interrupt handlers which must be provided for async support to work.
//! However, it provides four interrupt handlers: //! However, it provides two interrupt handlers:
//! //!
//! - [on_interrupt_uart_a] //! - [on_interrupt_rx]
//! - [on_interrupt_uart_b] //! - [on_interrupt_rx_overwriting]
//! - [on_interrupt_uart_a_overwriting]
//! - [on_interrupt_uart_b_overwriting]
//! //!
//! The first two are used for the [RxAsync] struct, while the latter two are used with the //! The first two are used for the [RxAsync] struct, while the latter two are used with the
//! [RxAsyncSharedConsumer] struct. The later two will overwrite old values in the used ring buffer. //! [RxAsyncOverwriting] struct. The later two will overwrite old values in the used ring buffer.
//! //!
//! Error handling is performed in the user interrupt handler by checking the [AsyncUartErrors] //! Error handling is performed in the user interrupt handler by checking the [AsyncUartErrors]
//! structure returned by the interrupt handlers. //! structure returned by the interrupt handlers.
@ -25,11 +23,10 @@ use core::{cell::RefCell, convert::Infallible, future::Future, sync::atomic::Ord
use critical_section::Mutex; use critical_section::Mutex;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embedded_io::ErrorType; use embedded_io::ErrorType;
use heapless::spsc::Consumer;
use portable_atomic::AtomicBool; use portable_atomic::AtomicBool;
use va108xx as pac; use va108xx::uarta as uart_base;
use super::{Instance, Rx, RxError, UartErrors}; use super::{Bank, Instance, Rx, RxError, UartErrors};
static UART_RX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2]; static UART_RX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
static RX_READ_ACTIVE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2]; static RX_READ_ACTIVE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
@ -72,7 +69,7 @@ pub struct AsyncUartErrors {
pub uart_errors: UartErrors, pub uart_errors: UartErrors,
} }
fn on_interrupt_handle_rx_errors<Uart: Instance>(uart: &Uart) -> Option<UartErrors> { fn on_interrupt_handle_rx_errors(uart: &'static uart_base::RegisterBlock) -> Option<UartErrors> {
let rx_status = uart.rxstatus().read(); let rx_status = uart.rxstatus().read();
if rx_status.rxovr().bit_is_set() if rx_status.rxovr().bit_is_set()
|| rx_status.rxfrm().bit_is_set() || rx_status.rxfrm().bit_is_set()
@ -94,81 +91,65 @@ fn on_interrupt_handle_rx_errors<Uart: Instance>(uart: &Uart) -> Option<UartErro
None None
} }
fn on_interrupt_rx_common_post_processing<Uart: Instance>( fn on_interrupt_rx_common_post_processing(
uart: &Uart, bank: Bank,
rx_enabled: bool, rx_enabled: bool,
read_some_data: bool, read_some_data: bool,
irq_end: u32, irq_end: u32,
) -> Option<UartErrors> { ) -> Option<UartErrors> {
let idx = bank as usize;
if read_some_data { if read_some_data {
RX_HAS_DATA[Uart::IDX as usize].store(true, Ordering::Relaxed); RX_HAS_DATA[idx].store(true, Ordering::Relaxed);
if RX_READ_ACTIVE[Uart::IDX as usize].load(Ordering::Relaxed) { if RX_READ_ACTIVE[idx].load(Ordering::Relaxed) {
UART_RX_WAKERS[Uart::IDX as usize].wake(); UART_RX_WAKERS[idx].wake();
} }
} }
let mut errors = None; let mut errors = None;
let uart_regs = unsafe { bank.reg_block() };
// Check for RX errors // Check for RX errors
if rx_enabled { if rx_enabled {
errors = on_interrupt_handle_rx_errors(uart); errors = on_interrupt_handle_rx_errors(uart_regs);
} }
// Clear the interrupt status bits // Clear the interrupt status bits
uart.irq_clr().write(|w| unsafe { w.bits(irq_end) }); uart_regs.irq_clr().write(|w| unsafe { w.bits(irq_end) });
errors errors
} }
/// Interrupt handler for UART A. /// Interrupt handler with overwriting behaviour when the ring buffer is full.
/// ///
/// Should be called in the user interrupt handler to enable /// Should be called in the user interrupt handler to enable
/// asynchronous reception. This variant will overwrite old data in the ring buffer in case /// asynchronous reception. This variant will overwrite old data in the ring buffer in case
/// the ring buffer is full. /// the ring buffer is full.
pub fn on_interrupt_uart_a_overwriting<const N: usize>( pub fn on_interrupt_rx_overwriting<const N: usize>(
bank: Bank,
prod: &mut heapless::spsc::Producer<u8, N>, prod: &mut heapless::spsc::Producer<u8, N>,
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>, shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
) -> Result<(), AsyncUartErrors> { ) -> Result<(), AsyncUartErrors> {
on_interrupt_rx_async_heapless_queue_overwriting( on_interrupt_rx_async_heapless_queue_overwriting(bank, prod, shared_consumer)
unsafe { pac::Uarta::steal() },
prod,
shared_consumer,
)
} }
/// Interrupt handler for UART B. pub fn on_interrupt_rx_async_heapless_queue_overwriting<const N: usize>(
/// bank: Bank,
/// Should be called in the user interrupt handler to enable
/// asynchronous reception. This variant will overwrite old data in the ring buffer in case
/// the ring buffer is full.
pub fn on_interrupt_uart_b_overwriting<const N: usize>(
prod: &mut heapless::spsc::Producer<u8, N>, prod: &mut heapless::spsc::Producer<u8, N>,
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>, shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
) -> Result<(), AsyncUartErrors> { ) -> Result<(), AsyncUartErrors> {
on_interrupt_rx_async_heapless_queue_overwriting( let uart_regs = unsafe { bank.reg_block() };
unsafe { pac::Uartb::steal() }, let irq_end = uart_regs.irq_end().read();
prod, let enb_status = uart_regs.enable().read();
shared_consumer,
)
}
pub fn on_interrupt_rx_async_heapless_queue_overwriting<Uart: Instance, const N: usize>(
uart: Uart,
prod: &mut heapless::spsc::Producer<u8, N>,
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
) -> Result<(), AsyncUartErrors> {
let irq_end = uart.irq_end().read();
let enb_status = uart.enable().read();
let rx_enabled = enb_status.rxenable().bit_is_set(); let rx_enabled = enb_status.rxenable().bit_is_set();
let mut read_some_data = false; let mut read_some_data = false;
let mut queue_overflow = false; let mut queue_overflow = false;
// Half-Full interrupt. We have a guaranteed amount of data we can read. // Half-Full interrupt. We have a guaranteed amount of data we can read.
if irq_end.irq_rx().bit_is_set() { if irq_end.irq_rx().bit_is_set() {
let available_bytes = uart.rxfifoirqtrg().read().bits() as usize; let available_bytes = uart_regs.rxfifoirqtrg().read().bits() as usize;
// If this interrupt bit is set, the trigger level is available at the very least. // If this interrupt bit is set, the trigger level is available at the very least.
// Read everything as fast as possible // Read everything as fast as possible
for _ in 0..available_bytes { for _ in 0..available_bytes {
let byte = uart.data().read().bits(); let byte = uart_regs.data().read().bits();
if !prod.ready() { if !prod.ready() {
queue_overflow = true; queue_overflow = true;
critical_section::with(|cs| { critical_section::with(|cs| {
@ -183,9 +164,9 @@ pub fn on_interrupt_rx_async_heapless_queue_overwriting<Uart: Instance, const N:
// Timeout, empty the FIFO completely. // Timeout, empty the FIFO completely.
if irq_end.irq_rx_to().bit_is_set() { if irq_end.irq_rx_to().bit_is_set() {
while uart.rxstatus().read().rdavl().bit_is_set() { while uart_regs.rxstatus().read().rdavl().bit_is_set() {
// 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 byte = uart.data().read().bits(); let byte = uart_regs.data().read().bits();
if !prod.ready() { if !prod.ready() {
queue_overflow = true; queue_overflow = true;
critical_section::with(|cs| { critical_section::with(|cs| {
@ -199,7 +180,7 @@ pub fn on_interrupt_rx_async_heapless_queue_overwriting<Uart: Instance, const N:
} }
let uart_errors = let uart_errors =
on_interrupt_rx_common_post_processing(&uart, rx_enabled, read_some_data, irq_end.bits()); on_interrupt_rx_common_post_processing(bank, rx_enabled, read_some_data, irq_end.bits());
if uart_errors.is_some() || queue_overflow { if uart_errors.is_some() || queue_overflow {
return Err(AsyncUartErrors { return Err(AsyncUartErrors {
queue_overflow, queue_overflow,
@ -209,29 +190,21 @@ pub fn on_interrupt_rx_async_heapless_queue_overwriting<Uart: Instance, const N:
Ok(()) Ok(())
} }
/// Interrupt handler for UART A. /// Interrupt handler for asynchronous RX operations.
/// ///
/// Should be called in the user interrupt handler to enable asynchronous reception. /// Should be called in the user interrupt handler to enable asynchronous reception.
pub fn on_interrupt_uart_a<const N: usize>( pub fn on_interrupt_rx<const N: usize>(
bank: Bank,
prod: &mut heapless::spsc::Producer<'_, u8, N>, prod: &mut heapless::spsc::Producer<'_, u8, N>,
) -> Result<(), AsyncUartErrors> { ) -> Result<(), AsyncUartErrors> {
on_interrupt_rx_async_heapless_queue(unsafe { pac::Uarta::steal() }, prod) on_interrupt_rx_async_heapless_queue(bank, prod)
} }
/// Interrupt handler for UART B. pub fn on_interrupt_rx_async_heapless_queue<const N: usize>(
/// bank: Bank,
/// Should be called in the user interrupt handler to enable asynchronous reception.
pub fn on_interrupt_uart_b<const N: usize>(
prod: &mut heapless::spsc::Producer<'_, u8, N>, prod: &mut heapless::spsc::Producer<'_, u8, N>,
) -> Result<(), AsyncUartErrors> { ) -> Result<(), AsyncUartErrors> {
on_interrupt_rx_async_heapless_queue(unsafe { pac::Uartb::steal() }, prod) let uart = unsafe { bank.reg_block() };
}
pub fn on_interrupt_rx_async_heapless_queue<Uart: Instance, const N: usize>(
uart: Uart,
prod: &mut heapless::spsc::Producer<'_, u8, N>,
) -> Result<(), AsyncUartErrors> {
//let uart = unsafe { Uart::steal() };
let irq_end = uart.irq_end().read(); let irq_end = uart.irq_end().read();
let enb_status = uart.enable().read(); let enb_status = uart.enable().read();
let rx_enabled = enb_status.rxenable().bit_is_set(); let rx_enabled = enb_status.rxenable().bit_is_set();
@ -268,7 +241,7 @@ pub fn on_interrupt_rx_async_heapless_queue<Uart: Instance, const N: usize>(
} }
let uart_errors = let uart_errors =
on_interrupt_rx_common_post_processing(&uart, rx_enabled, read_some_data, irq_end.bits()); on_interrupt_rx_common_post_processing(bank, rx_enabled, read_some_data, irq_end.bits());
if uart_errors.is_some() || queue_overflow { if uart_errors.is_some() || queue_overflow {
return Err(AsyncUartErrors { return Err(AsyncUartErrors {
queue_overflow, queue_overflow,
@ -286,24 +259,32 @@ impl Drop for ActiveReadGuard {
} }
} }
/// Core data structure to allow asynchronous UART reception. struct RxAsyncInner<Uart: Instance, const N: usize> {
///
/// If the ring buffer becomes full, data will be lost.
pub struct RxAsync<Uart: Instance, const N: usize> {
rx: Rx<Uart>, rx: Rx<Uart>,
pub queue: heapless::spsc::Consumer<'static, u8, N>, pub queue: heapless::spsc::Consumer<'static, u8, N>,
} }
/// Core data structure to allow asynchronous UART reception.
///
/// If the ring buffer becomes full, data will be lost.
pub struct RxAsync<Uart: Instance, const N: usize>(Option<RxAsyncInner<Uart, N>>);
impl<Uart: Instance, const N: usize> ErrorType for RxAsync<Uart, N> { impl<Uart: Instance, const N: usize> ErrorType for RxAsync<Uart, N> {
/// Error reporting is done using the result of the interrupt functions. /// Error reporting is done using the result of the interrupt functions.
type Error = Infallible; type Error = Infallible;
} }
fn stop_async_rx<Uart: Instance>(rx: &mut Rx<Uart>) {
rx.disable_interrupts();
rx.disable();
rx.clear_fifo();
}
impl<Uart: Instance, const N: usize> RxAsync<Uart, N> { impl<Uart: Instance, const N: usize> RxAsync<Uart, N> {
/// Create a new asynchronous receiver. /// Create a new asynchronous receiver.
/// ///
/// The passed [heapless::spsc::Consumer] will be used to asynchronously receive data which /// The passed [heapless::spsc::Consumer] will be used to asynchronously receive data which
/// is filled by the interrupt handler. /// is filled by the interrupt handler [on_interrupt_rx].
pub fn new(mut rx: Rx<Uart>, queue: heapless::spsc::Consumer<'static, u8, N>) -> Self { pub fn new(mut rx: Rx<Uart>, queue: heapless::spsc::Consumer<'static, u8, N>) -> Self {
rx.disable_interrupts(); rx.disable_interrupts();
rx.disable(); rx.disable();
@ -313,7 +294,23 @@ impl<Uart: Instance, const N: usize> RxAsync<Uart, N> {
rx.enable_interrupts(); rx.enable_interrupts();
rx.enable(); rx.enable();
}); });
Self { rx, queue } Self(Some(RxAsyncInner { rx, queue }))
}
pub fn stop(&mut self) {
stop_async_rx(&mut self.0.as_mut().unwrap().rx);
}
pub fn release(mut self) -> (Rx<Uart>, heapless::spsc::Consumer<'static, u8, N>) {
self.stop();
let inner = self.0.take().unwrap();
(inner.rx, inner.queue)
}
}
impl<Uart: Instance, const N: usize> Drop for RxAsync<Uart, N> {
fn drop(&mut self) {
self.stop();
} }
} }
@ -321,7 +318,7 @@ impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsync<Uart, N
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
// Need to wait for the IRQ to read data and set this flag. If the queue is not // Need to wait for the IRQ to read data and set this flag. If the queue is not
// empty, we can read data immediately. // empty, we can read data immediately.
if self.queue.len() == 0 { if self.0.as_ref().unwrap().queue.len() == 0 {
RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed); RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed);
} }
let _guard = ActiveReadGuard(Uart::IDX as usize); let _guard = ActiveReadGuard(Uart::IDX as usize);
@ -333,33 +330,38 @@ impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsync<Uart, N
} }
data_to_read data_to_read
}; };
let fut = RxFuture::new(&mut self.rx); let mut_ref = self.0.as_mut().unwrap();
let fut = RxFuture::new(&mut mut_ref.rx);
// Data is available, so read that data immediately. // Data is available, so read that data immediately.
let read_data = handle_data_in_queue(&mut self.queue); let read_data = handle_data_in_queue(&mut mut_ref.queue);
if read_data > 0 { if read_data > 0 {
return Ok(read_data); return Ok(read_data);
} }
// Await data. // Await data.
let _ = fut.await; let _ = fut.await;
Ok(handle_data_in_queue(&mut self.queue)) Ok(handle_data_in_queue(&mut mut_ref.queue))
} }
} }
struct RxAsyncOverwritingInner<Uart: Instance, const N: usize> {
rx: Rx<Uart>,
pub shared_consumer: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
}
/// Core data structure to allow asynchronous UART reception. /// Core data structure to allow asynchronous UART reception.
/// ///
/// If the ring buffer becomes full, the oldest data will be overwritten when using the /// If the ring buffer becomes full, the oldest data will be overwritten when using the
/// [on_interrupt_uart_a_overwriting] and [on_interrupt_uart_b_overwriting] interrupt handlers. /// [on_interrupt_rx_overwriting] interrupt handlers.
pub struct RxAsyncSharedConsumer<Uart: Instance, const N: usize> { pub struct RxAsyncOverwriting<Uart: Instance, const N: usize>(
rx: Rx<Uart>, Option<RxAsyncOverwritingInner<Uart, N>>,
queue: &'static Mutex<RefCell<Option<Consumer<'static, u8, N>>>>, );
}
impl<Uart: Instance, const N: usize> ErrorType for RxAsyncSharedConsumer<Uart, N> { impl<Uart: Instance, const N: usize> ErrorType for RxAsyncOverwriting<Uart, N> {
/// Error reporting is done using the result of the interrupt functions. /// Error reporting is done using the result of the interrupt functions.
type Error = Infallible; type Error = Infallible;
} }
impl<Uart: Instance, const N: usize> RxAsyncSharedConsumer<Uart, N> { impl<Uart: Instance, const N: usize> RxAsyncOverwriting<Uart, N> {
/// Create a new asynchronous receiver. /// Create a new asynchronous receiver.
/// ///
/// The passed shared [heapless::spsc::Consumer] will be used to asynchronously receive data /// The passed shared [heapless::spsc::Consumer] will be used to asynchronously receive data
@ -367,7 +369,7 @@ impl<Uart: Instance, const N: usize> RxAsyncSharedConsumer<Uart, N> {
/// interrupt handler to overwrite old data. /// interrupt handler to overwrite old data.
pub fn new( pub fn new(
mut rx: Rx<Uart>, mut rx: Rx<Uart>,
queue: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>, shared_consumer: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
) -> Self { ) -> Self {
rx.disable_interrupts(); rx.disable_interrupts();
rx.disable(); rx.disable();
@ -377,25 +379,44 @@ impl<Uart: Instance, const N: usize> RxAsyncSharedConsumer<Uart, N> {
rx.enable_interrupts(); rx.enable_interrupts();
rx.enable(); rx.enable();
}); });
Self { rx, queue } Self(Some(RxAsyncOverwritingInner {
rx,
shared_consumer,
}))
}
pub fn stop(&mut self) {
stop_async_rx(&mut self.0.as_mut().unwrap().rx);
}
pub fn release(mut self) -> Rx<Uart> {
self.stop();
let inner = self.0.take().unwrap();
inner.rx
} }
} }
impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsyncSharedConsumer<Uart, N> { impl<Uart: Instance, const N: usize> Drop for RxAsyncOverwriting<Uart, N> {
fn drop(&mut self) {
self.stop();
}
}
impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsyncOverwriting<Uart, N> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
// Need to wait for the IRQ to read data and set this flag. If the queue is not // Need to wait for the IRQ to read data and set this flag. If the queue is not
// empty, we can read data immediately. // empty, we can read data immediately.
critical_section::with(|cs| { critical_section::with(|cs| {
let queue = self.queue.borrow(cs); let queue = self.0.as_ref().unwrap().shared_consumer.borrow(cs);
if queue.borrow().as_ref().unwrap().len() == 0 { if queue.borrow().as_ref().unwrap().len() == 0 {
RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed); RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed);
} }
}); });
let _guard = ActiveReadGuard(Uart::IDX as usize); let _guard = ActiveReadGuard(Uart::IDX as usize);
let mut handle_data_in_queue = || { let mut handle_data_in_queue = |inner: &mut RxAsyncOverwritingInner<Uart, N>| {
critical_section::with(|cs| { critical_section::with(|cs| {
let mut consumer_ref = self.queue.borrow(cs).borrow_mut(); let mut consumer_ref = inner.shared_consumer.borrow(cs).borrow_mut();
let consumer = consumer_ref.as_mut().unwrap(); let consumer = consumer_ref.as_mut().unwrap();
let data_to_read = consumer.len().min(buf.len()); let data_to_read = consumer.len().min(buf.len());
for byte in buf.iter_mut().take(data_to_read) { for byte in buf.iter_mut().take(data_to_read) {
@ -405,15 +426,15 @@ impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsyncSharedCo
data_to_read data_to_read
}) })
}; };
let fut = RxFuture::new(&mut self.rx); let fut = RxFuture::new(&mut self.0.as_mut().unwrap().rx);
// Data is available, so read that data immediately. // Data is available, so read that data immediately.
let read_data = handle_data_in_queue(); let read_data = handle_data_in_queue(self.0.as_mut().unwrap());
if read_data > 0 { if read_data > 0 {
return Ok(read_data); return Ok(read_data);
} }
// Await data. // Await data.
let _ = fut.await; let _ = fut.await;
let read_data = handle_data_in_queue(); let read_data = handle_data_in_queue(self.0.as_mut().unwrap());
Ok(read_data) Ok(read_data)
} }
} }

View File

@ -3,13 +3,10 @@
//! This module provides the [TxAsync] struct which implements the [embedded_io_async::Write] trait. //! 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 //! 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. //! not specify/declare the interrupt handlers which must be provided for async support to work.
//! However, it provides two interrupt handlers: //! However, it the [on_interrupt_tx] interrupt handler.
//! //!
//! - [on_interrupt_uart_a_tx] //! This handler should be called in ALL user interrupt handlers which handle UART TX interrupts
//! - [on_interrupt_uart_b_tx] //! for a given UART bank.
//!
//! Those should be called in ALL user interrupt handlers which handle UART TX interrupts,
//! depending on which UARTs are used.
//! //!
//! # Example //! # Example
//! //!
@ -30,21 +27,14 @@ static TX_CONTEXTS: [Mutex<RefCell<TxContext>>; 2] =
// critical section. // critical section.
static TX_DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2]; static TX_DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
/// This is a generic interrupt handler to handle asynchronous UART TX operations. The user /// This is a generic interrupt handler to handle asynchronous UART TX operations for a given
/// has to call this once in the interrupt handler responsible for UART A TX interrupts for /// UART bank.
/// asynchronous operations to work. ///
pub fn on_interrupt_uart_a_tx() { /// The user has to call this once in the interrupt handler responsible for the TX interrupts on
on_interrupt_uart_tx(unsafe { pac::Uarta::steal() }); /// the given UART bank.
} pub fn on_interrupt_tx(bank: Bank) {
let uart = unsafe { bank.reg_block() };
/// This is a generic interrupt handler to handle asynchronous UART TX operations. The user let idx = bank as usize;
/// 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(); let irq_enb = uart.irq_enb().read();
// IRQ is not related to TX. // IRQ is not related to TX.
if irq_enb.irq_tx().bit_is_clear() || irq_enb.irq_tx_empty().bit_is_clear() { if irq_enb.irq_tx().bit_is_clear() || irq_enb.irq_tx_empty().bit_is_clear() {
@ -54,7 +44,7 @@ fn on_interrupt_uart_tx<Uart: Instance>(uart: Uart) {
let tx_status = uart.txstatus().read(); let tx_status = uart.txstatus().read();
let unexpected_overrun = tx_status.wrlost().bit_is_set(); let unexpected_overrun = tx_status.wrlost().bit_is_set();
let mut context = critical_section::with(|cs| { let mut context = critical_section::with(|cs| {
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs); let context_ref = TX_CONTEXTS[idx].borrow(cs);
*context_ref.borrow() *context_ref.borrow()
}); });
context.tx_overrun = unexpected_overrun; context.tx_overrun = unexpected_overrun;
@ -67,12 +57,12 @@ fn on_interrupt_uart_tx<Uart: Instance>(uart: Uart) {
uart.enable().modify(|_, w| w.txenable().clear_bit()); uart.enable().modify(|_, w| w.txenable().clear_bit());
// Write back updated context structure. // Write back updated context structure.
critical_section::with(|cs| { critical_section::with(|cs| {
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs); let context_ref = TX_CONTEXTS[idx].borrow(cs);
*context_ref.borrow_mut() = context; *context_ref.borrow_mut() = context;
}); });
// Transfer is done. // Transfer is done.
TX_DONE[Uart::IDX as usize].store(true, core::sync::atomic::Ordering::Relaxed); TX_DONE[idx].store(true, core::sync::atomic::Ordering::Relaxed);
UART_TX_WAKERS[Uart::IDX as usize].wake(); UART_TX_WAKERS[idx].wake();
return; return;
} }
// Safety: We documented that the user provided slice must outlive the future, so we convert // Safety: We documented that the user provided slice must outlive the future, so we convert
@ -92,7 +82,7 @@ fn on_interrupt_uart_tx<Uart: Instance>(uart: Uart) {
// Write back updated context structure. // Write back updated context structure.
critical_section::with(|cs| { critical_section::with(|cs| {
let context_ref = TX_CONTEXTS[Uart::IDX as usize].borrow(cs); let context_ref = TX_CONTEXTS[idx].borrow(cs);
*context_ref.borrow_mut() = context; *context_ref.borrow_mut() = context;
}); });
} }

View File

@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## [v0.5.0] 2025-02-17
- Re-generated PAC with `svd2rust` v0.35.0 and added optional `defmt` and `Debug` implementations
## [v0.4.0] 2025-02-12 ## [v0.4.0] 2025-02-12
- Re-generated PAC with `svd2rust` v0.35.0 - Re-generated PAC with `svd2rust` v0.35.0

View File

@ -1,6 +1,6 @@
[package] [package]
name = "va108xx" name = "va108xx"
version = "0.4.0" version = "0.5.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2021" edition = "2021"
description = "PAC for the Vorago VA108xx family of microcontrollers" description = "PAC for the Vorago VA108xx family of microcontrollers"
@ -13,6 +13,7 @@ categories = ["embedded", "no-std", "hardware-support"]
[dependencies] [dependencies]
cortex-m = "0.7" cortex-m = "0.7"
vcell = "0.1.3" vcell = "0.1.3"
defmt = { version = "0.3", optional = true }
critical-section = { version = "1", optional = true } critical-section = { version = "1", optional = true }
[dependencies.cortex-m-rt] [dependencies.cortex-m-rt]
@ -21,6 +22,8 @@ version = ">=0.6.15,<0.8"
[features] [features]
rt = ["cortex-m-rt/device"] rt = ["cortex-m-rt/device"]
# Adds Debug implementation
debug = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@ -26,6 +26,12 @@ The `rt` feature is optional and recommended. It brings in support for `cortex-m
For full details on the autgenerated API, please see the For full details on the autgenerated API, please see the
[svd2rust documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api). [svd2rust documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api).
## Optional Features
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for `defmt` by adding the
[`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
- `debug`: Add `Debug` derives for various structures
## Regenerating the PAC ## Regenerating the PAC
If you want to re-generate the PAC, for example if the register file `va416xx.svd` changes If you want to re-generate the PAC, for example if the register file `va416xx.svd` changes

View File

@ -30,7 +30,7 @@ fi
svdtools patch svd/va108xx-patch.yml svdtools patch svd/va108xx-patch.yml
# See https://github.com/rust-embedded/svd2rust/issues/830 for required re-export. # See https://github.com/rust-embedded/svd2rust/issues/830 for required re-export.
${svd2rust_bin} --reexport-interrupt -i svd/va108xx.svd.patched ${svd2rust_bin} --reexport-interrupt --impl-defmt defmt --impl-debug-feature debug -i svd/va108xx.svd.patched
result=$? result=$?
if [ $result -ne 0 ]; then if [ $result -ne 0 ]; then

View File

@ -2,6 +2,7 @@
pub type R = crate::R<AddressSpec>; pub type R = crate::R<AddressSpec>;
#[doc = "Register `ADDRESS` writer"] #[doc = "Register `ADDRESS` writer"]
pub type W = crate::W<AddressSpec>; pub type W = crate::W<AddressSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<ClktolimitSpec>; pub type R = crate::R<ClktolimitSpec>;
#[doc = "Register `CLKTOLIMIT` writer"] #[doc = "Register `CLKTOLIMIT` writer"]
pub type W = crate::W<ClktolimitSpec>; pub type W = crate::W<ClktolimitSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<CmdSpec>; pub type R = crate::R<CmdSpec>;
#[doc = "Register `CMD` writer"] #[doc = "Register `CMD` writer"]
pub type W = crate::W<CmdSpec>; pub type W = crate::W<CmdSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<DataSpec>; pub type R = crate::R<DataSpec>;
#[doc = "Register `DATA` writer"] #[doc = "Register `DATA` writer"]
pub type W = crate::W<DataSpec>; pub type W = crate::W<DataSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `RXCOUNT` reader"] #[doc = "Register `RXCOUNT` reader"]
pub type R = crate::R<RxcountSpec>; pub type R = crate::R<RxcountSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<RxfifoirqtrgSpec>; pub type R = crate::R<RxfifoirqtrgSpec>;
#[doc = "Register `RXFIFOIRQTRG` writer"] #[doc = "Register `RXFIFOIRQTRG` writer"]
pub type W = crate::W<RxfifoirqtrgSpec>; pub type W = crate::W<RxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0AddressSpec>; pub type R = crate::R<S0AddressSpec>;
#[doc = "Register `S0_ADDRESS` writer"] #[doc = "Register `S0_ADDRESS` writer"]
pub type W = crate::W<S0AddressSpec>; pub type W = crate::W<S0AddressSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0AddressbSpec>; pub type R = crate::R<S0AddressbSpec>;
#[doc = "Register `S0_ADDRESSB` writer"] #[doc = "Register `S0_ADDRESSB` writer"]
pub type W = crate::W<S0AddressbSpec>; pub type W = crate::W<S0AddressbSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0AddressmaskSpec>; pub type R = crate::R<S0AddressmaskSpec>;
#[doc = "Register `S0_ADDRESSMASK` writer"] #[doc = "Register `S0_ADDRESSMASK` writer"]
pub type W = crate::W<S0AddressmaskSpec>; pub type W = crate::W<S0AddressmaskSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0AddressmaskbSpec>; pub type R = crate::R<S0AddressmaskbSpec>;
#[doc = "Register `S0_ADDRESSMASKB` writer"] #[doc = "Register `S0_ADDRESSMASKB` writer"]
pub type W = crate::W<S0AddressmaskbSpec>; pub type W = crate::W<S0AddressmaskbSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0DataSpec>; pub type R = crate::R<S0DataSpec>;
#[doc = "Register `S0_DATA` writer"] #[doc = "Register `S0_DATA` writer"]
pub type W = crate::W<S0DataSpec>; pub type W = crate::W<S0DataSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `S0_LASTADDRESS` reader"] #[doc = "Register `S0_LASTADDRESS` reader"]
pub type R = crate::R<S0LastaddressSpec>; pub type R = crate::R<S0LastaddressSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0MaxwordsSpec>; pub type R = crate::R<S0MaxwordsSpec>;
#[doc = "Register `S0_MAXWORDS` writer"] #[doc = "Register `S0_MAXWORDS` writer"]
pub type W = crate::W<S0MaxwordsSpec>; pub type W = crate::W<S0MaxwordsSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `S0_RXCOUNT` reader"] #[doc = "Register `S0_RXCOUNT` reader"]
pub type R = crate::R<S0RxcountSpec>; pub type R = crate::R<S0RxcountSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0RxfifoirqtrgSpec>; pub type R = crate::R<S0RxfifoirqtrgSpec>;
#[doc = "Register `S0_RXFIFOIRQTRG` writer"] #[doc = "Register `S0_RXFIFOIRQTRG` writer"]
pub type W = crate::W<S0RxfifoirqtrgSpec>; pub type W = crate::W<S0RxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `S0_STATE` reader"] #[doc = "Register `S0_STATE` reader"]
pub type R = crate::R<S0StateSpec>; pub type R = crate::R<S0StateSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `S0_TXCOUNT` reader"] #[doc = "Register `S0_TXCOUNT` reader"]
pub type R = crate::R<S0TxcountSpec>; pub type R = crate::R<S0TxcountSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<S0TxfifoirqtrgSpec>; pub type R = crate::R<S0TxfifoirqtrgSpec>;
#[doc = "Register `S0_TXFIFOIRQTRG` writer"] #[doc = "Register `S0_TXFIFOIRQTRG` writer"]
pub type W = crate::W<S0TxfifoirqtrgSpec>; pub type W = crate::W<S0TxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `STATE` reader"] #[doc = "Register `STATE` reader"]
pub type R = crate::R<StateSpec>; pub type R = crate::R<StateSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<TmconfigSpec>; pub type R = crate::R<TmconfigSpec>;
#[doc = "Register `TMCONFIG` writer"] #[doc = "Register `TMCONFIG` writer"]
pub type W = crate::W<TmconfigSpec>; pub type W = crate::W<TmconfigSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `TXCOUNT` reader"] #[doc = "Register `TXCOUNT` reader"]
pub type R = crate::R<TxcountSpec>; pub type R = crate::R<TxcountSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<TxfifoirqtrgSpec>; pub type R = crate::R<TxfifoirqtrgSpec>;
#[doc = "Register `TXFIFOIRQTRG` writer"] #[doc = "Register `TXFIFOIRQTRG` writer"]
pub type W = crate::W<TxfifoirqtrgSpec>; pub type W = crate::W<TxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<WordsSpec>; pub type R = crate::R<WordsSpec>;
#[doc = "Register `WORDS` writer"] #[doc = "Register `WORDS` writer"]
pub type W = crate::W<WordsSpec>; pub type W = crate::W<WordsSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -3,6 +3,7 @@ pub type R = crate::R<PortaSpec>;
#[doc = "Register `PORTA[%s]` writer"] #[doc = "Register `PORTA[%s]` writer"]
pub type W = crate::W<PortaSpec>; pub type W = crate::W<PortaSpec>;
#[doc = "Input Filter Selectoin\n\nValue on reset: 0"] #[doc = "Input Filter Selectoin\n\nValue on reset: 0"]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum Flttype { pub enum Flttype {

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IntRamSbeSpec>; pub type R = crate::R<IntRamSbeSpec>;
#[doc = "Register `INT_RAM_SBE` writer"] #[doc = "Register `INT_RAM_SBE` writer"]
pub type W = crate::W<IntRamSbeSpec>; pub type W = crate::W<IntRamSbeSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -97,6 +97,7 @@ pub static __INTERRUPTS: [Vector; 32] = [
Vector { _handler: OC31 }, Vector { _handler: OC31 },
]; ];
#[doc = r"Enumeration of all the interrupts."] #[doc = r"Enumeration of all the interrupts."]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u16)] #[repr(u16)]
pub enum Interrupt { pub enum Interrupt {

View File

@ -1,5 +1,6 @@
#[doc = "Register `DATAIN` reader"] #[doc = "Register `DATAIN` reader"]
pub type R = crate::R<DatainSpec>; pub type R = crate::R<DatainSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `DATAINBYTE[%s]` reader"] #[doc = "Register `DATAINBYTE[%s]` reader"]
pub type R = crate::R<DatainbyteSpec>; pub type R = crate::R<DatainbyteSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<DatamaskSpec>; pub type R = crate::R<DatamaskSpec>;
#[doc = "Register `DATAMASK` writer"] #[doc = "Register `DATAMASK` writer"]
pub type W = crate::W<DatamaskSpec>; pub type W = crate::W<DatamaskSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<DatamaskbyteSpec>; pub type R = crate::R<DatamaskbyteSpec>;
#[doc = "Register `DATAMASKBYTE[%s]` writer"] #[doc = "Register `DATAMASKBYTE[%s]` writer"]
pub type W = crate::W<DatamaskbyteSpec>; pub type W = crate::W<DatamaskbyteSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `DATAOUT` writer"] #[doc = "Register `DATAOUT` writer"]
pub type W = crate::W<DataoutSpec>; pub type W = crate::W<DataoutSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for crate::generic::Reg<DataoutSpec> { impl core::fmt::Debug for crate::generic::Reg<DataoutSpec> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "(not readable)") write!(f, "(not readable)")

View File

@ -1,5 +1,6 @@
#[doc = "Register `DATAOUTBYTE[%s]` writer"] #[doc = "Register `DATAOUTBYTE[%s]` writer"]
pub type W = crate::W<DataoutbyteSpec>; pub type W = crate::W<DataoutbyteSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for crate::generic::Reg<DataoutbyteSpec> { impl core::fmt::Debug for crate::generic::Reg<DataoutbyteSpec> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "(not readable)") write!(f, "(not readable)")

View File

@ -2,6 +2,7 @@
pub type R = crate::R<EdgeStatusSpec>; pub type R = crate::R<EdgeStatusSpec>;
#[doc = "Register `EDGE_STATUS` writer"] #[doc = "Register `EDGE_STATUS` writer"]
pub type W = crate::W<EdgeStatusSpec>; pub type W = crate::W<EdgeStatusSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IrqEdgeSpec>; pub type R = crate::R<IrqEdgeSpec>;
#[doc = "Register `IRQ_EDGE` writer"] #[doc = "Register `IRQ_EDGE` writer"]
pub type W = crate::W<IrqEdgeSpec>; pub type W = crate::W<IrqEdgeSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IrqEnbSpec>; pub type R = crate::R<IrqEnbSpec>;
#[doc = "Register `IRQ_ENB` writer"] #[doc = "Register `IRQ_ENB` writer"]
pub type W = crate::W<IrqEnbSpec>; pub type W = crate::W<IrqEnbSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `IRQ_END` reader"] #[doc = "Register `IRQ_END` reader"]
pub type R = crate::R<IrqEndSpec>; pub type R = crate::R<IrqEndSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IrqEvtSpec>; pub type R = crate::R<IrqEvtSpec>;
#[doc = "Register `IRQ_EVT` writer"] #[doc = "Register `IRQ_EVT` writer"]
pub type W = crate::W<IrqEvtSpec>; pub type W = crate::W<IrqEvtSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `IRQ_RAW` reader"] #[doc = "Register `IRQ_RAW` reader"]
pub type R = crate::R<IrqRawSpec>; pub type R = crate::R<IrqRawSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IrqSenSpec>; pub type R = crate::R<IrqSenSpec>;
#[doc = "Register `IRQ_SEN` writer"] #[doc = "Register `IRQ_SEN` writer"]
pub type W = crate::W<IrqSenSpec>; pub type W = crate::W<IrqSenSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<ClkprescaleSpec>; pub type R = crate::R<ClkprescaleSpec>;
#[doc = "Register `CLKPRESCALE` writer"] #[doc = "Register `CLKPRESCALE` writer"]
pub type W = crate::W<ClkprescaleSpec>; pub type W = crate::W<ClkprescaleSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<DataSpec>; pub type R = crate::R<DataSpec>;
#[doc = "Register `DATA` writer"] #[doc = "Register `DATA` writer"]
pub type W = crate::W<DataSpec>; pub type W = crate::W<DataSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<RxfifoirqtrgSpec>; pub type R = crate::R<RxfifoirqtrgSpec>;
#[doc = "Register `RXFIFOIRQTRG` writer"] #[doc = "Register `RXFIFOIRQTRG` writer"]
pub type W = crate::W<RxfifoirqtrgSpec>; pub type W = crate::W<RxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `STATE` reader"] #[doc = "Register `STATE` reader"]
pub type R = crate::R<StateSpec>; pub type R = crate::R<StateSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<TxfifoirqtrgSpec>; pub type R = crate::R<TxfifoirqtrgSpec>;
#[doc = "Register `TXFIFOIRQTRG` writer"] #[doc = "Register `TXFIFOIRQTRG` writer"]
pub type W = crate::W<TxfifoirqtrgSpec>; pub type W = crate::W<TxfifoirqtrgSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `EF_CONFIG` reader"] #[doc = "Register `EF_CONFIG` reader"]
pub type R = crate::R<EfConfigSpec>; pub type R = crate::R<EfConfigSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `EF_ID` reader"] #[doc = "Register `EF_ID` reader"]
pub type R = crate::R<EfIdSpec>; pub type R = crate::R<EfIdSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<IoconfigClkdivSpec>; pub type R = crate::R<IoconfigClkdivSpec>;
#[doc = "Register `IOCONFIG_CLKDIV%s` writer"] #[doc = "Register `IOCONFIG_CLKDIV%s` writer"]
pub type W = crate::W<IoconfigClkdivSpec>; pub type W = crate::W<IoconfigClkdivSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `IOCONFIG_CLKDIV0` reader"] #[doc = "Register `IOCONFIG_CLKDIV0` reader"]
pub type R = crate::R<IoconfigClkdiv0Spec>; pub type R = crate::R<IoconfigClkdiv0Spec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `PROCID` reader"] #[doc = "Register `PROCID` reader"]
pub type R = crate::R<ProcidSpec>; pub type R = crate::R<ProcidSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<RamSbeSpec>; pub type R = crate::R<RamSbeSpec>;
#[doc = "Register `RAM_SBE` writer"] #[doc = "Register `RAM_SBE` writer"]
pub type W = crate::W<RamSbeSpec>; pub type W = crate::W<RamSbeSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<RefreshConfigSpec>; pub type R = crate::R<RefreshConfigSpec>;
#[doc = "Register `REFRESH_CONFIG` writer"] #[doc = "Register `REFRESH_CONFIG` writer"]
pub type W = crate::W<RefreshConfigSpec>; pub type W = crate::W<RefreshConfigSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -1,5 +1,6 @@
#[doc = "Register `ROM_RETRIES` reader"] #[doc = "Register `ROM_RETRIES` reader"]
pub type R = crate::R<RomRetriesSpec>; pub type R = crate::R<RomRetriesSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<TimClkEnableSpec>; pub type R = crate::R<TimClkEnableSpec>;
#[doc = "Register `TIM_CLK_ENABLE` writer"] #[doc = "Register `TIM_CLK_ENABLE` writer"]
pub type W = crate::W<TimClkEnableSpec>; pub type W = crate::W<TimClkEnableSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<TimResetSpec>; pub type R = crate::R<TimResetSpec>;
#[doc = "Register `TIM_RESET` writer"] #[doc = "Register `TIM_RESET` writer"]
pub type W = crate::W<TimResetSpec>; pub type W = crate::W<TimResetSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<CntValueSpec>; pub type R = crate::R<CntValueSpec>;
#[doc = "Register `CNT_VALUE` writer"] #[doc = "Register `CNT_VALUE` writer"]
pub type W = crate::W<CntValueSpec>; pub type W = crate::W<CntValueSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -21,6 +21,7 @@ pub type IrqEnbR = crate::BitReader;
#[doc = "Field `IRQ_ENB` writer - Interrupt Enable"] #[doc = "Field `IRQ_ENB` writer - Interrupt Enable"]
pub type IrqEnbW<'a, REG> = crate::BitWriter<'a, REG>; pub type IrqEnbW<'a, REG> = crate::BitWriter<'a, REG>;
#[doc = "Counter Status Selection\n\nValue on reset: 0"] #[doc = "Counter Status Selection\n\nValue on reset: 0"]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum StatusSel { pub enum StatusSel {

View File

@ -1,5 +1,6 @@
#[doc = "Register `PERID` reader"] #[doc = "Register `PERID` reader"]
pub type R = crate::R<PeridSpec>; pub type R = crate::R<PeridSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<PwmValueSpec>; pub type R = crate::R<PwmValueSpec>;
#[doc = "Register `PWM_VALUE` writer"] #[doc = "Register `PWM_VALUE` writer"]
pub type W = crate::W<PwmValueSpec>; pub type W = crate::W<PwmValueSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<PwmaValueSpec>; pub type R = crate::R<PwmaValueSpec>;
#[doc = "Register `PWMA_VALUE` writer"] #[doc = "Register `PWMA_VALUE` writer"]
pub type W = crate::W<PwmaValueSpec>; pub type W = crate::W<PwmaValueSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<PwmbValueSpec>; pub type R = crate::R<PwmbValueSpec>;
#[doc = "Register `PWMB_VALUE` writer"] #[doc = "Register `PWMB_VALUE` writer"]
pub type W = crate::W<PwmbValueSpec>; pub type W = crate::W<PwmbValueSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<RstValueSpec>; pub type R = crate::R<RstValueSpec>;
#[doc = "Register `RST_VALUE` writer"] #[doc = "Register `RST_VALUE` writer"]
pub type W = crate::W<RstValueSpec>; pub type W = crate::W<RstValueSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<Addr9Spec>; pub type R = crate::R<Addr9Spec>;
#[doc = "Register `ADDR9` writer"] #[doc = "Register `ADDR9` writer"]
pub type W = crate::W<Addr9Spec>; pub type W = crate::W<Addr9Spec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<Addr9maskSpec>; pub type R = crate::R<Addr9maskSpec>;
#[doc = "Register `ADDR9MASK` writer"] #[doc = "Register `ADDR9MASK` writer"]
pub type W = crate::W<Addr9maskSpec>; pub type W = crate::W<Addr9maskSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

View File

@ -2,6 +2,7 @@
pub type R = crate::R<DataSpec>; pub type R = crate::R<DataSpec>;
#[doc = "Register `DATA` writer"] #[doc = "Register `DATA` writer"]
pub type W = crate::W<DataSpec>; pub type W = crate::W<DataSpec>;
#[cfg(feature = "debug")]
impl core::fmt::Debug for R { impl core::fmt::Debug for R {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.bits()) write!(f, "{}", self.bits())

Some files were not shown because too many files have changed in this diff Show More