32 Commits

Author SHA1 Message Date
6402b9f014 small docs update 2025-02-10 11:44:49 +01:00
2fe92c76c6 va108xx v0.4.0: Regnerate PAC 2025-02-09 13:26:36 +01:00
b2d17e10ed Merge pull request 'bootloader tweak' (#26) from bootloader-tweak into main
Reviewed-on: #26
2025-01-14 10:30:08 +01:00
1412e1b7d1 bootloader tweak 2025-01-14 01:21:20 +01:00
88ee85a4cd Merge pull request 'new update for ringbuf' (#25) from update-for-ringbuf into main
Reviewed-on: #25
2025-01-11 11:39:59 +01:00
4b318ecc76 new update for ringbuf 2025-01-11 11:38:04 +01:00
badeea8071 Merge pull request 'fix memory x file' (#24) from fix-memory-x-file into main
Reviewed-on: #24
2025-01-10 17:49:45 +01:00
c95558ff55 Merge branch 'main' into fix-memory-x-file 2025-01-10 17:49:38 +01:00
cd222fd1e1 Merge pull request 'some clippy fixes' (#23) from some-clippy-fixes into main
Reviewed-on: #23
2025-01-10 17:49:20 +01:00
f438e7e40f some clippy fixes 2025-01-10 17:19:28 +01:00
9e547668c2 fix memory x file 2025-01-10 16:38:17 +01:00
cf55fe1504 Merge pull request 'bootloader and flashloader update' (#22) from bootloader-flashloader-update into main
Reviewed-on: #22
2025-01-10 16:31:39 +01:00
74eebdcc03 bootloader and flashloader update 2025-01-10 16:31:15 +01:00
35527f092a Merge pull request 'update probe-rs files' (#21) from probe-rs-update into main
Reviewed-on: #21
2024-11-26 10:23:37 +01:00
c6314f48d7 update probe-rs files 2024-11-26 10:23:27 +01:00
7189cb246b Merge pull request 'delete some more re-exports' (#20) from delete-some-re-exports into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #20
2024-10-07 09:48:13 +02:00
39b8633065 delete some more re-exports
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
2024-10-07 09:47:24 +02:00
df0760da98 Merge pull request 'prepare BSP release' (#19) from prep-bsp-release into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #19
2024-09-30 12:12:20 +02:00
8ed26db6a7 prepare BSP release
Some checks are pending
Rust/va108xx-rs/pipeline/head Build queued...
2024-09-30 12:10:03 +02:00
307174b938 Merge pull request 'prepare HAL release' (#18) from prep-hal-release into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #18
2024-09-30 12:02:23 +02:00
46df7f1007 prepare HAL release
Some checks are pending
Rust/va108xx-rs/pipeline/pr-main Build queued...
2024-09-30 11:58:04 +02:00
48dd00661f Merge pull request 'added correction for link' (#17) from link-correction into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #17
2024-09-30 11:47:57 +02:00
e98ef8501e added correction for link
Some checks are pending
Rust/va108xx-rs/pipeline/head Build queued...
2024-09-30 11:46:16 +02:00
b753a465bf Merge pull request 'Flashloader and Bootloader' (#16) from flashloader into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #16
2024-09-30 11:43:58 +02:00
d6f69d4a54 Finished flashloader and bootloader implementation
Some checks are pending
Rust/va108xx-rs/pipeline/pr-main Build queued...
2024-09-30 11:41:52 +02:00
e2a55e7309 Merge pull request 'bmstall is configurable now as well' (#15) from va108xx-update-package into main
Some checks failed
Rust/va108xx-rs/pipeline/head There was a failure building this commit
Reviewed-on: #15
2024-09-20 12:13:12 +02:00
e971e8dc0d bmstall is configurable now as well
All checks were successful
Rust/va108xx-rs/pipeline/pr-main This commit looks good
2024-09-20 11:42:41 +02:00
501d1c973e Merge pull request 'update package' (#14) from va108xx-update-package into main
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
Reviewed-on: #14
2024-09-20 11:29:58 +02:00
acb8b67ae7 update package
All checks were successful
Rust/va108xx-rs/pipeline/pr-main This commit looks good
- Add embassy example
- improve timer API
- restructure examples
- restructure and improve SPI
- Add REB1 M95M01 NVM module
2024-09-20 10:53:42 +02:00
405cc089c3 update flasher script file
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
2024-07-11 11:52:56 +02:00
f48ee8231a another link correction
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
2024-07-04 18:55:30 +02:00
4fb19fe234 link fix
All checks were successful
Rust/va108xx-rs/pipeline/head This commit looks good
2024-07-04 18:54:37 +02:00
208 changed files with 5629 additions and 2350 deletions

View File

@ -39,7 +39,9 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --all-features
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx-hal
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-reb1
clippy:
name: Clippy

2
.gitignore vendored
View File

@ -16,3 +16,5 @@ Cargo.lock
# JetBrains IDEs
/.idea
*.iml
/Embed.toml

View File

@ -5,11 +5,16 @@ members = [
"va108xx",
"va108xx-hal",
"examples/simple",
"examples/rtic",
"examples/embassy",
"board-tests",
"bootloader",
"flashloader",
]
exclude = [
"defmt-testapp",
"flashloader/slot-a-blinky",
"flashloader/slot-b-blinky",
]
[profile.dev]
@ -17,7 +22,8 @@ codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 'z' # <-
# 1 instead of 0, the flashloader is too larger otherwise..
# opt-level = 1 # <-
overflow-checks = true # <-
# cargo build/run --release
@ -29,3 +35,12 @@ incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-
[profile.small]
inherits = "release"
codegen-units = 1
debug-assertions = false # <-
lto = true
opt-level = 'z' # <-
overflow-checks = false # <-
strip = true # Automatically strip symbols from the binary.

12
Embed.toml.sample Normal file
View File

@ -0,0 +1,12 @@
[default.probe]
protocol = "Jtag"
[default.general]
chip = "VA108xx_RAM"
[default.rtt]
enabled = true
[default.gdb]
# Whether or not a GDB server should be opened after flashing.
enabled = false

View File

@ -19,9 +19,18 @@ This workspace contains the following released crates:
It also contains the following helper crates:
- The `board-tests` contains an application which can be used to test the libraries on the
board.
- The `examples` crates contains various example applications for the HAL and the PAC.
- The [`bootloader`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/bootloader)
crate contains a sample bootloader strongly based on the one provided by Vorago.
- The [`flashloader`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
crate contains a sample flashloader which is able to update the redundant images in the NVM which
is compatible to the provided bootloader as well.
- The [`board-tests`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/board-tests)
contains an application which can be used to test the libraries on the board.
- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples)
folder contains various example applications crates using the HAL and the PAC.
This folder also contains dedicated example applications using the
[`RTIC`](https://rtic.rs/2/book/en/) and [`embassy`](https://github.com/embassy-rs/embassy)
native Rust RTOSes.
## Using the `.cargo/config.toml` file
@ -94,6 +103,8 @@ example.
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`
@ -108,4 +119,5 @@ configuration variables in your `settings.json`:
- `"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`.
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.

View File

@ -25,7 +25,9 @@ pipeline {
stage('Docs') {
steps {
sh """
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --all-features
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx-hal
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-reb1
"""
}
}

View File

@ -4,10 +4,9 @@ version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m-rtic = "1"
panic-halt = "0.2"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
panic-halt = "0.2"
rtt-target = "0.5"
panic-rtt-target = "0.1.3"
embedded-hal = "1"
@ -15,7 +14,6 @@ embedded-hal-nb = "1"
embedded-io = "0.6"
[dependencies.va108xx-hal]
version = "0.7"
path = "../va108xx-hal"
features = ["rt"]

View File

@ -17,7 +17,7 @@ use va108xx_hal::{
pac::{self, interrupt},
prelude::*,
time::Hertz,
timer::{default_ms_irq_handler, set_up_ms_tick, CountDownTimer, IrqCfg},
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, IrqCfg},
};
#[allow(dead_code)]
@ -168,7 +168,7 @@ fn main() -> ! {
ms_timer.delay_ms(500);
}
let mut delay_timer = CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let mut delay_timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let mut pa0 = pinsa.pa0.into_readable_push_pull_output();
for _ in 0..5 {
led1.toggle().ok();

25
bootloader/Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
[package]
name = "bootloader"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = "1"
panic-rtt-target = { version = "0.1.3" }
panic-halt = { version = "0.2" }
rtt-target = { version = "0.5" }
crc = "3"
num_enum = { version = "0.7", default-features = false }
static_assertions = "1"
[dependencies.va108xx-hal]
path = "../va108xx-hal"
[dependencies.vorago-reb1]
path = "../vorago-reb1"
[features]
default = []
rtt-panic = []

51
bootloader/README.md Normal file
View File

@ -0,0 +1,51 @@
VA108xx Bootloader Application
=======
This is the Rust version of the bootloader supplied by Vorago.
## Memory Map
The bootloader uses the following memory map:
| Address | Notes | Size |
| ------ | ---- | ---- |
| 0x0 | Bootloader start | code up to 0x2FFE bytes |
| 0x2FFE | Bootloader CRC | half-word |
| 0x3000 | App image A start | code up to 0xE7F4 (~59K) bytes |
| 0x117F8 | App image A CRC check length | word |
| 0x117FC | App image A CRC check value | word |
| 0x117FC | App image B start | code up to 0xE7F4 (~59K) bytes |
| 0x1FFF0 | App image B CRC check length | word |
| 0x1FFF4 | App image B CRC check value | word |
| 0x1FFF8 | Reserved section, contains boot select parameter | 8 bytes |
| 0x20000 | End of NVM | end |
## Additional Information
This bootloader was specifically written for the REB1 board, so it assumes a M95M01 ST EEPROM
is used to load the application code. The bootloader will also delay for a configurable amount
of time before booting. This allows to catch the RTT printout, but should probably be disabled
for production firmware.
This bootloader does not provide tools to flash the NVM memory by itself. Instead, you can use
the [flashloader](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
application to perform this task using a CCSDS interface via a UART.
The bootloader performs the following steps:
1. The application will calculate the checksum of itself if the bootloader CRC is blank (all zeroes
or all ones). If the CRC is not blank and the checksum check fails, it will immediately boot
application image A. Otherwise, it proceeds to the next step.
2. Read the boot slot from a reserved section at the end of the EEPROM. If no valid value is read,
select boot slot A.
3. Check the checksum of the boot slot. If that checksum is valid, it will boot that slot. If not,
it will proceed to the next step.
4. Check the checksum of the other slot . If that checksum is valid, it will boot that slot. If
not, it will boot App A as the fallback image.
In your actual production application, a command to update the preferred boot slot could be exposed
to allow performing software updates in a safe way.
Please note that you *MUST* compile the application at slot A and slot B with an appropriate
`memory.x` file where the base address of the `FLASH` was adapted according to the base address
shown in the memory map above. The memory files to do this were provided in the `scripts` folder.

10
bootloader/src/lib.rs Normal file
View File

@ -0,0 +1,10 @@
#![no_std]
use core::convert::Infallible;
/// Simple trait which makes swapping the NVM easier. NVMs only need to implement this interface.
pub trait NvmInterface {
fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Infallible>;
fn read(&mut self, address: usize, buf: &mut [u8]) -> Result<(), Infallible>;
fn verify(&mut self, address: usize, data: &[u8]) -> Result<bool, Infallible>;
}

340
bootloader/src/main.rs Normal file
View File

@ -0,0 +1,340 @@
//! Vorago bootloader which can boot from two images.
#![no_main]
#![no_std]
use bootloader::NvmInterface;
use cortex_m_rt::entry;
use crc::{Crc, CRC_16_IBM_3740};
use embedded_hal::delay::DelayNs;
use num_enum::TryFromPrimitive;
#[cfg(not(feature = "rtt-panic"))]
use panic_halt as _;
#[cfg(feature = "rtt-panic")]
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{pac, time::Hertz, timer::CountdownTimer};
use vorago_reb1::m95m01::M95M01;
// Useful for debugging and see what the bootloader is doing. Enabled currently, because
// the binary stays small enough.
const RTT_PRINTOUT: bool = true;
const DEBUG_PRINTOUTS: bool = true;
// Small delay, allows RTT printout to catch up.
const BOOT_DELAY_MS: u32 = 2000;
// Dangerous option! An image with this option set to true will flash itself from RAM directly
// into the NVM. This can be used as a recovery option from a direct RAM flash to fix the NVM
// boot process. Please note that this will flash an image which will also always perform the
// self-flash itself. It is recommended that you use a tool like probe-rs, Keil IDE, or a flash
// loader to boot a bootloader without this feature.
const FLASH_SELF: bool = false;
// Register definitions for Cortex-M0 SCB register.
pub const SCB_AIRCR_VECTKEY_POS: u32 = 16;
pub const SCB_AIRCR_VECTKEY_MSK: u32 = 0xFFFF << SCB_AIRCR_VECTKEY_POS;
pub const SCB_AIRCR_SYSRESETREQ_POS: u32 = 2;
pub const SCB_AIRCR_SYSRESETREQ_MSK: u32 = 1 << SCB_AIRCR_SYSRESETREQ_POS;
const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000);
// Important bootloader addresses and offsets, vector table information.
const NVM_SIZE: u32 = 0x20000;
const BOOTLOADER_START_ADDR: u32 = 0x0;
const BOOTLOADER_CRC_ADDR: u32 = BOOTLOADER_END_ADDR - 2;
// This is also the maximum size of the bootloader.
const BOOTLOADER_END_ADDR: u32 = 0x3000;
const APP_A_START_ADDR: u32 = BOOTLOADER_END_ADDR;
// 0x117F8
const APP_A_SIZE_ADDR: u32 = APP_A_END_ADDR - 8;
// Four bytes reserved, even when only 2 byte CRC is used. Leaves flexibility to switch to CRC32.
// 0x117FC
const APP_A_CRC_ADDR: u32 = APP_A_END_ADDR - 4;
// 0x11800
pub const APP_A_END_ADDR: u32 = APP_A_START_ADDR + APP_IMG_SZ;
// The actual size of the image which is relevant for CRC calculation.
const APP_B_START_ADDR: u32 = APP_A_END_ADDR;
// The actual size of the image which is relevant for CRC calculation.
// 0x1FFF8
const APP_B_SIZE_ADDR: u32 = APP_B_END_ADDR - 8;
// Four bytes reserved, even when only 2 byte CRC is used. Leaves flexibility to switch to CRC32.
// 0x1FFFC
const APP_B_CRC_ADDR: u32 = APP_B_END_ADDR - 4;
// 0x20000. 8 bytes at end of EEPROM reserved for preferred image parameter. This reserved
// size should be a multiple of 8 due to alignment requirements.
pub const APP_B_END_ADDR: u32 = NVM_SIZE - 8;
pub const APP_IMG_SZ: u32 = (APP_B_END_ADDR - APP_A_START_ADDR) / 2;
static_assertions::const_assert!((APP_B_END_ADDR - BOOTLOADER_END_ADDR) % 2 == 0);
pub const VECTOR_TABLE_OFFSET: u32 = 0x0;
pub const VECTOR_TABLE_LEN: u32 = 0xC0;
pub const RESET_VECTOR_OFFSET: u32 = 0x4;
pub const PREFERRED_SLOT_OFFSET: u32 = 0x20000 - 1;
const CRC_ALGO: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive)]
#[repr(u8)]
enum AppSel {
A = 0,
B = 1,
}
pub struct NvmWrapper(pub M95M01);
// Newtype pattern. We could now more easily swap the used NVM type.
impl NvmInterface for NvmWrapper {
fn write(&mut self, address: usize, data: &[u8]) -> Result<(), core::convert::Infallible> {
self.0.write(address, data)
}
fn read(&mut self, address: usize, buf: &mut [u8]) -> Result<(), core::convert::Infallible> {
self.0.read(address, buf)
}
fn verify(&mut self, address: usize, data: &[u8]) -> Result<bool, core::convert::Infallible> {
self.0.verify(address, data)
}
}
#[entry]
fn main() -> ! {
if RTT_PRINTOUT {
rtt_init_print!();
rprintln!("-- VA108xx bootloader --");
}
let mut dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, CLOCK_FREQ, dp.tim0);
let mut nvm = M95M01::new(&mut dp.sysconfig, CLOCK_FREQ, dp.spic);
if FLASH_SELF {
let mut first_four_bytes: [u8; 4] = [0; 4];
read_four_bytes_at_addr_zero(&mut first_four_bytes);
let bootloader_data = {
unsafe {
&*core::ptr::slice_from_raw_parts(
(BOOTLOADER_START_ADDR + 4) as *const u8,
(BOOTLOADER_END_ADDR - BOOTLOADER_START_ADDR - 6) as usize,
)
}
};
let mut digest = CRC_ALGO.digest();
digest.update(&first_four_bytes);
digest.update(bootloader_data);
let bootloader_crc = digest.finalize();
nvm.write(0x0, &first_four_bytes)
.expect("writing to NVM failed");
nvm.write(0x4, bootloader_data)
.expect("writing to NVM failed");
if let Err(e) = nvm.verify(0x0, &first_four_bytes) {
if RTT_PRINTOUT {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
}
}
if let Err(e) = nvm.verify(0x4, bootloader_data) {
if RTT_PRINTOUT {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
}
}
nvm.write(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes())
.expect("writing CRC failed");
if let Err(e) = nvm.verify(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes()) {
if RTT_PRINTOUT {
rprintln!(
"error: CRC verification for bootloader self-flash failed: {:?}",
e
);
}
}
}
let mut nvm = NvmWrapper(nvm);
// Check bootloader's CRC (and write it if blank)
check_own_crc(&dp.sysconfig, &cp, &mut nvm, &mut timer);
let mut preferred_app_raw = [0; 1];
nvm.read(PREFERRED_SLOT_OFFSET as usize, &mut preferred_app_raw)
.expect("reading preferred slot failed");
let preferred_app = AppSel::try_from(preferred_app_raw[0]).unwrap_or(AppSel::A);
let other_app = if preferred_app == AppSel::A {
AppSel::B
} else {
AppSel::A
};
if check_app_crc(preferred_app) {
boot_app(&dp.sysconfig, &cp, preferred_app, &mut timer)
} else if check_app_crc(other_app) {
boot_app(&dp.sysconfig, &cp, other_app, &mut timer)
} else {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("both images corrupt! booting image A");
}
// TODO: Shift a CCSDS packet out to inform host/OBC about image corruption.
// Both images seem to be corrupt. Boot default image A.
boot_app(&dp.sysconfig, &cp, AppSel::A, &mut timer)
}
}
fn check_own_crc(
sysconfig: &pac::Sysconfig,
cp: &cortex_m::Peripherals,
nvm: &mut NvmWrapper,
timer: &mut CountdownTimer<pac::Tim0>,
) {
let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u16).read_unaligned().to_be() };
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
// panics.
let mut first_four_bytes: [u8; 4] = [0; 4];
read_four_bytes_at_addr_zero(&mut first_four_bytes);
let mut digest = CRC_ALGO.digest();
digest.update(&first_four_bytes);
digest.update(unsafe {
&*core::ptr::slice_from_raw_parts(
(BOOTLOADER_START_ADDR + 4) as *const u8,
(BOOTLOADER_END_ADDR - BOOTLOADER_START_ADDR - 6) as usize,
)
});
let crc_calc = digest.finalize();
if crc_exp == 0x0000 || crc_exp == 0xffff {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("BL CRC blank - prog new CRC");
}
// Blank CRC, write it to NVM.
nvm.write(BOOTLOADER_CRC_ADDR as usize, &crc_calc.to_be_bytes())
.expect("writing CRC failed");
// The Vorago bootloader resets here. I am not sure why this is done but I think it is
// necessary because somehow the boot will not work if we just continue as usual.
// cortex_m::peripheral::SCB::sys_reset();
} else if crc_exp != crc_calc {
// Bootloader is corrupted. Try to run App A.
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!(
"bootloader CRC corrupt, read {} and expected {}. booting image A immediately",
crc_calc,
crc_exp
);
}
// TODO: Shift out minimal CCSDS frame to notify about bootloader corruption.
boot_app(sysconfig, cp, AppSel::A, timer);
}
}
// Reading from address 0x0 is problematic in Rust.
// See https://users.rust-lang.org/t/reading-from-physical-address-0x0/117408/5.
// This solution falls back to assembler to deal with this.
fn read_four_bytes_at_addr_zero(buf: &mut [u8; 4]) {
unsafe {
core::arch::asm!(
"ldr r0, [{0}]", // Load 4 bytes from src into r0 register
"str r0, [{1}]", // Store r0 register into first_four_bytes
in(reg) BOOTLOADER_START_ADDR as *const u8, // Input: src pointer (0x0)
in(reg) buf as *mut [u8; 4], // Input: destination pointer
);
}
}
fn check_app_crc(app_sel: AppSel) -> bool {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("Checking image {:?}", app_sel);
}
if app_sel == AppSel::A {
check_app_given_addr(APP_A_CRC_ADDR, APP_A_START_ADDR, APP_A_SIZE_ADDR)
} else {
check_app_given_addr(APP_B_CRC_ADDR, APP_B_START_ADDR, APP_B_SIZE_ADDR)
}
}
fn check_app_given_addr(crc_addr: u32, start_addr: u32, image_size_addr: u32) -> bool {
let crc_exp = unsafe { (crc_addr as *const u16).read_unaligned().to_be() };
let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() };
// Sanity check.
if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 {
if RTT_PRINTOUT {
rprintln!("detected invalid app size {}", image_size);
}
return false;
}
let crc_calc = CRC_ALGO.checksum(unsafe {
core::slice::from_raw_parts(start_addr as *const u8, image_size as usize)
});
if crc_calc == crc_exp {
return true;
}
false
}
// The boot works by copying the interrupt vector table (IVT) of the respective app to the
// base address in code RAM (0x0) and then performing a soft reset.
fn boot_app(
syscfg: &pac::Sysconfig,
cp: &cortex_m::Peripherals,
app_sel: AppSel,
timer: &mut CountdownTimer<pac::Tim0>,
) -> ! {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("booting app {:?}", app_sel);
}
timer.delay_ms(BOOT_DELAY_MS);
// Clear all interrupts set.
unsafe {
cp.NVIC.icer[0].write(0xFFFFFFFF);
cp.NVIC.icpr[0].write(0xFFFFFFFF);
}
// Disable ROM protection.
syscfg.rom_prot().write(|w| w.wren().set_bit());
let base_addr = if app_sel == AppSel::A {
APP_A_START_ADDR
} else {
APP_B_START_ADDR
};
unsafe {
// First 4 bytes done with inline assembly, writing to the physical address 0x0 can not
// be done without it. See https://users.rust-lang.org/t/reading-from-physical-address-0x0/117408/2.
let first_four_bytes = core::ptr::read(base_addr as *const u32);
core::arch::asm!(
"str {0}, [{1}]",
in(reg) first_four_bytes, // Input: App vector table.
in(reg) BOOTLOADER_START_ADDR as *mut u32, // Input: destination pointer
);
core::slice::from_raw_parts_mut(
(BOOTLOADER_START_ADDR + 4) as *mut u8,
(VECTOR_TABLE_LEN - 4) as usize,
)
.copy_from_slice(core::slice::from_raw_parts(
(base_addr + 4) as *const u8,
(VECTOR_TABLE_LEN - 4) as usize,
));
}
// Disable re-loading from FRAM/code ROM on soft reset
syscfg
.rst_cntl_rom()
.modify(|_, w| w.sysrstreq().clear_bit());
soft_reset(cp);
}
// Soft reset based on https://github.com/ARM-software/CMSIS_6/blob/5782d6f8057906d360f4b95ec08a2354afe5c9b9/CMSIS/Core/Include/core_cm0.h#L874.
fn soft_reset(cp: &cortex_m::Peripherals) -> ! {
// Ensure all outstanding memory accesses included buffered write are completed before reset.
cortex_m::asm::dsb();
unsafe {
cp.SCB
.aircr
.write((0x5FA << SCB_AIRCR_VECTKEY_POS) | SCB_AIRCR_SYSRESETREQ_MSK);
}
// Ensure completion of memory access.
cortex_m::asm::dsb();
// Loop until the reset occurs.
loop {
cortex_m::asm::nop();
}
}

25
examples/README.md Normal file
View File

@ -0,0 +1,25 @@
VA108xx Example Applications
========
This folder contains various examples
Consult the main README first for setup of the repository.
## Simple examples
```rs
cargo run --example blinky
```
You can have a look at the `simple/examples` folder to see all available simple examples
## RTIC example
```rs
cargo run --bin rtic-example
```
## Embassy example
```rs
cargo run --bin embassy-example
```

View File

@ -0,0 +1,40 @@
[package]
name = "embassy-example"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
embedded-hal = "1"
rtt-target = { version = "0.5" }
panic-rtt-target = { version = "0.1" }
critical-section = "1"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
embassy-sync = { version = "0.6.0" }
embassy-time = { version = "0.3.2" }
embassy-time-driver = { version = "0.1" }
[dependencies.once_cell]
version = "1"
default-features = false
features = ["critical-section"]
[dependencies.embassy-executor]
version = "0.6.0"
features = [
"arch-cortex-m",
"executor-thread",
"executor-interrupt",
"integrated-timers",
]
[dependencies.va108xx-hal]
path = "../../va108xx-hal"
[features]
default = ["ticks-hz-1_000"]
ticks-hz-1_000 = ["embassy-time/tick-hz-1_000"]
ticks-hz-32_768 = ["embassy-time/tick-hz-32_768"]

View File

@ -0,0 +1,4 @@
#![no_std]
pub mod time_driver;
pub use time_driver::init;

View File

@ -0,0 +1,43 @@
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*};
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
// main is itself an async function.
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
rtt_init_print!();
rprintln!("-- VA108xx Embassy Demo --");
let mut dp = pac::Peripherals::take().unwrap();
// Safety: Only called once here.
unsafe {
embassy_example::init(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ,
dp.tim23,
dp.tim22,
)
};
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), 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 mut ticker = Ticker::every(Duration::from_secs(1));
loop {
ticker.next().await;
rprintln!("Current time: {}", Instant::now().as_secs());
led0.toggle().ok();
led1.toggle().ok();
led2.toggle().ok();
}
}

View File

@ -0,0 +1,333 @@
//! This is a sample time driver implementation for the VA108xx family of devices, supporting
//! one alarm and requiring/reserving 2 TIM peripherals. You could adapt this implementation to
//! support more alarms.
//!
//! This driver implementation reserves interrupts OC31 and OC30 for the timekeeping.
use core::{cell::Cell, mem, ptr};
use critical_section::CriticalSection;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use portable_atomic::{AtomicU32, AtomicU8, Ordering};
use embassy_time_driver::{time_driver_impl, AlarmHandle, Driver, TICK_HZ};
use once_cell::sync::OnceCell;
use va108xx_hal::{
clock::enable_peripheral_clock,
enable_interrupt,
pac::{self, interrupt},
prelude::*,
timer::{enable_tim_clk, ValidTim},
PeripheralSelect,
};
pub type TimekeeperClk = pac::Tim23;
pub type AlarmClk0 = pac::Tim22;
pub type AlarmClk1 = pac::Tim21;
pub type AlarmClk2 = pac::Tim20;
const TIMEKEEPER_IRQ: pac::Interrupt = pac::Interrupt::OC31;
const ALARM_IRQ: pac::Interrupt = pac::Interrupt::OC30;
/// Initialization method for embassy
///
/// # Safety
/// This has to be called once at initialization time to initiate the time driver for
/// embassy.
pub unsafe fn init(
syscfg: &mut pac::Sysconfig,
irqsel: &pac::Irqsel,
sysclk: impl Into<Hertz>,
timekeeper: TimekeeperClk,
alarm_tim: AlarmClk0,
) {
DRIVER.init(syscfg, irqsel, sysclk, timekeeper, alarm_tim)
}
time_driver_impl!(
static DRIVER: TimerDriverEmbassy = TimerDriverEmbassy {
periods: AtomicU32::new(0),
alarm_count: AtomicU8::new(0),
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [AlarmState::new(); ALARM_COUNT])
});
/// Timekeeper interrupt.
#[interrupt]
#[allow(non_snake_case)]
fn OC31() {
DRIVER.on_interrupt_timekeeping()
}
/// Alarm timer interrupt.
#[interrupt]
#[allow(non_snake_case)]
fn OC30() {
DRIVER.on_interrupt_alarm(0)
}
#[inline(always)]
const fn alarm_tim(idx: usize) -> &'static pac::tim0::RegisterBlock {
// Safety: This is a static memory-mapped peripheral.
match idx {
0 => unsafe { &*AlarmClk0::ptr() },
1 => unsafe { &*AlarmClk1::ptr() },
2 => unsafe { &*AlarmClk2::ptr() },
_ => {
panic!("invalid alarm timer index")
}
}
}
#[inline(always)]
const fn timekeeping_tim() -> &'static pac::tim0::RegisterBlock {
// Safety: This is a memory-mapped peripheral.
unsafe { &*TimekeeperClk::ptr() }
}
struct AlarmState {
timestamp: Cell<u64>,
// This is really a Option<(fn(*mut ()), *mut ())>
// but fn pointers aren't allowed in const yet
callback: Cell<*const ()>,
ctx: Cell<*mut ()>,
}
impl AlarmState {
const fn new() -> Self {
Self {
timestamp: Cell::new(u64::MAX),
callback: Cell::new(ptr::null()),
ctx: Cell::new(ptr::null_mut()),
}
}
}
unsafe impl Send for AlarmState {}
const ALARM_COUNT: usize = 1;
static SCALE: OnceCell<u64> = OnceCell::new();
pub struct TimerDriverEmbassy {
periods: AtomicU32,
alarm_count: AtomicU8,
/// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
}
impl TimerDriverEmbassy {
fn init(
&self,
syscfg: &mut pac::Sysconfig,
irqsel: &pac::Irqsel,
sysclk: impl Into<Hertz>,
timekeeper: TimekeeperClk,
alarm_tim: AlarmClk0,
) {
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
enable_tim_clk(syscfg, TimekeeperClk::TIM_ID);
let sysclk = sysclk.into();
// Initiate scale value here. This is required to convert timer ticks back to a timestamp.
SCALE.set((sysclk.raw() / TICK_HZ as u32) as u64).unwrap();
timekeeper
.rst_value()
.write(|w| unsafe { w.bits(u32::MAX) });
// Decrementing counter.
timekeeper
.cnt_value()
.write(|w| unsafe { w.bits(u32::MAX) });
// Switch on. Timekeeping should always be done.
irqsel
.tim0(TimekeeperClk::TIM_ID as usize)
.write(|w| unsafe { w.bits(TIMEKEEPER_IRQ as u32) });
unsafe {
enable_interrupt(TIMEKEEPER_IRQ);
}
timekeeper.ctrl().modify(|_, w| w.irq_enb().set_bit());
timekeeper.enable().write(|w| unsafe { w.bits(1) });
enable_tim_clk(syscfg, AlarmClk0::TIM_ID);
// Explicitely disable alarm timer until needed.
alarm_tim.ctrl().modify(|_, w| {
w.irq_enb().clear_bit();
w.enable().clear_bit()
});
// Enable general interrupts. The IRQ enable of the peripheral remains cleared.
unsafe {
enable_interrupt(ALARM_IRQ);
}
irqsel
.tim0(AlarmClk0::TIM_ID as usize)
.write(|w| unsafe { w.bits(ALARM_IRQ as u32) });
}
// Should be called inside the IRQ of the timekeeper timer.
fn on_interrupt_timekeeping(&self) {
self.next_period();
}
// Should be called inside the IRQ of the alarm timer.
fn on_interrupt_alarm(&self, idx: usize) {
critical_section::with(|cs| {
if self.alarms.borrow(cs)[idx].timestamp.get() <= self.now() {
self.trigger_alarm(idx, cs)
}
})
}
fn next_period(&self) {
let period = self.periods.fetch_add(1, Ordering::AcqRel) + 1;
let t = (period as u64) << 32;
critical_section::with(|cs| {
for i in 0..ALARM_COUNT {
let alarm = &self.alarms.borrow(cs)[i];
let at = alarm.timestamp.get();
let alarm_tim = alarm_tim(0);
if at < t {
self.trigger_alarm(i, cs);
} else {
let remaining_ticks = (at - t) * *SCALE.get().unwrap();
if remaining_ticks <= u32::MAX as u64 {
alarm_tim.enable().write(|w| unsafe { w.bits(0) });
alarm_tim
.cnt_value()
.write(|w| unsafe { w.bits(remaining_ticks as u32) });
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
alarm_tim.enable().write(|w| unsafe { w.bits(1) })
}
}
}
})
}
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
// safety: we're allowed to assume the AlarmState is created by us, and
// we never create one that's out of bounds.
unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
}
fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
alarm_tim(n).ctrl().modify(|_, w| {
w.irq_enb().clear_bit();
w.enable().clear_bit()
});
let alarm = &self.alarms.borrow(cs)[n];
// Setting the maximum value disables the alarm.
alarm.timestamp.set(u64::MAX);
// Call after clearing alarm, so the callback can set another alarm.
// safety:
// - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
// - other than that we only store valid function pointers into alarm.callback
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
f(alarm.ctx.get());
}
}
impl Driver for TimerDriverEmbassy {
fn now(&self) -> u64 {
if SCALE.get().is_none() {
return 0;
}
let mut period1: u32;
let mut period2: u32;
let mut counter_val: u32;
loop {
// Acquire ensures that we get the latest value of `periods` and
// no instructions can be reordered before the load.
period1 = self.periods.load(Ordering::Acquire);
counter_val = u32::MAX - timekeeping_tim().cnt_value().read().bits();
// Double read to protect against race conditions when the counter is overflowing.
period2 = self.periods.load(Ordering::Relaxed);
if period1 == period2 {
let now = (((period1 as u64) << 32) | counter_val as u64) / *SCALE.get().unwrap();
return now;
}
}
}
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
let id = self
.alarm_count
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
if x < ALARM_COUNT as u8 {
Some(x + 1)
} else {
None
}
});
match id {
Ok(id) => Some(AlarmHandle::new(id)),
Err(_) => None,
}
}
fn set_alarm_callback(
&self,
alarm: embassy_time_driver::AlarmHandle,
callback: fn(*mut ()),
ctx: *mut (),
) {
critical_section::with(|cs| {
let alarm = self.get_alarm(cs, alarm);
alarm.callback.set(callback as *const ());
alarm.ctx.set(ctx);
})
}
fn set_alarm(&self, alarm: embassy_time_driver::AlarmHandle, timestamp: u64) -> bool {
if SCALE.get().is_none() {
return false;
}
critical_section::with(|cs| {
let n = alarm.id();
let alarm_tim = alarm_tim(n.into());
alarm_tim.ctrl().modify(|_, w| {
w.irq_enb().clear_bit();
w.enable().clear_bit()
});
let alarm = self.get_alarm(cs, alarm);
alarm.timestamp.set(timestamp);
let t = self.now();
if timestamp <= t {
alarm.timestamp.set(u64::MAX);
return false;
}
// If it hasn't triggered yet, setup the relevant reset value, regardless of whether
// the interrupts are enabled or not. When they are enabled at a later point, the
// right value is already set.
// If the timestamp is in the next few ticks, add a bit of buffer to be sure the alarm
// is not missed.
//
// This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
// and we don't do that here.
let safe_timestamp = timestamp.max(t + 3);
let timer_ticks = (safe_timestamp - t) * *SCALE.get().unwrap();
alarm_tim.rst_value().write(|w| unsafe { w.bits(u32::MAX) });
if timer_ticks <= u32::MAX as u64 {
alarm_tim
.cnt_value()
.write(|w| unsafe { w.bits(timer_ticks as u32) });
alarm_tim.ctrl().modify(|_, w| w.irq_enb().set_bit());
alarm_tim.enable().write(|w| unsafe { w.bits(1) });
}
// If it's too far in the future, don't enable timer yet.
// It will be enabled later by `next_period`.
true
})
}
}

44
examples/rtic/Cargo.toml Normal file
View File

@ -0,0 +1,44 @@
[package]
name = "rtic-example"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-io = "0.6"
rtt-target = { version = "0.5" }
panic-rtt-target = { version = "0.1" }
# Even though we do not use this directly, we need to activate this feature explicitely
# so that RTIC compiles because thumv6 does not have CAS operations natively.
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
[dependencies.rtic]
version = "2"
features = ["thumbv6-backend"]
[dependencies.rtic-monotonics]
version = "2"
features = ["cortex-m-systick"]
[dependencies.rtic-sync]
version = "1.3"
features = ["defmt-03"]
[dependencies.once_cell]
version = "1"
default-features = false
features = ["critical-section"]
[dependencies.ringbuf]
version = "0.4.7"
default-features = false
features = ["portable-atomic"]
[dependencies.va108xx-hal]
version = "0.8"
[dependencies.vorago-reb1]
path = "../../vorago-reb1"

View File

@ -5,7 +5,7 @@
#[rtic::app(device = pac)]
mod app {
use panic_rtt_target as _;
use rtic_monotonics::systick::Systick;
use rtic_example::SYSCLK_FREQ;
use rtt_target::{rprintln, rtt_init_default, set_print_channel};
use va108xx_hal::{
clock::{set_clk_div_register, FilterClkSel},
@ -17,6 +17,8 @@ mod app {
use vorago_reb1::button::Button;
use vorago_reb1::leds::Leds;
rtic_monotonics::systick_monotonic!(Mono, 1_000);
#[derive(Debug, PartialEq)]
pub enum PressMode {
Toggle,
@ -44,17 +46,11 @@ mod app {
struct Shared {}
#[init]
fn init(ctx: init::Context) -> (Shared, Local) {
fn init(cx: init::Context) -> (Shared, Local) {
let channels = rtt_init_default!();
set_print_channel(channels.up.0);
rprintln!("-- Vorago Button IRQ Example --");
// Initialize the systick interrupt & obtain the token to prove that we did
let systick_mono_token = rtic_monotonics::create_systick_token!();
Systick::start(
ctx.core.SYST,
Hertz::from(50.MHz()).raw(),
systick_mono_token,
);
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let mode = match CFG_MODE {
// Ask mode from user via RTT
@ -64,7 +60,7 @@ mod app {
};
rprintln!("Using {:?} mode", mode);
let mut dp = ctx.device;
let mut dp = cx.device;
let pinsa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let edge_irq = match mode {
PressMode::Toggle => InterruptEdge::HighToLow,
@ -117,14 +113,12 @@ mod app {
let mode = cx.local.mode;
if *mode == PressMode::Toggle {
leds[0].toggle();
} else {
if button.released() {
} else if button.released() {
leds[0].off();
} else {
leds[0].on();
}
}
}
#[task(binds = OC0)]
fn ms_tick(_cx: ms_tick::Context) {
@ -138,14 +132,11 @@ mod app {
let mut read;
loop {
read = down_channel.read(&mut read_buf);
for i in 0..read {
let val = read_buf[i] as char;
if val == '0' || val == '1' {
return if val == '0' {
PressMode::Toggle
} else {
PressMode::Keep
};
for &byte in &read_buf[..read] {
match byte as char {
'0' => return PressMode::Toggle,
'1' => return PressMode::Keep,
_ => continue, // Ignore other characters
}
}
}

View File

@ -0,0 +1,132 @@
//! More complex UART application
//!
//! Uses the IRQ capabilities of the VA10820 peripheral and the RTIC framework to poll the UART in
//! a non-blocking way. All received data will be sent back to the sender.
#![no_main]
#![no_std]
use ringbuf::StaticRb;
// Larger buffer for TC to be able to hold the possibly large memory write packets.
const RX_RING_BUF_SIZE: usize = 1024;
#[rtic::app(device = pac, dispatchers = [OC4])]
mod app {
use super::*;
use embedded_io::Write;
use panic_rtt_target as _;
use ringbuf::traits::{Consumer, Observer, Producer};
use rtic_example::SYSCLK_FREQ;
use rtic_monotonics::Monotonic;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
gpio::PinsA,
pac,
prelude::*,
uart::{self, RxWithIrq, Tx},
};
#[local]
struct Local {
rx: RxWithIrq<pac::Uarta>,
tx: Tx<pac::Uarta>,
}
#[shared]
struct Shared {
rb: StaticRb<u8, RX_RING_BUF_SIZE>,
}
rtic_monotonics::systick_monotonic!(Mono, 1_000);
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
rtt_init_print!();
rprintln!("-- VA108xx UART Echo with IRQ example application--");
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let mut dp = cx.device;
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let tx = gpioa.pa9.into_funsel_2();
let rx = gpioa.pa8.into_funsel_2();
let irq_uart = uart::Uart::new(
&mut dp.sysconfig,
SYSCLK_FREQ,
dp.uarta,
(tx, rx),
115200.Hz(),
);
let (tx, rx) = irq_uart.split();
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC3);
rx.start();
echo_handler::spawn().unwrap();
(
Shared {
rb: StaticRb::default(),
},
Local {
rx,
tx,
},
)
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
cortex_m::asm::nop();
}
}
#[task(
binds = OC3,
shared = [rb],
local = [
rx,
],
)]
fn reception_task(mut cx: reception_task::Context) {
let mut buf: [u8; 16] = [0; 16];
let mut ringbuf_full = false;
let result = cx.local.rx.irq_handler(&mut buf);
if result.bytes_read > 0 && result.errors.is_none() {
cx.shared.rb.lock(|rb| {
if rb.vacant_len() < result.bytes_read {
ringbuf_full = true;
} else {
rb.push_slice(&buf[0..result.bytes_read]);
}
});
}
if ringbuf_full {
// Could also drop oldest data, but that would require the consumer to be shared.
rprintln!("buffer full, data was dropped");
}
}
#[task(shared = [rb], local = [
buf: [u8; RX_RING_BUF_SIZE] = [0; RX_RING_BUF_SIZE],
tx
], priority=1)]
async fn echo_handler(mut cx: echo_handler::Context) {
loop {
cx.shared.rb.lock(|rb| {
let bytes_to_read = rb.occupied_len();
if bytes_to_read > 0 {
let actual_read_bytes = rb.pop_slice(&mut cx.local.buf[0..bytes_to_read]);
cx.local
.tx
.write_all(&cx.local.buf[0..actual_read_bytes])
.expect("Failed to write to TX");
}
});
Mono::delay(50.millis()).await;
}
}
}

4
examples/rtic/src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
#![no_std]
use va108xx_hal::time::Hertz;
pub const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);

71
examples/rtic/src/main.rs Normal file
View File

@ -0,0 +1,71 @@
//! RTIC minimal blinky
#![no_main]
#![no_std]
#[rtic::app(device = pac, dispatchers = [OC31, OC30, OC29])]
mod app {
use cortex_m::asm;
use embedded_hal::digital::StatefulOutputPin;
use panic_rtt_target as _;
use rtic_example::SYSCLK_FREQ;
use rtic_monotonics::systick::prelude::*;
use rtic_monotonics::Monotonic;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
gpio::{OutputReadablePushPull, Pin, PinsA, PA10, PA6, PA7},
pac,
};
#[local]
struct Local {
led0: Pin<PA10, OutputReadablePushPull>,
led1: Pin<PA7, OutputReadablePushPull>,
led2: Pin<PA6, OutputReadablePushPull>,
}
#[shared]
struct Shared {}
rtic_monotonics::systick_monotonic!(Mono, 1_000);
#[init]
fn init(mut cx: init::Context) -> (Shared, Local) {
rtt_init_print!();
rprintln!("-- Vorago VA108xx RTIC template --");
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let porta = PinsA::new(
&mut cx.device.sysconfig,
Some(cx.device.ioconfig),
cx.device.porta,
);
let led0 = porta.pa10.into_readable_push_pull_output();
let led1 = porta.pa7.into_readable_push_pull_output();
let led2 = porta.pa6.into_readable_push_pull_output();
blinky::spawn().ok();
(Shared {}, Local { led0, led1, led2 })
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
asm::nop();
}
}
#[task(
priority = 3,
local=[led0, led1, led2],
)]
async fn blinky(cx: blinky::Context) {
loop {
rprintln!("toggling LEDs");
cx.local.led0.toggle().ok();
cx.local.led1.toggle().ok();
cx.local.led2.toggle().ok();
Mono::delay(1000.millis()).await;
}
}
}

View File

@ -4,30 +4,20 @@ version = "0.1.0"
edition = "2021"
[dependencies]
panic-halt = "0.2"
cortex-m = {version = "0.7", features = ["critical-section-single-core"]}
panic-rtt-target = "0.1"
cortex-m-rt = "0.7"
panic-halt = "0.2"
panic-rtt-target = "0.1"
critical-section = "1"
rtt-target = "0.5"
rtic-sync = { version = "1.3", features = ["defmt-03"] }
embedded-hal = "1"
embedded-hal-nb = "1"
embedded-io = "0.6"
cortex-m-semihosting = "0.5.0"
# I'd really like to use those, but it is tricky without probe-rs..
# defmt = "0.3"
# defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] }
# panic-probe = { version = "0.3", features = ["print-defmt"] }
[dependencies.rtic]
version = "2"
features = ["thumbv6-backend"]
[dependencies.rtic-monotonics]
version = "1"
features = ["cortex-m-systick"]
[dependencies.va108xx-hal]
version = "0.7"
path = "../../va108xx-hal"
version = "0.8"
features = ["rt", "defmt"]
[dependencies.vorago-reb1]
path = "../../vorago-reb1"

View File

@ -16,8 +16,8 @@ use va108xx_hal::{
gpio::PinsA,
pac::{self, interrupt},
prelude::*,
pwm::{default_ms_irq_handler, set_up_ms_tick, CountDownTimer},
timer::DelayMs,
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer},
IrqCfg,
};
@ -32,7 +32,7 @@ fn main() -> ! {
dp.tim0,
))
.unwrap();
let mut delay_tim1 = CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let mut delay_tim1 = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim1);
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let mut led1 = porta.pa10.into_readable_push_pull_output();
let mut led2 = porta.pa7.into_readable_push_pull_output();

View File

@ -17,13 +17,13 @@ use va108xx_hal::{
prelude::*,
timer::{
default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource,
CountDownTimer, Event, IrqCfg,
CountdownTimer, Event, IrqCfg,
},
};
static CSD_TGT_1: Mutex<RefCell<Option<CountDownTimer<pac::Tim4>>>> =
static CSD_TGT_1: Mutex<RefCell<Option<CountdownTimer<pac::Tim4>>>> =
Mutex::new(RefCell::new(None));
static CSD_TGT_2: Mutex<RefCell<Option<CountDownTimer<pac::Tim5>>>> =
static CSD_TGT_2: Mutex<RefCell<Option<CountdownTimer<pac::Tim5>>>> =
Mutex::new(RefCell::new(None));
#[entry]
@ -36,7 +36,7 @@ fn main() -> ! {
// Will be started periodically to trigger a cascade
let mut cascade_triggerer =
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim3).auto_disable(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim3).auto_disable(true);
cascade_triggerer.listen(
Event::TimeOut,
IrqCfg::new(pac::Interrupt::OC1, true, false),
@ -46,9 +46,9 @@ fn main() -> ! {
// First target for cascade
let mut cascade_target_1 =
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim4).auto_deactivate(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim4).auto_deactivate(true);
cascade_target_1
.cascade_0_source(CascadeSource::TimBase, Some(3))
.cascade_0_source(CascadeSource::Tim(3))
.expect("Configuring cascade source for TIM4 failed");
let mut csd_cfg = CascadeCtrl {
enb_start_src_csd0: true,
@ -72,10 +72,10 @@ fn main() -> ! {
// Activated by first cascade target
let mut cascade_target_2 =
CountDownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim5).auto_deactivate(true);
CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim5).auto_deactivate(true);
// Set TIM4 as cascade source
cascade_target_2
.cascade_1_source(CascadeSource::TimBase, Some(4))
.cascade_1_source(CascadeSource::Tim(4))
.expect("Configuring cascade source for TIM5 failed");
csd_cfg = CascadeCtrl::default();

View File

@ -15,8 +15,8 @@ use va108xx_hal::{
gpio::{PinsA, PinsB},
pac::{self, interrupt},
prelude::*,
pwm::{default_ms_irq_handler, set_up_ms_tick},
spi::{self, Spi, SpiBase, TransferConfig},
spi::{self, Spi, SpiBase, SpiClkConfig, TransferConfigWithHwcs},
timer::{default_ms_irq_handler, set_up_ms_tick},
IrqCfg,
};
@ -24,8 +24,7 @@ use va108xx_hal::{
pub enum ExampleSelect {
// Enter loopback mode. It is not necessary to tie MOSI/MISO together for this
Loopback,
// Send a test buffer and print everything received
TestBuffer,
MosiMisoTiedTogetherManually,
}
#[derive(PartialEq, Debug)]
@ -55,6 +54,8 @@ fn main() -> ! {
dp.tim0,
);
let spi_clk_cfg = SpiClkConfig::from_clk(50.MHz(), SPI_SPEED_KHZ.kHz())
.expect("creating SPI clock config failed");
let spia_ref: RefCell<Option<SpiBase<pac::Spia, u8>>> = RefCell::new(None);
let spib_ref: RefCell<Option<SpiBase<pac::Spib, u8>>> = RefCell::new(None);
let pinsa = PinsA::new(&mut dp.sysconfig, None, dp.porta);
@ -79,7 +80,6 @@ fn main() -> ! {
dp.spia,
(sck, miso, mosi),
spi_cfg,
None,
);
spia.set_fill_word(FILL_WORD);
spia_ref.borrow_mut().replace(spia.downgrade());
@ -96,7 +96,6 @@ fn main() -> ! {
dp.spia,
(sck, miso, mosi),
spi_cfg,
None,
);
spia.set_fill_word(FILL_WORD);
spia_ref.borrow_mut().replace(spia.downgrade());
@ -113,7 +112,6 @@ fn main() -> ! {
dp.spib,
(sck, miso, mosi),
spi_cfg,
None,
);
spib.set_fill_word(FILL_WORD);
spib_ref.borrow_mut().replace(spib.downgrade());
@ -123,19 +121,25 @@ fn main() -> ! {
match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
if let Some(ref mut spi) = *spia_ref.borrow_mut() {
let transfer_cfg =
TransferConfig::new_no_hw_cs(SPI_SPEED_KHZ.kHz(), SPI_MODE, BLOCKMODE, false);
let transfer_cfg = TransferConfigWithHwcs::new_no_hw_cs(
Some(spi_clk_cfg),
Some(SPI_MODE),
BLOCKMODE,
true,
false,
);
spi.cfg_transfer(&transfer_cfg);
}
}
SpiBusSelect::SpiBPortB => {
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
let hw_cs_pin = pinsb.pb2.into_funsel_1();
let transfer_cfg = TransferConfig::new(
SPI_SPEED_KHZ.kHz(),
SPI_MODE,
let transfer_cfg = TransferConfigWithHwcs::new(
Some(spi_clk_cfg),
Some(SPI_MODE),
Some(hw_cs_pin),
BLOCKMODE,
true,
false,
);
spi.cfg_transfer(&transfer_cfg);
@ -149,7 +153,6 @@ fn main() -> ! {
match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {
if let Some(ref mut spi) = *spia_ref.borrow_mut() {
if EXAMPLE_SEL == ExampleSelect::Loopback {
// Can't really verify correct reply here.
spi.write(&[0x42]).expect("write failed");
// Because of the loopback mode, we should get back the fill word here.
@ -177,28 +180,12 @@ fn main() -> ! {
tx_rx_buf[2]
);
assert_eq!(&tx_rx_buf[0..3], &[0x03, 0x02, 0x01]);
} else {
let send_buf: [u8; 3] = [0x01, 0x02, 0x03];
spi.transfer(&mut reply_buf[0..3], &send_buf).unwrap();
rprintln!(
"Received reply: {}, {}, {}",
reply_buf[0],
reply_buf[1],
reply_buf[2]
);
delay.delay_ms(1000_u32);
}
}
}
SpiBusSelect::SpiBPortB => {
if let Some(ref mut spi) = *spib_ref.borrow_mut() {
if EXAMPLE_SEL == ExampleSelect::Loopback {
// Can't really verify correct reply here.
spi.write(&[0x42]).expect("write failed");
// Need small delay.. otherwise we will read back the sent byte (which we don't want here).
// The write function will return as soon as all bytes were shifted out, ignoring the
// reply bytes.
delay.delay_us(50);
// Because of the loopback mode, we should get back the fill word here.
spi.read(&mut reply_buf[0..1]).unwrap();
assert_eq!(reply_buf[0], FILL_WORD);
@ -224,17 +211,6 @@ fn main() -> ! {
tx_rx_buf[2]
);
assert_eq!(&tx_rx_buf[0..3], &[0x03, 0x02, 0x01]);
} else {
let send_buf: [u8; 3] = [0x01, 0x02, 0x03];
spi.transfer(&mut reply_buf[0..3], &send_buf).unwrap();
rprintln!(
"Received reply: {}, {}, {}",
reply_buf[0],
reply_buf[1],
reply_buf[2]
);
delay.delay_ms(1000_u32);
}
}
}
}

View File

@ -3,8 +3,8 @@
#![no_std]
use core::cell::Cell;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use critical_section::Mutex;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
@ -12,7 +12,7 @@ use va108xx_hal::{
pac::{self, interrupt},
prelude::*,
time::Hertz,
timer::{default_ms_irq_handler, set_up_ms_tick, CountDownTimer, Event, IrqCfg, MS_COUNTER},
timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, Event, IrqCfg, MS_COUNTER},
};
#[allow(dead_code)]
@ -72,7 +72,7 @@ fn main() -> ! {
dp.tim0,
);
let mut second_timer =
CountDownTimer::new(&mut dp.sysconfig, get_sys_clock().unwrap(), dp.tim1);
CountdownTimer::new(&mut dp.sysconfig, get_sys_clock().unwrap(), dp.tim1);
second_timer.listen(
Event::TimeOut,
IrqCfg::new(interrupt::OC1, true, true),
@ -83,11 +83,12 @@ fn main() -> ! {
}
}
loop {
let current_ms = cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get());
let current_ms = critical_section::with(|cs| MS_COUNTER.borrow(cs).get());
if current_ms - last_ms >= 1000 {
last_ms = current_ms;
// To prevent drift.
last_ms += 1000;
rprintln!("MS counter: {}", current_ms);
let second = cortex_m::interrupt::free(|cs| SEC_COUNTER.borrow(cs).get());
let second = critical_section::with(|cs| SEC_COUNTER.borrow(cs).get());
rprintln!("Second counter: {}", second);
}
cortex_m::asm::delay(10000);
@ -110,7 +111,7 @@ fn OC0() {
#[interrupt]
#[allow(non_snake_case)]
fn OC1() {
cortex_m::interrupt::free(|cs| {
critical_section::with(|cs| {
let mut sec = SEC_COUNTER.borrow(cs).get();
sec += 1;
SEC_COUNTER.borrow(cs).set(sec);

View File

@ -1,172 +0,0 @@
//! More complex UART application
//!
//! Uses the IRQ capabilities of the VA10820 peripheral and the RTIC framework to poll the UART in
//! a non-blocking way. You can send variably sized strings to the VA10820 which will be echoed
//! back to the sender.
//!
//! This script was tested with an Arduino Due. You can find the test script in the
//! [`/test/DueSerialTest`](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/test/DueSerialTest)
//! folder.
#![no_main]
#![no_std]
#[rtic::app(device = pac, dispatchers = [OC4])]
mod app {
use embedded_io::Write;
use panic_rtt_target as _;
use rtic_monotonics::systick::Systick;
use rtic_sync::make_channel;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
gpio::PinsB,
pac,
prelude::*,
time::Hertz,
uart::{self, IrqCfg, IrqResult, UartWithIrqBase},
};
#[local]
struct Local {
rx_info_tx: rtic_sync::channel::Sender<'static, RxInfo, 3>,
rx_info_rx: rtic_sync::channel::Receiver<'static, RxInfo, 3>,
}
#[shared]
struct Shared {
irq_uart: UartWithIrqBase<pac::Uartb>,
rx_buf: [u8; 64],
}
#[derive(Debug, Copy, Clone)]
struct RxInfo {
pub bytes_read: usize,
pub end_idx: usize,
pub timeout: bool,
}
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
rtt_init_print!();
//set_print_channel(channels.up.0);
rprintln!("-- VA108xx UART IRQ example application--");
// Initialize the systick interrupt & obtain the token to prove that we did
let systick_mono_token = rtic_monotonics::create_systick_token!();
Systick::start(
cx.core.SYST,
Hertz::from(50.MHz()).raw(),
systick_mono_token,
);
let mut dp = cx.device;
let gpiob = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb);
let tx = gpiob.pb21.into_funsel_1();
let rx = gpiob.pb20.into_funsel_1();
let irq_cfg = IrqCfg::new(pac::interrupt::OC3, true, true);
let (mut irq_uart, _) =
uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uartb, (tx, rx), 115200.Hz())
.into_uart_with_irq(irq_cfg, Some(&mut dp.sysconfig), Some(&mut dp.irqsel))
.downgrade();
irq_uart
.read_fixed_len_using_irq(64, true)
.expect("Read initialization failed");
let (rx_info_tx, rx_info_rx) = make_channel!(RxInfo, 3);
let rx_buf: [u8; 64] = [0; 64];
//reply_handler::spawn().expect("spawning reply handler failed");
(
Shared { irq_uart, rx_buf },
Local {
rx_info_tx,
rx_info_rx,
},
)
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
cortex_m::asm::nop();
}
}
#[task(
binds = OC3,
shared = [irq_uart, rx_buf],
local = [cnt: u32 = 0, result: IrqResult = IrqResult::new(), rx_info_tx],
)]
fn reception_task(cx: reception_task::Context) {
let result = cx.local.result;
let cnt: &mut u32 = cx.local.cnt;
let irq_uart = cx.shared.irq_uart;
let rx_buf = cx.shared.rx_buf;
let (completed, end_idx) = (irq_uart, rx_buf).lock(|irq_uart, rx_buf| {
match irq_uart.irq_handler(result, rx_buf) {
Ok(_) => {
if result.complete() {
// Initiate next transfer immediately
irq_uart
.read_fixed_len_using_irq(64, true)
.expect("Read operation init failed");
let mut end_idx = 0;
for idx in 0..rx_buf.len() {
if (rx_buf[idx] as char) == '\n' {
end_idx = idx;
break;
}
}
(true, end_idx)
} else {
(false, 0)
}
}
Err(e) => {
rprintln!("reception error {:?}", e);
(false, 0)
}
}
});
if completed {
rprintln!("counter: {}", cnt);
cx.local
.rx_info_tx
.try_send(RxInfo {
bytes_read: result.bytes_read,
end_idx,
timeout: result.timeout(),
})
.expect("RX queue full");
}
*cnt += 1;
}
#[task(shared = [irq_uart, rx_buf], local = [rx_info_rx], priority=1)]
async fn reply_handler(cx: reply_handler::Context) {
let mut irq_uart = cx.shared.irq_uart;
let mut rx_buf = cx.shared.rx_buf;
loop {
match cx.local.rx_info_rx.recv().await {
Ok(rx_info) => {
rprintln!("reception success, {} bytes read", rx_info.bytes_read);
if rx_info.timeout {
rprintln!("timeout occurred");
}
rx_buf.lock(|rx_buf| {
let string = core::str::from_utf8(&rx_buf[0..rx_info.end_idx])
.expect("Invalid string format");
rprintln!("read string: {}", string);
irq_uart.lock(|uart| {
writeln!(uart.uart, "{}", string).expect("Sending reply failed");
});
});
}
Err(e) => {
rprintln!("error receiving RX info: {:?}", e);
}
}
}
}
}

1
flashloader/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/venv

66
flashloader/Cargo.toml Normal file
View File

@ -0,0 +1,66 @@
[package]
name = "flashloader"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-hal-nb = "1"
embedded-io = "0.6"
panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" }
num_enum = { version = "0.7", default-features = false }
log = "0.4"
crc = "3"
[dependencies.satrs]
version = "0.2"
default-features = false
[dependencies.rtt-log]
version = "0.4"
[dependencies.ringbuf]
version = "0.4.7"
default-features = false
features = ["portable-atomic"]
[dependencies.once_cell]
version = "1"
default-features = false
features = ["critical-section"]
[dependencies.spacepackets]
version = "0.11"
default-features = false
[dependencies.cobs]
git = "https://github.com/robamu/cobs.rs.git"
branch = "all_features"
default-features = false
# Even though we do not use this directly, we need to activate this feature explicitely
# so that RTIC compiles because thumv6 does not have CAS operations natively.
[dependencies.portable-atomic]
version = "1"
features = ["unsafe-assume-single-core"]
[dependencies.rtic]
version = "2"
features = ["thumbv6-backend"]
[dependencies.rtic-monotonics]
version = "2"
features = ["cortex-m-systick"]
[dependencies.rtic-sync]
version = "1"
features = ["defmt-03"]
[dependencies.va108xx-hal]
path = "../va108xx-hal"
[dependencies.vorago-reb1]
path = "../vorago-reb1"

75
flashloader/README.md Normal file
View File

@ -0,0 +1,75 @@
VA108xx Flashloader Application
========
This flashloader shows a minimal example for a self-updatable Rust software which exposes
a simple PUS (CCSDS) interface to update the software. It also provides a Python application
called the `image-loader.py` which can be used to upload compiled images to the flashloader
application to write them to the NVM.
Please note that the both the application and the image loader are tailored towards usage
with the [bootloader provided by this repository](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/bootloader).
The software can quickly be adapted to interface with a real primary on-board software instead of
the Python script provided here to upload images because it uses a low-level CCSDS based packet
interface.
## Using the Python image loader
The Python image loader communicates with the Rust flashload application using a dedicated serial
port with a baudrate of 115200.
It is recommended to run the script in a dedicated virtual environment. For example, on UNIX
systems you can use `python3 -m venv venv` and then `source venv/bin/activate` to create
and activate a virtual environment.
After that, you can use
```sh
pip install -r requirements.txt
```
to install all required dependencies.
After that, it is recommended to use `./image-load.py -h` to get an overview of some options.
The flash loader uses the UART0 with the Pins PA8 (RX) and PA9 (TX) interface of the VA108xx to perform CCSDS based
communication. The Python image loader application will search for a file named `loader.toml` and
use the `serial_port` key to determine the serial port to use for serial communication.
### Examples
You can use
```sh
./image-loader.py -p
```
to send a ping an verify the connection.
You can use
```sh
cd flashloader/slot-a-blinky
cargo build --release
cd ../..
./image-loader.py -t a ./slot-a-blinky/target/thumbv6m-none-eabi/release/slot-a-blinky
```
to build the slot A sample application and upload it to a running flash loader application
to write it to slot A.
You can use
```sh
./image-loader.py -s a
```
to select the Slot A as a boot slot. The boot slot is stored in a reserved section in EEPROM
and will be read and used by the bootloader to determine which slot to boot.
You can use
```sh
./image-loader.py -c -t a
```
to corrupt the image A and test that it switches to image B after a failed CRC check instead.

475
flashloader/image-loader.py Executable file
View File

@ -0,0 +1,475 @@
#!/usr/bin/env python3
from typing import List, Tuple
from spacepackets.ecss.defs import PusService
from spacepackets.ecss.tm import PusTm
from tmtccmd.com import ComInterface
import toml
import struct
import logging
import argparse
import time
import enum
from tmtccmd.com.serial_base import SerialCfg
from tmtccmd.com.serial_cobs import SerialCobsComIF
from tmtccmd.com.ser_utils import prompt_com_port
from crcmod.predefined import PredefinedCrc
from spacepackets.ecss.tc import PusTc
from spacepackets.ecss.pus_verificator import PusVerificator, StatusField
from spacepackets.ecss.pus_1_verification import Service1Tm, UnpackParams
from spacepackets.seqcount import SeqCountProvider
from pathlib import Path
import dataclasses
from elftools.elf.elffile import ELFFile
BAUD_RATE = 115200
BOOTLOADER_START_ADDR = 0x0
BOOTLOADER_END_ADDR = 0x3000
BOOTLOADER_CRC_ADDR = BOOTLOADER_END_ADDR - 2
BOOTLOADER_MAX_SIZE = BOOTLOADER_END_ADDR - BOOTLOADER_START_ADDR - 2
APP_A_START_ADDR = 0x3000
APP_B_END_ADDR = 0x20000 - 8
IMG_SLOT_SIZE = (APP_B_END_ADDR - APP_A_START_ADDR) // 2
APP_A_END_ADDR = APP_A_START_ADDR + IMG_SLOT_SIZE
# The actual size of the image which is relevant for CRC calculation.
APP_A_SIZE_ADDR = APP_A_END_ADDR - 8
APP_A_CRC_ADDR = APP_A_END_ADDR - 4
APP_A_MAX_SIZE = APP_A_END_ADDR - APP_A_START_ADDR - 8
APP_B_START_ADDR = APP_A_END_ADDR
# The actual size of the image which is relevant for CRC calculation.
APP_B_SIZE_ADDR = APP_B_END_ADDR - 8
APP_B_CRC_ADDR = APP_B_END_ADDR - 4
APP_B_MAX_SIZE = APP_A_END_ADDR - APP_A_START_ADDR - 8
CHUNK_SIZE = 400
MEMORY_SERVICE = 6
ACTION_SERVICE = 8
RAW_MEMORY_WRITE_SUBSERVICE = 2
BOOT_NVM_MEMORY_ID = 1
PING_PAYLOAD_SIZE = 0
class ActionId(enum.IntEnum):
CORRUPT_APP_A = 128
CORRUPT_APP_B = 129
SET_BOOT_SLOT = 130
_LOGGER = logging.getLogger(__name__)
SEQ_PROVIDER = SeqCountProvider(bit_width=14)
@dataclasses.dataclass
class LoadableSegment:
name: str
offset: int
size: int
data: bytes
class Target(enum.Enum):
BOOTLOADER = 0
APP_A = 1
APP_B = 2
class AppSel(enum.IntEnum):
APP_A = 0
APP_B = 1
class ImageLoader:
def __init__(self, com_if: ComInterface, verificator: PusVerificator) -> None:
self.com_if = com_if
self.verificator = verificator
def handle_boot_sel_cmd(self, target: AppSel):
_LOGGER.info("Sending ping command")
action_tc = PusTc(
apid=0x00,
service=PusService.S8_FUNC_CMD,
subservice=ActionId.SET_BOOT_SLOT,
seq_count=SEQ_PROVIDER.get_and_increment(),
app_data=bytes([target]),
)
self.verificator.add_tc(action_tc)
self.com_if.send(bytes(action_tc.pack()))
data_available = self.com_if.data_available(0.4)
if not data_available:
_LOGGER.warning("no reply received for boot image selection command")
for reply in self.com_if.receive():
result = self.verificator.add_tm(
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
)
if result is not None and result.completed:
_LOGGER.info("received boot image selection command confirmation")
def handle_ping_cmd(self):
_LOGGER.info("Sending ping command")
ping_tc = PusTc(
apid=0x00,
service=PusService.S17_TEST,
subservice=1,
seq_count=SEQ_PROVIDER.get_and_increment(),
app_data=bytes(PING_PAYLOAD_SIZE),
)
self.verificator.add_tc(ping_tc)
self.com_if.send(bytes(ping_tc.pack()))
data_available = self.com_if.data_available(0.4)
if not data_available:
_LOGGER.warning("no ping reply received")
for reply in self.com_if.receive():
result = self.verificator.add_tm(
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
)
if result is not None and result.completed:
_LOGGER.info("received ping completion reply")
def handle_corruption_cmd(self, target: Target):
if target == Target.BOOTLOADER:
_LOGGER.error("can not corrupt bootloader")
if target == Target.APP_A:
self.send_tc(
PusTc(
apid=0,
service=ACTION_SERVICE,
subservice=ActionId.CORRUPT_APP_A,
),
)
if target == Target.APP_B:
self.send_tc(
PusTc(
apid=0,
service=ACTION_SERVICE,
subservice=ActionId.CORRUPT_APP_B,
),
)
def handle_flash_cmd(self, target: Target, file_path: Path) -> int:
loadable_segments = []
_LOGGER.info("Parsing ELF file for loadable sections")
total_size = 0
loadable_segments, total_size = create_loadable_segments(target, file_path)
check_segments(target, total_size)
print_segments_info(target, loadable_segments, total_size, file_path)
result = self._perform_flashing_algorithm(loadable_segments)
if result != 0:
return result
self._crc_and_app_size_postprocessing(target, total_size, loadable_segments)
return 0
def _perform_flashing_algorithm(
self,
loadable_segments: List[LoadableSegment],
) -> int:
# Perform the flashing algorithm.
for segment in loadable_segments:
segment_end = segment.offset + segment.size
current_addr = segment.offset
pos_in_segment = 0
while pos_in_segment < segment.size:
next_chunk_size = min(segment_end - current_addr, CHUNK_SIZE)
data = segment.data[pos_in_segment : pos_in_segment + next_chunk_size]
next_packet = pack_memory_write_command(current_addr, data)
_LOGGER.info(
f"Sending memory write command for address {current_addr:#08x} and data with "
f"length {len(data)}"
)
self.verificator.add_tc(next_packet)
self.com_if.send(bytes(next_packet.pack()))
current_addr += next_chunk_size
pos_in_segment += next_chunk_size
start_time = time.time()
while True:
if time.time() - start_time > 1.0:
_LOGGER.error("Timeout while waiting for reply")
return -1
data_available = self.com_if.data_available(0.1)
done = False
if not data_available:
continue
replies = self.com_if.receive()
for reply in replies:
tm = PusTm.unpack(reply, 0)
if tm.service != 1:
continue
service_1_tm = Service1Tm.from_tm(tm, UnpackParams(0))
check_result = self.verificator.add_tm(service_1_tm)
# We could send after we have received the step reply, but that can
# somehow lead to overrun errors. I think it's okay to do it like
# this as long as the flash loader only uses polling..
if (
check_result is not None
and check_result.status.completed == StatusField.SUCCESS
):
done = True
# This is an optimized variant, but I think the small delay is not an issue.
"""
if (
check_result is not None
and check_result.status.step == StatusField.SUCCESS
and len(check_result.status.step_list) == 1
):
done = True
"""
self.verificator.remove_completed_entries()
if done:
break
return 0
def _crc_and_app_size_postprocessing(
self,
target: Target,
total_size: int,
loadable_segments: List[LoadableSegment],
):
if target == Target.BOOTLOADER:
_LOGGER.info("Blanking the bootloader checksum")
# Blank the checksum. For the bootloader, the bootloader will calculate the
# checksum itself on the initial run.
checksum_write_packet = pack_memory_write_command(
BOOTLOADER_CRC_ADDR, bytes([0x00, 0x00])
)
self.send_tc(checksum_write_packet)
else:
crc_addr = None
size_addr = None
if target == Target.APP_A:
crc_addr = APP_A_CRC_ADDR
size_addr = APP_A_SIZE_ADDR
elif target == Target.APP_B:
crc_addr = APP_B_CRC_ADDR
size_addr = APP_B_SIZE_ADDR
assert crc_addr is not None
assert size_addr is not None
_LOGGER.info(f"Writing app size {total_size} at address {size_addr:#08x}")
size_write_packet = pack_memory_write_command(
size_addr, struct.pack("!I", total_size)
)
self.com_if.send(bytes(size_write_packet.pack()))
time.sleep(0.2)
crc_calc = PredefinedCrc("crc-ccitt-false")
for segment in loadable_segments:
crc_calc.update(segment.data)
checksum = crc_calc.digest()
_LOGGER.info(
f"Writing checksum 0x[{checksum.hex(sep=',')}] at address {crc_addr:#08x}"
)
self.send_tc(pack_memory_write_command(crc_addr, checksum))
def send_tc(self, tc: PusTc):
self.com_if.send(bytes(tc.pack()))
def main() -> int:
print("Python VA108XX Image Loader Application")
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s", level=logging.DEBUG
)
parser = argparse.ArgumentParser(
prog="image-loader", description="Python VA416XX Image Loader Application"
)
parser.add_argument("-p", "--ping", action="store_true", help="Send ping command")
parser.add_argument(
"-s", "--sel", choices=["a", "b"], help="Set boot slot (Slot A or B)"
)
parser.add_argument("-c", "--corrupt", action="store_true", help="Corrupt a target")
parser.add_argument(
"-t",
"--target",
choices=["bl", "a", "b"],
help="Target (Bootloader or slot A or B)",
)
parser.add_argument(
"path", nargs="?", default=None, help="Path to the App to flash"
)
args = parser.parse_args()
serial_port = None
if Path("loader.toml").exists():
with open("loader.toml", "r") as toml_file:
parsed_toml = toml.loads(toml_file.read())
if "serial_port" in parsed_toml:
serial_port = parsed_toml["serial_port"]
if serial_port is None:
serial_port = prompt_com_port()
serial_cfg = SerialCfg(
com_if_id="ser_cobs",
serial_port=serial_port,
baud_rate=BAUD_RATE,
serial_timeout=0.1,
)
verificator = PusVerificator()
com_if = SerialCobsComIF(serial_cfg)
com_if.open()
target = None
if args.target == "bl":
target = Target.BOOTLOADER
elif args.target == "a":
target = Target.APP_A
elif args.target == "b":
target = Target.APP_B
boot_sel = None
if args.sel:
if args.sel == "a":
boot_sel = AppSel.APP_A
elif args.sel == "b":
boot_sel = AppSel.APP_B
image_loader = ImageLoader(com_if, verificator)
file_path = None
result = -1
if args.ping:
image_loader.handle_ping_cmd()
com_if.close()
return 0
if args.sel and boot_sel is not None:
image_loader.handle_boot_sel_cmd(boot_sel)
if target:
if not args.corrupt:
if not args.path:
_LOGGER.error("App Path needs to be specified for the flash process")
file_path = Path(args.path)
if not file_path.exists():
_LOGGER.error("File does not exist")
if args.corrupt:
if not target:
_LOGGER.error("target for corruption command required")
com_if.close()
return -1
image_loader.handle_corruption_cmd(target)
else:
if file_path is not None:
assert target is not None
result = image_loader.handle_flash_cmd(target, file_path)
com_if.close()
return result
def create_loadable_segments(
target: Target, file_path: Path
) -> Tuple[List[LoadableSegment], int]:
loadable_segments = []
total_size = 0
with open(file_path, "rb") as app_file:
elf_file = ELFFile(app_file)
for idx, segment in enumerate(elf_file.iter_segments("PT_LOAD")):
if segment.header.p_filesz == 0:
continue
# Basic validity checks of the base addresses.
if idx == 0:
if (
target == Target.BOOTLOADER
and segment.header.p_paddr != BOOTLOADER_START_ADDR
):
raise ValueError(
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
f"bootloader, expected {BOOTLOADER_START_ADDR}"
)
if (
target == Target.APP_A
and segment.header.p_paddr != APP_A_START_ADDR
):
raise ValueError(
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
f"App A, expected {APP_A_START_ADDR}"
)
if (
target == Target.APP_B
and segment.header.p_paddr != APP_B_START_ADDR
):
raise ValueError(
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
f"App B, expected {APP_B_START_ADDR}"
)
name = None
for section in elf_file.iter_sections():
if (
section.header.sh_offset == segment.header.p_offset
and section.header.sh_size > 0
):
name = section.name
if name is None:
_LOGGER.warning("no fitting section found for segment")
continue
# print(f"Segment Addr: {segment.header.p_paddr}")
# print(f"Segment Offset: {segment.header.p_offset}")
# print(f"Segment Filesize: {segment.header.p_filesz}")
loadable_segments.append(
LoadableSegment(
name=name,
offset=segment.header.p_paddr,
size=segment.header.p_filesz,
data=segment.data(),
)
)
total_size += segment.header.p_filesz
return loadable_segments, total_size
def check_segments(
target: Target,
total_size: int,
):
# Set context string and perform basic sanity checks.
if target == Target.BOOTLOADER and total_size > BOOTLOADER_MAX_SIZE:
raise ValueError(
f"provided bootloader app larger than allowed {total_size} bytes"
)
elif target == Target.APP_A and total_size > APP_A_MAX_SIZE:
raise ValueError(f"provided App A larger than allowed {total_size} bytes")
elif target == Target.APP_B and total_size > APP_B_MAX_SIZE:
raise ValueError(f"provided App B larger than allowed {total_size} bytes")
def print_segments_info(
target: Target,
loadable_segments: List[LoadableSegment],
total_size: int,
file_path: Path,
):
# Set context string and perform basic sanity checks.
if target == Target.BOOTLOADER:
context_str = "Bootloader"
elif target == Target.APP_A:
context_str = "App Slot A"
elif target == Target.APP_B:
context_str = "App Slot B"
_LOGGER.info(f"Flashing {context_str} with image {file_path} (size {total_size})")
for idx, segment in enumerate(loadable_segments):
_LOGGER.info(
f"Loadable section {idx} {segment.name} with offset {segment.offset:#08x} and "
f"size {segment.size}"
)
def pack_memory_write_command(addr: int, data: bytes) -> PusTc:
app_data = bytearray()
app_data.append(BOOT_NVM_MEMORY_ID)
# N parameter is always 1 here.
app_data.append(1)
app_data.extend(struct.pack("!I", addr))
app_data.extend(struct.pack("!I", len(data)))
app_data.extend(data)
return PusTc(
apid=0,
service=MEMORY_SERVICE,
subservice=RAW_MEMORY_WRITE_SUBSERVICE,
seq_count=SEQ_PROVIDER.get_and_increment(),
app_data=bytes(app_data),
)
if __name__ == "__main__":
main()

1
flashloader/loader.toml Normal file
View File

@ -0,0 +1 @@
serial_port = "/dev/ttyUSB0"

View File

@ -0,0 +1,5 @@
spacepackets == 0.24
tmtccmd == 8.0.2
toml == 0.10
pyelftools == 0.31
crcmod == 1.7

2
flashloader/slot-a-blinky/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/app.map

View File

@ -0,0 +1,42 @@
[package]
name = "slot-a-blinky"
version = "0.1.0"
edition = "2021"
[workspace]
[dependencies]
cortex-m-rt = "0.7"
panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
embedded-hal = "1"
va108xx-hal = { path = "../../va108xx-hal" }
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
# This is problematic for stepping..
# opt-level = 'z' # <-
overflow-checks = true # <-
# cargo build/run --release
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-
[profile.small]
inherits = "release"
codegen-units = 1
debug-assertions = false # <-
lto = true
opt-level = 'z' # <-
overflow-checks = false # <-
# strip = true # Automatically strip symbols from the binary.

View File

@ -0,0 +1,11 @@
/* Special linker script for application slot A with an offset at address 0x3000 */
MEMORY
{
FLASH : ORIGIN = 0x00003000, LENGTH = 0xE7FC
RAM : ORIGIN = 0x10000000, LENGTH = 0x08000 /* 32K */
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);

View File

@ -0,0 +1,25 @@
//! Simple blinky example using the HAL
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer};
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("VA108xx HAL blinky example for App Slot A");
let mut dp = pac::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0);
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let mut led1 = porta.pa10.into_readable_push_pull_output();
loop {
led1.toggle().ok();
timer.delay_ms(500);
}
}

2
flashloader/slot-b-blinky/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/app.map

View File

@ -0,0 +1,42 @@
[package]
name = "slot-b-blinky"
version = "0.1.0"
edition = "2021"
[workspace]
[dependencies]
cortex-m-rt = "0.7"
panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
embedded-hal = "1"
va108xx-hal = { path = "../../va108xx-hal" }
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
# This is problematic for stepping..
# opt-level = 'z' # <-
overflow-checks = true # <-
# cargo build/run --release
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-
[profile.small]
inherits = "release"
codegen-units = 1
debug-assertions = false # <-
lto = true
opt-level = 'z' # <-
overflow-checks = false # <-
# strip = true # Automatically strip symbols from the binary.

View File

@ -0,0 +1,11 @@
/* Special linker script for application slot B */
MEMORY
{
FLASH : ORIGIN = 0x000117FC, LENGTH = 0xE7FC
RAM : ORIGIN = 0x10000000, LENGTH = 0x08000 /* 32K */
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);

View File

@ -0,0 +1,25 @@
//! Simple blinky example using the HAL
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer};
#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("VA108xx HAL blinky example for App Slot B");
let mut dp = pac::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0);
let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let mut led2 = porta.pa7.into_readable_push_pull_output();
loop {
led2.toggle().ok();
timer.delay_ms(1000);
}
}

9
flashloader/src/lib.rs Normal file
View File

@ -0,0 +1,9 @@
#![no_std]
#[cfg(test)]
mod tests {
#[test]
fn simple() {
assert_eq!(1 + 1, 2);
}
}

467
flashloader/src/main.rs Normal file
View File

@ -0,0 +1,467 @@
//! Vorago flashloader which can be used to flash image A and image B via a simple
//! low-level CCSDS memory interface via a UART interface.
#![no_main]
#![no_std]
use num_enum::TryFromPrimitive;
use panic_rtt_target as _;
use ringbuf::{
traits::{Consumer, Observer, Producer},
StaticRb,
};
use va108xx_hal::prelude::*;
const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
const MAX_TC_SIZE: usize = 524;
const MAX_TC_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TC_SIZE);
const MAX_TM_SIZE: usize = 128;
const MAX_TM_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TM_SIZE);
const UART_BAUDRATE: u32 = 115200;
const BOOT_NVM_MEMORY_ID: u8 = 1;
const RX_DEBUGGING: bool = false;
pub enum ActionId {
CorruptImageA = 128,
CorruptImageB = 129,
SetBootSlot = 130,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive)]
#[repr(u8)]
enum AppSel {
A = 0,
B = 1,
}
// Larger buffer for TC to be able to hold the possibly large memory write packets.
const BUF_RB_SIZE_TC: usize = 1024;
const SIZES_RB_SIZE_TC: usize = 16;
const BUF_RB_SIZE_TM: usize = 256;
const SIZES_RB_SIZE_TM: usize = 16;
pub struct RingBufWrapper<const BUF_SIZE: usize, const SIZES_LEN: usize> {
pub buf: StaticRb<u8, BUF_SIZE>,
pub sizes: StaticRb<usize, SIZES_LEN>,
}
pub const APP_A_START_ADDR: u32 = 0x3000;
pub const APP_A_END_ADDR: u32 = 0x117FC;
pub const APP_B_START_ADDR: u32 = APP_A_END_ADDR;
pub const APP_B_END_ADDR: u32 = 0x20000;
pub const PREFERRED_SLOT_OFFSET: u32 = 0x20000 - 1;
#[rtic::app(device = pac, dispatchers = [OC20, OC21, OC22])]
mod app {
use super::*;
use cortex_m::asm;
use embedded_io::Write;
use panic_rtt_target as _;
use rtic::Mutex;
use rtic_monotonics::systick::prelude::*;
use rtt_target::rprintln;
use satrs::pus::verification::{FailParams, VerificationReportCreator};
use spacepackets::ecss::PusServiceId;
use spacepackets::ecss::{
tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket,
};
use va108xx_hal::gpio::PinsA;
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
use va108xx_hal::{pac, uart};
use vorago_reb1::m95m01::M95M01;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum CobsReaderStates {
#[default]
WaitingForStart,
WatingForEnd,
FrameOverflow,
}
#[local]
struct Local {
uart_rx: uart::RxWithIrq<pac::Uarta>,
uart_tx: uart::Tx<pac::Uarta>,
rx_context: IrqContextTimeoutOrMaxSize,
verif_reporter: VerificationReportCreator,
nvm: M95M01,
}
#[shared]
struct Shared {
// Having this shared allows multiple tasks to generate telemetry.
tm_rb: RingBufWrapper<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
tc_rb: RingBufWrapper<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
}
rtic_monotonics::systick_monotonic!(Mono, 1000);
#[init]
fn init(cx: init::Context) -> (Shared, Local) {
rtt_log::init();
rprintln!("-- Vorago flashloader --");
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let mut dp = cx.device;
let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let tx = gpioa.pa9.into_funsel_2();
let rx = gpioa.pa8.into_funsel_2();
let irq_uart = uart::Uart::new(
&mut dp.sysconfig,
SYSCLK_FREQ,
dp.uarta,
(tx, rx),
UART_BAUDRATE.Hz(),
);
let (tx, rx) = irq_uart.split();
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC0);
let verif_reporter = VerificationReportCreator::new(0).unwrap();
let mut rx_context = IrqContextTimeoutOrMaxSize::new(MAX_TC_FRAME_SIZE);
rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context)
.expect("initiating UART RX failed");
pus_tc_handler::spawn().unwrap();
pus_tm_tx_handler::spawn().unwrap();
(
Shared {
tc_rb: RingBufWrapper {
buf: StaticRb::default(),
sizes: StaticRb::default(),
},
tm_rb: RingBufWrapper {
buf: StaticRb::default(),
sizes: StaticRb::default(),
},
},
Local {
uart_rx: rx,
uart_tx: tx,
rx_context,
verif_reporter,
nvm,
},
)
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
asm::nop();
}
}
// This is the interrupt handler to read all bytes received on the UART0.
#[task(
binds = OC0,
local = [
cnt: u32 = 0,
rx_buf: [u8; MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE],
rx_context,
uart_rx,
],
shared = [tc_rb]
)]
fn uart_rx_irq(mut cx: uart_rx_irq::Context) {
match cx
.local
.uart_rx
.irq_handler_max_size_or_timeout_based(cx.local.rx_context, cx.local.rx_buf)
{
Ok(result) => {
if RX_DEBUGGING {
log::debug!("RX Info: {:?}", cx.local.rx_context);
log::debug!("RX Result: {:?}", result);
}
if result.complete() {
// Check frame validity (must have COBS format) and decode the frame.
// Currently, we expect a full frame or a frame received through a timeout
// to be one COBS frame. We could parse for multiple COBS packets in one
// frame, but the additional complexity is not necessary here..
if cx.local.rx_buf[0] == 0 && cx.local.rx_buf[result.bytes_read - 1] == 0 {
let decoded_size =
cobs::decode_in_place(&mut cx.local.rx_buf[1..result.bytes_read]);
if decoded_size.is_err() {
log::warn!("COBS decoding failed");
} else {
let decoded_size = decoded_size.unwrap();
let mut tc_rb_full = false;
cx.shared.tc_rb.lock(|rb| {
if rb.sizes.vacant_len() >= 1 && rb.buf.vacant_len() >= decoded_size
{
rb.sizes.try_push(decoded_size).unwrap();
rb.buf.push_slice(&cx.local.rx_buf[1..1 + decoded_size]);
} else {
tc_rb_full = true;
}
});
if tc_rb_full {
log::warn!("COBS TC queue full");
}
}
} else {
log::warn!("COBS frame with invalid format, start and end bytes are not 0");
}
// Initiate next transfer.
cx.local
.uart_rx
.read_fixed_len_or_timeout_based_using_irq(cx.local.rx_context)
.expect("read operation failed");
}
if result.has_errors() {
log::warn!("UART error: {:?}", result.errors.unwrap());
}
}
Err(e) => {
log::warn!("UART error: {:?}", e);
}
}
}
#[task(
priority = 2,
local=[
tc_buf: [u8; MAX_TC_SIZE] = [0; MAX_TC_SIZE],
readback_buf: [u8; MAX_TC_SIZE] = [0; MAX_TC_SIZE],
src_data_buf: [u8; 16] = [0; 16],
verif_buf: [u8; 32] = [0; 32],
nvm,
verif_reporter
],
shared=[tm_rb, tc_rb]
)]
async fn pus_tc_handler(mut cx: pus_tc_handler::Context) {
loop {
// Try to read a TC from the ring buffer.
let packet_len = cx.shared.tc_rb.lock(|rb| rb.sizes.try_pop());
if packet_len.is_none() {
// Small delay, TCs might arrive very quickly.
Mono::delay(20.millis()).await;
continue;
}
let packet_len = packet_len.unwrap();
log::info!(target: "TC Handler", "received packet with length {}", packet_len);
let popped_packet_len = cx.shared.tc_rb.lock(|rb| {
rb.buf
.pop_slice(&mut cx.local.tc_buf[0..packet_len])
});
assert_eq!(popped_packet_len, packet_len);
// Read a telecommand, now handle it.
handle_valid_pus_tc(&mut cx);
}
}
fn handle_valid_pus_tc(cx: &mut pus_tc_handler::Context) {
let pus_tc = PusTcReader::new(cx.local.tc_buf);
if pus_tc.is_err() {
log::warn!(target: "TC Handler", "PUS TC error: {}", pus_tc.unwrap_err());
return;
}
let (pus_tc, _) = pus_tc.unwrap();
let mut write_and_send = |tm: &PusTmCreator| {
let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap();
cx.shared.tm_rb.lock(|prod| {
prod.sizes.try_push(tm.len_written()).unwrap();
prod.buf
.push_slice(&cx.local.verif_buf[0..written_size]);
});
};
let token = cx.local.verif_reporter.add_tc(&pus_tc);
let (tm, accepted_token) = cx
.local
.verif_reporter
.acceptance_success(cx.local.src_data_buf, token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
let (tm, started_token) = cx
.local
.verif_reporter
.start_success(cx.local.src_data_buf, accepted_token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
if pus_tc.service() == PusServiceId::Action as u8 {
let mut corrupt_image = |base_addr: u32| {
let mut buf = [0u8; 4];
cx.local
.nvm
.read(base_addr as usize + 32, &mut buf)
.expect("reading from NVM failed");
buf[0] += 1;
cx.local
.nvm
.write(base_addr as usize + 32, &buf)
.expect("writing to NVM failed");
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
};
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
rprintln!("corrupting App Image A");
corrupt_image(APP_A_START_ADDR);
}
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
rprintln!("corrupting App Image B");
corrupt_image(APP_B_START_ADDR);
}
if pus_tc.subservice() == ActionId::SetBootSlot as u8 {
if pus_tc.app_data().is_empty() {
log::warn!(target: "TC Handler", "App data for preferred image command too short");
}
let app_sel_result = AppSel::try_from(pus_tc.app_data()[0]);
if app_sel_result.is_err() {
log::warn!("Invalid app selection value: {}", pus_tc.app_data()[0]);
}
log::info!(target: "TC Handler", "received boot selection command with app select: {:?}", app_sel_result.unwrap());
cx.local
.nvm
.write(PREFERRED_SLOT_OFFSET as usize, &[pus_tc.app_data()[0]])
.expect("writing to NVM failed");
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
}
}
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
log::info!(target: "TC Handler", "received ping TC");
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
let tm = cx
.local
.verif_reporter
.step_success(
cx.local.src_data_buf,
&started_token,
0,
0,
&[],
EcssEnumU8::new(0),
)
.expect("step success failed");
write_and_send(&tm);
// Raw memory write TC
if pus_tc.subservice() == 2 {
let app_data = pus_tc.app_data();
if app_data.len() < 10 {
log::warn!(
target: "TC Handler",
"app data for raw memory write is too short: {}",
app_data.len()
);
}
let memory_id = app_data[0];
if memory_id != BOOT_NVM_MEMORY_ID {
log::warn!(target: "TC Handler", "memory ID {} not supported", memory_id);
// TODO: Error reporting
return;
}
let offset = u32::from_be_bytes(app_data[2..6].try_into().unwrap());
let data_len = u32::from_be_bytes(app_data[6..10].try_into().unwrap());
if 10 + data_len as usize > app_data.len() {
log::warn!(
target: "TC Handler",
"invalid data length {} for raw mem write detected",
data_len
);
// TODO: Error reporting
return;
}
let data = &app_data[10..10 + data_len as usize];
log::info!(
target: "TC Handler",
"writing {} bytes at offset {} to NVM",
data_len,
offset
);
cx.local
.nvm
.write(offset as usize, data)
.expect("writing to NVM failed");
let tm = if !cx
.local
.nvm
.verify(offset as usize, data)
.expect("NVM verification failed")
{
log::warn!("verification of data written to NVM failed");
cx.local
.verif_reporter
.completion_failure(
cx.local.src_data_buf,
started_token,
0,
0,
FailParams::new(&[], &EcssEnumU8::new(0), &[]),
)
.expect("completion success failed")
} else {
cx.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed")
};
write_and_send(&tm);
log::info!(
target: "TC Handler",
"NVM operation done");
}
}
}
#[task(
priority = 1,
local=[
read_buf: [u8;MAX_TM_SIZE] = [0; MAX_TM_SIZE],
encoded_buf: [u8;MAX_TM_FRAME_SIZE] = [0; MAX_TM_FRAME_SIZE],
uart_tx,
],
shared=[tm_rb]
)]
async fn pus_tm_tx_handler(mut cx: pus_tm_tx_handler::Context) {
loop {
let mut occupied_len = cx.shared.tm_rb.lock(|rb| rb.sizes.occupied_len());
while occupied_len > 0 {
let next_size = cx.shared.tm_rb.lock(|rb| {
let next_size = rb.sizes.try_pop().unwrap();
rb.buf.pop_slice(&mut cx.local.read_buf[0..next_size]);
next_size
});
cx.local.encoded_buf[0] = 0;
let send_size = cobs::encode(
&cx.local.read_buf[0..next_size],
&mut cx.local.encoded_buf[1..],
);
cx.local.encoded_buf[send_size + 1] = 0;
cx.local
.uart_tx
.write(&cx.local.encoded_buf[0..send_size + 2])
.unwrap();
occupied_len -= 1;
Mono::delay(2.millis()).await;
}
Mono::delay(50.millis()).await;
}
}
}

View File

@ -9,27 +9,56 @@ variants:
core_access_options: !Arm
ap: 0
psel: 0x0
jtag_tap: 1
memory_map:
- !Ram
name: IRAM1
name: DRAM
range:
start: 0x10000000
end: 0x10008000
cores:
- main
- !Nvm
name: IROM1
name: NVM
range:
start: 0x0
end: 0x20000
is_boot_memory: true
cores:
- main
access:
write: false
boot: true
flash_algorithms:
- va108xx_fm25v20a_fram_128kb_prog
- va108xx_m95m01_128kb_prog
- va108xx_mr25h10_1mb_prog
- va108xx_ttflash_prog
- name: VA108xx_RAM
cores:
- name: main
type: armv6m
core_access_options: !Arm
ap: 0
psel: 0x0
jtag_tap: 1
memory_map:
- !Ram
name: DRAM
range:
start: 0x10000000
end: 0x10008000
cores:
- main
- !Ram
name: IRAM
range:
start: 0x0
end: 0x20000
cores:
- main
access:
write: false
boot: true
flash_algorithms:
- name: va108xx_fm25v20a_fram_128kb_prog
description: VA108_FM25V20A_FRAM_128KB

10
scripts/memory_app_a.x Normal file
View File

@ -0,0 +1,10 @@
MEMORY
{
FLASH : ORIGIN = 0x00003000, LENGTH = 0xE7F8 /* (128k - 12k) / 2 - 8 */
RAM : ORIGIN = 0x10000000, LENGTH = 0x08000 /* 32K */
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);

10
scripts/memory_app_b.x Normal file
View File

@ -0,0 +1,10 @@
MEMORY
{
FLASH : ORIGIN = 0x00011800, LENGTH = 0xE7F8 /* (128k - 12k) / 2 - 8 */
RAM : ORIGIN = 0x10000000, LENGTH = 0x08000 /* 32K */
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);

View File

@ -6,6 +6,28 @@ 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.9.0] 2024-10-07
- Deleted some HAL re-exports in the PWM module
## [v0.8.0] 2024-09-30
## Changed
- Improves `CascardSource` handling and general API when chosing cascade sources.
- Replaced `utility::unmask_irq` by `enable_interrupt` and `disable_interrupt` API.
- Improve and fix SPI abstractions. Add new low level interface. The primary SPI constructor now
only expects a configuration structure and the transfer configuration needs to be applied in a
separate step.
- Removed complete `timer` module re-export in `pwm` module
- `CountDownTimer` renamed to `CountdownTimer`
## Fixes
- Fixes for SPI peripheral: Flush implementation was incorrect and should now flush properly.
## [v0.7.0] 2024-07-04
- Replace `uarta` and `uartb` `Uart` constructors by `new` constructor

View File

@ -1,6 +1,6 @@
[package]
name = "va108xx-hal"
version = "0.7.0"
version = "0.8.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2021"
description = "HAL for the Vorago VA108xx family of microcontrollers"
@ -19,7 +19,7 @@ embedded-hal-nb = "1"
embedded-io = "0.6"
fugit = "0.3"
typenum = "1"
defmt = { version = "0.3", optional = true }
critical-section = "1"
delegate = "0.12"
[dependencies.va108xx]
@ -38,9 +38,14 @@ default-features = false
version = "1.14"
default-features = false
[dependencies.defmt]
version = "0.3"
optional = true
[features]
default = ["rt"]
rt = ["va108xx/rt"]
defmt = ["dep:defmt", "fugit/defmt"]
[package.metadata.docs.rs]
all-features = true

View File

@ -320,7 +320,6 @@ macro_rules! pin_id {
//==================================================================================================
/// A type-level GPIO pin, parameterized by [PinId] and [PinMode] types
pub struct Pin<I: PinId, M: PinMode> {
pub(in crate::gpio) regs: Registers<I>,
mode: PhantomData<M>,

View File

@ -2,7 +2,7 @@
//!
//! ## Examples
//!
//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/adt75-temp-sensor.rs
//! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/adt75-temp-sensor.rs)
use crate::{
clock::enable_peripheral_clock, pac, time::Hertz, typelevel::Sealed, PeripheralSelect,
};

View File

@ -15,7 +15,6 @@ pub mod time;
pub mod timer;
pub mod typelevel;
pub mod uart;
pub mod utility;
#[derive(Debug, Eq, Copy, Clone, PartialEq)]
pub enum FunSel {
@ -98,3 +97,21 @@ pub fn port_mux(
}
}
}
/// Enable a specific interrupt using the NVIC peripheral.
///
/// # Safety
///
/// This function is `unsafe` because it can break mask-based critical sections.
#[inline]
pub unsafe fn enable_interrupt(irq: pac::Interrupt) {
unsafe {
cortex_m::peripheral::NVIC::unmask(irq);
}
}
/// Disable a specific interrupt using the NVIC peripheral.
#[inline]
pub fn disable_interrupt(irq: pac::Interrupt) {
cortex_m::peripheral::NVIC::mask(irq);
}

View File

@ -9,8 +9,11 @@ use core::convert::Infallible;
use core::marker::PhantomData;
use crate::pac;
use crate::time::Hertz;
use crate::timer::{
TimAndPinRegister, TimDynRegister, TimPin, TimRegInterface, ValidTim, ValidTimAndPin,
};
use crate::{clock::enable_peripheral_clock, gpio::DynPinId};
pub use crate::{gpio::PinId, time::Hertz, timer::*};
const DUTY_MAX: u16 = u16::MAX;

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,11 @@
//! ## Examples
//!
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/timer-ticks.rs)
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-hal/src/branch/main/examples/cascade.rs)
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/cascade.rs)
pub use crate::IrqCfg;
use crate::{
clock::{enable_peripheral_clock, PeripheralClocks},
enable_interrupt,
gpio::{
AltFunc1, AltFunc2, AltFunc3, DynPinId, Pin, PinId, PA0, PA1, PA10, PA11, PA12, PA13, PA14,
PA15, PA2, PA24, PA25, PA26, PA27, PA28, PA29, PA3, PA30, PA31, PA4, PA5, PA6, PA7, PA8,
@ -17,10 +18,9 @@ use crate::{
time::Hertz,
timer,
typelevel::Sealed,
utility::unmask_irq,
};
use core::cell::Cell;
use cortex_m::interrupt::Mutex;
use critical_section::Mutex;
use fugit::RateExtU32;
const IRQ_DST_NONE: u32 = 0xffffffff;
@ -72,25 +72,46 @@ pub enum CascadeSel {
Csd2 = 2,
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidCascadeSourceId;
/// The numbers are the base numbers for bundles like PORTA, PORTB or TIM
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum CascadeSource {
PortABase = 0,
PortBBase = 32,
TimBase = 64,
PortA(u8),
PortB(u8),
Tim(u8),
RamSbe = 96,
RamMbe = 97,
RomSbe = 98,
RomMbe = 99,
Txev = 100,
ClockDividerBase = 120,
ClockDivider(u8),
}
#[derive(Debug, PartialEq, Eq)]
pub enum TimerErrors {
Canceled,
/// Invalid input for Cascade source
InvalidCsdSourceInput,
impl CascadeSource {
fn id(&self) -> Result<u8, InvalidCascadeSourceId> {
let port_check = |base: u8, id: u8, len: u8| {
if id > len - 1 {
return Err(InvalidCascadeSourceId);
}
Ok(base + id)
};
match self {
CascadeSource::PortA(id) => port_check(0, *id, 32),
CascadeSource::PortB(id) => port_check(32, *id, 32),
CascadeSource::Tim(id) => port_check(64, *id, 24),
CascadeSource::RamSbe => Ok(96),
CascadeSource::RamMbe => Ok(97),
CascadeSource::RomSbe => Ok(98),
CascadeSource::RomMbe => Ok(99),
CascadeSource::Txev => Ok(100),
CascadeSource::ClockDivider(id) => port_check(120, *id, 8),
}
}
}
//==================================================================================================
@ -350,7 +371,7 @@ unsafe impl TimRegInterface for TimDynRegister {
//==================================================================================================
/// Hardware timers
pub struct CountDownTimer<TIM: ValidTim> {
pub struct CountdownTimer<TIM: ValidTim> {
tim: TimRegister<TIM>,
curr_freq: Hertz,
irq_cfg: Option<IrqCfg>,
@ -360,94 +381,31 @@ pub struct CountDownTimer<TIM: ValidTim> {
listening: bool,
}
fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
#[inline(always)]
pub fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
syscfg
.tim_clk_enable()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << idx)) });
}
unsafe impl<TIM: ValidTim> TimRegInterface for CountDownTimer<TIM> {
#[inline(always)]
pub fn disable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
syscfg
.tim_clk_enable()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << idx)) });
}
unsafe impl<TIM: ValidTim> TimRegInterface for CountdownTimer<TIM> {
fn tim_id(&self) -> u8 {
TIM::TIM_ID
}
}
macro_rules! csd_sel {
($func_name:ident, $csd_reg:ident) => {
/// Configure the Cascade sources
pub fn $func_name(
&mut self,
src: CascadeSource,
id: Option<u8>,
) -> Result<(), TimerErrors> {
let mut id_num = 0;
if let CascadeSource::PortABase
| CascadeSource::PortBBase
| CascadeSource::ClockDividerBase
| CascadeSource::TimBase = src
{
if id.is_none() {
return Err(TimerErrors::InvalidCsdSourceInput);
}
}
if id.is_some() {
id_num = id.unwrap();
}
match src {
CascadeSource::PortABase => {
if id_num > 55 {
return Err(TimerErrors::InvalidCsdSourceInput);
}
self.tim.reg().$csd_reg().write(|w| unsafe {
w.cassel().bits(CascadeSource::PortABase as u8 + id_num)
});
Ok(())
}
CascadeSource::PortBBase => {
if id_num > 23 {
return Err(TimerErrors::InvalidCsdSourceInput);
}
self.tim.reg().$csd_reg().write(|w| unsafe {
w.cassel().bits(CascadeSource::PortBBase as u8 + id_num)
});
Ok(())
}
CascadeSource::TimBase => {
if id_num > 23 {
return Err(TimerErrors::InvalidCsdSourceInput);
}
self.tim.reg().$csd_reg().write(|w| unsafe {
w.cassel().bits(CascadeSource::TimBase as u8 + id_num)
});
Ok(())
}
CascadeSource::ClockDividerBase => {
if id_num > 7 {
return Err(TimerErrors::InvalidCsdSourceInput);
}
self.tim.reg().cascade0().write(|w| unsafe {
w.cassel()
.bits(CascadeSource::ClockDividerBase as u8 + id_num)
});
Ok(())
}
_ => {
self.tim
.reg()
.$csd_reg()
.write(|w| unsafe { w.cassel().bits(src as u8) });
Ok(())
}
}
}
};
}
impl<TIM: ValidTim> CountDownTimer<TIM> {
impl<TIM: ValidTim> CountdownTimer<TIM> {
/// Configures a TIM peripheral as a periodic count down timer
pub fn new(syscfg: &mut pac::Sysconfig, sys_clk: impl Into<Hertz>, tim: TIM) -> Self {
enable_tim_clk(syscfg, TIM::TIM_ID);
let cd_timer = CountDownTimer {
let cd_timer = CountdownTimer {
tim: unsafe { TimRegister::new(tim) },
sys_clk: sys_clk.into(),
irq_cfg: None,
@ -554,18 +512,18 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
#[inline(always)]
pub fn enable(&mut self) {
self.tim.reg().ctrl().modify(|_, w| w.enable().set_bit());
if let Some(irq_cfg) = self.irq_cfg {
self.enable_interrupt();
if irq_cfg.enable {
unmask_irq(irq_cfg.irq);
unsafe { enable_interrupt(irq_cfg.irq) };
}
}
self.tim.reg().enable().write(|w| unsafe { w.bits(1) });
}
#[inline(always)]
pub fn disable(&mut self) {
self.tim.reg().ctrl().modify(|_, w| w.enable().clear_bit());
self.tim.reg().enable().write(|w| unsafe { w.bits(0) });
}
/// Disable the counter, setting both enable and active bit to 0
@ -619,9 +577,32 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
});
}
csd_sel!(cascade_0_source, cascade0);
csd_sel!(cascade_1_source, cascade1);
csd_sel!(cascade_2_source, cascade2);
pub fn cascade_0_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
let id = src.id()?;
self.tim
.reg()
.cascade0()
.write(|w| unsafe { w.cassel().bits(id) });
Ok(())
}
pub fn cascade_1_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
let id = src.id()?;
self.tim
.reg()
.cascade1()
.write(|w| unsafe { w.cassel().bits(id) });
Ok(())
}
pub fn cascade_2_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
let id = src.id()?;
self.tim
.reg()
.cascade2()
.write(|w| unsafe { w.cassel().bits(id) });
Ok(())
}
pub fn curr_freq(&self) -> Hertz {
self.curr_freq
@ -633,7 +614,7 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
}
/// CountDown implementation for TIMx
impl<TIM: ValidTim> CountDownTimer<TIM> {
impl<TIM: ValidTim> CountdownTimer<TIM> {
#[inline]
pub fn start<T>(&mut self, timeout: T)
where
@ -656,16 +637,17 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
}
}
pub fn cancel(&mut self) -> Result<(), TimerErrors> {
/// Returns [false] if the timer was not active, and true otherwise.
pub fn cancel(&mut self) -> bool {
if !self.tim.reg().ctrl().read().enable().bit_is_set() {
return Err(TimerErrors::Canceled);
return false;
}
self.tim.reg().ctrl().write(|w| w.enable().clear_bit());
Ok(())
true
}
}
impl<TIM: ValidTim> embedded_hal::delay::DelayNs for CountDownTimer<TIM> {
impl<TIM: ValidTim> embedded_hal::delay::DelayNs for CountdownTimer<TIM> {
fn delay_ns(&mut self, ns: u32) {
let ticks = (u64::from(ns)) * (u64::from(self.sys_clk.raw())) / 1_000_000_000;
@ -727,8 +709,8 @@ pub fn set_up_ms_tick<TIM: ValidTim>(
irq_sel: Option<&mut pac::Irqsel>,
sys_clk: impl Into<Hertz>,
tim0: TIM,
) -> CountDownTimer<TIM> {
let mut ms_timer = CountDownTimer::new(sys_cfg, sys_clk, tim0);
) -> CountdownTimer<TIM> {
let mut ms_timer = CountdownTimer::new(sys_cfg, sys_clk, tim0);
ms_timer.listen(timer::Event::TimeOut, irq_cfg, irq_sel, Some(sys_cfg));
ms_timer.start(1000.Hz());
ms_timer
@ -738,8 +720,8 @@ pub fn set_up_ms_delay_provider<TIM: ValidTim>(
sys_cfg: &mut pac::Sysconfig,
sys_clk: impl Into<Hertz>,
tim: TIM,
) -> CountDownTimer<TIM> {
let mut provider = CountDownTimer::new(sys_cfg, sys_clk, tim);
) -> CountdownTimer<TIM> {
let mut provider = CountdownTimer::new(sys_cfg, sys_clk, tim);
provider.start(1000.Hz());
provider
}
@ -747,7 +729,7 @@ pub fn set_up_ms_delay_provider<TIM: ValidTim>(
/// This function can be called in a specified interrupt handler to increment
/// the MS counter
pub fn default_ms_irq_handler() {
cortex_m::interrupt::free(|cs| {
critical_section::with(|cs| {
let mut ms = MS_COUNTER.borrow(cs).get();
ms += 1;
MS_COUNTER.borrow(cs).set(ms);
@ -756,17 +738,17 @@ pub fn default_ms_irq_handler() {
/// Get the current MS tick count
pub fn get_ms_ticks() -> u32 {
cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get())
critical_section::with(|cs| MS_COUNTER.borrow(cs).get())
}
//==================================================================================================
// Delay implementations
//==================================================================================================
pub struct DelayMs(CountDownTimer<pac::Tim0>);
pub struct DelayMs(CountdownTimer<pac::Tim0>);
impl DelayMs {
pub fn new(timer: CountDownTimer<pac::Tim0>) -> Option<Self> {
pub fn new(timer: CountdownTimer<pac::Tim0>) -> Option<Self> {
if timer.curr_freq() != Hertz::from_raw(1000) || !timer.listening() {
return None;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
//! # API for utility functions like the Error Detection and Correction (EDAC) block
//!
//! Some more information about the recommended scrub rates can be found on the
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the
//! application note AN1212
use crate::pac;
/// Unmask and enable an IRQ with the given interrupt number
///
/// ## Safety
///
/// The unmask function can break mask-based critical sections
#[inline]
pub(crate) fn unmask_irq(irq: pac::Interrupt) {
unsafe { cortex_m::peripheral::NVIC::unmask(irq) };
}

View File

@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased]
## [v0.4.0]
- Re-generated PAC with `svd2rust` v0.35.0
## [v0.3.0] 2024-06-16
- Re-generated PAC with `svd2rust` v0.33.3

View File

@ -1,6 +1,6 @@
[package]
name = "va108xx"
version = "0.3.0"
version = "0.4.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2021"
description = "PAC for the Vorago VA108xx family of microcontrollers"

View File

@ -24,7 +24,7 @@ features = ["rt"]
The `rt` feature is optional and recommended. It brings in support for `cortex-m-rt`.
For full details on the autgenerated API, please see the
[svd2rust documentation](https://docs.rs/svd2rust/0.19.0/svd2rust/#peripheral-api).
[svd2rust documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api).
## Regenerating the PAC

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# Use installed tool by default
svd2rust_bin="svd2rust"

View File

@ -82,169 +82,6 @@ pub trait Resettable: RegisterSpec {
Self::RESET_VALUE
}
}
#[doc = " This structure provides volatile access to registers."]
#[repr(transparent)]
pub struct Reg<REG: RegisterSpec> {
register: vcell::VolatileCell<REG::Ux>,
_marker: marker::PhantomData<REG>,
}
unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}
impl<REG: RegisterSpec> Reg<REG> {
#[doc = " Returns the underlying memory address of register."]
#[doc = ""]
#[doc = " ```ignore"]
#[doc = " let reg_ptr = periph.reg.as_ptr();"]
#[doc = " ```"]
#[inline(always)]
pub fn as_ptr(&self) -> *mut REG::Ux {
self.register.as_ptr()
}
}
impl<REG: Readable> Reg<REG> {
#[doc = " Reads the contents of a `Readable` register."]
#[doc = ""]
#[doc = " You can read the raw contents of a register by using `bits`:"]
#[doc = " ```ignore"]
#[doc = " let bits = periph.reg.read().bits();"]
#[doc = " ```"]
#[doc = " or get the content of a particular field of a register:"]
#[doc = " ```ignore"]
#[doc = " let reader = periph.reg.read();"]
#[doc = " let bits = reader.field1().bits();"]
#[doc = " let flag = reader.field2().bit_is_set();"]
#[doc = " ```"]
#[inline(always)]
pub fn read(&self) -> R<REG> {
R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
}
}
impl<REG: Resettable + Writable> Reg<REG> {
#[doc = " Writes the reset value to `Writable` register."]
#[doc = ""]
#[doc = " Resets the register to its initial state."]
#[inline(always)]
pub fn reset(&self) {
self.register.set(REG::RESET_VALUE)
}
#[doc = " Writes bits to a `Writable` register."]
#[doc = ""]
#[doc = " You can write raw bits into a register:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| unsafe { w.bits(rawbits) });"]
#[doc = " ```"]
#[doc = " or write only the fields you need:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| w"]
#[doc = " .field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT)"]
#[doc = " );"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT)"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " In the latter case, other fields will be set to their reset value."]
#[inline(always)]
pub fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.register.set(
f(&mut W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
})
.bits,
);
}
}
impl<REG: Writable> Reg<REG> {
#[doc = " Writes 0 to a `Writable` register."]
#[doc = ""]
#[doc = " Similar to `write`, but unused bits will contain 0."]
#[doc = ""]
#[doc = " # Safety"]
#[doc = ""]
#[doc = " Unsafe to use with registers which don't allow to write 0."]
#[inline(always)]
pub unsafe fn write_with_zero<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.register.set(
f(&mut W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
})
.bits,
);
}
}
impl<REG: Readable + Writable> Reg<REG> {
#[doc = " Modifies the contents of the register by reading and then writing it."]
#[doc = ""]
#[doc = " E.g. to do a read-modify-write sequence to change parts of a register:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|r, w| unsafe { w.bits("]
#[doc = " r.bits() | 3"]
#[doc = " ) });"]
#[doc = " ```"]
#[doc = " or"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| w"]
#[doc = " .field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT)"]
#[doc = " );"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT)"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " Other fields will have the value they had before the call to `modify`."]
#[inline(always)]
pub fn modify<F>(&self, f: F)
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
{
let bits = self.register.get();
self.register.set(
f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
},
)
.bits,
);
}
}
impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
where
R<REG>: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.read(), f)
}
}
#[doc(hidden)]
pub mod raw;
#[doc = " Register reader."]
@ -369,7 +206,7 @@ pub struct RangeTo<const MAX: u64>;
#[doc = " Write field Proxy"]
pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> =
raw::FieldWriter<'a, REG, WI, FI, Safety>;
impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety>
impl<REG, const WI: u8, FI, Safety> FieldWriter<'_, REG, WI, FI, Safety>
where
REG: Writable + RegisterSpec,
FI: FieldSpec,
@ -616,3 +453,278 @@ where
self.w
}
}
#[doc = " This structure provides volatile access to registers."]
#[repr(transparent)]
pub struct Reg<REG: RegisterSpec> {
register: vcell::VolatileCell<REG::Ux>,
_marker: marker::PhantomData<REG>,
}
unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}
impl<REG: RegisterSpec> Reg<REG> {
#[doc = " Returns the underlying memory address of register."]
#[doc = ""]
#[doc = " ```ignore"]
#[doc = " let reg_ptr = periph.reg.as_ptr();"]
#[doc = " ```"]
#[inline(always)]
pub fn as_ptr(&self) -> *mut REG::Ux {
self.register.as_ptr()
}
}
impl<REG: Readable> Reg<REG> {
#[doc = " Reads the contents of a `Readable` register."]
#[doc = ""]
#[doc = " You can read the raw contents of a register by using `bits`:"]
#[doc = " ```ignore"]
#[doc = " let bits = periph.reg.read().bits();"]
#[doc = " ```"]
#[doc = " or get the content of a particular field of a register:"]
#[doc = " ```ignore"]
#[doc = " let reader = periph.reg.read();"]
#[doc = " let bits = reader.field1().bits();"]
#[doc = " let flag = reader.field2().bit_is_set();"]
#[doc = " ```"]
#[inline(always)]
pub fn read(&self) -> R<REG> {
R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
}
}
impl<REG: Resettable + Writable> Reg<REG> {
#[doc = " Writes the reset value to `Writable` register."]
#[doc = ""]
#[doc = " Resets the register to its initial state."]
#[inline(always)]
pub fn reset(&self) {
self.register.set(REG::RESET_VALUE)
}
#[doc = " Writes bits to a `Writable` register."]
#[doc = ""]
#[doc = " You can write raw bits into a register:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| unsafe { w.bits(rawbits) });"]
#[doc = " ```"]
#[doc = " or write only the fields you need:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| w"]
#[doc = " .field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT)"]
#[doc = " );"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write(|w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT)"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " In the latter case, other fields will be set to their reset value."]
#[inline(always)]
pub fn write<F>(&self, f: F) -> REG::Ux
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
let value = f(&mut W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
})
.bits;
self.register.set(value);
value
}
#[doc = " Writes bits to a `Writable` register and produce a value."]
#[doc = ""]
#[doc = " You can write raw bits into a register:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write_and(|w| unsafe { w.bits(rawbits); });"]
#[doc = " ```"]
#[doc = " or write only the fields you need:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write_and(|w| {"]
#[doc = " w.field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT);"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.write_and(|w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT);"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " In the latter case, other fields will be set to their reset value."]
#[doc = ""]
#[doc = " Values can be returned from the closure:"]
#[doc = " ```ignore"]
#[doc = " let state = periph.reg.write_and(|w| State::set(w.field1()));"]
#[doc = " ```"]
#[inline(always)]
pub fn from_write<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
{
let mut writer = W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
};
let result = f(&mut writer);
self.register.set(writer.bits);
result
}
}
impl<REG: Writable> Reg<REG> {
#[doc = " Writes 0 to a `Writable` register."]
#[doc = ""]
#[doc = " Similar to `write`, but unused bits will contain 0."]
#[doc = ""]
#[doc = " # Safety"]
#[doc = ""]
#[doc = " Unsafe to use with registers which don't allow to write 0."]
#[inline(always)]
pub unsafe fn write_with_zero<F>(&self, f: F) -> REG::Ux
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
let value = f(&mut W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
})
.bits;
self.register.set(value);
value
}
#[doc = " Writes 0 to a `Writable` register and produces a value."]
#[doc = ""]
#[doc = " Similar to `write`, but unused bits will contain 0."]
#[doc = ""]
#[doc = " # Safety"]
#[doc = ""]
#[doc = " Unsafe to use with registers which don't allow to write 0."]
#[inline(always)]
pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
{
let mut writer = W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
};
let result = f(&mut writer);
self.register.set(writer.bits);
result
}
}
impl<REG: Readable + Writable> Reg<REG> {
#[doc = " Modifies the contents of the register by reading and then writing it."]
#[doc = ""]
#[doc = " E.g. to do a read-modify-write sequence to change parts of a register:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|r, w| unsafe { w.bits("]
#[doc = " r.bits() | 3"]
#[doc = " ) });"]
#[doc = " ```"]
#[doc = " or"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| w"]
#[doc = " .field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT)"]
#[doc = " );"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT)"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " Other fields will have the value they had before the call to `modify`."]
#[inline(always)]
pub fn modify<F>(&self, f: F) -> REG::Ux
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
{
let bits = self.register.get();
let value = f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
},
)
.bits;
self.register.set(value);
value
}
#[doc = " Modifies the contents of the register by reading and then writing it"]
#[doc = " and produces a value."]
#[doc = ""]
#[doc = " E.g. to do a read-modify-write sequence to change parts of a register:"]
#[doc = " ```ignore"]
#[doc = " let bits = periph.reg.modify(|r, w| {"]
#[doc = " let new_bits = r.bits() | 3;"]
#[doc = " unsafe {"]
#[doc = " w.bits(new_bits);"]
#[doc = " }"]
#[doc = ""]
#[doc = " new_bits"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " or"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| {"]
#[doc = " w.field1().bits(newfield1bits)"]
#[doc = " .field2().set_bit()"]
#[doc = " .field3().variant(VARIANT);"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " or an alternative way of saying the same:"]
#[doc = " ```ignore"]
#[doc = " periph.reg.modify(|_, w| {"]
#[doc = " w.field1().bits(newfield1bits);"]
#[doc = " w.field2().set_bit();"]
#[doc = " w.field3().variant(VARIANT);"]
#[doc = " });"]
#[doc = " ```"]
#[doc = " Other fields will have the value they had before the call to `modify`."]
#[inline(always)]
pub fn from_modify<F, T>(&self, f: F) -> T
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
{
let bits = self.register.get();
let mut writer = W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
};
let result = f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut writer,
);
self.register.set(writer.bits);
result
}
}
impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
where
R<REG>: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.read(), f)
}
}

View File

@ -41,6 +41,7 @@ impl<FI> BitReader<FI> {
}
}
}
#[must_use = "after creating `FieldWriter` you need to call field value setting method"]
pub struct FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe>
where
REG: Writable + RegisterSpec,
@ -66,6 +67,7 @@ where
}
}
}
#[must_use = "after creating `BitWriter` you need to call bit setting method"]
pub struct BitWriter<'a, REG, FI = bool, M = BitM>
where
REG: Writable + RegisterSpec,

View File

@ -240,67 +240,67 @@ impl RegisterBlock {
&self.perid
}
}
#[doc = "CTRL (rw) register accessor: Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`ctrl::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`ctrl::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@ctrl`]
#[doc = "CTRL (rw) register accessor: Control Register\n\nYou can [`read`](crate::Reg::read) this register and get [`ctrl::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`ctrl::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@ctrl`]
module"]
#[doc(alias = "CTRL")]
pub type Ctrl = crate::Reg<ctrl::CtrlSpec>;
#[doc = "Control Register"]
pub mod ctrl;
#[doc = "CLKSCALE (rw) register accessor: Clock Scale divide value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`clkscale::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`clkscale::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@clkscale`]
#[doc = "CLKSCALE (rw) register accessor: Clock Scale divide value\n\nYou can [`read`](crate::Reg::read) this register and get [`clkscale::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`clkscale::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@clkscale`]
module"]
#[doc(alias = "CLKSCALE")]
pub type Clkscale = crate::Reg<clkscale::ClkscaleSpec>;
#[doc = "Clock Scale divide value"]
pub mod clkscale;
#[doc = "WORDS (rw) register accessor: Word Count value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`words::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`words::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@words`]
#[doc = "WORDS (rw) register accessor: Word Count value\n\nYou can [`read`](crate::Reg::read) this register and get [`words::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`words::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@words`]
module"]
#[doc(alias = "WORDS")]
pub type Words = crate::Reg<words::WordsSpec>;
#[doc = "Word Count value"]
pub mod words;
#[doc = "ADDRESS (rw) register accessor: I2C Address value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`address::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`address::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@address`]
#[doc = "ADDRESS (rw) register accessor: I2C Address value\n\nYou can [`read`](crate::Reg::read) this register and get [`address::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`address::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@address`]
module"]
#[doc(alias = "ADDRESS")]
pub type Address = crate::Reg<address::AddressSpec>;
#[doc = "I2C Address value"]
pub mod address;
#[doc = "DATA (rw) register accessor: Data Input/Output\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`data::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`data::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@data`]
#[doc = "DATA (rw) register accessor: Data Input/Output\n\nYou can [`read`](crate::Reg::read) this register and get [`data::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`data::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@data`]
module"]
#[doc(alias = "DATA")]
pub type Data = crate::Reg<data::DataSpec>;
#[doc = "Data Input/Output"]
pub mod data;
#[doc = "CMD (rw) register accessor: Command Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cmd::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cmd::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@cmd`]
#[doc = "CMD (rw) register accessor: Command Register\n\nYou can [`read`](crate::Reg::read) this register and get [`cmd::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`cmd::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@cmd`]
module"]
#[doc(alias = "CMD")]
pub type Cmd = crate::Reg<cmd::CmdSpec>;
#[doc = "Command Register"]
pub mod cmd;
#[doc = "STATUS (r) register accessor: I2C Controller Status Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`status::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@status`]
#[doc = "STATUS (r) register accessor: I2C Controller Status Register\n\nYou can [`read`](crate::Reg::read) this register and get [`status::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@status`]
module"]
#[doc(alias = "STATUS")]
pub type Status = crate::Reg<status::StatusSpec>;
#[doc = "I2C Controller Status Register"]
pub mod status;
#[doc = "STATE (r) register accessor: Internal STATE of I2C Master Controller\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`state::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@state`]
#[doc = "STATE (r) register accessor: Internal STATE of I2C Master Controller\n\nYou can [`read`](crate::Reg::read) this register and get [`state::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@state`]
module"]
#[doc(alias = "STATE")]
pub type State = crate::Reg<state::StateSpec>;
#[doc = "Internal STATE of I2C Master Controller"]
pub mod state;
#[doc = "TXCOUNT (r) register accessor: TX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`txcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@txcount`]
#[doc = "TXCOUNT (r) register accessor: TX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`txcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@txcount`]
module"]
#[doc(alias = "TXCOUNT")]
pub type Txcount = crate::Reg<txcount::TxcountSpec>;
#[doc = "TX Count Register"]
pub mod txcount;
#[doc = "RXCOUNT (r) register accessor: RX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@rxcount`]
#[doc = "RXCOUNT (r) register accessor: RX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`rxcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@rxcount`]
module"]
#[doc(alias = "RXCOUNT")]
pub type Rxcount = crate::Reg<rxcount::RxcountSpec>;
#[doc = "RX Count Register"]
pub mod rxcount;
#[doc = "IRQ_ENB (rw) register accessor: Interrupt Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_enb::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_enb::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_enb`]
#[doc = "IRQ_ENB (rw) register accessor: Interrupt Enable Register\n\nYou can [`read`](crate::Reg::read) this register and get [`irq_enb::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`irq_enb::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@irq_enb`]
module"]
#[doc(alias = "IRQ_ENB")]
pub type IrqEnb = crate::Reg<irq_enb::IrqEnbSpec>;
@ -312,97 +312,97 @@ pub use irq_enb as irq_clr;
pub use IrqEnb as IrqRaw;
pub use IrqEnb as IrqEnd;
pub use IrqEnb as IrqClr;
#[doc = "RXFIFOIRQTRG (rw) register accessor: Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxfifoirqtrg::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@rxfifoirqtrg`]
#[doc = "RXFIFOIRQTRG (rw) register accessor: Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`rxfifoirqtrg::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@rxfifoirqtrg`]
module"]
#[doc(alias = "RXFIFOIRQTRG")]
pub type Rxfifoirqtrg = crate::Reg<rxfifoirqtrg::RxfifoirqtrgSpec>;
#[doc = "Rx FIFO IRQ Trigger Level"]
pub mod rxfifoirqtrg;
#[doc = "TXFIFOIRQTRG (rw) register accessor: Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`txfifoirqtrg::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`txfifoirqtrg::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@txfifoirqtrg`]
#[doc = "TXFIFOIRQTRG (rw) register accessor: Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`txfifoirqtrg::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`txfifoirqtrg::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@txfifoirqtrg`]
module"]
#[doc(alias = "TXFIFOIRQTRG")]
pub type Txfifoirqtrg = crate::Reg<txfifoirqtrg::TxfifoirqtrgSpec>;
#[doc = "Tx FIFO IRQ Trigger Level"]
pub mod txfifoirqtrg;
#[doc = "FIFO_CLR (w) register accessor: Clear FIFO Register\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`fifo_clr::W`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@fifo_clr`]
#[doc = "FIFO_CLR (w) register accessor: Clear FIFO Register\n\nYou can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`fifo_clr::W`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@fifo_clr`]
module"]
#[doc(alias = "FIFO_CLR")]
pub type FifoClr = crate::Reg<fifo_clr::FifoClrSpec>;
#[doc = "Clear FIFO Register"]
pub mod fifo_clr;
#[doc = "TMCONFIG (rw) register accessor: Timing Config Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`tmconfig::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`tmconfig::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@tmconfig`]
#[doc = "TMCONFIG (rw) register accessor: Timing Config Register\n\nYou can [`read`](crate::Reg::read) this register and get [`tmconfig::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`tmconfig::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@tmconfig`]
module"]
#[doc(alias = "TMCONFIG")]
pub type Tmconfig = crate::Reg<tmconfig::TmconfigSpec>;
#[doc = "Timing Config Register"]
pub mod tmconfig;
#[doc = "CLKTOLIMIT (rw) register accessor: Clock Low Timeout Limit Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`clktolimit::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`clktolimit::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@clktolimit`]
#[doc = "CLKTOLIMIT (rw) register accessor: Clock Low Timeout Limit Register\n\nYou can [`read`](crate::Reg::read) this register and get [`clktolimit::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`clktolimit::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@clktolimit`]
module"]
#[doc(alias = "CLKTOLIMIT")]
pub type Clktolimit = crate::Reg<clktolimit::ClktolimitSpec>;
#[doc = "Clock Low Timeout Limit Register"]
pub mod clktolimit;
#[doc = "S0_CTRL (rw) register accessor: Slave Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_ctrl::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_ctrl::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_ctrl`]
#[doc = "S0_CTRL (rw) register accessor: Slave Control Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_ctrl::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_ctrl::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_ctrl`]
module"]
#[doc(alias = "S0_CTRL")]
pub type S0Ctrl = crate::Reg<s0_ctrl::S0CtrlSpec>;
#[doc = "Slave Control Register"]
pub mod s0_ctrl;
#[doc = "S0_MAXWORDS (rw) register accessor: Slave MaxWords Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_maxwords::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_maxwords::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_maxwords`]
#[doc = "S0_MAXWORDS (rw) register accessor: Slave MaxWords Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_maxwords::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_maxwords::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_maxwords`]
module"]
#[doc(alias = "S0_MAXWORDS")]
pub type S0Maxwords = crate::Reg<s0_maxwords::S0MaxwordsSpec>;
#[doc = "Slave MaxWords Register"]
pub mod s0_maxwords;
#[doc = "S0_ADDRESS (rw) register accessor: Slave I2C Address Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_address::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_address::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_address`]
#[doc = "S0_ADDRESS (rw) register accessor: Slave I2C Address Value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_address::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_address::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_address`]
module"]
#[doc(alias = "S0_ADDRESS")]
pub type S0Address = crate::Reg<s0_address::S0AddressSpec>;
#[doc = "Slave I2C Address Value"]
pub mod s0_address;
#[doc = "S0_ADDRESSMASK (rw) register accessor: Slave I2C Address Mask value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressmask::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressmask::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressmask`]
#[doc = "S0_ADDRESSMASK (rw) register accessor: Slave I2C Address Mask value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressmask::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressmask::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressmask`]
module"]
#[doc(alias = "S0_ADDRESSMASK")]
pub type S0Addressmask = crate::Reg<s0_addressmask::S0AddressmaskSpec>;
#[doc = "Slave I2C Address Mask value"]
pub mod s0_addressmask;
#[doc = "S0_DATA (rw) register accessor: Slave Data Input/Output\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_data::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_data::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_data`]
#[doc = "S0_DATA (rw) register accessor: Slave Data Input/Output\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_data::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_data::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_data`]
module"]
#[doc(alias = "S0_DATA")]
pub type S0Data = crate::Reg<s0_data::S0DataSpec>;
#[doc = "Slave Data Input/Output"]
pub mod s0_data;
#[doc = "S0_LASTADDRESS (r) register accessor: Slave I2C Last Address value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_lastaddress::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_lastaddress`]
#[doc = "S0_LASTADDRESS (r) register accessor: Slave I2C Last Address value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_lastaddress::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_lastaddress`]
module"]
#[doc(alias = "S0_LASTADDRESS")]
pub type S0Lastaddress = crate::Reg<s0_lastaddress::S0LastaddressSpec>;
#[doc = "Slave I2C Last Address value"]
pub mod s0_lastaddress;
#[doc = "S0_STATUS (r) register accessor: Slave I2C Controller Status Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_status::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_status`]
#[doc = "S0_STATUS (r) register accessor: Slave I2C Controller Status Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_status::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_status`]
module"]
#[doc(alias = "S0_STATUS")]
pub type S0Status = crate::Reg<s0_status::S0StatusSpec>;
#[doc = "Slave I2C Controller Status Register"]
pub mod s0_status;
#[doc = "S0_STATE (r) register accessor: Internal STATE of I2C Slave Controller\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_state::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_state`]
#[doc = "S0_STATE (r) register accessor: Internal STATE of I2C Slave Controller\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_state::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_state`]
module"]
#[doc(alias = "S0_STATE")]
pub type S0State = crate::Reg<s0_state::S0StateSpec>;
#[doc = "Internal STATE of I2C Slave Controller"]
pub mod s0_state;
#[doc = "S0_TXCOUNT (r) register accessor: Slave TX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_txcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_txcount`]
#[doc = "S0_TXCOUNT (r) register accessor: Slave TX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_txcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_txcount`]
module"]
#[doc(alias = "S0_TXCOUNT")]
pub type S0Txcount = crate::Reg<s0_txcount::S0TxcountSpec>;
#[doc = "Slave TX Count Register"]
pub mod s0_txcount;
#[doc = "S0_RXCOUNT (r) register accessor: Slave RX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_rxcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_rxcount`]
#[doc = "S0_RXCOUNT (r) register accessor: Slave RX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_rxcount::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_rxcount`]
module"]
#[doc(alias = "S0_RXCOUNT")]
pub type S0Rxcount = crate::Reg<s0_rxcount::S0RxcountSpec>;
#[doc = "Slave RX Count Register"]
pub mod s0_rxcount;
#[doc = "S0_IRQ_ENB (rw) register accessor: Slave Interrupt Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_irq_enb::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_irq_enb::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_irq_enb`]
#[doc = "S0_IRQ_ENB (rw) register accessor: Slave Interrupt Enable Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_irq_enb::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_irq_enb::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_irq_enb`]
module"]
#[doc(alias = "S0_IRQ_ENB")]
pub type S0IrqEnb = crate::Reg<s0_irq_enb::S0IrqEnbSpec>;
@ -414,37 +414,37 @@ pub use s0_irq_enb as s0_irq_clr;
pub use S0IrqEnb as S0IrqRaw;
pub use S0IrqEnb as S0IrqEnd;
pub use S0IrqEnb as S0IrqClr;
#[doc = "S0_RXFIFOIRQTRG (rw) register accessor: Slave Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_rxfifoirqtrg::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_rxfifoirqtrg::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_rxfifoirqtrg`]
#[doc = "S0_RXFIFOIRQTRG (rw) register accessor: Slave Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_rxfifoirqtrg::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_rxfifoirqtrg::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_rxfifoirqtrg`]
module"]
#[doc(alias = "S0_RXFIFOIRQTRG")]
pub type S0Rxfifoirqtrg = crate::Reg<s0_rxfifoirqtrg::S0RxfifoirqtrgSpec>;
#[doc = "Slave Rx FIFO IRQ Trigger Level"]
pub mod s0_rxfifoirqtrg;
#[doc = "S0_TXFIFOIRQTRG (rw) register accessor: Slave Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_txfifoirqtrg::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_txfifoirqtrg::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_txfifoirqtrg`]
#[doc = "S0_TXFIFOIRQTRG (rw) register accessor: Slave Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_txfifoirqtrg::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_txfifoirqtrg::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_txfifoirqtrg`]
module"]
#[doc(alias = "S0_TXFIFOIRQTRG")]
pub type S0Txfifoirqtrg = crate::Reg<s0_txfifoirqtrg::S0TxfifoirqtrgSpec>;
#[doc = "Slave Tx FIFO IRQ Trigger Level"]
pub mod s0_txfifoirqtrg;
#[doc = "S0_FIFO_CLR (w) register accessor: Slave Clear FIFO Register\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_fifo_clr::W`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_fifo_clr`]
#[doc = "S0_FIFO_CLR (w) register accessor: Slave Clear FIFO Register\n\nYou can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_fifo_clr::W`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_fifo_clr`]
module"]
#[doc(alias = "S0_FIFO_CLR")]
pub type S0FifoClr = crate::Reg<s0_fifo_clr::S0FifoClrSpec>;
#[doc = "Slave Clear FIFO Register"]
pub mod s0_fifo_clr;
#[doc = "S0_ADDRESSB (rw) register accessor: Slave I2C Address B Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressb::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressb::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressb`]
#[doc = "S0_ADDRESSB (rw) register accessor: Slave I2C Address B Value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressb::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressb::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressb`]
module"]
#[doc(alias = "S0_ADDRESSB")]
pub type S0Addressb = crate::Reg<s0_addressb::S0AddressbSpec>;
#[doc = "Slave I2C Address B Value"]
pub mod s0_addressb;
#[doc = "S0_ADDRESSMASKB (rw) register accessor: Slave I2C Address B Mask value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressmaskb::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressmaskb::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressmaskb`]
#[doc = "S0_ADDRESSMASKB (rw) register accessor: Slave I2C Address B Mask value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressmaskb::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressmaskb::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@s0_addressmaskb`]
module"]
#[doc(alias = "S0_ADDRESSMASKB")]
pub type S0Addressmaskb = crate::Reg<s0_addressmaskb::S0AddressmaskbSpec>;
#[doc = "Slave I2C Address B Mask value"]
pub mod s0_addressmaskb;
#[doc = "PERID (r) register accessor: Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@perid`]
#[doc = "PERID (r) register accessor: Peripheral ID Register\n\nYou can [`read`](crate::Reg::read) this register and get [`perid::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@perid`]
module"]
#[doc(alias = "PERID")]
pub type Perid = crate::Reg<perid::PeridSpec>;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "I2C Address value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`address::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`address::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "I2C Address value\n\nYou can [`read`](crate::Reg::read) this register and get [`address::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`address::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct AddressSpec;
impl crate::RegisterSpec for AddressSpec {
type Ux = u32;

View File

@ -25,18 +25,16 @@ impl R {
impl W {
#[doc = "Bits 0:30 - Enable FastMode"]
#[inline(always)]
#[must_use]
pub fn value(&mut self) -> ValueW<ClkscaleSpec> {
ValueW::new(self, 0)
}
#[doc = "Bit 31 - Enable FastMode"]
#[inline(always)]
#[must_use]
pub fn fastmode(&mut self) -> FastmodeW<ClkscaleSpec> {
FastmodeW::new(self, 31)
}
}
#[doc = "Clock Scale divide value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`clkscale::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`clkscale::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Clock Scale divide value\n\nYou can [`read`](crate::Reg::read) this register and get [`clkscale::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`clkscale::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct ClkscaleSpec;
impl crate::RegisterSpec for ClkscaleSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Clock Low Timeout Limit Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`clktolimit::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`clktolimit::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Clock Low Timeout Limit Register\n\nYou can [`read`](crate::Reg::read) this register and get [`clktolimit::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`clktolimit::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct ClktolimitSpec;
impl crate::RegisterSpec for ClktolimitSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Command Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`cmd::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`cmd::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Command Register\n\nYou can [`read`](crate::Reg::read) this register and get [`cmd::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`cmd::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct CmdSpec;
impl crate::RegisterSpec for CmdSpec {
type Ux = u32;

View File

@ -88,60 +88,51 @@ impl R {
impl W {
#[doc = "Bit 0 - I2C CLK Enabled"]
#[inline(always)]
#[must_use]
pub fn clkenabled(&mut self) -> ClkenabledW<CtrlSpec> {
ClkenabledW::new(self, 0)
}
#[doc = "Bit 1 - I2C Activated"]
#[inline(always)]
#[must_use]
pub fn enabled(&mut self) -> EnabledW<CtrlSpec> {
EnabledW::new(self, 1)
}
#[doc = "Bit 2 - I2C Active"]
#[inline(always)]
#[must_use]
pub fn enable(&mut self) -> EnableW<CtrlSpec> {
EnableW::new(self, 2)
}
#[doc = "Bit 3 - TX FIFIO Empty Mode"]
#[inline(always)]
#[must_use]
pub fn txfemd(&mut self) -> TxfemdW<CtrlSpec> {
TxfemdW::new(self, 3)
}
#[doc = "Bit 4 - RX FIFO Full Mode"]
#[inline(always)]
#[must_use]
pub fn rxffmd(&mut self) -> RxffmdW<CtrlSpec> {
RxffmdW::new(self, 4)
}
#[doc = "Bit 5 - Enable Input Analog Glitch Filter"]
#[inline(always)]
#[must_use]
pub fn algfilter(&mut self) -> AlgfilterW<CtrlSpec> {
AlgfilterW::new(self, 5)
}
#[doc = "Bit 6 - Enable Input Digital Glitch Filter"]
#[inline(always)]
#[must_use]
pub fn dlgfilter(&mut self) -> DlgfilterW<CtrlSpec> {
DlgfilterW::new(self, 6)
}
#[doc = "Bit 8 - Enable LoopBack Mode"]
#[inline(always)]
#[must_use]
pub fn loopback(&mut self) -> LoopbackW<CtrlSpec> {
LoopbackW::new(self, 8)
}
#[doc = "Bit 9 - Enable Timing Config Register"]
#[inline(always)]
#[must_use]
pub fn tmconfigenb(&mut self) -> TmconfigenbW<CtrlSpec> {
TmconfigenbW::new(self, 9)
}
}
#[doc = "Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`ctrl::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`ctrl::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Control Register\n\nYou can [`read`](crate::Reg::read) this register and get [`ctrl::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`ctrl::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct CtrlSpec;
impl crate::RegisterSpec for CtrlSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Data Input/Output\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`data::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`data::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Data Input/Output\n\nYou can [`read`](crate::Reg::read) this register and get [`data::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`data::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct DataSpec;
impl crate::RegisterSpec for DataSpec {
type Ux = u32;

View File

@ -7,18 +7,16 @@ pub type TxfifoW<'a, REG> = crate::BitWriter<'a, REG>;
impl W {
#[doc = "Bit 0 - Clear Rx FIFO"]
#[inline(always)]
#[must_use]
pub fn rxfifo(&mut self) -> RxfifoW<FifoClrSpec> {
RxfifoW::new(self, 0)
}
#[doc = "Bit 1 - Clear Tx FIFO"]
#[inline(always)]
#[must_use]
pub fn txfifo(&mut self) -> TxfifoW<FifoClrSpec> {
TxfifoW::new(self, 1)
}
}
#[doc = "Clear FIFO Register\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`fifo_clr::W`](W). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Clear FIFO Register\n\nYou can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`fifo_clr::W`](W). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct FifoClrSpec;
impl crate::RegisterSpec for FifoClrSpec {
type Ux = u32;

View File

@ -133,90 +133,76 @@ impl R {
impl W {
#[doc = "Bit 0 - I2C Bus is Idle"]
#[inline(always)]
#[must_use]
pub fn i2cidle(&mut self) -> I2cidleW<IrqEnbSpec> {
I2cidleW::new(self, 0)
}
#[doc = "Bit 1 - Controller is Idle"]
#[inline(always)]
#[must_use]
pub fn idle(&mut self) -> IdleW<IrqEnbSpec> {
IdleW::new(self, 1)
}
#[doc = "Bit 2 - Controller is Waiting"]
#[inline(always)]
#[must_use]
pub fn waiting(&mut self) -> WaitingW<IrqEnbSpec> {
WaitingW::new(self, 2)
}
#[doc = "Bit 3 - Controller is Stalled"]
#[inline(always)]
#[must_use]
pub fn stalled(&mut self) -> StalledW<IrqEnbSpec> {
StalledW::new(self, 3)
}
#[doc = "Bit 4 - I2C Arbitration was lost"]
#[inline(always)]
#[must_use]
pub fn arblost(&mut self) -> ArblostW<IrqEnbSpec> {
ArblostW::new(self, 4)
}
#[doc = "Bit 5 - I2C Address was not Acknowledged"]
#[inline(always)]
#[must_use]
pub fn nackaddr(&mut self) -> NackaddrW<IrqEnbSpec> {
NackaddrW::new(self, 5)
}
#[doc = "Bit 6 - I2C Data was not Acknowledged"]
#[inline(always)]
#[must_use]
pub fn nackdata(&mut self) -> NackdataW<IrqEnbSpec> {
NackdataW::new(self, 6)
}
#[doc = "Bit 7 - I2C Clock Low Timeout"]
#[inline(always)]
#[must_use]
pub fn clkloto(&mut self) -> ClklotoW<IrqEnbSpec> {
ClklotoW::new(self, 7)
}
#[doc = "Bit 10 - TX FIFO Overflowed"]
#[inline(always)]
#[must_use]
pub fn txoverflow(&mut self) -> TxoverflowW<IrqEnbSpec> {
TxoverflowW::new(self, 10)
}
#[doc = "Bit 11 - TX FIFO Overflowed"]
#[inline(always)]
#[must_use]
pub fn rxoverflow(&mut self) -> RxoverflowW<IrqEnbSpec> {
RxoverflowW::new(self, 11)
}
#[doc = "Bit 12 - TX FIFO Ready"]
#[inline(always)]
#[must_use]
pub fn txready(&mut self) -> TxreadyW<IrqEnbSpec> {
TxreadyW::new(self, 12)
}
#[doc = "Bit 13 - RX FIFO Ready"]
#[inline(always)]
#[must_use]
pub fn rxready(&mut self) -> RxreadyW<IrqEnbSpec> {
RxreadyW::new(self, 13)
}
#[doc = "Bit 14 - TX FIFO Empty"]
#[inline(always)]
#[must_use]
pub fn txempty(&mut self) -> TxemptyW<IrqEnbSpec> {
TxemptyW::new(self, 14)
}
#[doc = "Bit 15 - RX FIFO Full"]
#[inline(always)]
#[must_use]
pub fn rxfull(&mut self) -> RxfullW<IrqEnbSpec> {
RxfullW::new(self, 15)
}
}
#[doc = "Interrupt Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`irq_enb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`irq_enb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Interrupt Enable Register\n\nYou can [`read`](crate::Reg::read) this register and get [`irq_enb::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`irq_enb::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct IrqEnbSpec;
impl crate::RegisterSpec for IrqEnbSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Peripheral ID Register\n\nYou can [`read`](crate::Reg::read) this register and get [`perid::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct PeridSpec;
impl crate::RegisterSpec for PeridSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "RX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "RX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`rxcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct RxcountSpec;
impl crate::RegisterSpec for RxcountSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`rxfifoirqtrg::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`rxfifoirqtrg::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`rxfifoirqtrg::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct RxfifoirqtrgSpec;
impl crate::RegisterSpec for RxfifoirqtrgSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave I2C Address Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_address::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_address::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Address Value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_address::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_address::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0AddressSpec;
impl crate::RegisterSpec for S0AddressSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave I2C Address B Value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Address B Value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressb::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressb::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0AddressbSpec;
impl crate::RegisterSpec for S0AddressbSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave I2C Address Mask value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressmask::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressmask::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Address Mask value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressmask::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressmask::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0AddressmaskSpec;
impl crate::RegisterSpec for S0AddressmaskSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave I2C Address B Mask value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_addressmaskb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_addressmaskb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Address B Mask value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_addressmaskb::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_addressmaskb::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0AddressmaskbSpec;
impl crate::RegisterSpec for S0AddressmaskbSpec {
type Ux = u32;

View File

@ -52,36 +52,31 @@ impl R {
impl W {
#[doc = "Bit 0 - I2C Enabled"]
#[inline(always)]
#[must_use]
pub fn clkenabled(&mut self) -> ClkenabledW<S0CtrlSpec> {
ClkenabledW::new(self, 0)
}
#[doc = "Bit 1 - I2C Activated"]
#[inline(always)]
#[must_use]
pub fn enabled(&mut self) -> EnabledW<S0CtrlSpec> {
EnabledW::new(self, 1)
}
#[doc = "Bit 2 - I2C Active"]
#[inline(always)]
#[must_use]
pub fn enable(&mut self) -> EnableW<S0CtrlSpec> {
EnableW::new(self, 2)
}
#[doc = "Bit 3 - TX FIFIO Empty Mode"]
#[inline(always)]
#[must_use]
pub fn txfemd(&mut self) -> TxfemdW<S0CtrlSpec> {
TxfemdW::new(self, 3)
}
#[doc = "Bit 4 - RX FIFO Full Mode"]
#[inline(always)]
#[must_use]
pub fn rxffmd(&mut self) -> RxffmdW<S0CtrlSpec> {
RxffmdW::new(self, 4)
}
}
#[doc = "Slave Control Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_ctrl::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_ctrl::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Control Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_ctrl::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_ctrl::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0CtrlSpec;
impl crate::RegisterSpec for S0CtrlSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave Data Input/Output\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_data::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_data::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Data Input/Output\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_data::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_data::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0DataSpec;
impl crate::RegisterSpec for S0DataSpec {
type Ux = u32;

View File

@ -7,18 +7,16 @@ pub type TxfifoW<'a, REG> = crate::BitWriter<'a, REG>;
impl W {
#[doc = "Bit 0 - Clear Rx FIFO"]
#[inline(always)]
#[must_use]
pub fn rxfifo(&mut self) -> RxfifoW<S0FifoClrSpec> {
RxfifoW::new(self, 0)
}
#[doc = "Bit 1 - Clear Tx FIFO"]
#[inline(always)]
#[must_use]
pub fn txfifo(&mut self) -> TxfifoW<S0FifoClrSpec> {
TxfifoW::new(self, 1)
}
}
#[doc = "Slave Clear FIFO Register\n\nYou can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_fifo_clr::W`](W). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Clear FIFO Register\n\nYou can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_fifo_clr::W`](W). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0FifoClrSpec;
impl crate::RegisterSpec for S0FifoClrSpec {
type Ux = u32;

View File

@ -151,102 +151,86 @@ impl R {
impl W {
#[doc = "Bit 0 - Controller Complted a Transaction"]
#[inline(always)]
#[must_use]
pub fn completed(&mut self) -> CompletedW<S0IrqEnbSpec> {
CompletedW::new(self, 0)
}
#[doc = "Bit 1 - Controller is Idle"]
#[inline(always)]
#[must_use]
pub fn idle(&mut self) -> IdleW<S0IrqEnbSpec> {
IdleW::new(self, 1)
}
#[doc = "Bit 2 - Controller is Waiting"]
#[inline(always)]
#[must_use]
pub fn waiting(&mut self) -> WaitingW<S0IrqEnbSpec> {
WaitingW::new(self, 2)
}
#[doc = "Bit 3 - Controller is Tx Stalled"]
#[inline(always)]
#[must_use]
pub fn txstalled(&mut self) -> TxstalledW<S0IrqEnbSpec> {
TxstalledW::new(self, 3)
}
#[doc = "Bit 4 - Controller is Rx Stalled"]
#[inline(always)]
#[must_use]
pub fn rxstalled(&mut self) -> RxstalledW<S0IrqEnbSpec> {
RxstalledW::new(self, 4)
}
#[doc = "Bit 5 - I2C Address Match"]
#[inline(always)]
#[must_use]
pub fn addressmatch(&mut self) -> AddressmatchW<S0IrqEnbSpec> {
AddressmatchW::new(self, 5)
}
#[doc = "Bit 6 - I2C Data was not Acknowledged"]
#[inline(always)]
#[must_use]
pub fn nackdata(&mut self) -> NackdataW<S0IrqEnbSpec> {
NackdataW::new(self, 6)
}
#[doc = "Bit 7 - Pending Data is first Byte following Address"]
#[inline(always)]
#[must_use]
pub fn rxdatafirst(&mut self) -> RxdatafirstW<S0IrqEnbSpec> {
RxdatafirstW::new(self, 7)
}
#[doc = "Bit 8 - I2C Start Condition"]
#[inline(always)]
#[must_use]
pub fn i2c_start(&mut self) -> I2cStartW<S0IrqEnbSpec> {
I2cStartW::new(self, 8)
}
#[doc = "Bit 9 - I2C Stop Condition"]
#[inline(always)]
#[must_use]
pub fn i2c_stop(&mut self) -> I2cStopW<S0IrqEnbSpec> {
I2cStopW::new(self, 9)
}
#[doc = "Bit 10 - TX FIFO Underflowed"]
#[inline(always)]
#[must_use]
pub fn txunderflow(&mut self) -> TxunderflowW<S0IrqEnbSpec> {
TxunderflowW::new(self, 10)
}
#[doc = "Bit 11 - TX FIFO Overflowed"]
#[inline(always)]
#[must_use]
pub fn rxoverflow(&mut self) -> RxoverflowW<S0IrqEnbSpec> {
RxoverflowW::new(self, 11)
}
#[doc = "Bit 12 - TX FIFO Ready"]
#[inline(always)]
#[must_use]
pub fn txready(&mut self) -> TxreadyW<S0IrqEnbSpec> {
TxreadyW::new(self, 12)
}
#[doc = "Bit 13 - RX FIFO Ready"]
#[inline(always)]
#[must_use]
pub fn rxready(&mut self) -> RxreadyW<S0IrqEnbSpec> {
RxreadyW::new(self, 13)
}
#[doc = "Bit 14 - TX FIFO Empty"]
#[inline(always)]
#[must_use]
pub fn txempty(&mut self) -> TxemptyW<S0IrqEnbSpec> {
TxemptyW::new(self, 14)
}
#[doc = "Bit 15 - RX FIFO Full"]
#[inline(always)]
#[must_use]
pub fn rxfull(&mut self) -> RxfullW<S0IrqEnbSpec> {
RxfullW::new(self, 15)
}
}
#[doc = "Slave Interrupt Enable Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_irq_enb::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_irq_enb::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Interrupt Enable Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_irq_enb::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_irq_enb::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0IrqEnbSpec;
impl crate::RegisterSpec for S0IrqEnbSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Slave I2C Last Address value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_lastaddress::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Last Address value\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_lastaddress::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0LastaddressSpec;
impl crate::RegisterSpec for S0LastaddressSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave MaxWords Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_maxwords::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_maxwords::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave MaxWords Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_maxwords::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_maxwords::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0MaxwordsSpec;
impl crate::RegisterSpec for S0MaxwordsSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Slave RX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_rxcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave RX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_rxcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0RxcountSpec;
impl crate::RegisterSpec for S0RxcountSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_rxfifoirqtrg::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_rxfifoirqtrg::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Rx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_rxfifoirqtrg::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_rxfifoirqtrg::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0RxfifoirqtrgSpec;
impl crate::RegisterSpec for S0RxfifoirqtrgSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Internal STATE of I2C Slave Controller\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_state::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Internal STATE of I2C Slave Controller\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_state::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0StateSpec;
impl crate::RegisterSpec for S0StateSpec {
type Ux = u32;

View File

@ -121,7 +121,7 @@ impl R {
RawSclR::new(((self.bits >> 31) & 1) != 0)
}
}
#[doc = "Slave I2C Controller Status Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_status::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave I2C Controller Status Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_status::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0StatusSpec;
impl crate::RegisterSpec for S0StatusSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Slave TX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_txcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave TX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_txcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0TxcountSpec;
impl crate::RegisterSpec for S0TxcountSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Slave Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`s0_txfifoirqtrg::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`s0_txfifoirqtrg::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Slave Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`s0_txfifoirqtrg::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`s0_txfifoirqtrg::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct S0TxfifoirqtrgSpec;
impl crate::RegisterSpec for S0TxfifoirqtrgSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Internal STATE of I2C Master Controller\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`state::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Internal STATE of I2C Master Controller\n\nYou can [`read`](crate::Reg::read) this register and get [`state::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct StateSpec;
impl crate::RegisterSpec for StateSpec {
type Ux = u32;

View File

@ -107,7 +107,7 @@ impl R {
RawSclR::new(((self.bits >> 31) & 1) != 0)
}
}
#[doc = "I2C Controller Status Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`status::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "I2C Controller Status Register\n\nYou can [`read`](crate::Reg::read) this register and get [`status::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct StatusSpec;
impl crate::RegisterSpec for StatusSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Timing Config Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`tmconfig::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`tmconfig::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Timing Config Register\n\nYou can [`read`](crate::Reg::read) this register and get [`tmconfig::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`tmconfig::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct TmconfigSpec;
impl crate::RegisterSpec for TmconfigSpec {
type Ux = u32;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "TX Count Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`txcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "TX Count Register\n\nYou can [`read`](crate::Reg::read) this register and get [`txcount::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct TxcountSpec;
impl crate::RegisterSpec for TxcountSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`txfifoirqtrg::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`txfifoirqtrg::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Tx FIFO IRQ Trigger Level\n\nYou can [`read`](crate::Reg::read) this register and get [`txfifoirqtrg::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`txfifoirqtrg::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct TxfifoirqtrgSpec;
impl crate::RegisterSpec for TxfifoirqtrgSpec {
type Ux = u32;

View File

@ -8,7 +8,7 @@ impl core::fmt::Debug for R {
}
}
impl W {}
#[doc = "Word Count value\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`words::R`](R). You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`words::W`](W). You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Word Count value\n\nYou can [`read`](crate::Reg::read) this register and get [`words::R`](R). You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`words::W`](W). You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct WordsSpec;
impl crate::RegisterSpec for WordsSpec {
type Ux = u32;

View File

@ -2,8 +2,8 @@
#[doc = "Register block"]
pub struct RegisterBlock {
porta: [Porta; 32],
portb0: [Portb; 32],
_reserved2: [u8; 0x0efc],
portbs: Portbs,
_reserved2: [u8; 0x0f78],
perid: Perid,
}
impl RegisterBlock {
@ -18,16 +18,10 @@ impl RegisterBlock {
pub fn porta_iter(&self) -> impl Iterator<Item = &Porta> {
self.porta.iter()
}
#[doc = "0x80..0x100 - PORTB Pin Configuration Register"]
#[doc = "0x80 - PORTB Pin Configuration Register"]
#[inline(always)]
pub const fn portb0(&self, n: usize) -> &Portb {
&self.portb0[n]
}
#[doc = "Iterator for array of:"]
#[doc = "0x80..0x100 - PORTB Pin Configuration Register"]
#[inline(always)]
pub fn portb0_iter(&self) -> impl Iterator<Item = &Portb> {
self.portb0.iter()
pub const fn portbs(&self) -> &Portbs {
&self.portbs
}
#[doc = "0xffc - Peripheral ID Register"]
#[inline(always)]
@ -35,15 +29,15 @@ impl RegisterBlock {
&self.perid
}
}
#[doc = "PORTA (rw) register accessor: PORTA Pin Configuration Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`porta::R`]. You can [`reset`](crate::generic::Reg::reset), [`write`](crate::generic::Reg::write), [`write_with_zero`](crate::generic::Reg::write_with_zero) this register using [`porta::W`]. You can also [`modify`](crate::generic::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@porta`]
#[doc = "PORTA (rw) register accessor: PORTA Pin Configuration Register\n\nYou can [`read`](crate::Reg::read) this register and get [`porta::R`]. You can [`reset`](crate::Reg::reset), [`write`](crate::Reg::write), [`write_with_zero`](crate::Reg::write_with_zero) this register using [`porta::W`]. You can also [`modify`](crate::Reg::modify) this register. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@porta`]
module"]
#[doc(alias = "PORTA")]
pub type Porta = crate::Reg<porta::PortaSpec>;
#[doc = "PORTA Pin Configuration Register"]
pub mod porta;
pub use porta as portb;
pub use Porta as Portb;
#[doc = "PERID (r) register accessor: Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@perid`]
pub use porta as portbs;
pub use Porta as Portbs;
#[doc = "PERID (r) register accessor: Peripheral ID Register\n\nYou can [`read`](crate::Reg::read) this register and get [`perid::R`]. See [API](https://docs.rs/svd2rust/#read--modify--write-api).\n\nFor information about available fields see [`mod@perid`]
module"]
#[doc(alias = "PERID")]
pub type Perid = crate::Reg<perid::PeridSpec>;

View File

@ -5,7 +5,7 @@ impl core::fmt::Debug for R {
write!(f, "{}", self.bits())
}
}
#[doc = "Peripheral ID Register\n\nYou can [`read`](crate::generic::Reg::read) this register and get [`perid::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
#[doc = "Peripheral ID Register\n\nYou can [`read`](crate::Reg::read) this register and get [`perid::R`](R). See [API](https://docs.rs/svd2rust/#read--modify--write-api)."]
pub struct PeridSpec;
impl crate::RegisterSpec for PeridSpec {
type Ux = u32;

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