Compare commits
31 Commits
va108xx-v0
...
61c9b00de4
Author | SHA1 | Date | |
---|---|---|---|
61c9b00de4 | |||
e25fb20b08 | |||
67af1bb9b5 | |||
1a83f932b5 | |||
cdc4807686 | |||
62a4123f82 | |||
17f13fc4dc
|
|||
b4f1512463 | |||
e9ec01fc60 | |||
d57cd383cd | |||
df4e943f48 | |||
93b67a4795
|
|||
a9f2e6dcee
|
|||
271c853df1 | |||
107189b166 | |||
872944bebf | |||
d077bb6210 | |||
bd286bdb2a | |||
d3cc00a4a5
|
|||
1018a65447 | |||
0a31b637e6 | |||
6e1ae70054 | |||
8ae2d6189a
|
|||
549a98dbaf | |||
e24fc608a3
|
|||
7b74312013 | |||
417f5b7f67 | |||
3e796ef22b | |||
b145047b95 | |||
82b4c16f8e | |||
189ac2d256
|
@ -4,10 +4,9 @@
|
|||||||
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
|
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
|
||||||
# runner = "gdb-multiarch -q -x openocd.gdb"
|
# runner = "gdb-multiarch -q -x openocd.gdb"
|
||||||
# runner = "gdb -q -x openocd.gdb"
|
# runner = "gdb -q -x openocd.gdb"
|
||||||
runner = "gdb-multiarch -q -x jlink.gdb"
|
# runner = "gdb-multiarch -q -x jlink.gdb"
|
||||||
|
|
||||||
# Probe-rs is currently problematic: https://github.com/probe-rs/probe-rs/issues/2567
|
runner = "probe-rs run --chip VA108xx_RAM --protocol jtag"
|
||||||
# runner = "probe-rs run --chip VA108xx --chip-description-path ./scripts/VA108xx_Series.yaml"
|
|
||||||
# runner = ["probe-rs", "run", "--chip", "$CHIP", "--log-format", "{L} {s}"]
|
# runner = ["probe-rs", "run", "--chip", "$CHIP", "--log-format", "{L} {s}"]
|
||||||
|
|
||||||
rustflags = [
|
rustflags = [
|
||||||
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -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
|
||||||
|
75
README.md
75
README.md
@ -14,6 +14,8 @@ This workspace contains the following released crates:
|
|||||||
crate containing basic low-level register definition.
|
crate containing basic low-level register definition.
|
||||||
- The [`va108xx-hal`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/va108xx-hal)
|
- The [`va108xx-hal`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/va108xx-hal)
|
||||||
HAL crate containing higher-level abstractions on top of the PAC register crate.
|
HAL crate containing higher-level abstractions on top of the PAC register crate.
|
||||||
|
- The [`va108xx-embassy`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/va108xx-embassy)
|
||||||
|
crate containing support for running the embassy-rs RTOS.
|
||||||
- The [`vorago-reb1`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1)
|
- The [`vorago-reb1`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1)
|
||||||
BSP crate containing support for the REB1 development board.
|
BSP crate containing support for the REB1 development board.
|
||||||
|
|
||||||
@ -58,14 +60,56 @@ You can then adapt the files in `.vscode` to your needs.
|
|||||||
You can use CLI or VS Code for flashing, running and debugging. In any case, take
|
You can use CLI or VS Code for flashing, running and debugging. In any case, take
|
||||||
care of installing the pre-requisites first.
|
care of installing the pre-requisites first.
|
||||||
|
|
||||||
### Pre-Requisites
|
### Using CLI with probe-rs
|
||||||
|
|
||||||
|
Install [probe-rs](https://probe.rs/docs/getting-started/installation/) first.
|
||||||
|
|
||||||
|
You can use `probe-rs` to run the software and display RTT log output. However, debugging does not
|
||||||
|
work yet.
|
||||||
|
|
||||||
|
After installation, you can run the following command
|
||||||
|
|
||||||
|
```sh
|
||||||
|
probe-rs run --chip VA108xx_RAM --protocol jtag target/thumbv6m-none-eabi/debug/examples/blinky
|
||||||
|
```
|
||||||
|
|
||||||
|
to flash and run the blinky program on the RAM. There is also a `VA108xx` chip target
|
||||||
|
available for persistent flashing.
|
||||||
|
|
||||||
|
Runner configuration avilable in the `.cargo/def-config.toml` file to use `probe-rs` for
|
||||||
|
convenience.
|
||||||
|
|
||||||
|
### Using VS Code
|
||||||
|
|
||||||
|
Assuming a working debug connection to your VA108xx board, you can debug using VS Code with
|
||||||
|
the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
|
||||||
|
Please make sure that [`objdump-multiarch` and `nm-multiarch`](https://forums.raspberrypi.com/viewtopic.php?t=333146)
|
||||||
|
are installed as well.
|
||||||
|
|
||||||
|
Some sample configuration files for VS code were provided and can be used by running
|
||||||
|
`cp -rT vscode .vscode` like specified above. After that, you can use `Run and Debug`
|
||||||
|
to automatically rebuild and flash your application.
|
||||||
|
|
||||||
|
If you would like to use a custom GDB application, you can specify the gdb binary in the following
|
||||||
|
configuration variables in your `settings.json`:
|
||||||
|
|
||||||
|
- `"cortex-debug.gdbPath"`
|
||||||
|
- `"cortex-debug.gdbPath.linux"`
|
||||||
|
- `"cortex-debug.gdbPath.windows"`
|
||||||
|
- `"cortex-debug.gdbPath.osx"`
|
||||||
|
|
||||||
|
The provided VS Code configurations also provide an integrated RTT logger, which you can access
|
||||||
|
via the terminal at `RTT Ch:0 console`. In order for the RTT block address detection to
|
||||||
|
work properly, `objdump-multiarch` and `nm-multiarch` need to be installed.
|
||||||
|
|
||||||
|
### Using CLI with GDB and Segger J-Link Tools
|
||||||
|
|
||||||
|
Install the following two tools first:
|
||||||
|
|
||||||
1. [SEGGER J-Link tools](https://www.segger.com/downloads/jlink/) installed
|
1. [SEGGER J-Link tools](https://www.segger.com/downloads/jlink/) installed
|
||||||
2. [gdb-multiarch](https://packages.debian.org/sid/gdb-multiarch) or similar
|
2. [gdb-multiarch](https://packages.debian.org/sid/gdb-multiarch) or similar
|
||||||
cross-architecture debugger installed. All commands here assume `gdb-multiarch`.
|
cross-architecture debugger installed. All commands here assume `gdb-multiarch`.
|
||||||
|
|
||||||
### Using CLI
|
|
||||||
|
|
||||||
You can build the blinky example application with the following command
|
You can build the blinky example application with the following command
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@ -99,25 +143,8 @@ runner = "gdb-multiarch -q -x jlink/jlink.gdb"
|
|||||||
After that, you can simply use `cargo run --example blinky` to flash the blinky
|
After that, you can simply use `cargo run --example blinky` to flash the blinky
|
||||||
example.
|
example.
|
||||||
|
|
||||||
### Using VS Code
|
### Using the RTT Viewer
|
||||||
|
|
||||||
Assuming a working debug connection to your VA108xx board, you can debug using VS Code with
|
The Segger RTT viewer can be used to display log messages received from the target. The base
|
||||||
the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
|
address for the RTT block placement is 0x10000000. It is recommended to use a search range of
|
||||||
Please make sure that [`objdump-multiarch` and `nm-multiarch`](https://forums.raspberrypi.com/viewtopic.php?t=333146)
|
0x1000 around that base address when using the RTT viewer.
|
||||||
are installed as well.
|
|
||||||
|
|
||||||
Some sample configuration files for VS code were provided and can be used by running
|
|
||||||
`cp -rT vscode .vscode` like specified above. After that, you can use `Run and Debug`
|
|
||||||
to automatically rebuild and flash your application.
|
|
||||||
|
|
||||||
If you would like to use a custom GDB application, you can specify the gdb binary in the following
|
|
||||||
configuration variables in your `settings.json`:
|
|
||||||
|
|
||||||
- `"cortex-debug.gdbPath"`
|
|
||||||
- `"cortex-debug.gdbPath.linux"`
|
|
||||||
- `"cortex-debug.gdbPath.windows"`
|
|
||||||
- `"cortex-debug.gdbPath.osx"`
|
|
||||||
|
|
||||||
The provided VS Code configurations also provide an integrated RTT logger, which you can access
|
|
||||||
via the terminal at `RTT Ch:0 console`. In order for the RTT block address detection to
|
|
||||||
work properly, `objdump-multiarch` and `nm-multiarch` need to be installed.
|
|
||||||
|
@ -122,14 +122,14 @@ 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().unwrap();
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
output_pulsed.set_high().unwrap();
|
output_pulsed.set_high().unwrap();
|
||||||
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().unwrap();
|
||||||
@ -137,15 +137,12 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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().unwrap();
|
||||||
out_1.toggle().unwrap();
|
out_1.toggle().unwrap();
|
||||||
|
@ -15,10 +15,12 @@ num_enum = { version = "0.7", default-features = false }
|
|||||||
static_assertions = "1"
|
static_assertions = "1"
|
||||||
|
|
||||||
[dependencies.va108xx-hal]
|
[dependencies.va108xx-hal]
|
||||||
path = "../va108xx-hal"
|
version = "0.9"
|
||||||
|
# path = "../va108xx-hal"
|
||||||
|
|
||||||
[dependencies.vorago-reb1]
|
[dependencies.vorago-reb1]
|
||||||
path = "../vorago-reb1"
|
version = "0.7"
|
||||||
|
# path = "../vorago-reb1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -9,7 +9,10 @@ cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
|||||||
cortex-m-rt = "0.7"
|
cortex-m-rt = "0.7"
|
||||||
embedded-hal = "1"
|
embedded-hal = "1"
|
||||||
embedded-hal-async = "1"
|
embedded-hal-async = "1"
|
||||||
|
embedded-io = "0.6"
|
||||||
embedded-io-async = "0.6"
|
embedded-io-async = "0.6"
|
||||||
|
heapless = "0.8"
|
||||||
|
static_cell = "2"
|
||||||
|
|
||||||
rtt-target = "0.6"
|
rtt-target = "0.6"
|
||||||
panic-rtt-target = "0.2"
|
panic-rtt-target = "0.2"
|
||||||
@ -24,8 +27,8 @@ embassy-executor = { version = "0.7", features = [
|
|||||||
"executor-interrupt"
|
"executor-interrupt"
|
||||||
]}
|
]}
|
||||||
|
|
||||||
va108xx-hal = { path = "../../va108xx-hal" }
|
va108xx-hal = "0.9"
|
||||||
va108xx-embassy = { path = "../../va108xx-embassy", default-features = false }
|
va108xx-embassy = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]
|
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]
|
||||||
|
171
examples/embassy/src/bin/async-uart-rx.rs
Normal file
171
examples/embassy/src/bin/async-uart-rx.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//! Asynchronous UART reception example application.
|
||||||
|
//!
|
||||||
|
//! This application receives data on two UARTs permanently using a ring buffer.
|
||||||
|
//! The ring buffer are read them asynchronously. UART A is received on ports PA8 and PA9.
|
||||||
|
//! UART B is received on ports PA2 and PA3.
|
||||||
|
//!
|
||||||
|
//! Instructions:
|
||||||
|
//!
|
||||||
|
//! 1. Tie a USB to UART converter with RX to PA9 and TX to PA8 for UART A.
|
||||||
|
//! Tie a USB to UART converter with RX to PA3 and TX to PA2 for UART B.
|
||||||
|
//! 2. Connect to the serial interface by using an application like Putty or picocom. You can
|
||||||
|
//! type something in the terminal and check if the data is echoed back. You can also check the
|
||||||
|
//! RTT logs to see received data.
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_time::Instant;
|
||||||
|
use embedded_hal::digital::StatefulOutputPin;
|
||||||
|
use embedded_io::Write;
|
||||||
|
use embedded_io_async::Read;
|
||||||
|
use heapless::spsc::{Consumer, Producer, Queue};
|
||||||
|
use panic_rtt_target as _;
|
||||||
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
|
use va108xx_embassy::embassy;
|
||||||
|
use va108xx_hal::{
|
||||||
|
gpio::PinsA,
|
||||||
|
pac::{self, interrupt},
|
||||||
|
prelude::*,
|
||||||
|
uart::{
|
||||||
|
self, on_interrupt_uart_b_overwriting,
|
||||||
|
rx_asynch::{on_interrupt_uart_a, RxAsync},
|
||||||
|
RxAsyncSharedConsumer, Tx,
|
||||||
|
},
|
||||||
|
InterruptConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
|
||||||
|
|
||||||
|
static QUEUE_UART_A: static_cell::ConstStaticCell<Queue<u8, 256>> =
|
||||||
|
static_cell::ConstStaticCell::new(Queue::new());
|
||||||
|
static PRODUCER_UART_A: Mutex<RefCell<Option<Producer<u8, 256>>>> = Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
static QUEUE_UART_B: static_cell::ConstStaticCell<Queue<u8, 256>> =
|
||||||
|
static_cell::ConstStaticCell::new(Queue::new());
|
||||||
|
static PRODUCER_UART_B: Mutex<RefCell<Option<Producer<u8, 256>>>> = Mutex::new(RefCell::new(None));
|
||||||
|
static CONSUMER_UART_B: Mutex<RefCell<Option<Consumer<u8, 256>>>> = Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
// main is itself an async function.
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
rtt_init_print!();
|
||||||
|
rprintln!("-- VA108xx Async UART RX Demo --");
|
||||||
|
|
||||||
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Safety: Only called once here.
|
||||||
|
unsafe {
|
||||||
|
embassy::init(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
&dp.irqsel,
|
||||||
|
SYSCLK_FREQ,
|
||||||
|
dp.tim23,
|
||||||
|
dp.tim22,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let porta = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
|
let mut led0 = porta.pa10.into_readable_push_pull_output();
|
||||||
|
let mut led1 = porta.pa7.into_readable_push_pull_output();
|
||||||
|
let mut led2 = porta.pa6.into_readable_push_pull_output();
|
||||||
|
|
||||||
|
let tx_uart_a = porta.pa9.into_funsel_2();
|
||||||
|
let rx_uart_a = porta.pa8.into_funsel_2();
|
||||||
|
|
||||||
|
let uarta = uart::Uart::new_with_interrupt(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
50.MHz(),
|
||||||
|
dp.uarta,
|
||||||
|
(tx_uart_a, rx_uart_a),
|
||||||
|
115200.Hz(),
|
||||||
|
InterruptConfig::new(pac::Interrupt::OC2, true, true),
|
||||||
|
);
|
||||||
|
|
||||||
|
let tx_uart_b = porta.pa3.into_funsel_2();
|
||||||
|
let rx_uart_b = porta.pa2.into_funsel_2();
|
||||||
|
|
||||||
|
let uartb = uart::Uart::new_with_interrupt(
|
||||||
|
&mut dp.sysconfig,
|
||||||
|
50.MHz(),
|
||||||
|
dp.uartb,
|
||||||
|
(tx_uart_b, rx_uart_b),
|
||||||
|
115200.Hz(),
|
||||||
|
InterruptConfig::new(pac::Interrupt::OC3, true, true),
|
||||||
|
);
|
||||||
|
let (mut tx_uart_a, rx_uart_a) = uarta.split();
|
||||||
|
let (tx_uart_b, rx_uart_b) = uartb.split();
|
||||||
|
let (prod_uart_a, cons_uart_a) = QUEUE_UART_A.take().split();
|
||||||
|
// Pass the producer to the interrupt handler.
|
||||||
|
let (prod_uart_b, cons_uart_b) = QUEUE_UART_B.take().split();
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
*PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod_uart_a);
|
||||||
|
*PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod_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 async_rx_uart_b = RxAsyncSharedConsumer::new(rx_uart_b, &CONSUMER_UART_B);
|
||||||
|
spawner
|
||||||
|
.spawn(uart_b_task(async_rx_uart_b, tx_uart_b))
|
||||||
|
.unwrap();
|
||||||
|
let mut buf = [0u8; 256];
|
||||||
|
loop {
|
||||||
|
rprintln!("Current time UART A: {}", Instant::now().as_secs());
|
||||||
|
led0.toggle().ok();
|
||||||
|
led1.toggle().ok();
|
||||||
|
led2.toggle().ok();
|
||||||
|
let read_bytes = async_rx_uart_a.read(&mut buf).await.unwrap();
|
||||||
|
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
|
||||||
|
rprintln!(
|
||||||
|
"Read {} bytes asynchronously on UART A: {:?}",
|
||||||
|
read_bytes,
|
||||||
|
read_str
|
||||||
|
);
|
||||||
|
tx_uart_a.write_all(read_str.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn uart_b_task(mut async_rx: RxAsyncSharedConsumer<pac::Uartb, 256>, mut tx: Tx<pac::Uartb>) {
|
||||||
|
let mut buf = [0u8; 256];
|
||||||
|
loop {
|
||||||
|
rprintln!("Current time UART B: {}", Instant::now().as_secs());
|
||||||
|
// Infallible asynchronous operation.
|
||||||
|
let read_bytes = async_rx.read(&mut buf).await.unwrap();
|
||||||
|
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
|
||||||
|
rprintln!(
|
||||||
|
"Read {} bytes asynchronously on UART B: {:?}",
|
||||||
|
read_bytes,
|
||||||
|
read_str
|
||||||
|
);
|
||||||
|
tx.write_all(read_str.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn OC2() {
|
||||||
|
let mut prod =
|
||||||
|
critical_section::with(|cs| PRODUCER_UART_A.borrow(cs).borrow_mut().take().unwrap());
|
||||||
|
let errors = on_interrupt_uart_a(&mut 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.
|
||||||
|
if let Err(errors) = errors {
|
||||||
|
rprintln!("UART A errors: {:?}", errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn OC3() {
|
||||||
|
let mut prod =
|
||||||
|
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);
|
||||||
|
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.
|
||||||
|
if let Err(errors) = errors {
|
||||||
|
rprintln!("UART B errors: {:?}", errors);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,13 @@
|
|||||||
|
//! Asynchronous UART transmission example application.
|
||||||
|
//!
|
||||||
|
//! This application receives sends 4 strings with different sizes permanently using UART A.
|
||||||
|
//! Ports PA8 and PA9 are used for this.
|
||||||
|
//!
|
||||||
|
//! Instructions:
|
||||||
|
//!
|
||||||
|
//! 1. Tie a USB to UART converter with RX to PA9 and TX to PA8 for UART A.
|
||||||
|
//! 2. Connect to the serial interface by using an application like Putty or picocom. You can
|
||||||
|
//! can verify the correctness of the sent strings.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
@ -28,7 +38,7 @@ const STR_LIST: &[&str] = &[
|
|||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
rtt_init_print!();
|
rtt_init_print!();
|
||||||
rprintln!("-- VA108xx Embassy Demo --");
|
rprintln!("-- VA108xx Async UART TX Demo --");
|
||||||
|
|
||||||
let mut dp = pac::Peripherals::take().unwrap();
|
let mut dp = pac::Peripherals::take().unwrap();
|
||||||
|
|
@ -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 = { version = "0.8", path = "../../va108xx-hal" }
|
va108xx-hal = "0.9"
|
||||||
vorago-reb1 = { path = "../../vorago-reb1" }
|
vorago-reb1 = "0.7"
|
||||||
|
@ -16,9 +16,8 @@ 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.8"
|
|
||||||
features = ["rt", "defmt"]
|
features = ["rt", "defmt"]
|
||||||
|
|
||||||
[dependencies.vorago-reb1]
|
[dependencies.vorago-reb1]
|
||||||
path = "../../vorago-reb1"
|
version = "0.7"
|
||||||
|
@ -27,15 +27,15 @@ fn main() -> ! {
|
|||||||
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||||
let tx = gpioa.pa9.into_funsel_2();
|
let tx = gpioa.pa9.into_funsel_2();
|
||||||
let rx = gpioa.pa8.into_funsel_2();
|
let rx = gpioa.pa8.into_funsel_2();
|
||||||
|
let uart = uart::Uart::new_without_interrupt(
|
||||||
let uarta = uart::Uart::new_without_interrupt(
|
|
||||||
&mut dp.sysconfig,
|
&mut dp.sysconfig,
|
||||||
50.MHz(),
|
50.MHz(),
|
||||||
dp.uarta,
|
dp.uarta,
|
||||||
(tx, rx),
|
(tx, rx),
|
||||||
115200.Hz(),
|
115200.Hz(),
|
||||||
);
|
);
|
||||||
let (mut tx, mut rx) = uarta.split();
|
|
||||||
|
let (mut tx, mut rx) = uart.split();
|
||||||
writeln!(tx, "Hello World\r").unwrap();
|
writeln!(tx, "Hello World\r").unwrap();
|
||||||
loop {
|
loop {
|
||||||
// Echo what is received on the serial link.
|
// Echo what is received on the serial link.
|
||||||
|
@ -29,7 +29,9 @@ rtic-monotonics = { version = "2", features = ["cortex-m-systick"] }
|
|||||||
rtic-sync = {version = "1", features = ["defmt-03"]}
|
rtic-sync = {version = "1", features = ["defmt-03"]}
|
||||||
|
|
||||||
[dependencies.va108xx-hal]
|
[dependencies.va108xx-hal]
|
||||||
path = "../va108xx-hal"
|
version = "0.9"
|
||||||
|
# path = "../va108xx-hal"
|
||||||
|
|
||||||
[dependencies.vorago-reb1]
|
[dependencies.vorago-reb1]
|
||||||
path = "../vorago-reb1"
|
version = "0.7"
|
||||||
|
# path = "../vorago-reb1"
|
||||||
|
17
va108xx-embassy/CHANGELOG.md
Normal file
17
va108xx-embassy/CHANGELOG.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Change Log
|
||||||
|
=======
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [unreleased]
|
||||||
|
|
||||||
|
## [v0.1.2] and [v0.1.1] 2025-02-13
|
||||||
|
|
||||||
|
Docs patch
|
||||||
|
|
||||||
|
## [v0.1.0] 2025-02-13
|
||||||
|
|
||||||
|
Initial release
|
@ -1,11 +1,17 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "va108xx-embassy"
|
name = "va108xx-embassy"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||||
|
description = "Embassy-rs support for the Vorago VA108xx family of microcontrollers"
|
||||||
|
homepage = "https://egit.irs.uni-stuttgart.de/rust/va108xx-rs"
|
||||||
|
repository = "https://egit.irs.uni-stuttgart.de/rust/va108xx-rs"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
keywords = ["no-std", "hal", "cortex-m", "vorago", "va108xx"]
|
||||||
|
categories = ["aerospace", "embedded", "no-std", "hardware-support"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
critical-section = "1"
|
critical-section = "1"
|
||||||
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
|
|
||||||
|
|
||||||
embassy-sync = "0.6"
|
embassy-sync = "0.6"
|
||||||
embassy-executor = "0.7"
|
embassy-executor = "0.7"
|
||||||
@ -14,8 +20,12 @@ 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"] }
|
||||||
|
|
||||||
[dependencies.va108xx-hal]
|
va108xx-hal = "0.9"
|
||||||
path = "../va108xx-hal"
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
|
||||||
|
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
|
||||||
|
[target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies]
|
||||||
|
portable-atomic = "1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["irq-oc30-oc31"]
|
default = ["irq-oc30-oc31"]
|
||||||
@ -25,3 +35,6 @@ irqs-in-lib = []
|
|||||||
irq-oc28-oc29 = ["irqs-in-lib"]
|
irq-oc28-oc29 = ["irqs-in-lib"]
|
||||||
irq-oc29-oc30 = ["irqs-in-lib"]
|
irq-oc29-oc30 = ["irqs-in-lib"]
|
||||||
irq-oc30-oc31 = ["irqs-in-lib"]
|
irq-oc30-oc31 = ["irqs-in-lib"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
rustdoc-args = ["--generate-link-to-definition"]
|
||||||
|
3
va108xx-embassy/docs.sh
Executable file
3
va108xx-embassy/docs.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||||
|
cargo +nightly doc --open
|
@ -23,17 +23,17 @@
|
|||||||
//!
|
//!
|
||||||
//! You can disable the default features and then specify one of the features above to use the
|
//! You can disable the default features and then specify one of the features above to use the
|
||||||
//! documented combination of IRQs. It is also possible to specify custom IRQs by importing and
|
//! documented combination of IRQs. It is also possible to specify custom IRQs by importing and
|
||||||
//! using the [embassy::embassy_time_driver_irqs] macro to declare the IRQ handlers in the
|
//! using the [embassy_time_driver_irqs] macro to declare the IRQ handlers in the
|
||||||
//! application code. If this is done, [embassy::init_with_custom_irqs] must be used
|
//! application code. If this is done, [embassy::init_with_custom_irqs] must be used
|
||||||
//! method to pass the IRQ numbers to the library.
|
//! method to pass the IRQ numbers to the library.
|
||||||
//!
|
//!
|
||||||
//! ## Examples
|
//! ## Examples
|
||||||
//!
|
//!
|
||||||
//! [embassy example project](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy)
|
//! [embassy example projects](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy)
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
use core::cell::{Cell, RefCell};
|
use core::cell::{Cell, RefCell};
|
||||||
use critical_section::CriticalSection;
|
use critical_section::{CriticalSection, Mutex};
|
||||||
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
|
|
||||||
use portable_atomic::{AtomicU32, Ordering};
|
use portable_atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
use embassy_time_driver::{time_driver_impl, Driver, TICK_HZ};
|
use embassy_time_driver::{time_driver_impl, Driver, TICK_HZ};
|
||||||
@ -45,7 +45,7 @@ use va108xx_hal::{
|
|||||||
clock::enable_peripheral_clock,
|
clock::enable_peripheral_clock,
|
||||||
enable_nvic_interrupt, pac,
|
enable_nvic_interrupt, pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::{enable_tim_clk, get_tim_raw, TimRegInterface},
|
timer::{enable_tim_clk, get_tim_raw, TimRegInterface, ValidTim},
|
||||||
PeripheralSelect,
|
PeripheralSelect,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ time_driver_impl!(
|
|||||||
/// the feature flags specified. However, the macro is exported to allow users to specify the
|
/// the feature flags specified. However, the macro is exported to allow users to specify the
|
||||||
/// interrupt handlers themselves.
|
/// interrupt handlers themselves.
|
||||||
///
|
///
|
||||||
/// Please note that you have to explicitely import the [va108xx_hal::pac::interrupt]
|
/// Please note that you have to explicitely import the [macro@va108xx_hal::pac::interrupt]
|
||||||
/// macro in the application code in case this macro is used there.
|
/// macro in the application code in case this macro is used there.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! embassy_time_driver_irqs {
|
macro_rules! embassy_time_driver_irqs {
|
||||||
@ -115,12 +115,15 @@ pub mod embassy {
|
|||||||
/// This has to be called once at initialization time to initiate the time driver for
|
/// This has to be called once at initialization time to initiate the time driver for
|
||||||
/// embassy.
|
/// embassy.
|
||||||
#[cfg(feature = "irqs-in-lib")]
|
#[cfg(feature = "irqs-in-lib")]
|
||||||
pub unsafe fn init(
|
pub unsafe fn init<
|
||||||
|
TimekeeperTim: TimRegInterface + ValidTim,
|
||||||
|
AlarmTim: TimRegInterface + ValidTim,
|
||||||
|
>(
|
||||||
syscfg: &mut pac::Sysconfig,
|
syscfg: &mut pac::Sysconfig,
|
||||||
irqsel: &pac::Irqsel,
|
irqsel: &pac::Irqsel,
|
||||||
sysclk: impl Into<Hertz>,
|
sysclk: impl Into<Hertz>,
|
||||||
timekeeper_tim: impl TimRegInterface,
|
timekeeper_tim: TimekeeperTim,
|
||||||
alarm_tim: impl TimRegInterface,
|
alarm_tim: AlarmTim,
|
||||||
) {
|
) {
|
||||||
TIME_DRIVER.init(
|
TIME_DRIVER.init(
|
||||||
syscfg,
|
syscfg,
|
||||||
@ -139,12 +142,15 @@ pub mod embassy {
|
|||||||
///
|
///
|
||||||
/// This has to be called once at initialization time to initiate the time driver for
|
/// This has to be called once at initialization time to initiate the time driver for
|
||||||
/// embassy.
|
/// embassy.
|
||||||
pub unsafe fn init_with_custom_irqs(
|
pub unsafe fn init_with_custom_irqs<
|
||||||
|
TimekeeperTim: TimRegInterface + ValidTim,
|
||||||
|
AlarmTim: TimRegInterface + ValidTim,
|
||||||
|
>(
|
||||||
syscfg: &mut pac::Sysconfig,
|
syscfg: &mut pac::Sysconfig,
|
||||||
irqsel: &pac::Irqsel,
|
irqsel: &pac::Irqsel,
|
||||||
sysclk: impl Into<Hertz>,
|
sysclk: impl Into<Hertz>,
|
||||||
timekeeper_tim: impl TimRegInterface,
|
timekeeper_tim: TimekeeperTim,
|
||||||
alarm_tim: impl TimRegInterface,
|
alarm_tim: AlarmTim,
|
||||||
timekeeper_irq: pac::Interrupt,
|
timekeeper_irq: pac::Interrupt,
|
||||||
alarm_irq: pac::Interrupt,
|
alarm_irq: pac::Interrupt,
|
||||||
) {
|
) {
|
||||||
@ -187,21 +193,21 @@ pub struct TimerDriver {
|
|||||||
|
|
||||||
impl TimerDriver {
|
impl TimerDriver {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn init(
|
fn init<TimekeeperTim: TimRegInterface + ValidTim, AlarmTim: TimRegInterface + ValidTim>(
|
||||||
&self,
|
&self,
|
||||||
syscfg: &mut pac::Sysconfig,
|
syscfg: &mut pac::Sysconfig,
|
||||||
irqsel: &pac::Irqsel,
|
irqsel: &pac::Irqsel,
|
||||||
sysclk: impl Into<Hertz>,
|
sysclk: impl Into<Hertz>,
|
||||||
timekeeper_tim: impl TimRegInterface,
|
timekeeper_tim: TimekeeperTim,
|
||||||
alarm_tim: impl TimRegInterface,
|
alarm_tim: AlarmTim,
|
||||||
timekeeper_irq: pac::Interrupt,
|
timekeeper_irq: pac::Interrupt,
|
||||||
alarm_irq: pac::Interrupt,
|
alarm_irq: pac::Interrupt,
|
||||||
) {
|
) {
|
||||||
if ALARM_TIM.get().is_some() {
|
if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ALARM_TIM.set(alarm_tim.tim_id()).ok();
|
ALARM_TIM.set(AlarmTim::TIM_ID).ok();
|
||||||
TIMEKEEPER_TIM.set(timekeeper_tim.tim_id()).ok();
|
TIMEKEEPER_TIM.set(TimekeeperTim::TIM_ID).ok();
|
||||||
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
|
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
|
||||||
enable_tim_clk(syscfg, timekeeper_tim.tim_id());
|
enable_tim_clk(syscfg, timekeeper_tim.tim_id());
|
||||||
let timekeeper_reg_block = timekeeper_tim.reg_block();
|
let timekeeper_reg_block = timekeeper_tim.reg_block();
|
||||||
@ -299,7 +305,7 @@ impl TimerDriver {
|
|||||||
.cnt_value()
|
.cnt_value()
|
||||||
.write(|w| unsafe { w.bits(remaining_ticks.unwrap() as u32) });
|
.write(|w| unsafe { w.bits(remaining_ticks.unwrap() as u32) });
|
||||||
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
|
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
|
||||||
alarm_tim.enable().write(|w| unsafe { w.bits(1) })
|
alarm_tim.enable().write(|w| unsafe { w.bits(1) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -8,8 +8,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
|
## [v0.10.0]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- A lot of missing `defmt::Format` implementations.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Missing GPIO API replacements from `x` to `configure_x`
|
||||||
|
|
||||||
## [v0.9.0]
|
## [v0.9.0]
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Important bugfix for UART driver which causes UART B drivers not to work.
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
- Deleted some HAL re-exports in the PWM module
|
- Deleted some HAL re-exports in the PWM module
|
||||||
@ -38,6 +52,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `enable_interrupt` and `disable_interrupt` renamed to `enable_nvic_interrupt` and
|
- `enable_interrupt` and `disable_interrupt` renamed to `enable_nvic_interrupt` and
|
||||||
`disable_nvic_interrupt` to distinguish them from peripheral interrupts more clearly.
|
`disable_nvic_interrupt` to distinguish them from peripheral interrupts more clearly.
|
||||||
- `port_mux` renamed to `port_function_select`
|
- `port_mux` renamed to `port_function_select`
|
||||||
|
- Renamed `IrqUartErrors` to `UartErrors`.
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
@ -45,6 +60,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
methods.
|
methods.
|
||||||
- Asynchronous GPIO support.
|
- Asynchronous GPIO support.
|
||||||
- Asynchronous UART TX support.
|
- Asynchronous UART TX support.
|
||||||
|
- Asynchronous UART RX support.
|
||||||
- Add new `get_tim_raw` unsafe method to retrieve TIM peripheral blocks.
|
- Add new `get_tim_raw` unsafe method to retrieve TIM peripheral blocks.
|
||||||
- `Uart::with_with_interrupt` and `Uart::new_without_interrupt`
|
- `Uart::with_with_interrupt` and `Uart::new_without_interrupt`
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "va108xx-hal"
|
name = "va108xx-hal"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "HAL for the Vorago VA108xx family of microcontrollers"
|
description = "HAL for the Vorago VA108xx family of microcontrollers"
|
||||||
@ -24,10 +24,12 @@ fugit = "0.3"
|
|||||||
typenum = "1"
|
typenum = "1"
|
||||||
critical-section = "1"
|
critical-section = "1"
|
||||||
delegate = ">=0.12, <=0.13"
|
delegate = ">=0.12, <=0.13"
|
||||||
|
heapless = "0.8"
|
||||||
|
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.3", default-features = false, features = ["critical-section"] }
|
va108xx = { version = "0.4", default-features = false, features = ["critical-section"] }
|
||||||
embassy-sync = "0.6"
|
embassy-sync = "0.6"
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
@ -40,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
|
||||||
|
@ -25,12 +25,6 @@ rustup target add thumbv6m-none-eabi
|
|||||||
|
|
||||||
After that, you can use `cargo build` to build the development version of the crate.
|
After that, you can use `cargo build` to build the development version of the crate.
|
||||||
|
|
||||||
If you have not done this yet, it is recommended to read some of the excellent resources
|
|
||||||
available to learn Rust:
|
|
||||||
|
|
||||||
- [Rust Embedded Book](https://docs.rust-embedded.org/book/)
|
|
||||||
- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/)
|
|
||||||
|
|
||||||
## Setting up your own binary crate
|
## Setting up your own binary crate
|
||||||
|
|
||||||
If you have a custom board, you might be interested in setting up a new binary crate for your
|
If you have a custom board, you might be interested in setting up a new binary crate for your
|
||||||
@ -65,3 +59,11 @@ is contained within the
|
|||||||
|
|
||||||
7. Flashing the board might work differently for different boards and there is usually
|
7. Flashing the board might work differently for different boards and there is usually
|
||||||
more than one way. You can find example instructions in primary README.
|
more than one way. You can find example instructions in primary README.
|
||||||
|
|
||||||
|
## Embedded Rust
|
||||||
|
|
||||||
|
If you have not done this yet, it is recommended to read some of the excellent resources available
|
||||||
|
to learn Rust:
|
||||||
|
|
||||||
|
- [Rust Embedded Book](https://docs.rust-embedded.org/book/)
|
||||||
|
- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/)
|
||||||
|
@ -11,6 +11,7 @@ static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new());
|
|||||||
pub type PeripheralClocks = PeripheralSelect;
|
pub type PeripheralClocks = PeripheralSelect;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum FilterClkSel {
|
pub enum FilterClkSel {
|
||||||
SysClk = 0,
|
SysClk = 0,
|
||||||
Clk1 = 1,
|
Clk1 = 1,
|
||||||
@ -39,13 +40,27 @@ pub fn get_sys_clock() -> Option<Hertz> {
|
|||||||
pub fn set_clk_div_register(syscfg: &mut va108xx::Sysconfig, clk_sel: FilterClkSel, div: u32) {
|
pub fn set_clk_div_register(syscfg: &mut va108xx::Sysconfig, clk_sel: FilterClkSel, div: u32) {
|
||||||
match clk_sel {
|
match clk_sel {
|
||||||
FilterClkSel::SysClk => (),
|
FilterClkSel::SysClk => (),
|
||||||
FilterClkSel::Clk1 => syscfg.ioconfig_clkdiv1().write(|w| unsafe { w.bits(div) }),
|
FilterClkSel::Clk1 => {
|
||||||
FilterClkSel::Clk2 => syscfg.ioconfig_clkdiv2().write(|w| unsafe { w.bits(div) }),
|
syscfg.ioconfig_clkdiv1().write(|w| unsafe { w.bits(div) });
|
||||||
FilterClkSel::Clk3 => syscfg.ioconfig_clkdiv3().write(|w| unsafe { w.bits(div) }),
|
}
|
||||||
FilterClkSel::Clk4 => syscfg.ioconfig_clkdiv4().write(|w| unsafe { w.bits(div) }),
|
FilterClkSel::Clk2 => {
|
||||||
FilterClkSel::Clk5 => syscfg.ioconfig_clkdiv5().write(|w| unsafe { w.bits(div) }),
|
syscfg.ioconfig_clkdiv2().write(|w| unsafe { w.bits(div) });
|
||||||
FilterClkSel::Clk6 => syscfg.ioconfig_clkdiv6().write(|w| unsafe { w.bits(div) }),
|
}
|
||||||
FilterClkSel::Clk7 => syscfg.ioconfig_clkdiv7().write(|w| unsafe { w.bits(div) }),
|
FilterClkSel::Clk3 => {
|
||||||
|
syscfg.ioconfig_clkdiv3().write(|w| unsafe { w.bits(div) });
|
||||||
|
}
|
||||||
|
FilterClkSel::Clk4 => {
|
||||||
|
syscfg.ioconfig_clkdiv4().write(|w| unsafe { w.bits(div) });
|
||||||
|
}
|
||||||
|
FilterClkSel::Clk5 => {
|
||||||
|
syscfg.ioconfig_clkdiv5().write(|w| unsafe { w.bits(div) });
|
||||||
|
}
|
||||||
|
FilterClkSel::Clk6 => {
|
||||||
|
syscfg.ioconfig_clkdiv6().write(|w| unsafe { w.bits(div) });
|
||||||
|
}
|
||||||
|
FilterClkSel::Clk7 => {
|
||||||
|
syscfg.ioconfig_clkdiv7().write(|w| unsafe { w.bits(div) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
//! 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 one generic
|
||||||
//! [handler][handle_interrupt_for_async_gpio] which should be called in ALL user interrupt handlers
|
//! [handler][on_interrupt_for_asynch_gpio] which should be called in ALL user interrupt handlers
|
||||||
//! which handle GPIO interrupts.
|
//! which handle GPIO interrupts.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
@ -90,7 +90,7 @@ pub struct InputPinFuture {
|
|||||||
impl InputPinFuture {
|
impl InputPinFuture {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This calls [Self::new] but uses [pac::Peripherals::steal] to get the system configuration
|
/// This calls [Self::new_with_dyn_pin] but uses [pac::Peripherals::steal] to get the system configuration
|
||||||
/// and IRQ selection peripherals. Users must ensure that the registers and configuration
|
/// and IRQ selection peripherals. Users must ensure that the registers and configuration
|
||||||
/// related to this input pin are not being used elsewhere concurrently.
|
/// related to this input pin are not being used elsewhere concurrently.
|
||||||
pub unsafe fn new_unchecked_with_dyn_pin(
|
pub unsafe fn new_unchecked_with_dyn_pin(
|
||||||
@ -115,7 +115,7 @@ impl InputPinFuture {
|
|||||||
|
|
||||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.interrupt_edge(
|
pin.configure_edge_interrupt(
|
||||||
edge,
|
edge,
|
||||||
InterruptConfig::new(irq, true, true),
|
InterruptConfig::new(irq, true, true),
|
||||||
Some(sys_cfg),
|
Some(sys_cfg),
|
||||||
@ -127,7 +127,7 @@ impl InputPinFuture {
|
|||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This calls [Self::new] but uses [pac::Peripherals::steal] to get the system configuration
|
/// 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
|
/// and IRQ selection peripherals. Users must ensure that the registers and configuration
|
||||||
/// related to this input pin are not being used elsewhere concurrently.
|
/// related to this input pin are not being used elsewhere concurrently.
|
||||||
pub unsafe fn new_unchecked_with_pin<I: PinId, C: InputConfig>(
|
pub unsafe fn new_unchecked_with_pin<I: PinId, C: InputConfig>(
|
||||||
@ -200,7 +200,7 @@ 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 [handle_interrupt_for_async_gpio] function must be called inside that function for
|
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for
|
||||||
/// the asynchronous functionality to work.
|
/// 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() {
|
||||||
@ -335,7 +335,7 @@ 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 [handle_interrupt_for_async_gpio] function must be called inside that function for
|
/// generic [on_interrupt_for_asynch_gpio] function must be called inside that function for
|
||||||
/// the asynchronous functionality to work.
|
/// 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 }
|
||||||
|
@ -69,6 +69,7 @@ use crate::{clock::FilterClkSel, enable_nvic_interrupt, pac, FunSel, InterruptCo
|
|||||||
|
|
||||||
/// Value-level `enum` for disabled configurations
|
/// Value-level `enum` for disabled configurations
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum DynDisabled {
|
pub enum DynDisabled {
|
||||||
Floating,
|
Floating,
|
||||||
PullDown,
|
PullDown,
|
||||||
@ -156,14 +157,16 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// Value-level `enum` for pin groups
|
/// Value-level `enum` for pin groups
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum DynGroup {
|
pub enum DynGroup {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Value-level `struct` representing pin IDs
|
/// Value-level `struct` representing pin IDs
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct DynPinId {
|
pub struct DynPinId {
|
||||||
pub group: DynGroup,
|
pub group: DynGroup,
|
||||||
pub num: u8,
|
pub num: u8,
|
||||||
@ -177,6 +180,8 @@ pub struct DynPinId {
|
|||||||
///
|
///
|
||||||
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to
|
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to
|
||||||
/// access the corresponding regsiters.
|
/// access the corresponding regsiters.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub(crate) struct DynRegisters(DynPinId);
|
pub(crate) struct DynRegisters(DynPinId);
|
||||||
|
|
||||||
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
|
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
|
||||||
@ -209,6 +214,7 @@ impl DynRegisters {
|
|||||||
///
|
///
|
||||||
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented
|
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented
|
||||||
/// 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)]
|
||||||
pub struct DynPin {
|
pub struct DynPin {
|
||||||
pub(crate) regs: DynRegisters,
|
pub(crate) regs: DynRegisters,
|
||||||
mode: DynPinMode,
|
mode: DynPinMode,
|
||||||
@ -387,11 +393,15 @@ impl DynPin {
|
|||||||
/// - 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) -> Result<Self, InvalidPinTypeError> {
|
pub fn configure_delay(
|
||||||
|
&mut self,
|
||||||
|
delay_1: bool,
|
||||||
|
delay_2: bool,
|
||||||
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Output(_) => {
|
DynPinMode::Output(_) => {
|
||||||
self.regs.delay(delay_1, delay_2);
|
self.regs.configure_delay(delay_1, delay_2);
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(self.mode)),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
@ -401,7 +411,7 @@ impl DynPin {
|
|||||||
/// 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
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pulse_mode(
|
pub fn configure_pulse_mode(
|
||||||
&mut self,
|
&mut self,
|
||||||
enable: bool,
|
enable: bool,
|
||||||
default_state: PinState,
|
default_state: PinState,
|
||||||
@ -417,14 +427,14 @@ impl DynPin {
|
|||||||
|
|
||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filter_type(
|
pub fn configure_filter_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
filter: FilterType,
|
filter: FilterType,
|
||||||
clksel: FilterClkSel,
|
clksel: FilterClkSel,
|
||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) => {
|
DynPinMode::Input(_) => {
|
||||||
self.regs.filter_type(filter, clksel);
|
self.regs.configure_filter_type(filter, clksel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(self.mode)),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
@ -432,7 +442,7 @@ impl DynPin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn interrupt_edge(
|
pub fn configure_edge_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
@ -441,7 +451,7 @@ impl DynPin {
|
|||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -450,7 +460,7 @@ impl DynPin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn interrupt_level(
|
pub fn configure_level_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
@ -459,7 +469,7 @@ impl DynPin {
|
|||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ use paste::paste;
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptEdge {
|
pub enum InterruptEdge {
|
||||||
HighToLow,
|
HighToLow,
|
||||||
LowToHigh,
|
LowToHigh,
|
||||||
@ -96,12 +97,14 @@ pub enum InterruptEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptLevel {
|
pub enum InterruptLevel {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PinState {
|
pub enum PinState {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
@ -119,8 +122,11 @@ pub trait InputConfig: Sealed {
|
|||||||
const DYN: DynInput;
|
const DYN: DynInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Floating {}
|
pub enum Floating {}
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum PullDown {}
|
pub enum PullDown {}
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum PullUp {}
|
pub enum PullUp {}
|
||||||
|
|
||||||
impl InputConfig for Floating {
|
impl InputConfig for Floating {
|
||||||
@ -148,6 +154,7 @@ pub type InputPullUp = Input<PullUp>;
|
|||||||
///
|
///
|
||||||
/// Type `C` is one of three input configurations: [`Floating`], [`PullDown`] or
|
/// Type `C` is one of three input configurations: [`Floating`], [`PullDown`] or
|
||||||
/// [`PullUp`]
|
/// [`PullUp`]
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Input<C: InputConfig> {
|
pub struct Input<C: InputConfig> {
|
||||||
cfg: PhantomData<C>,
|
cfg: PhantomData<C>,
|
||||||
}
|
}
|
||||||
@ -177,13 +184,17 @@ pub trait OutputConfig: Sealed {
|
|||||||
pub trait ReadableOutput: Sealed {}
|
pub trait ReadableOutput: Sealed {}
|
||||||
|
|
||||||
/// Type-level variant of [`OutputConfig`] for a push-pull configuration
|
/// Type-level variant of [`OutputConfig`] for a push-pull configuration
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum PushPull {}
|
pub enum PushPull {}
|
||||||
/// Type-level variant of [`OutputConfig`] for an open drain configuration
|
/// Type-level variant of [`OutputConfig`] for an open drain configuration
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum OpenDrain {}
|
pub enum OpenDrain {}
|
||||||
|
|
||||||
/// Type-level variant of [`OutputConfig`] for a readable push-pull configuration
|
/// Type-level variant of [`OutputConfig`] for a readable push-pull configuration
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ReadablePushPull {}
|
pub enum ReadablePushPull {}
|
||||||
/// Type-level variant of [`OutputConfig`] for a readable open-drain configuration
|
/// Type-level variant of [`OutputConfig`] for a readable open-drain configuration
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ReadableOpenDrain {}
|
pub enum ReadableOpenDrain {}
|
||||||
|
|
||||||
impl Sealed for PushPull {}
|
impl Sealed for PushPull {}
|
||||||
@ -210,6 +221,7 @@ impl OutputConfig for ReadableOpenDrain {
|
|||||||
///
|
///
|
||||||
/// Type `C` is one of four output configurations: [`PushPull`], [`OpenDrain`] or
|
/// Type `C` is one of four output configurations: [`PushPull`], [`OpenDrain`] or
|
||||||
/// their respective readable versions
|
/// their respective readable versions
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Output<C: OutputConfig> {
|
pub struct Output<C: OutputConfig> {
|
||||||
cfg: PhantomData<C>,
|
cfg: PhantomData<C>,
|
||||||
}
|
}
|
||||||
@ -304,6 +316,7 @@ macro_rules! pin_id {
|
|||||||
// Need paste macro to use ident in doc attribute
|
// Need paste macro to use ident in doc attribute
|
||||||
paste! {
|
paste! {
|
||||||
#[doc = "Pin ID representing pin " $Id]
|
#[doc = "Pin ID representing pin " $Id]
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum $Id {}
|
pub enum $Id {}
|
||||||
impl Sealed for $Id {}
|
impl Sealed for $Id {}
|
||||||
impl PinId for $Id {
|
impl PinId for $Id {
|
||||||
@ -321,6 +334,7 @@ macro_rules! pin_id {
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/// A type-level GPIO pin, parameterized by [PinId] and [PinMode] types
|
/// A type-level GPIO pin, parameterized by [PinId] and [PinMode] types
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Pin<I: PinId, M: PinMode> {
|
pub struct Pin<I: PinId, M: PinMode> {
|
||||||
inner: DynPin,
|
inner: DynPin,
|
||||||
phantom: PhantomData<(I, M)>,
|
phantom: PhantomData<(I, M)>,
|
||||||
@ -342,6 +356,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn id(&self) -> DynPinId {
|
pub fn id(&self) -> DynPinId {
|
||||||
self.inner.id()
|
self.inner.id()
|
||||||
}
|
}
|
||||||
@ -471,11 +486,6 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
self.inner.regs.write_pin(false)
|
self.inner.regs.write_pin(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn _toggle_with_toggle_reg(&mut self) {
|
|
||||||
self.inner.regs.toggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _is_low(&self) -> bool {
|
pub(crate) fn _is_low(&self) -> bool {
|
||||||
!self.inner.regs.read_pin()
|
!self.inner.regs.read_pin()
|
||||||
@ -588,7 +598,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +609,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_level(level_type);
|
self.inner.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,23 +621,34 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
/// - 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.regs.configure_delay(delay_1, delay_2);
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn toggle_with_toggle_reg(&mut self) {
|
pub fn toggle_with_toggle_reg(&mut self) {
|
||||||
self._toggle_with_toggle_reg()
|
self.inner.regs.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_pulse_mode` method instead"
|
||||||
|
)]
|
||||||
|
pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
||||||
|
self.configure_pulse_mode(enable, default_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.regs.pulse_mode(enable, default_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_edge_interrupt` method instead"
|
||||||
|
)]
|
||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
@ -635,18 +656,43 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn configure_edge_interrupt(
|
||||||
|
&mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
irq_cfg: InterruptConfig,
|
||||||
|
syscfg: Option<&mut Sysconfig>,
|
||||||
|
irqsel: Option<&mut Irqsel>,
|
||||||
|
) {
|
||||||
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_level_interrupt` method instead"
|
||||||
|
)]
|
||||||
|
pub fn level_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_level(level_type);
|
self.configure_level_interrupt(level_type, 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.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,7 +701,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.regs.configure_filter_type(filter, clksel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,6 +787,7 @@ macro_rules! pins {
|
|||||||
) => {
|
) => {
|
||||||
paste!(
|
paste!(
|
||||||
/// Collection of all the individual [`Pin`]s for a given port (PORTA or PORTB)
|
/// Collection of all the individual [`Pin`]s for a given port (PORTA or PORTB)
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct $PinsName {
|
pub struct $PinsName {
|
||||||
port: $Port,
|
port: $Port,
|
||||||
$(
|
$(
|
||||||
|
@ -240,7 +240,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
|
/// 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
|
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
|
fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -267,7 +267,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Configure which edge or level type triggers an interrupt
|
/// Configure which edge or level type triggers an interrupt
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_level(&mut self, level: InterruptLevel) {
|
fn configure_level_interrupt(&mut self, level: InterruptLevel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -286,7 +286,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Only useful for input pins
|
/// Only useful for input pins
|
||||||
#[inline]
|
#[inline]
|
||||||
fn filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.iocfg_port().modify(|_, w| {
|
self.iocfg_port().modify(|_, w| {
|
||||||
// Safety: Only write to register for this Pin ID
|
// Safety: Only write to register for this Pin ID
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -304,7 +304,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
unsafe {
|
unsafe {
|
||||||
portreg
|
portreg
|
||||||
.datamask()
|
.datamask()
|
||||||
.modify(|r, w| w.bits(r.bits() | self.mask_32()))
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
unsafe {
|
unsafe {
|
||||||
portreg
|
portreg
|
||||||
.datamask()
|
.datamask()
|
||||||
.modify(|r, w| w.bits(r.bits() & !self.mask_32()))
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Only useful for output pins
|
/// Only useful for output pins
|
||||||
fn delay(&self, delay_1: bool, delay_2: bool) {
|
fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
|
||||||
let portreg = self.port_reg();
|
let portreg = self.port_reg();
|
||||||
unsafe {
|
unsafe {
|
||||||
if delay_1 {
|
if delay_1 {
|
||||||
|
@ -18,6 +18,7 @@ const CLK_400K: Hertz = Hertz::from_raw(400_000);
|
|||||||
const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000);
|
const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum FifoEmptyMode {
|
pub enum FifoEmptyMode {
|
||||||
Stall = 0,
|
Stall = 0,
|
||||||
EndTransaction = 1,
|
EndTransaction = 1,
|
||||||
@ -35,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")]
|
||||||
@ -81,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,
|
||||||
@ -89,18 +89,21 @@ enum I2cCmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum I2cSpeed {
|
pub enum I2cSpeed {
|
||||||
Regular100khz = 0,
|
Regular100khz = 0,
|
||||||
Fast400khz = 1,
|
Fast400khz = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum I2cDirection {
|
pub enum I2cDirection {
|
||||||
Send = 0,
|
Send = 0,
|
||||||
Read = 1,
|
Read = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum I2cAddress {
|
pub enum I2cAddress {
|
||||||
Regular(u8),
|
Regular(u8),
|
||||||
TenBit(u16),
|
TenBit(u16),
|
||||||
@ -141,9 +144,12 @@ impl Instance for pac::I2cb {
|
|||||||
// Config
|
// Config
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct TrTfThighTlow(u8, u8, u8, u8);
|
pub struct TrTfThighTlow(u8, u8, u8, u8);
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct TsuStoTsuStaThdStaTBuf(u8, u8, u8, u8);
|
pub struct TsuStoTsuStaThdStaTBuf(u8, u8, u8, u8);
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct TimingCfg {
|
pub struct TimingCfg {
|
||||||
// 4 bit max width
|
// 4 bit max width
|
||||||
tr: u8,
|
tr: u8,
|
||||||
@ -218,6 +224,7 @@ impl Default for TimingCfg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct MasterConfig {
|
pub struct MasterConfig {
|
||||||
pub tx_fe_mode: FifoEmptyMode,
|
pub tx_fe_mode: FifoEmptyMode,
|
||||||
pub rx_fe_mode: FifoEmptyMode,
|
pub rx_fe_mode: FifoEmptyMode,
|
||||||
@ -244,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,
|
||||||
@ -384,12 +393,12 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b);
|
let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b);
|
||||||
self.i2c
|
self.i2c
|
||||||
.s0_addressb()
|
.s0_addressb()
|
||||||
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) })
|
.write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) });
|
||||||
}
|
}
|
||||||
if let Some(addr_b_mask) = sl_cfg.addr_b_mask {
|
if let Some(addr_b_mask) = sl_cfg.addr_b_mask {
|
||||||
self.i2c
|
self.i2c
|
||||||
.s0_addressmaskb()
|
.s0_addressmaskb()
|
||||||
.write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) })
|
.write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,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
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -665,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
|
||||||
//======================================================================================
|
//======================================================================================
|
||||||
|
@ -31,7 +31,7 @@ pub enum PortSel {
|
|||||||
PortB,
|
PortB,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(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 PeripheralSelect {
|
pub enum PeripheralSelect {
|
||||||
PortA = 0,
|
PortA = 0,
|
||||||
@ -51,9 +51,10 @@ pub enum PeripheralSelect {
|
|||||||
|
|
||||||
/// Generic interrupt config which can be used to specify whether the HAL driver will
|
/// Generic interrupt config which can be used to specify whether the HAL driver will
|
||||||
/// use the IRQSEL register to route an interrupt, and whether the IRQ will be unmasked in the
|
/// use the IRQSEL register to route an interrupt, and whether the IRQ will be unmasked in the
|
||||||
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might perform
|
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
|
||||||
/// this 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,
|
||||||
@ -77,6 +78,7 @@ impl InterruptConfig {
|
|||||||
pub type IrqCfg = InterruptConfig;
|
pub type IrqCfg = InterruptConfig;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct InvalidPin(pub(crate) ());
|
pub struct InvalidPin(pub(crate) ());
|
||||||
|
|
||||||
/// Can be used to manually manipulate the function select of port pins
|
/// Can be used to manually manipulate the function select of port pins
|
||||||
|
@ -15,7 +15,9 @@ use crate::{clock::enable_peripheral_clock, gpio::DynPinId};
|
|||||||
|
|
||||||
const DUTY_MAX: u16 = u16::MAX;
|
const DUTY_MAX: u16 = u16::MAX;
|
||||||
|
|
||||||
pub struct PwmCommon {
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub(crate) struct PwmCommon {
|
||||||
sys_clk: Hertz,
|
sys_clk: Hertz,
|
||||||
/// For PWMB, this is the upper limit
|
/// For PWMB, this is the upper limit
|
||||||
current_duty: u16,
|
current_duty: u16,
|
||||||
|
@ -33,10 +33,12 @@ 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;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum HwChipSelectId {
|
pub enum HwChipSelectId {
|
||||||
Id0 = 0,
|
Id0 = 0,
|
||||||
Id1 = 1,
|
Id1 = 1,
|
||||||
@ -50,6 +52,7 @@ pub enum HwChipSelectId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum SpiPort {
|
pub enum SpiPort {
|
||||||
Porta = 0,
|
Porta = 0,
|
||||||
Portb = 1,
|
Portb = 1,
|
||||||
@ -58,6 +61,7 @@ pub enum SpiPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum WordSize {
|
pub enum WordSize {
|
||||||
OneBit = 0x00,
|
OneBit = 0x00,
|
||||||
FourBits = 0x03,
|
FourBits = 0x03,
|
||||||
@ -285,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,
|
||||||
@ -293,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>,
|
||||||
@ -380,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
|
||||||
@ -529,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),
|
||||||
@ -572,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,
|
||||||
@ -789,7 +799,7 @@ where
|
|||||||
// initialization. Returns the amount of written bytes.
|
// initialization. Returns the amount of written bytes.
|
||||||
fn initial_send_fifo_pumping_with_words(&self, words: &[Word]) -> usize {
|
fn initial_send_fifo_pumping_with_words(&self, words: &[Word]) -> usize {
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit())
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit());
|
||||||
}
|
}
|
||||||
// Fill the first half of the write FIFO
|
// Fill the first half of the write FIFO
|
||||||
let mut current_write_idx = 0;
|
let mut current_write_idx = 0;
|
||||||
@ -803,7 +813,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit())
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit());
|
||||||
}
|
}
|
||||||
current_write_idx
|
current_write_idx
|
||||||
}
|
}
|
||||||
@ -812,7 +822,7 @@ where
|
|||||||
// initialization.
|
// initialization.
|
||||||
fn initial_send_fifo_pumping_with_fill_words(&self, send_len: usize) -> usize {
|
fn initial_send_fifo_pumping_with_fill_words(&self, send_len: usize) -> usize {
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit())
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().set_bit());
|
||||||
}
|
}
|
||||||
// Fill the first half of the write FIFO
|
// Fill the first half of the write FIFO
|
||||||
let mut current_write_idx = 0;
|
let mut current_write_idx = 0;
|
||||||
@ -826,7 +836,7 @@ where
|
|||||||
current_write_idx += 1;
|
current_write_idx += 1;
|
||||||
}
|
}
|
||||||
if self.blockmode {
|
if self.blockmode {
|
||||||
self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit())
|
self.spi.ctrl1().modify(|_, w| w.mtxpause().clear_bit());
|
||||||
}
|
}
|
||||||
current_write_idx
|
current_write_idx
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub fn enable_rom_scrubbing(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_rom_scrubbing(syscfg: &mut pac::Sysconfig) {
|
pub fn disable_rom_scrubbing(syscfg: &mut pac::Sysconfig) {
|
||||||
syscfg.rom_scrub().write(|w| unsafe { w.bits(0) })
|
syscfg.rom_scrub().write(|w| unsafe { w.bits(0) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable scrubbing for the RAM
|
/// Enable scrubbing for the RAM
|
||||||
@ -39,7 +39,7 @@ pub fn enable_ram_scrubbing(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_ram_scrubbing(syscfg: &mut pac::Sysconfig) {
|
pub fn disable_ram_scrubbing(syscfg: &mut pac::Sysconfig) {
|
||||||
syscfg.ram_scrub().write(|w| unsafe { w.bits(0) })
|
syscfg.ram_scrub().write(|w| unsafe { w.bits(0) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the reset bit. This register is active low, so doing this will hold the peripheral
|
/// Clear the reset bit. This register is active low, so doing this will hold the peripheral
|
||||||
|
@ -79,6 +79,7 @@ pub enum Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct CascadeCtrl {
|
pub struct CascadeCtrl {
|
||||||
/// Enable Cascade 0 signal active as a requirement for counting
|
/// Enable Cascade 0 signal active as a requirement for counting
|
||||||
pub enb_start_src_csd0: bool,
|
pub enb_start_src_csd0: bool,
|
||||||
@ -108,6 +109,7 @@ pub struct CascadeCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum CascadeSel {
|
pub enum CascadeSel {
|
||||||
Csd0 = 0,
|
Csd0 = 0,
|
||||||
Csd1 = 1,
|
Csd1 = 1,
|
||||||
@ -319,7 +321,7 @@ pub unsafe trait TimRegInterface {
|
|||||||
va108xx::Peripherals::steal()
|
va108xx::Peripherals::steal()
|
||||||
.sysconfig
|
.sysconfig
|
||||||
.tim_reset()
|
.tim_reset()
|
||||||
.modify(|r, w| w.bits(r.bits() & !self.mask_32()))
|
.modify(|r, w| w.bits(r.bits() & !self.mask_32()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +332,7 @@ pub unsafe trait TimRegInterface {
|
|||||||
va108xx::Peripherals::steal()
|
va108xx::Peripherals::steal()
|
||||||
.sysconfig
|
.sysconfig
|
||||||
.tim_reset()
|
.tim_reset()
|
||||||
.modify(|r, w| w.bits(r.bits() | self.mask_32()))
|
.modify(|r, w| w.bits(r.bits() | self.mask_32()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
//! - [Flashloader exposing a CCSDS interface via UART](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
|
//! - [Flashloader exposing a CCSDS interface via UART](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
|
||||||
use core::{convert::Infallible, ops::Deref};
|
use core::{convert::Infallible, ops::Deref};
|
||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
use va108xx::Uarta;
|
|
||||||
|
|
||||||
pub use crate::InterruptConfig;
|
pub use crate::InterruptConfig;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -23,6 +22,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use embedded_hal_nb::serial::Read;
|
use embedded_hal_nb::serial::Read;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Bank {
|
||||||
|
A = 0,
|
||||||
|
B = 1,
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Type-Level support
|
// Type-Level support
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -232,6 +238,7 @@ impl From<Hertz> for Config {
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct IrqContextTimeoutOrMaxSize {
|
pub struct IrqContextTimeoutOrMaxSize {
|
||||||
rx_idx: usize,
|
rx_idx: usize,
|
||||||
mode: IrqReceptionMode,
|
mode: IrqReceptionMode,
|
||||||
@ -257,17 +264,19 @@ impl IrqContextTimeoutOrMaxSize {
|
|||||||
|
|
||||||
/// This struct is used to return the default IRQ handler result to the user
|
/// This struct is used to return the default IRQ handler result to the user
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct IrqResult {
|
pub struct IrqResult {
|
||||||
pub bytes_read: usize,
|
pub bytes_read: usize,
|
||||||
pub errors: Option<IrqUartError>,
|
pub errors: Option<UartErrors>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This struct is used to return the default IRQ handler result to the user
|
/// This struct is used to return the default IRQ handler result to the user
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct IrqResultMaxSizeOrTimeout {
|
pub struct IrqResultMaxSizeOrTimeout {
|
||||||
complete: bool,
|
complete: bool,
|
||||||
timeout: bool,
|
timeout: bool,
|
||||||
pub errors: Option<IrqUartError>,
|
pub errors: Option<UartErrors>,
|
||||||
pub bytes_read: usize,
|
pub bytes_read: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,20 +323,22 @@ impl IrqResultMaxSizeOrTimeout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
enum IrqReceptionMode {
|
enum IrqReceptionMode {
|
||||||
Idle,
|
Idle,
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
pub struct IrqUartError {
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct UartErrors {
|
||||||
overflow: bool,
|
overflow: bool,
|
||||||
framing: bool,
|
framing: bool,
|
||||||
parity: bool,
|
parity: bool,
|
||||||
other: bool,
|
other: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqUartError {
|
impl UartErrors {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn overflow(&self) -> bool {
|
pub fn overflow(&self) -> bool {
|
||||||
self.overflow
|
self.overflow
|
||||||
@ -349,7 +360,7 @@ impl IrqUartError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqUartError {
|
impl UartErrors {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn error(&self) -> bool {
|
pub fn error(&self) -> bool {
|
||||||
self.overflow || self.framing || self.parity
|
self.overflow || self.framing || self.parity
|
||||||
@ -401,7 +412,7 @@ impl Instance for pac::Uarta {
|
|||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uarta::ptr() as *const _
|
Self::ptr() as *const _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +427,7 @@ impl Instance for pac::Uartb {
|
|||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ptr() -> *const uart_base::RegisterBlock {
|
fn ptr() -> *const uart_base::RegisterBlock {
|
||||||
Uarta::ptr() as *const _
|
Self::ptr() as *const _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,6 +763,34 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_rx(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.enable().modify(|_, w| w.rxenable().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable_rx(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.enable().modify(|_, w| w.rxenable().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_rx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.irq_enb().modify(|_, w| {
|
||||||
|
w.irq_rx().set_bit();
|
||||||
|
w.irq_rx_to().set_bit();
|
||||||
|
w.irq_rx_status().set_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn disable_rx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
|
uart.irq_enb().modify(|_, w| {
|
||||||
|
w.irq_rx().clear_bit();
|
||||||
|
w.irq_rx_to().clear_bit();
|
||||||
|
w.irq_rx_status().clear_bit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -760,6 +799,7 @@ pub struct Rx<Uart> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Uart: Instance> Rx<Uart> {
|
impl<Uart: Instance> Rx<Uart> {
|
||||||
|
#[inline(always)]
|
||||||
fn new(uart: Uart) -> Self {
|
fn new(uart: Uart) -> Self {
|
||||||
Self { uart }
|
Self { uart }
|
||||||
}
|
}
|
||||||
@ -769,6 +809,7 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// 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)]
|
||||||
pub unsafe fn uart(&self) -> &Uart {
|
pub unsafe fn uart(&self) -> &Uart {
|
||||||
&self.uart
|
&self.uart
|
||||||
}
|
}
|
||||||
@ -778,14 +819,23 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
self.uart.fifo_clr().write(|w| w.rxfifo().set_bit());
|
self.uart.fifo_clr().write(|w| w.rxfifo().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_interrupts(&mut self) {
|
||||||
|
disable_rx_interrupts(unsafe { Uart::reg_block() });
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_interrupts(&mut self) {
|
||||||
|
enable_rx_interrupts(unsafe { Uart::reg_block() });
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
self.uart.enable().modify(|_, w| w.rxenable().set_bit());
|
enable_rx(unsafe { Uart::reg_block() });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable(&mut self) {
|
pub fn disable(&mut self) {
|
||||||
self.uart.enable().modify(|_, w| w.rxenable().clear_bit());
|
disable_rx(unsafe { Uart::reg_block() });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Low level function to read a word from the UART FIFO.
|
/// Low level function to read a word from the UART FIFO.
|
||||||
@ -819,6 +869,7 @@ impl<Uart: Instance> Rx<Uart> {
|
|||||||
RxWithInterrupt::new(self)
|
RxWithInterrupt::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn release(self) -> Uart {
|
pub fn release(self) -> Uart {
|
||||||
self.uart
|
self.uart
|
||||||
}
|
}
|
||||||
@ -877,14 +928,17 @@ impl<Uart: Instance> embedded_io::Read for Rx<Uart> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn enable_tx(uart: &uart_base::RegisterBlock) {
|
pub fn enable_tx(uart: &uart_base::RegisterBlock) {
|
||||||
uart.enable().modify(|_, w| w.txenable().set_bit());
|
uart.enable().modify(|_, w| w.txenable().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn disable_tx(uart: &uart_base::RegisterBlock) {
|
pub fn disable_tx(uart: &uart_base::RegisterBlock) {
|
||||||
uart.enable().modify(|_, w| w.txenable().clear_bit());
|
uart.enable().modify(|_, w| w.txenable().clear_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn enable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
pub fn enable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
uart.irq_enb().modify(|_, w| {
|
uart.irq_enb().modify(|_, w| {
|
||||||
w.irq_tx().set_bit();
|
w.irq_tx().set_bit();
|
||||||
@ -893,6 +947,7 @@ pub fn enable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn disable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
pub fn disable_tx_interrupts(uart: &uart_base::RegisterBlock) {
|
||||||
uart.irq_enb().modify(|_, w| {
|
uart.irq_enb().modify(|_, w| {
|
||||||
w.irq_tx().clear_bit();
|
w.irq_tx().clear_bit();
|
||||||
@ -914,12 +969,14 @@ impl<Uart: Instance> Tx<Uart> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Circumvents the HAL safety guarantees.
|
/// Circumvents the HAL safety guarantees.
|
||||||
|
#[inline(always)]
|
||||||
pub unsafe fn steal() -> Self {
|
pub unsafe fn steal() -> Self {
|
||||||
Self {
|
Self {
|
||||||
uart: Uart::steal(),
|
uart: Uart::steal(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn new(uart: Uart) -> Self {
|
fn new(uart: Uart) -> Self {
|
||||||
Self { uart }
|
Self { uart }
|
||||||
}
|
}
|
||||||
@ -929,6 +986,7 @@ impl<Uart: Instance> Tx<Uart> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// 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)]
|
||||||
pub unsafe fn uart(&self) -> &Uart {
|
pub unsafe fn uart(&self) -> &Uart {
|
||||||
&self.uart
|
&self.uart
|
||||||
}
|
}
|
||||||
@ -1055,10 +1113,10 @@ impl<Uart: Instance> embedded_io::Write for Tx<Uart> {
|
|||||||
///
|
///
|
||||||
/// 1. The first way simply empties the FIFO on an interrupt into a user provided buffer. You
|
/// 1. The first way simply empties the FIFO on an interrupt into a user provided buffer. You
|
||||||
/// can simply use [Self::start] to prepare the peripheral and then call the
|
/// can simply use [Self::start] to prepare the peripheral and then call the
|
||||||
/// [Self::irq_handler] in the interrupt service routine.
|
/// [Self::on_interrupt] in the interrupt service routine.
|
||||||
/// 2. The second way reads packets bounded by a maximum size or a baudtick based timeout. You
|
/// 2. The second way reads packets bounded by a maximum size or a baudtick based timeout. You
|
||||||
/// can use [Self::read_fixed_len_or_timeout_based_using_irq] to prepare the peripheral and
|
/// can use [Self::read_fixed_len_or_timeout_based_using_irq] to prepare the peripheral and
|
||||||
/// then call the [Self::irq_handler_max_size_or_timeout_based] in the interrupt service
|
/// then call the [Self::on_interrupt_max_size_or_timeout_based] in the interrupt service
|
||||||
/// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
|
/// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
|
||||||
/// start reading the next packet.
|
/// start reading the next packet.
|
||||||
pub struct RxWithInterrupt<Uart>(Rx<Uart>);
|
pub struct RxWithInterrupt<Uart>(Rx<Uart>);
|
||||||
@ -1069,7 +1127,7 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This function should be called once at initialization time if the regular
|
/// This function should be called once at initialization time if the regular
|
||||||
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
|
/// [Self::on_interrupt] is used to read the UART receiver to enable and start the receiver.
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.0.enable();
|
self.0.enable();
|
||||||
self.enable_rx_irq_sources(true);
|
self.enable_rx_irq_sources(true);
|
||||||
@ -1080,13 +1138,13 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
&self.0.uart
|
&self.0.uart
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is used together with the [Self::irq_handler_max_size_or_timeout_based]
|
/// This function is used together with the [Self::on_interrupt_max_size_or_timeout_based]
|
||||||
/// function to read packets with a maximum size or variable sized packets by using the
|
/// function to read packets with a maximum size or variable sized packets by using the
|
||||||
/// receive timeout of the hardware.
|
/// receive timeout of the hardware.
|
||||||
///
|
///
|
||||||
/// This function should be called once at initialization to initiate the context state
|
/// This function should be called once at initialization to initiate the context state
|
||||||
/// and to [Self::start] the receiver. After that, it should be called after each
|
/// and to [Self::start] the receiver. After that, it should be called after each
|
||||||
/// completed [Self::irq_handler_max_size_or_timeout_based] call to restart the reception
|
/// completed [Self::on_interrupt_max_size_or_timeout_based] call to restart the reception
|
||||||
/// of a packet.
|
/// of a packet.
|
||||||
pub fn read_fixed_len_or_timeout_based_using_irq(
|
pub fn read_fixed_len_or_timeout_based_using_irq(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1266,7 +1324,7 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
|
|
||||||
fn read_handler(
|
fn read_handler(
|
||||||
&self,
|
&self,
|
||||||
errors: &mut Option<IrqUartError>,
|
errors: &mut Option<UartErrors>,
|
||||||
read_res: &nb::Result<u8, RxError>,
|
read_res: &nb::Result<u8, RxError>,
|
||||||
) -> Option<u8> {
|
) -> Option<u8> {
|
||||||
match read_res {
|
match read_res {
|
||||||
@ -1274,7 +1332,7 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
Err(nb::Error::WouldBlock) => None,
|
Err(nb::Error::WouldBlock) => None,
|
||||||
Err(nb::Error::Other(e)) => {
|
Err(nb::Error::Other(e)) => {
|
||||||
// Ensure `errors` is Some(IrqUartError), initializing if it's None
|
// Ensure `errors` is Some(IrqUartError), initializing if it's None
|
||||||
let err = errors.get_or_insert(IrqUartError::default());
|
let err = errors.get_or_insert(UartErrors::default());
|
||||||
|
|
||||||
// Now we can safely modify fields inside `err`
|
// Now we can safely modify fields inside `err`
|
||||||
match e {
|
match e {
|
||||||
@ -1287,14 +1345,14 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_errors(&self, errors: &mut Option<IrqUartError>) {
|
fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
|
||||||
let rx_status = self.uart().rxstatus().read();
|
let rx_status = self.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()
|
||||||
|| rx_status.rxpar().bit_is_set()
|
|| rx_status.rxpar().bit_is_set()
|
||||||
{
|
{
|
||||||
let err = errors.get_or_insert(IrqUartError::default());
|
let err = errors.get_or_insert(UartErrors::default());
|
||||||
|
|
||||||
if rx_status.rxovr().bit_is_set() {
|
if rx_status.rxovr().bit_is_set() {
|
||||||
err.overflow = true;
|
err.overflow = true;
|
||||||
@ -1331,5 +1389,8 @@ impl<Uart: Instance> RxWithInterrupt<Uart> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod asynch;
|
pub mod tx_asynch;
|
||||||
pub use asynch::*;
|
pub use tx_asynch::*;
|
||||||
|
|
||||||
|
pub mod rx_asynch;
|
||||||
|
pub use rx_asynch::*;
|
||||||
|
419
va108xx-hal/src/uart/rx_asynch.rs
Normal file
419
va108xx-hal/src/uart/rx_asynch.rs
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
//! # Async UART reception functionality for the VA108xx family.
|
||||||
|
//!
|
||||||
|
//! This module provides the [RxAsync] and [RxAsyncSharedConsumer] struct which both implement the
|
||||||
|
//! [embedded_io_async::Read] trait.
|
||||||
|
//! 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.
|
||||||
|
//! However, it provides four interrupt handlers:
|
||||||
|
//!
|
||||||
|
//! - [on_interrupt_uart_a]
|
||||||
|
//! - [on_interrupt_uart_b]
|
||||||
|
//! - [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
|
||||||
|
//! [RxAsyncSharedConsumer] 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]
|
||||||
|
//! structure returned by the interrupt handlers.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! - [Async UART RX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-rx.rs)
|
||||||
|
use core::{cell::RefCell, convert::Infallible, future::Future, sync::atomic::Ordering};
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
use embedded_io::ErrorType;
|
||||||
|
use heapless::spsc::Consumer;
|
||||||
|
use portable_atomic::AtomicBool;
|
||||||
|
use va108xx as pac;
|
||||||
|
|
||||||
|
use super::{Instance, Rx, RxError, UartErrors};
|
||||||
|
|
||||||
|
static UART_RX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
|
||||||
|
static RX_READ_ACTIVE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||||
|
static RX_HAS_DATA: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2];
|
||||||
|
|
||||||
|
struct RxFuture {
|
||||||
|
uart_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxFuture {
|
||||||
|
pub fn new<Uart: Instance>(_rx: &mut Rx<Uart>) -> Self {
|
||||||
|
RX_READ_ACTIVE[Uart::IDX as usize].store(true, Ordering::Relaxed);
|
||||||
|
Self {
|
||||||
|
uart_idx: Uart::IDX as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for RxFuture {
|
||||||
|
type Output = Result<(), RxError>;
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> core::task::Poll<Self::Output> {
|
||||||
|
UART_RX_WAKERS[self.uart_idx].register(cx.waker());
|
||||||
|
if RX_HAS_DATA[self.uart_idx].load(Ordering::Relaxed) {
|
||||||
|
return core::task::Poll::Ready(Ok(()));
|
||||||
|
}
|
||||||
|
core::task::Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct AsyncUartErrors {
|
||||||
|
/// Queue has overflowed, data might have been lost.
|
||||||
|
pub queue_overflow: bool,
|
||||||
|
/// UART errors.
|
||||||
|
pub uart_errors: UartErrors,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_interrupt_handle_rx_errors<Uart: Instance>(uart: &Uart) -> Option<UartErrors> {
|
||||||
|
let rx_status = uart.rxstatus().read();
|
||||||
|
if rx_status.rxovr().bit_is_set()
|
||||||
|
|| rx_status.rxfrm().bit_is_set()
|
||||||
|
|| rx_status.rxpar().bit_is_set()
|
||||||
|
{
|
||||||
|
let mut errors_val = UartErrors::default();
|
||||||
|
|
||||||
|
if rx_status.rxovr().bit_is_set() {
|
||||||
|
errors_val.overflow = true;
|
||||||
|
}
|
||||||
|
if rx_status.rxfrm().bit_is_set() {
|
||||||
|
errors_val.framing = true;
|
||||||
|
}
|
||||||
|
if rx_status.rxpar().bit_is_set() {
|
||||||
|
errors_val.parity = true;
|
||||||
|
}
|
||||||
|
return Some(errors_val);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_interrupt_rx_common_post_processing<Uart: Instance>(
|
||||||
|
uart: &Uart,
|
||||||
|
rx_enabled: bool,
|
||||||
|
read_some_data: bool,
|
||||||
|
irq_end: u32,
|
||||||
|
) -> Option<UartErrors> {
|
||||||
|
if read_some_data {
|
||||||
|
RX_HAS_DATA[Uart::IDX as usize].store(true, Ordering::Relaxed);
|
||||||
|
if RX_READ_ACTIVE[Uart::IDX as usize].load(Ordering::Relaxed) {
|
||||||
|
UART_RX_WAKERS[Uart::IDX as usize].wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut errors = None;
|
||||||
|
// Check for RX errors
|
||||||
|
if rx_enabled {
|
||||||
|
errors = on_interrupt_handle_rx_errors(uart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the interrupt status bits
|
||||||
|
uart.irq_clr().write(|w| unsafe { w.bits(irq_end) });
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler for UART A.
|
||||||
|
///
|
||||||
|
/// 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_a_overwriting<const N: usize>(
|
||||||
|
prod: &mut heapless::spsc::Producer<u8, N>,
|
||||||
|
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue_overwriting(
|
||||||
|
unsafe { pac::Uarta::steal() },
|
||||||
|
prod,
|
||||||
|
shared_consumer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler for UART B.
|
||||||
|
///
|
||||||
|
/// 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>,
|
||||||
|
shared_consumer: &Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue_overwriting(
|
||||||
|
unsafe { pac::Uartb::steal() },
|
||||||
|
prod,
|
||||||
|
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 mut read_some_data = false;
|
||||||
|
let mut queue_overflow = false;
|
||||||
|
|
||||||
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
|
if irq_end.irq_rx().bit_is_set() {
|
||||||
|
let available_bytes = uart.rxfifoirqtrg().read().bits() as usize;
|
||||||
|
|
||||||
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
|
// Read everything as fast as possible
|
||||||
|
for _ in 0..available_bytes {
|
||||||
|
let byte = uart.data().read().bits();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut cons_ref = shared_consumer.borrow(cs).borrow_mut();
|
||||||
|
cons_ref.as_mut().unwrap().dequeue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prod.enqueue(byte as u8).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout, empty the FIFO completely.
|
||||||
|
if irq_end.irq_rx_to().bit_is_set() {
|
||||||
|
while uart.rxstatus().read().rdavl().bit_is_set() {
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
let byte = uart.data().read().bits();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut cons_ref = shared_consumer.borrow(cs).borrow_mut();
|
||||||
|
cons_ref.as_mut().unwrap().dequeue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prod.enqueue(byte as u8).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uart_errors =
|
||||||
|
on_interrupt_rx_common_post_processing(&uart, rx_enabled, read_some_data, irq_end.bits());
|
||||||
|
if uart_errors.is_some() || queue_overflow {
|
||||||
|
return Err(AsyncUartErrors {
|
||||||
|
queue_overflow,
|
||||||
|
uart_errors: uart_errors.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler for UART A.
|
||||||
|
///
|
||||||
|
/// Should be called in the user interrupt handler to enable asynchronous reception.
|
||||||
|
pub fn on_interrupt_uart_a<const N: usize>(
|
||||||
|
prod: &mut heapless::spsc::Producer<'_, u8, N>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue(unsafe { pac::Uarta::steal() }, prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler for UART B.
|
||||||
|
///
|
||||||
|
/// 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>,
|
||||||
|
) -> Result<(), AsyncUartErrors> {
|
||||||
|
on_interrupt_rx_async_heapless_queue(unsafe { pac::Uartb::steal() }, prod)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 enb_status = uart.enable().read();
|
||||||
|
let rx_enabled = enb_status.rxenable().bit_is_set();
|
||||||
|
let mut read_some_data = false;
|
||||||
|
let mut queue_overflow = false;
|
||||||
|
|
||||||
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
|
if irq_end.irq_rx().bit_is_set() {
|
||||||
|
let available_bytes = uart.rxfifoirqtrg().read().bits() as usize;
|
||||||
|
|
||||||
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
|
// Read everything as fast as possible
|
||||||
|
for _ in 0..available_bytes {
|
||||||
|
let byte = uart.data().read().bits();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
}
|
||||||
|
prod.enqueue(byte as u8).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout, empty the FIFO completely.
|
||||||
|
if irq_end.irq_rx_to().bit_is_set() {
|
||||||
|
while uart.rxstatus().read().rdavl().bit_is_set() {
|
||||||
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
|
let byte = uart.data().read().bits();
|
||||||
|
if !prod.ready() {
|
||||||
|
queue_overflow = true;
|
||||||
|
}
|
||||||
|
prod.enqueue(byte as u8).ok();
|
||||||
|
}
|
||||||
|
read_some_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uart_errors =
|
||||||
|
on_interrupt_rx_common_post_processing(&uart, rx_enabled, read_some_data, irq_end.bits());
|
||||||
|
if uart_errors.is_some() || queue_overflow {
|
||||||
|
return Err(AsyncUartErrors {
|
||||||
|
queue_overflow,
|
||||||
|
uart_errors: uart_errors.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ActiveReadGuard(usize);
|
||||||
|
|
||||||
|
impl Drop for ActiveReadGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
RX_READ_ACTIVE[self.0].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
rx: Rx<Uart>,
|
||||||
|
pub queue: heapless::spsc::Consumer<'static, u8, N>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance, const N: usize> ErrorType for RxAsync<Uart, N> {
|
||||||
|
/// Error reporting is done using the result of the interrupt functions.
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance, const N: usize> RxAsync<Uart, N> {
|
||||||
|
/// Create a new asynchronous receiver.
|
||||||
|
///
|
||||||
|
/// The passed [heapless::spsc::Consumer] will be used to asynchronously receive data which
|
||||||
|
/// is filled by the interrupt handler.
|
||||||
|
pub fn new(mut rx: Rx<Uart>, queue: heapless::spsc::Consumer<'static, u8, N>) -> Self {
|
||||||
|
rx.disable_interrupts();
|
||||||
|
rx.disable();
|
||||||
|
rx.clear_fifo();
|
||||||
|
// Enable those together.
|
||||||
|
critical_section::with(|_| {
|
||||||
|
rx.enable_interrupts();
|
||||||
|
rx.enable();
|
||||||
|
});
|
||||||
|
Self { rx, queue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
// Need to wait for the IRQ to read data and set this flag. If the queue is not
|
||||||
|
// empty, we can read data immediately.
|
||||||
|
if self.queue.len() == 0 {
|
||||||
|
RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
let _guard = ActiveReadGuard(Uart::IDX as usize);
|
||||||
|
let mut handle_data_in_queue = |consumer: &mut heapless::spsc::Consumer<'static, u8, N>| {
|
||||||
|
let data_to_read = consumer.len().min(buf.len());
|
||||||
|
for byte in buf.iter_mut().take(data_to_read) {
|
||||||
|
// We own the consumer and we checked that the amount of data is guaranteed to be available.
|
||||||
|
*byte = unsafe { consumer.dequeue_unchecked() };
|
||||||
|
}
|
||||||
|
data_to_read
|
||||||
|
};
|
||||||
|
let fut = RxFuture::new(&mut self.rx);
|
||||||
|
// Data is available, so read that data immediately.
|
||||||
|
let read_data = handle_data_in_queue(&mut self.queue);
|
||||||
|
if read_data > 0 {
|
||||||
|
return Ok(read_data);
|
||||||
|
}
|
||||||
|
// Await data.
|
||||||
|
let _ = fut.await;
|
||||||
|
Ok(handle_data_in_queue(&mut self.queue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Core data structure to allow asynchronous UART reception.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
pub struct RxAsyncSharedConsumer<Uart: Instance, const N: usize> {
|
||||||
|
rx: Rx<Uart>,
|
||||||
|
queue: &'static Mutex<RefCell<Option<Consumer<'static, u8, N>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance, const N: usize> ErrorType for RxAsyncSharedConsumer<Uart, N> {
|
||||||
|
/// Error reporting is done using the result of the interrupt functions.
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance, const N: usize> RxAsyncSharedConsumer<Uart, N> {
|
||||||
|
/// Create a new asynchronous receiver.
|
||||||
|
///
|
||||||
|
/// The passed shared [heapless::spsc::Consumer] will be used to asynchronously receive data
|
||||||
|
/// which is filled by the interrupt handler. The shared property allows using it in the
|
||||||
|
/// interrupt handler to overwrite old data.
|
||||||
|
pub fn new(
|
||||||
|
mut rx: Rx<Uart>,
|
||||||
|
queue: &'static Mutex<RefCell<Option<heapless::spsc::Consumer<'static, u8, N>>>>,
|
||||||
|
) -> Self {
|
||||||
|
rx.disable_interrupts();
|
||||||
|
rx.disable();
|
||||||
|
rx.clear_fifo();
|
||||||
|
// Enable those together.
|
||||||
|
critical_section::with(|_| {
|
||||||
|
rx.enable_interrupts();
|
||||||
|
rx.enable();
|
||||||
|
});
|
||||||
|
Self { rx, queue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Uart: Instance, const N: usize> embedded_io_async::Read for RxAsyncSharedConsumer<Uart, N> {
|
||||||
|
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
|
||||||
|
// empty, we can read data immediately.
|
||||||
|
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let queue = self.queue.borrow(cs);
|
||||||
|
if queue.borrow().as_ref().unwrap().len() == 0 {
|
||||||
|
RX_HAS_DATA[Uart::IDX as usize].store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _guard = ActiveReadGuard(Uart::IDX as usize);
|
||||||
|
let mut handle_data_in_queue = || {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut consumer_ref = self.queue.borrow(cs).borrow_mut();
|
||||||
|
let consumer = consumer_ref.as_mut().unwrap();
|
||||||
|
let data_to_read = consumer.len().min(buf.len());
|
||||||
|
for byte in buf.iter_mut().take(data_to_read) {
|
||||||
|
// We own the consumer and we checked that the amount of data is guaranteed to be available.
|
||||||
|
*byte = unsafe { consumer.dequeue_unchecked() };
|
||||||
|
}
|
||||||
|
data_to_read
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let fut = RxFuture::new(&mut self.rx);
|
||||||
|
// Data is available, so read that data immediately.
|
||||||
|
let read_data = handle_data_in_queue();
|
||||||
|
if read_data > 0 {
|
||||||
|
return Ok(read_data);
|
||||||
|
}
|
||||||
|
// Await data.
|
||||||
|
let _ = fut.await;
|
||||||
|
let read_data = handle_data_in_queue();
|
||||||
|
Ok(read_data)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
//! # Async GPIO functionality for the VA108xx family.
|
//! # Async UART transmission functionality for the VA108xx family.
|
||||||
//!
|
//!
|
||||||
//! 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
|
||||||
@ -13,7 +13,7 @@
|
|||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
//! - [Async UART example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/async-gpio/examples/embassy/src/bin/async-uart.rs)
|
//! - [Async UART TX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-tx.rs)
|
||||||
use core::{cell::RefCell, future::Future};
|
use core::{cell::RefCell, future::Future};
|
||||||
|
|
||||||
use critical_section::Mutex;
|
use critical_section::Mutex;
|
||||||
@ -23,7 +23,7 @@ use portable_atomic::AtomicBool;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
static UART_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
|
static UART_TX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2];
|
||||||
static TX_CONTEXTS: [Mutex<RefCell<TxContext>>; 2] =
|
static TX_CONTEXTS: [Mutex<RefCell<TxContext>>; 2] =
|
||||||
[const { Mutex::new(RefCell::new(TxContext::new())) }; 2];
|
[const { Mutex::new(RefCell::new(TxContext::new())) }; 2];
|
||||||
// Completion flag. Kept outside of the context structure as an atomic to avoid
|
// Completion flag. Kept outside of the context structure as an atomic to avoid
|
||||||
@ -72,7 +72,7 @@ fn on_interrupt_uart_tx<Uart: Instance>(uart: Uart) {
|
|||||||
});
|
});
|
||||||
// Transfer is done.
|
// Transfer is done.
|
||||||
TX_DONE[Uart::IDX as usize].store(true, core::sync::atomic::Ordering::Relaxed);
|
TX_DONE[Uart::IDX as usize].store(true, core::sync::atomic::Ordering::Relaxed);
|
||||||
UART_WAKERS[Uart::IDX as usize].wake();
|
UART_TX_WAKERS[Uart::IDX as usize].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
|
||||||
@ -199,7 +199,7 @@ impl Future for TxFuture {
|
|||||||
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> {
|
||||||
UART_WAKERS[self.uart_idx].register(cx.waker());
|
UART_TX_WAKERS[self.uart_idx].register(cx.waker());
|
||||||
if TX_DONE[self.uart_idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
if TX_DONE[self.uart_idx].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||||
let progress = critical_section::with(|cs| {
|
let progress = critical_section::with(|cs| {
|
||||||
TX_CONTEXTS[self.uart_idx].borrow(cs).borrow().progress
|
TX_CONTEXTS[self.uart_idx].borrow(cs).borrow().progress
|
@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
|
## [v0.5.0] 2025-02-14
|
||||||
|
|
||||||
|
- 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
|
||||||
|
@ -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 = "0.3"
|
||||||
critical-section = { version = "1", optional = true }
|
critical-section = { version = "1", optional = true }
|
||||||
|
|
||||||
[dependencies.cortex-m-rt]
|
[dependencies.cortex-m-rt]
|
||||||
@ -21,6 +22,10 @@ version = ">=0.6.15,<0.8"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
rt = ["cortex-m-rt/device"]
|
rt = ["cortex-m-rt/device"]
|
||||||
|
# Adds defmt support
|
||||||
|
defmt = []
|
||||||
|
# Adds Debug implementation
|
||||||
|
debug = []
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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)")
|
||||||
|
@ -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)")
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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())
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user