1 Commits

Author SHA1 Message Date
4fb72ecba6 init new shared periph crate 2025-04-22 13:51:51 +02:00
45 changed files with 611 additions and 233 deletions

View File

@@ -34,9 +34,6 @@ It also contains the following helper crates:
[`RTIC`](https://rtic.rs/2/book/en/) and [`embassy`](https://github.com/embassy-rs/embassy) [`RTIC`](https://rtic.rs/2/book/en/) and [`embassy`](https://github.com/embassy-rs/embassy)
native Rust RTOSes. native Rust RTOSes.
The majority of the HAL implementation and the Embassy-rs support are contained in the external
[`vorago-shared-periphs`](https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs) crate.
## Using the `.cargo/config.toml` file ## Using the `.cargo/config.toml` file
Use the following command to have a starting `config.toml` file Use the following command to have a starting `config.toml` file
@@ -79,7 +76,7 @@ probe-rs run --chip VA108xx_RAM --protocol jtag target/thumbv6m-none-eabi/debug/
to flash and run the blinky program on the RAM. There is also a `VA108xx` chip target to flash and run the blinky program on the RAM. There is also a `VA108xx` chip target
available for persistent flashing. available for persistent flashing.
Runner configuration is available in the `.cargo/def-config.toml` file to use `probe-rs` for Runner configuration avilable in the `.cargo/def-config.toml` file to use `probe-rs` for
convenience. `probe-rs` is also able to process and display `defmt` strings directly. convenience. `probe-rs` is also able to process and display `defmt` strings directly.
### Using VS Code ### Using VS Code
@@ -153,10 +150,11 @@ address for the RTT block placement is 0x10000000. It is recommended to use a se
0x1000 around that base address when using the RTT viewer. 0x1000 around that base address when using the RTT viewer.
The RTT viewer will not be able to process `defmt` printouts. However, you can view the defmt The RTT viewer will not be able to process `defmt` printouts. However, you can view the defmt
logs by [installing defmt-print](https://crates.io/crates/defmt-print) first and then running logs by [installing defmt-print](https://crates.io/crates/defmt-print) first and then piping
the output on telnet port 19021 into `defmt-print`, for example by running
```sh ```sh
defmt-print -e <pathToElfFile> tcp telnet localhost 19021 | defmt-print -e <pathToElfFile>
``` ```
The path of the ELF file which is being debugged needs to be specified for this to work. The path of the ELF file which is being debugged needs to be specified for this to work.

View File

@@ -4,15 +4,16 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
defmt = "1" panic-halt = "1"
defmt-rtt = "1" rtt-target = "0.6"
panic-probe = { version = "1", features = ["print-defmt"] } panic-rtt-target = "0.2"
embedded-hal = "1" embedded-hal = "1"
embedded-hal-nb = "1"
embedded-io = "0.6"
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
features = ["rt"] features = ["rt"]
path = "../va108xx-hal"

View File

@@ -7,21 +7,18 @@
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
// Logging provider use panic_rtt_target as _;
use defmt_rtt as _; use rtt_target::{rprintln, rtt_init_print};
// Panic provider
use panic_probe as _;
use va108xx_hal::{ use va108xx_hal::{
gpio::{regs::Gpio, Input, Output, PinState, Pull}, gpio::{PinState, PinsA, PinsB},
pac, pac::{self, interrupt},
pins::{PinsA, PinsB, Port},
prelude::*, prelude::*,
time::Hertz, time::Hertz,
timer::CountdownTimer, timer::{default_ms_irq_handler, set_up_ms_tick, CountdownTimer, InterruptConfig},
}; };
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, defmt::Format)] #[derive(Debug)]
enum TestCase { enum TestCase {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
TestBasic, TestBasic,
@@ -35,18 +32,18 @@ enum TestCase {
Pulse, Pulse,
// Tie PA0, PA1 and PA3 to an oscilloscope // Tie PA0, PA1 and PA3 to an oscilloscope
DelayGpio, DelayGpio,
// PA0 can be checked with an oscillsope to verify timing correctness.
DelayMs, DelayMs,
} }
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
defmt::println!("-- VA108xx Test Application --"); rtt_init_print!();
let dp = pac::Peripherals::take().unwrap(); rprintln!("-- VA108xx Test Application --");
let mut dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap();
let pinsa = PinsA::new(dp.porta); let pinsa = PinsA::new(&mut dp.sysconfig, dp.porta);
let pinsb = PinsB::new(dp.portb); let pinsb = PinsB::new(&mut dp.sysconfig, dp.portb);
let mut led1 = Output::new(pinsa.pa10, PinState::Low); let mut led1 = pinsa.pa10.into_readable_push_pull_output();
let test_case = TestCase::DelayMs; let test_case = TestCase::DelayMs;
match test_case { match test_case {
@@ -54,20 +51,20 @@ fn main() -> ! {
| TestCase::TestPulldown | TestCase::TestPulldown
| TestCase::TestPullup | TestCase::TestPullup
| TestCase::TestMask => { | TestCase::TestMask => {
defmt::info!( rprintln!(
"Test case {:?}. Make sure to tie PORTA[0] to PORTA[1]", "Test case {:?}. Make sure to tie PORTA[0] to PORTA[1]",
test_case test_case
); );
} }
_ => { _ => {
defmt::info!("Test case {:?}", test_case); rprintln!("Test case {:?}", test_case);
} }
} }
match test_case { match test_case {
TestCase::TestBasic => { TestCase::TestBasic => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let mut out = Output::new(pinsa.pa0, PinState::Low); let mut out = pinsa.pa0.into_readable_push_pull_output();
let input = Input::new_floating(pinsa.pa1); let input = pinsa.pa1.into_floating_input();
out.set_high(); out.set_high();
assert!(input.is_high()); assert!(input.is_high());
out.set_low(); out.set_low();
@@ -75,74 +72,73 @@ fn main() -> ! {
} }
TestCase::TestPullup => { TestCase::TestPullup => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let input = Input::new_with_pull(pinsa.pa1, Pull::Up); let input = pinsa.pa1.into_pull_up_input();
assert!(input.is_high()); assert!(input.is_high());
let mut out = Output::new(pinsa.pa0, PinState::Low); let mut out = pinsa.pa0.into_readable_push_pull_output();
out.set_low(); out.set_low();
assert!(input.is_low()); assert!(input.is_low());
out.set_high(); out.set_high();
assert!(input.is_high()); assert!(input.is_high());
out.into_floating_input();
assert!(input.is_high());
} }
TestCase::TestPulldown => { TestCase::TestPulldown => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
let input = Input::new_with_pull(pinsa.pa1, Pull::Down); let input = pinsa.pa1.into_pull_down_input();
assert!(input.is_low()); assert!(input.is_low());
let mut out = Output::new(pinsa.pa0, PinState::Low); let mut out = pinsa.pa0.into_push_pull_output();
out.set_low(); out.set_low();
assert!(input.is_low()); assert!(input.is_low());
out.set_high(); out.set_high();
assert!(input.is_high()); assert!(input.is_high());
out.into_floating_input();
assert!(input.is_low());
} }
TestCase::TestMask => { TestCase::TestMask => {
// Tie PORTA[0] to PORTA[1] for these tests! // Tie PORTA[0] to PORTA[1] for these tests!
// Need to test this low-level.. let mut input = pinsa.pa1.into_pull_down_input();
/*
let mut input = Input::new_with_pull(pinsa.pa1, Pull::Down);
input.clear_datamask(); input.clear_datamask();
assert!(!input.datamask()); assert!(!input.datamask());
let mut out = pinsa.pa0.into_push_pull_output(); let mut out = pinsa.pa0.into_push_pull_output();
out.clear_datamask(); out.clear_datamask();
assert!(input.is_low_masked().is_err()); assert!(input.is_low_masked().is_err());
assert!(out.set_high_masked().is_err()); assert!(out.set_high_masked().is_err());
*/
} }
TestCase::PortB => { TestCase::PortB => {
// Tie PORTB[22] to PORTB[23] for these tests! // Tie PORTB[22] to PORTB[23] for these tests!
let mut out = Output::new(pinsb.pb22, PinState::Low); let mut out = pinsb.pb22.into_readable_push_pull_output();
let input = Input::new_floating(pinsb.pb23); let input = pinsb.pb23.into_floating_input();
out.set_high(); out.set_high();
assert!(input.is_high()); assert!(input.is_high());
out.set_low(); out.set_low();
assert!(input.is_low()); assert!(input.is_low());
} }
TestCase::Perid => { TestCase::Perid => {
let mmio_porta = Gpio::new_mmio(Port::A); assert_eq!(PinsA::get_perid(), 0x004007e1);
assert_eq!(mmio_porta.read_perid(), 0x004007e1); assert_eq!(PinsB::get_perid(), 0x004007e1);
let mmio_porta = Gpio::new_mmio(Port::B);
assert_eq!(mmio_porta.read_perid(), 0x004007e1);
} }
TestCase::Pulse => { TestCase::Pulse => {
let mut output_pulsed = Output::new(pinsa.pa0, PinState::Low); let mut output_pulsed = pinsa.pa0.into_push_pull_output();
output_pulsed.configure_pulse_mode(true, PinState::Low); output_pulsed.configure_pulse_mode(true, PinState::Low);
defmt::info!("Pulsing high 10 times.."); rprintln!("Pulsing high 10 times..");
output_pulsed.set_low(); output_pulsed.set_low();
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_high(); output_pulsed.set_high();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
output_pulsed.configure_pulse_mode(true, PinState::High); output_pulsed.configure_pulse_mode(true, PinState::High);
defmt::info!("Pulsing low 10 times.."); rprintln!("Pulsing low 10 times..");
for _ in 0..10 { for _ in 0..10 {
output_pulsed.set_low(); output_pulsed.set_low();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
} }
TestCase::DelayGpio => { TestCase::DelayGpio => {
let mut out_0 = Output::new(pinsa.pa0, PinState::Low); let mut out_0 = pinsa.pa0.into_readable_push_pull_output();
out_0.configure_delay(true, false); out_0.configure_delay(true, false);
let mut out_1 = Output::new(pinsa.pa1, PinState::Low); let mut out_1 = pinsa.pa1.into_readable_push_pull_output();
out_1.configure_delay(false, true); out_1.configure_delay(false, true);
let mut out_2 = Output::new(pinsa.pa3, PinState::Low); let mut out_2 = pinsa.pa3.into_readable_push_pull_output();
out_2.configure_delay(true, true); out_2.configure_delay(true, true);
for _ in 0..20 { for _ in 0..20 {
out_0.toggle(); out_0.toggle();
@@ -152,8 +148,22 @@ fn main() -> ! {
} }
} }
TestCase::DelayMs => { TestCase::DelayMs => {
let mut delay_timer = CountdownTimer::new(dp.tim1, 50.MHz()); let mut ms_timer = set_up_ms_tick(
let mut pa0 = Output::new(pinsa.pa0, PinState::Low); InterruptConfig::new(pac::Interrupt::OC0, true, true),
&mut dp.sysconfig,
Some(&mut dp.irqsel),
50.MHz(),
dp.tim0,
);
for _ in 0..5 {
led1.toggle();
ms_timer.delay_ms(500);
led1.toggle();
ms_timer.delay_ms(500);
}
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 { for _ in 0..5 {
led1.toggle(); led1.toggle();
delay_timer.delay_ms(500); delay_timer.delay_ms(500);
@@ -162,23 +172,30 @@ fn main() -> ! {
} }
let ahb_freq: Hertz = 50.MHz(); let ahb_freq: Hertz = 50.MHz();
let mut syst_delay = cortex_m::delay::Delay::new(cp.SYST, ahb_freq.raw()); let mut syst_delay = cortex_m::delay::Delay::new(cp.SYST, ahb_freq.raw());
// Release image should be used to verify timings for pin PA0 // Test usecond delay using both TIM peripheral and SYST. Use the release image if you
for _ in 0..5 { // want to verify the timings!
pa0.toggle(); loop {
syst_delay.delay_us(50);
pa0.toggle();
syst_delay.delay_us(50);
pa0.toggle(); pa0.toggle();
delay_timer.delay_us(50); delay_timer.delay_us(50);
pa0.toggle(); pa0.toggle();
delay_timer.delay_us(50); delay_timer.delay_us(50);
pa0.toggle();
syst_delay.delay_us(50);
pa0.toggle();
syst_delay.delay_us(50);
} }
} }
} }
defmt::info!("Test success"); rprintln!("Test success");
loop { loop {
led1.toggle(); led1.toggle();
cortex_m::asm::delay(25_000_000); cortex_m::asm::delay(25_000_000);
} }
} }
#[interrupt]
#[allow(non_snake_case)]
fn OC0() {
default_ms_irq_handler()
}

View File

@@ -7,9 +7,9 @@ edition = "2021"
cortex-m = "0.7" cortex-m = "0.7"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embedded-hal = "1" embedded-hal = "1"
defmt-rtt = "1" panic-rtt-target = "0.2"
defmt = "1" panic-halt = "1"
panic-probe = { version = "1", features = ["defmt"] } rtt-target = "0.6"
crc = "3" crc = "3"
num_enum = { version = "0.7", default-features = false } num_enum = { version = "0.7", default-features = false }
static_assertions = "1" static_assertions = "1"
@@ -17,7 +17,6 @@ static_assertions = "1"
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
path = "../va108xx-hal" path = "../va108xx-hal"
features = ["defmt"]
[dependencies.vorago-reb1] [dependencies.vorago-reb1]
version = "0.8" version = "0.8"

View File

@@ -12,8 +12,8 @@ The bootloader uses the following memory map:
| 0x0 | Bootloader start | code up to 0x2FFE bytes | | 0x0 | Bootloader start | code up to 0x2FFE bytes |
| 0x2FFE | Bootloader CRC | half-word | | 0x2FFE | Bootloader CRC | half-word |
| 0x3000 | App image A start | code up to 0xE7F4 (~59K) bytes | | 0x3000 | App image A start | code up to 0xE7F4 (~59K) bytes |
| 0x117F4 | App image A CRC check length | word | | 0x117F8 | App image A CRC check length | word |
| 0x117F8 | App image A CRC check value | word | | 0x117FC | App image A CRC check value | word |
| 0x117FC | App image B start | code up to 0xE7F4 (~59K) bytes | | 0x117FC | App image B start | code up to 0xE7F4 (~59K) bytes |
| 0x1FFF0 | App image B CRC check length | word | | 0x1FFF0 | App image B CRC check length | word |
| 0x1FFF4 | App image B CRC check value | word | | 0x1FFF4 | App image B CRC check value | word |

View File

@@ -6,16 +6,17 @@ use cortex_m_rt::entry;
use crc::{Crc, CRC_16_IBM_3740}; use crc::{Crc, CRC_16_IBM_3740};
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
// Import panic provider. #[cfg(not(feature = "rtt-panic"))]
use panic_probe as _; use panic_halt as _;
// Import logger. #[cfg(feature = "rtt-panic")]
use defmt_rtt as _; use panic_rtt_target as _;
use va108xx_hal::{pac, spi::SpiClkConfig, time::Hertz, timer::CountdownTimer}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{pac, time::Hertz, timer::CountdownTimer};
use vorago_reb1::m95m01::M95M01; use vorago_reb1::m95m01::M95M01;
// Useful for debugging and see what the bootloader is doing. Enabled currently, because // Useful for debugging and see what the bootloader is doing. Enabled currently, because
// the binary stays small enough. // the binary stays small enough.
const DEFMT_PRINTOUT: bool = true; const RTT_PRINTOUT: bool = true;
const DEBUG_PRINTOUTS: bool = true; const DEBUG_PRINTOUTS: bool = true;
// Small delay, allows RTT printout to catch up. // Small delay, allows RTT printout to catch up.
const BOOT_DELAY_MS: u32 = 2000; const BOOT_DELAY_MS: u32 = 2000;
@@ -73,7 +74,7 @@ pub const PREFERRED_SLOT_OFFSET: u32 = 0x20000 - 1;
const CRC_ALGO: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740); const CRC_ALGO: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, defmt::Format)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive)]
#[repr(u8)] #[repr(u8)]
enum AppSel { enum AppSel {
A = 0, A = 0,
@@ -99,15 +100,15 @@ impl NvmInterface for NvmWrapper {
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
if DEFMT_PRINTOUT { if RTT_PRINTOUT {
defmt::println!("-- VA108xx bootloader --"); rtt_init_print!();
rprintln!("-- VA108xx bootloader --");
} }
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(dp.tim0, CLOCK_FREQ); let mut timer = CountdownTimer::new(CLOCK_FREQ, dp.tim0);
let clk_config = SpiClkConfig::new(2, 4); let mut nvm = M95M01::new(CLOCK_FREQ, dp.spic);
let mut nvm = M95M01::new(dp.spic, clk_config);
if FLASH_SELF { if FLASH_SELF {
let mut first_four_bytes: [u8; 4] = [0; 4]; let mut first_four_bytes: [u8; 4] = [0; 4];
@@ -130,21 +131,21 @@ fn main() -> ! {
nvm.write(0x4, bootloader_data) nvm.write(0x4, bootloader_data)
.expect("writing to NVM failed"); .expect("writing to NVM failed");
if let Err(e) = nvm.verify(0x0, &first_four_bytes) { if let Err(e) = nvm.verify(0x0, &first_four_bytes) {
if DEFMT_PRINTOUT { if RTT_PRINTOUT {
defmt::error!("verification of self-flash to NVM failed: {:?}", e); rprintln!("verification of self-flash to NVM failed: {:?}", e);
} }
} }
if let Err(e) = nvm.verify(0x4, bootloader_data) { if let Err(e) = nvm.verify(0x4, bootloader_data) {
if DEFMT_PRINTOUT { if RTT_PRINTOUT {
defmt::error!("verification of self-flash to NVM failed: {:?}", e); rprintln!("verification of self-flash to NVM failed: {:?}", e);
} }
} }
nvm.write(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes()) nvm.write(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes())
.expect("writing CRC failed"); .expect("writing CRC failed");
if let Err(e) = nvm.verify(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes()) { if let Err(e) = nvm.verify(BOOTLOADER_CRC_ADDR as usize, &bootloader_crc.to_be_bytes()) {
if DEFMT_PRINTOUT { if RTT_PRINTOUT {
defmt::error!( rprintln!(
"error: CRC verification for bootloader self-flash failed: {:?}", "error: CRC verification for bootloader self-flash failed: {:?}",
e e
); );
@@ -172,8 +173,8 @@ fn main() -> ! {
} else if check_app_crc(other_app) { } else if check_app_crc(other_app) {
boot_app(&dp.sysconfig, &cp, other_app, &mut timer) boot_app(&dp.sysconfig, &cp, other_app, &mut timer)
} else { } else {
if DEBUG_PRINTOUTS && DEFMT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
defmt::error!("both images corrupt! booting image A"); rprintln!("both images corrupt! booting image A");
} }
// TODO: Shift a CCSDS packet out to inform host/OBC about image corruption. // TODO: Shift a CCSDS packet out to inform host/OBC about image corruption.
// Both images seem to be corrupt. Boot default image A. // Both images seem to be corrupt. Boot default image A.
@@ -203,8 +204,8 @@ fn check_own_crc(
}); });
let crc_calc = digest.finalize(); let crc_calc = digest.finalize();
if crc_exp == 0x0000 || crc_exp == 0xffff { if crc_exp == 0x0000 || crc_exp == 0xffff {
if DEBUG_PRINTOUTS && DEFMT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
defmt::info!("BL CRC blank - prog new CRC"); rprintln!("BL CRC blank - prog new CRC");
} }
// Blank CRC, write it to NVM. // Blank CRC, write it to NVM.
nvm.write(BOOTLOADER_CRC_ADDR as usize, &crc_calc.to_be_bytes()) nvm.write(BOOTLOADER_CRC_ADDR as usize, &crc_calc.to_be_bytes())
@@ -214,8 +215,8 @@ fn check_own_crc(
// cortex_m::peripheral::SCB::sys_reset(); // cortex_m::peripheral::SCB::sys_reset();
} else if crc_exp != crc_calc { } else if crc_exp != crc_calc {
// Bootloader is corrupted. Try to run App A. // Bootloader is corrupted. Try to run App A.
if DEBUG_PRINTOUTS && DEFMT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
defmt::warn!( rprintln!(
"bootloader CRC corrupt, read {} and expected {}. booting image A immediately", "bootloader CRC corrupt, read {} and expected {}. booting image A immediately",
crc_calc, crc_calc,
crc_exp crc_exp
@@ -240,8 +241,8 @@ fn read_four_bytes_at_addr_zero(buf: &mut [u8; 4]) {
} }
} }
fn check_app_crc(app_sel: AppSel) -> bool { fn check_app_crc(app_sel: AppSel) -> bool {
if DEBUG_PRINTOUTS && DEFMT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
defmt::info!("Checking image {:?}", app_sel); rprintln!("Checking image {:?}", app_sel);
} }
if app_sel == AppSel::A { if app_sel == AppSel::A {
check_app_given_addr(APP_A_CRC_ADDR, APP_A_START_ADDR, APP_A_SIZE_ADDR) check_app_given_addr(APP_A_CRC_ADDR, APP_A_START_ADDR, APP_A_SIZE_ADDR)
@@ -255,8 +256,8 @@ fn check_app_given_addr(crc_addr: u32, start_addr: u32, image_size_addr: u32) ->
let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() }; let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() };
// Sanity check. // Sanity check.
if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 { if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 {
if DEFMT_PRINTOUT { if RTT_PRINTOUT {
defmt::error!("detected invalid app size {}", image_size); rprintln!("detected invalid app size {}", image_size);
} }
return false; return false;
} }
@@ -277,8 +278,8 @@ fn boot_app(
app_sel: AppSel, app_sel: AppSel,
timer: &mut CountdownTimer, timer: &mut CountdownTimer,
) -> ! { ) -> ! {
if DEBUG_PRINTOUTS && DEFMT_PRINTOUT { if DEBUG_PRINTOUTS && RTT_PRINTOUT {
defmt::info!("booting app {:?}", app_sel); rprintln!("booting app {:?}", app_sel);
} }
timer.delay_ms(BOOT_DELAY_MS); timer.delay_ms(BOOT_DELAY_MS);

View File

@@ -5,7 +5,9 @@ edition = "2021"
[dependencies] [dependencies]
cfg-if = "1" cfg-if = "1"
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-hal-async = "1" embedded-hal-async = "1"
embedded-io = "0.6" embedded-io = "0.6"
embedded-io-async = "0.6" embedded-io-async = "0.6"
@@ -13,12 +15,13 @@ heapless = "0.8"
static_cell = "2" static_cell = "2"
defmt = "1" defmt = "1"
defmt-rtt = "1" defmt-rtt = "0.4"
panic-probe = { version = "1", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
critical-section = "1" critical-section = "1"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
embassy-sync = "0.7" embassy-sync = "0.6"
embassy-time = "0.4" embassy-time = "0.4"
embassy-executor = { version = "0.7", features = [ embassy-executor = { version = "0.7", features = [
"arch-cortex-m", "arch-cortex-m",
@@ -27,13 +30,10 @@ embassy-executor = { version = "0.7", features = [
]} ]}
va108xx-hal = { version = "0.11", path = "../../va108xx-hal", features = ["defmt"] } va108xx-hal = { version = "0.11", path = "../../va108xx-hal", features = ["defmt"] }
va108xx-embassy = { version = "0.2", path = "../../va108xx-embassy" } va108xx-embassy = { version = "0.2" }
[features] [features]
default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"] default = ["ticks-hz-1_000", "va108xx-embassy/irq-oc30-oc31"]
custom-irqs = [] custom-irqs = []
ticks-hz-1_000 = ["embassy-time/tick-hz-1_000"] ticks-hz-1_000 = ["embassy-time/tick-hz-1_000"]
ticks-hz-32_768 = ["embassy-time/tick-hz-32_768"] ticks-hz-32_768 = ["embassy-time/tick-hz-32_768"]
[package.metadata.cargo-machete]
ignored = ["cortex-m-rt"]

View File

@@ -59,10 +59,16 @@ static CHANNEL_PB22_TO_PB23: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
defmt::println!("-- VA108xx Async GPIO Demo --"); defmt::println!("-- VA108xx Async GPIO Demo --");
let dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
// Safety: Only called once here. // Safety: Only called once here.
va108xx_embassy::init(dp.tim23, dp.tim22, SYSCLK_FREQ); va108xx_embassy::init(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ,
dp.tim23,
dp.tim22,
);
let porta = PinsA::new(dp.porta); let porta = PinsA::new(dp.porta);
let portb = PinsB::new(dp.portb); let portb = PinsB::new(dp.portb);

View File

@@ -52,10 +52,16 @@ static CONSUMER_UART_B: Mutex<RefCell<Option<Consumer<u8, 256>>>> = Mutex::new(R
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
defmt::println!("-- VA108xx Async UART RX Demo --"); defmt::println!("-- VA108xx Async UART RX Demo --");
let dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
// Safety: Only called once here. // Safety: Only called once here.
va108xx_embassy::init(dp.tim23, dp.tim22, SYSCLK_FREQ); va108xx_embassy::init(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ,
dp.tim23,
dp.tim22,
);
let porta = PinsA::new(dp.porta); let porta = PinsA::new(dp.porta);
let mut led0 = Output::new(porta.pa10, PinState::Low); let mut led0 = Output::new(porta.pa10, PinState::Low);
@@ -66,10 +72,9 @@ async fn main(spawner: Spawner) {
let rx_uart_a = porta.pa8; let rx_uart_a = porta.pa8;
let uarta = uart::Uart::new_with_interrupt( let uarta = uart::Uart::new_with_interrupt(
dp.uarta,
tx_uart_a,
rx_uart_a,
50.MHz(), 50.MHz(),
dp.uarta,
(tx_uart_a, rx_uart_a),
115200.Hz().into(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC2, true, true), InterruptConfig::new(pac::Interrupt::OC2, true, true),
) )
@@ -79,10 +84,9 @@ async fn main(spawner: Spawner) {
let rx_uart_b = porta.pa2; let rx_uart_b = porta.pa2;
let uartb = uart::Uart::new_with_interrupt( let uartb = uart::Uart::new_with_interrupt(
dp.uartb,
tx_uart_b,
rx_uart_b,
50.MHz(), 50.MHz(),
dp.uartb,
(tx_uart_b, rx_uart_b),
115200.Hz().into(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC3, true, true), InterruptConfig::new(pac::Interrupt::OC3, true, true),
) )

View File

@@ -39,10 +39,16 @@ const STR_LIST: &[&str] = &[
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
defmt::println!("-- VA108xx Async UART TX Demo --"); defmt::println!("-- VA108xx Async UART TX Demo --");
let dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
// Safety: Only called once here. // Safety: Only called once here.
va108xx_embassy::init(dp.tim23, dp.tim22, SYSCLK_FREQ); va108xx_embassy::init(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ,
dp.tim23,
dp.tim22,
);
let porta = PinsA::new(dp.porta); let porta = PinsA::new(dp.porta);
@@ -54,10 +60,9 @@ async fn main(_spawner: Spawner) {
let rx = porta.pa8; let rx = porta.pa8;
let uarta = uart::Uart::new_with_interrupt( let uarta = uart::Uart::new_with_interrupt(
dp.uarta,
tx,
rx,
50.MHz(), 50.MHz(),
dp.uarta,
(tx, rx),
115200.Hz().into(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC2, true, true), InterruptConfig::new(pac::Interrupt::OC2, true, true),
) )

View File

@@ -26,21 +26,23 @@ const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
defmt::println!("-- VA108xx Embassy Demo --"); defmt::println!("-- VA108xx Embassy Demo --");
let dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
// Safety: Only called once here. // Safety: Only called once here.
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(not(feature = "custom-irqs"))] { if #[cfg(not(feature = "custom-irqs"))] {
va108xx_embassy::init( va108xx_embassy::init(
&mut dp.sysconfig,
&dp.irqsel,
SYSCLK_FREQ,
dp.tim23, dp.tim23,
dp.tim22, dp.tim22,
SYSCLK_FREQ,
); );
} else { } else {
va108xx_embassy::init_with_custom_irqs( va108xx_embassy::init_with_custom_irqs(
SYSCLK_FREQ,
dp.tim23, dp.tim23,
dp.tim22, dp.tim22,
SYSCLK_FREQ,
pac::Interrupt::OC23, pac::Interrupt::OC23,
pac::Interrupt::OC24, pac::Interrupt::OC24,
); );

View File

@@ -5,12 +5,22 @@ edition = "2021"
[dependencies] [dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-io = "0.6" embedded-io = "0.6"
defmt-rtt = "1" defmt-rtt = "0.4"
defmt = "1" defmt = "1"
panic-probe = { version = "1", features = ["defmt"] } panic-probe = { version = "1", features = ["defmt"] }
# 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"]}
rtic = { version = "2", features = ["thumbv6-backend"] } rtic = { version = "2", features = ["thumbv6-backend"] }
rtic-monotonics = { version = "2", features = ["cortex-m-systick"] } rtic-monotonics = { version = "2", features = ["cortex-m-systick"] }
rtic-sync = { version = "1.3", features = ["defmt-03"] }
once_cell = {version = "1", default-features = false, features = ["critical-section"]}
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] } ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
va108xx-hal = { version = "0.11", path = "../../va108xx-hal" } va108xx-hal = { version = "0.11", path = "../../va108xx-hal" }

View File

@@ -54,10 +54,9 @@ mod app {
let rx = gpioa.pa8; let rx = gpioa.pa8;
let irq_uart = uart::Uart::new_with_interrupt( let irq_uart = uart::Uart::new_with_interrupt(
dp.uarta,
tx,
rx,
SYSCLK_FREQ, SYSCLK_FREQ,
dp.uarta,
(tx, rx),
115200.Hz().into(), 115200.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC3, true, true), InterruptConfig::new(pac::Interrupt::OC3, true, true),
) )

View File

@@ -7,15 +7,21 @@ edition = "2021"
cortex-m = {version = "0.7", features = ["critical-section-single-core"]} cortex-m = {version = "0.7", features = ["critical-section-single-core"]}
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
panic-halt = "1" panic-halt = "1"
defmt-rtt = "1" critical-section = "1"
defmt-rtt = "0.4"
defmt = "1" defmt = "1"
panic-probe = { version = "1", features = ["defmt"] } panic-probe = { version = "1", features = ["defmt"] }
embedded-hal = "1" embedded-hal = "1"
embedded-hal-nb = "1" embedded-hal-nb = "1"
embedded-io = "0.6" embedded-io = "0.6"
cortex-m-semihosting = "0.5.0"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] } portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
path = "../../va108xx-hal" path = "../../va108xx-hal"
features = ["defmt"] features = ["defmt"]
[dependencies.vorago-reb1]
path = "../../vorago-reb1"
version = "0.8"

View File

@@ -20,7 +20,7 @@ use va108xx_hal::{
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim1, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim1);
let porta = PinsA::new(dp.porta); let porta = PinsA::new(dp.porta);
let mut led1 = Output::new(porta.pa10, PinState::Low); let mut led1 = Output::new(porta.pa10, PinState::Low);
let mut led2 = Output::new(porta.pa7, PinState::Low); let mut led2 = Output::new(porta.pa7, PinState::Low);

View File

@@ -23,16 +23,16 @@ fn main() -> ! {
defmt::println!("-- VA108xx Cascade example application--"); defmt::println!("-- VA108xx Cascade example application--");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
// Will be started periodically to trigger a cascade // Will be started periodically to trigger a cascade
let mut cascade_triggerer = CountdownTimer::new(dp.tim3, 50.MHz()); let mut cascade_triggerer = CountdownTimer::new(50.MHz(), dp.tim3);
cascade_triggerer.auto_disable(true); cascade_triggerer.auto_disable(true);
cascade_triggerer.enable_interrupt(InterruptConfig::new(pac::Interrupt::OC1, true, false)); cascade_triggerer.enable_interrupt(InterruptConfig::new(pac::Interrupt::OC1, true, false));
cascade_triggerer.enable(); cascade_triggerer.enable();
// First target for cascade // First target for cascade
let mut cascade_target_1 = CountdownTimer::new(dp.tim4, 50.MHz()); let mut cascade_target_1 = CountdownTimer::new(50.MHz(), dp.tim4);
cascade_target_1.auto_deactivate(true); cascade_target_1.auto_deactivate(true);
cascade_target_1 cascade_target_1
.cascade_source(CascadeSelect::Csd0, CascadeSource::Tim(3)) .cascade_source(CascadeSelect::Csd0, CascadeSource::Tim(3))
@@ -52,7 +52,7 @@ fn main() -> ! {
cascade_target_1.start(1.Hz()); cascade_target_1.start(1.Hz());
// Activated by first cascade target // Activated by first cascade target
let mut cascade_target_2 = CountdownTimer::new(dp.tim5, 50.MHz()); let mut cascade_target_2 = CountdownTimer::new(50.MHz(), dp.tim5);
cascade_target_2.auto_deactivate(true); cascade_target_2.auto_deactivate(true);
// Set TIM4 as cascade source // Set TIM4 as cascade source
cascade_target_2 cascade_target_2

View File

@@ -23,8 +23,8 @@ fn main() -> ! {
defmt::println!("-- VA108xx PWM example application--"); defmt::println!("-- VA108xx PWM example application--");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let pinsa = PinsA::new(dp.porta); let pinsa = PinsA::new(dp.porta);
let mut pwm = pwm::PwmPin::new(pinsa.pa3, dp.tim3, 50.MHz(), 10.Hz()).unwrap(); let mut pwm = pwm::PwmPin::new(50.MHz(), (pinsa.pa3, dp.tim3), 10.Hz()).unwrap();
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let mut current_duty_cycle = 0.0; let mut current_duty_cycle = 0.0;
pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle)) pwm.set_duty_cycle(get_duty_from_percent(current_duty_cycle))
.unwrap(); .unwrap();

View File

@@ -43,7 +43,7 @@ const FILL_WORD: u8 = 0x0f;
fn main() -> ! { fn main() -> ! {
defmt::println!("-- VA108xx SPI example application--"); defmt::println!("-- VA108xx SPI example application--");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let spi_clk_cfg = SpiClkConfig::from_clk(50.MHz(), SPI_SPEED_KHZ.kHz()) let spi_clk_cfg = SpiClkConfig::from_clk(50.MHz(), SPI_SPEED_KHZ.kHz())
.expect("creating SPI clock config failed"); .expect("creating SPI clock config failed");
@@ -59,19 +59,19 @@ fn main() -> ! {
let mut spi = match SPI_BUS_SEL { let mut spi = match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA => { SpiBusSelect::SpiAPortA => {
let (sck, mosi, miso) = (pinsa.pa31, pinsa.pa30, pinsa.pa29); let (sck, mosi, miso) = (pinsa.pa31, pinsa.pa30, pinsa.pa29);
let mut spia = Spi::new(dp.spia, (sck, miso, mosi), spi_cfg).unwrap(); let mut spia = Spi::new(50.MHz(), dp.spia, (sck, miso, mosi), spi_cfg).unwrap();
spia.set_fill_word(FILL_WORD); spia.set_fill_word(FILL_WORD);
spia spia
} }
SpiBusSelect::SpiAPortB => { SpiBusSelect::SpiAPortB => {
let (sck, mosi, miso) = (pinsb.pb9, pinsb.pb8, pinsb.pb7); let (sck, mosi, miso) = (pinsb.pb9, pinsb.pb8, pinsb.pb7);
let mut spia = Spi::new(dp.spia, (sck, miso, mosi), spi_cfg).unwrap(); let mut spia = Spi::new(50.MHz(), dp.spia, (sck, miso, mosi), spi_cfg).unwrap();
spia.set_fill_word(FILL_WORD); spia.set_fill_word(FILL_WORD);
spia spia
} }
SpiBusSelect::SpiBPortB => { SpiBusSelect::SpiBPortB => {
let (sck, mosi, miso) = (pinsb.pb5, pinsb.pb4, pinsb.pb3); let (sck, mosi, miso) = (pinsb.pb5, pinsb.pb4, pinsb.pb3);
let mut spib = Spi::new(dp.spib, (sck, miso, mosi), spi_cfg).unwrap(); let mut spib = Spi::new(50.MHz(), dp.spib, (sck, miso, mosi), spi_cfg).unwrap();
spib.set_fill_word(FILL_WORD); spib.set_fill_word(FILL_WORD);
spib spib
} }

View File

@@ -10,6 +10,7 @@ use panic_probe as _;
use defmt_rtt as _; use defmt_rtt as _;
use portable_atomic::AtomicU32; use portable_atomic::AtomicU32;
use va108xx_hal::{ use va108xx_hal::{
clock::{get_sys_clock, set_sys_clock},
pac::{self, interrupt}, pac::{self, interrupt},
prelude::*, prelude::*,
time::Hertz, time::Hertz,
@@ -28,9 +29,10 @@ static SEC_COUNTER: AtomicU32 = AtomicU32::new(0);
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim2, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim2);
let mut last_ms = 0; let mut last_ms = 0;
defmt::info!("-- Vorago system ticks using timers --"); defmt::info!("-- Vorago system ticks using timers --");
set_sys_clock(50.MHz());
let lib_type = LibType::Hal; let lib_type = LibType::Hal;
match lib_type { match lib_type {
LibType::Pac => { LibType::Pac => {
@@ -65,10 +67,10 @@ fn main() -> ! {
} }
} }
LibType::Hal => { LibType::Hal => {
let mut ms_timer = CountdownTimer::new(dp.tim0, 50.MHz()); let mut ms_timer = CountdownTimer::new(get_sys_clock().unwrap(), dp.tim0);
ms_timer.enable_interrupt(InterruptConfig::new(interrupt::OC0, true, true)); ms_timer.enable_interrupt(InterruptConfig::new(interrupt::OC0, true, true));
ms_timer.start(1.kHz()); ms_timer.start(1.kHz());
let mut second_timer = CountdownTimer::new(dp.tim1, 50.MHz()); let mut second_timer = CountdownTimer::new(get_sys_clock().unwrap(), dp.tim1);
second_timer.enable_interrupt(InterruptConfig::new(interrupt::OC1, true, true)); second_timer.enable_interrupt(InterruptConfig::new(interrupt::OC1, true, true));
second_timer.start(1.Hz()); second_timer.start(1.Hz());
} }

View File

@@ -28,8 +28,8 @@ fn main() -> ! {
let gpioa = PinsA::new(dp.porta); let gpioa = PinsA::new(dp.porta);
let tx = gpioa.pa9; let tx = gpioa.pa9;
let rx = gpioa.pa8; let rx = gpioa.pa8;
let uart = let uart = uart::Uart::new_without_interrupt(50.MHz(), dp.uarta, (tx, rx), 115200.Hz().into())
uart::Uart::new_without_interrupt(dp.uarta, tx, rx, 50.MHz(), 115200.Hz().into()).unwrap(); .unwrap();
let (mut tx, mut rx) = uart.split(); let (mut tx, mut rx) = uart.split();
writeln!(tx, "Hello World\r").unwrap(); writeln!(tx, "Hello World\r").unwrap();

View File

@@ -4,23 +4,28 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"]} cortex-m = "0.7"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-hal-nb = "1"
embedded-io = "0.6" embedded-io = "0.6"
defmt = "1" defmt = "1"
defmt-rtt = { version = "1" } defmt-rtt = { version = "0.4" }
panic-probe = { version = "1", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
num_enum = { version = "0.7", default-features = false } num_enum = { version = "0.7", default-features = false }
cobs = { version = "0.4", default-features = false } crc = "3"
satrs = { version = "0.3.0-alpha.1", default-features = false } cobs = { version = "0.3", default-features = false }
satrs = { version = "0.2", default-features = false }
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] } ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
spacepackets = { version = "0.15", default-features = false, features = ["defmt"] } once_cell = { version = "1", default-features = false, features = ["critical-section"] }
spacepackets = { version = "0.11", default-features = false, features = ["defmt"] }
# Even though we do not use this directly, we need to activate this feature explicitely # 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. # so that RTIC compiles because thumv6 does not have CAS operations natively.
portable-atomic = {version = "1", features = ["unsafe-assume-single-core"]} portable-atomic = {version = "1", features = ["unsafe-assume-single-core"]}
rtic = { version = "2", features = ["thumbv6-backend"] } rtic = { version = "2", features = ["thumbv6-backend"] }
rtic-monotonics = { version = "2", features = ["cortex-m-systick"] } rtic-monotonics = { version = "2", features = ["cortex-m-systick"] }
rtic-sync = {version = "1", features = ["defmt-03"]}
[dependencies.va108xx-hal] [dependencies.va108xx-hal]
version = "0.11" version = "0.11"
@@ -29,6 +34,3 @@ features = ["defmt"]
[dependencies.vorago-reb1] [dependencies.vorago-reb1]
version = "0.8" version = "0.8"
[package.metadata.cargo-machete]
ignored = ["portable-atomic", "cortex-m-rt"]

View File

@@ -9,8 +9,9 @@ edition = "2021"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
panic-rtt-target = { version = "0.1.3" } panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" } rtt-target = { version = "0.5" }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
embedded-hal = "1" embedded-hal = "1"
va108xx-hal = { version = "0.11" } va108xx-hal = { version = "0.10.0" }
[profile.dev] [profile.dev]
codegen-units = 1 codegen-units = 1

View File

@@ -3,7 +3,7 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin};
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer}; use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer};
@@ -15,11 +15,11 @@ fn main() -> ! {
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0); let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0);
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let mut led1 = porta.pa10.into_readable_push_pull_output(); let mut led1 = porta.pa10.into_readable_push_pull_output();
loop { loop {
led1.toggle(); led1.toggle().ok();
timer.delay_ms(500); timer.delay_ms(500);
} }
} }

View File

@@ -9,8 +9,9 @@ edition = "2021"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
panic-rtt-target = { version = "0.1.3" } panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" } rtt-target = { version = "0.5" }
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
embedded-hal = "1" embedded-hal = "1"
va108xx-hal = { version = "0.11" } va108xx-hal = { version = "0.10.0" }
[profile.dev] [profile.dev]
codegen-units = 1 codegen-units = 1

View File

@@ -3,7 +3,7 @@
#![no_std] #![no_std]
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::{delay::DelayNs, digital::StatefulOutputPin};
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer}; use va108xx_hal::{gpio::PinsA, pac, prelude::*, timer::CountdownTimer};
@@ -15,11 +15,11 @@ fn main() -> ! {
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0); let mut timer = CountdownTimer::new(&mut dp.sysconfig, 50.MHz(), dp.tim0);
let porta = PinsA::new(&mut dp.sysconfig, dp.porta); let porta = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let mut led2 = porta.pa7.into_readable_push_pull_output(); let mut led2 = porta.pa7.into_readable_push_pull_output();
loop { loop {
led2.toggle(); led2.toggle().ok();
timer.delay_ms(1000); timer.delay_ms(1000);
} }
} }

View File

@@ -113,10 +113,9 @@ mod app {
let rx = gpioa.pa8; let rx = gpioa.pa8;
let irq_uart = uart::Uart::new_with_interrupt( let irq_uart = uart::Uart::new_with_interrupt(
dp.uarta,
tx,
rx,
SYSCLK_FREQ, SYSCLK_FREQ,
dp.uarta,
(tx, rx),
UART_BAUDRATE.Hz().into(), UART_BAUDRATE.Hz().into(),
InterruptConfig::new(pac::Interrupt::OC0, true, true), InterruptConfig::new(pac::Interrupt::OC0, true, true),
) )
@@ -270,7 +269,7 @@ mod app {
defmt::warn!("PUS TC error: {}", pus_tc.unwrap_err()); defmt::warn!("PUS TC error: {}", pus_tc.unwrap_err());
return; return;
} }
let pus_tc = pus_tc.unwrap(); let (pus_tc, _) = pus_tc.unwrap();
let mut write_and_send = |tm: &PusTmCreator| { let mut write_and_send = |tm: &PusTmCreator| {
let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap(); let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap();
cx.shared.tm_rb.lock(|prod| { cx.shared.tm_rb.lock(|prod| {
@@ -278,18 +277,18 @@ mod app {
prod.buf.push_slice(&cx.local.verif_buf[0..written_size]); prod.buf.push_slice(&cx.local.verif_buf[0..written_size]);
}); });
}; };
let request_id = VerificationReportCreator::read_request_id_from_tc(&pus_tc); let token = cx.local.verif_reporter.add_tc(&pus_tc);
let tm = cx let (tm, accepted_token) = cx
.local .local
.verif_reporter .verif_reporter
.acceptance_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .acceptance_success(cx.local.src_data_buf, token, 0, 0, &[])
.expect("acceptance success failed"); .expect("acceptance success failed");
write_and_send(&tm); write_and_send(&tm);
let tm = cx let (tm, started_token) = cx
.local .local
.verif_reporter .verif_reporter
.start_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .start_success(cx.local.src_data_buf, accepted_token, 0, 0, &[])
.expect("acceptance success failed"); .expect("acceptance success failed");
write_and_send(&tm); write_and_send(&tm);
@@ -308,7 +307,7 @@ mod app {
let tm = cx let tm = cx
.local .local
.verif_reporter .verif_reporter
.completion_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed"); .expect("completion success failed");
write_and_send(&tm); write_and_send(&tm);
}; };
@@ -339,7 +338,7 @@ mod app {
let tm = cx let tm = cx
.local .local
.verif_reporter .verif_reporter
.completion_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed"); .expect("completion success failed");
write_and_send(&tm); write_and_send(&tm);
} }
@@ -349,7 +348,7 @@ mod app {
let tm = cx let tm = cx
.local .local
.verif_reporter .verif_reporter
.completion_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed"); .expect("completion success failed");
write_and_send(&tm); write_and_send(&tm);
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 { } else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
@@ -358,7 +357,7 @@ mod app {
.verif_reporter .verif_reporter
.step_success( .step_success(
cx.local.src_data_buf, cx.local.src_data_buf,
&request_id, &started_token,
0, 0,
0, 0,
&[], &[],
@@ -408,7 +407,7 @@ mod app {
.verif_reporter .verif_reporter
.completion_failure( .completion_failure(
cx.local.src_data_buf, cx.local.src_data_buf,
&request_id, started_token,
0, 0,
0, 0,
FailParams::new(&[], &EcssEnumU8::new(0), &[]), FailParams::new(&[], &EcssEnumU8::new(0), &[]),
@@ -417,7 +416,7 @@ mod app {
} else { } else {
cx.local cx.local
.verif_reporter .verif_reporter
.completion_success(cx.local.src_data_buf, &request_id, 0, 0, &[]) .completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed") .expect("completion success failed")
}; };
write_and_send(&tm); write_and_send(&tm);

View File

@@ -11,8 +11,21 @@ keywords = ["no-std", "hal", "cortex-m", "vorago", "va108xx"]
categories = ["aerospace", "embedded", "no-std", "hardware-support"] categories = ["aerospace", "embedded", "no-std", "hardware-support"]
[dependencies] [dependencies]
vorago-shared-periphs = { git = "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs.git", features = ["vor1x"] } critical-section = "1"
va108xx-hal = { path = "../va108xx-hal" }
embassy-sync = "0.6"
embassy-executor = "0.7"
embassy-time-driver = "0.2"
embassy-time-queue-utils = "0.1"
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
va108xx-hal = { version = ">=0.10, <=0.11", path = "../va108xx-hal" }
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
[target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies]
portable-atomic = "1"
[features] [features]
default = ["irq-oc30-oc31"] default = ["irq-oc30-oc31"]

View File

@@ -32,12 +32,33 @@
//! [embassy example projects](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy) //! [embassy example projects](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy)
#![no_std] #![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
use core::cell::{Cell, RefCell};
use critical_section::{CriticalSection, Mutex};
use portable_atomic::{AtomicU32, Ordering};
use embassy_time_driver::{time_driver_impl, Driver, TICK_HZ};
use embassy_time_queue_utils::Queue;
use once_cell::sync::OnceCell;
#[cfg(feature = "irqs-in-lib")] #[cfg(feature = "irqs-in-lib")]
use va108xx_hal::pac::{self, interrupt}; use va108xx_hal::pac::interrupt;
use va108xx_hal::time::Hertz; use va108xx_hal::{
use va108xx_hal::timer::TimMarker; clock::enable_peripheral_clock,
use vorago_shared_periphs::embassy::time_driver; enable_nvic_interrupt, pac,
prelude::*,
timer::{
enable_tim_clk,
regs::{EnableControl, MmioTimer},
TimId, TimMarker,
},
PeripheralSelect,
};
time_driver_impl!(
static TIME_DRIVER: TimerDriver = TimerDriver {
periods: AtomicU32::new(0),
alarms: Mutex::new(AlarmState::new()),
queue: Mutex::new(RefCell::new(Queue::new())),
});
/// Macro to define the IRQ handlers for the time driver. /// Macro to define the IRQ handlers for the time driver.
/// ///
@@ -82,28 +103,286 @@ embassy_time_driver_irqs!(timekeeper_irq = OC30, alarm_irq = OC29);
#[cfg(feature = "irq-oc28-oc29")] #[cfg(feature = "irq-oc28-oc29")]
embassy_time_driver_irqs!(timekeeper_irq = OC29, alarm_irq = OC28); embassy_time_driver_irqs!(timekeeper_irq = OC29, alarm_irq = OC28);
/// Expose the time driver so the user can specify the IRQ handlers themselves.
pub fn time_driver() -> &'static TimerDriver {
&TIME_DRIVER
}
/// Initialization method for embassy. /// Initialization method for embassy.
/// ///
/// This should be used if the interrupt handler is provided by the library, which is the /// This should be used if the interrupt handler is provided by the library, which is the
/// default case. /// default case.
#[cfg(feature = "irqs-in-lib")] #[cfg(feature = "irqs-in-lib")]
pub fn init<TimekeeperTim: TimMarker, AlarmTim: TimMarker>( pub fn init<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
sysclk: Hertz,
timekeeper_tim: TimekeeperTim, timekeeper_tim: TimekeeperTim,
alarm_tim: AlarmTim, alarm_tim: AlarmTim,
sysclk: Hertz,
) { ) {
time_driver().__init(sysclk, timekeeper_tim, alarm_tim, TIMEKEEPER_IRQ, ALARM_IRQ) TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, TIMEKEEPER_IRQ, ALARM_IRQ)
} }
/// Initialization method for embassy when using custom IRQ handlers. /// Initialization method for embassy when using custom IRQ handlers.
/// ///
/// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs. /// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs.
pub fn init_with_custom_irqs<TimekeeperTim: TimMarker, AlarmTim: TimMarker>( pub fn init_with_custom_irqs<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
sysclk: Hertz,
timekeeper_tim: TimekeeperTim, timekeeper_tim: TimekeeperTim,
alarm_tim: AlarmTim, alarm_tim: AlarmTim,
sysclk: Hertz,
timekeeper_irq: pac::Interrupt, timekeeper_irq: pac::Interrupt,
alarm_irq: pac::Interrupt, alarm_irq: pac::Interrupt,
) { ) {
time_driver().__init(sysclk, timekeeper_tim, alarm_tim, timekeeper_irq, alarm_irq) TIME_DRIVER.init(sysclk, timekeeper_tim, alarm_tim, timekeeper_irq, alarm_irq)
}
struct AlarmState {
timestamp: Cell<u64>,
}
impl AlarmState {
const fn new() -> Self {
Self {
timestamp: Cell::new(u64::MAX),
}
}
}
unsafe impl Send for AlarmState {}
static SCALE: OnceCell<u64> = OnceCell::new();
static TIMEKEEPER_TIM: OnceCell<TimId> = OnceCell::new();
static ALARM_TIM: OnceCell<TimId> = OnceCell::new();
pub struct TimerDriver {
periods: AtomicU32,
/// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
alarms: Mutex<AlarmState>,
queue: Mutex<RefCell<Queue>>,
}
impl TimerDriver {
#[allow(clippy::too_many_arguments)]
fn init<TimekeeperTim: TimMarker, AlarmTim: TimMarker>(
&self,
sysclk: Hertz,
_timekeeper_tim: TimekeeperTim,
_alarm_tim: AlarmTim,
timekeeper_irq: pac::Interrupt,
alarm_irq: pac::Interrupt,
) {
if ALARM_TIM.get().is_some() || TIMEKEEPER_TIM.get().is_some() {
return;
}
ALARM_TIM.set(AlarmTim::ID).ok();
TIMEKEEPER_TIM.set(TimekeeperTim::ID).ok();
enable_peripheral_clock(PeripheralSelect::Irqsel);
enable_tim_clk(TimekeeperTim::ID);
let mut timekeeper_reg_block = unsafe { TimekeeperTim::ID.steal_regs() };
let mut alarm_tim_reg_block = unsafe { AlarmTim::ID.steal_regs() };
// 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_reg_block.write_reset_value(u32::MAX);
// Decrementing counter.
timekeeper_reg_block.write_count_value(u32::MAX);
let irqsel = unsafe { va108xx_hal::pac::Irqsel::steal() };
// Switch on. Timekeeping should always be done.
irqsel
.tim0(TimekeeperTim::ID.value() as usize)
.write(|w| unsafe { w.bits(timekeeper_irq as u32) });
unsafe {
enable_nvic_interrupt(timekeeper_irq);
}
timekeeper_reg_block.modify_control(|mut value| {
value.set_irq_enable(true);
value
});
timekeeper_reg_block.write_enable_control(EnableControl::new_enable());
enable_tim_clk(AlarmTim::ID);
// Explicitely disable alarm timer until needed.
alarm_tim_reg_block.modify_control(|mut value| {
value.set_irq_enable(false);
value.set_enable(false);
value
});
// Enable general interrupts. The IRQ enable of the peripheral remains cleared.
unsafe {
enable_nvic_interrupt(alarm_irq);
}
irqsel
.tim0(AlarmTim::ID.value() as usize)
.write(|w| unsafe { w.bits(alarm_irq as u32) });
}
/// Should be called inside the IRQ of the timekeeper timer.
///
/// # Safety
///
/// This function has to be called once by the TIM IRQ used for the timekeeping.
pub unsafe fn on_interrupt_timekeeping(&self) {
self.next_period();
}
/// Should be called inside the IRQ of the alarm timer.
///
/// # Safety
///
///This function has to be called once by the TIM IRQ used for the timekeeping.
pub unsafe fn on_interrupt_alarm(&self) {
critical_section::with(|cs| {
if self.alarms.borrow(cs).timestamp.get() <= self.now() {
self.trigger_alarm(cs)
}
})
}
fn timekeeper_tim() -> MmioTimer<'static> {
TIMEKEEPER_TIM
.get()
.map(|id| unsafe { id.steal_regs() })
.unwrap()
}
fn alarm_tim() -> MmioTimer<'static> {
ALARM_TIM
.get()
.map(|id| unsafe { id.steal_regs() })
.unwrap()
}
fn next_period(&self) {
let period = self.periods.fetch_add(1, Ordering::AcqRel) + 1;
let t = (period as u64) << 32;
critical_section::with(|cs| {
let alarm = &self.alarms.borrow(cs);
let at = alarm.timestamp.get();
if at < t {
self.trigger_alarm(cs);
} else {
let mut alarm_tim = Self::alarm_tim();
let remaining_ticks = (at - t).checked_mul(*SCALE.get().unwrap());
if remaining_ticks.is_some_and(|v| v <= u32::MAX as u64) {
alarm_tim.write_enable_control(EnableControl::new_disable());
alarm_tim.write_count_value(remaining_ticks.unwrap() as u32);
alarm_tim.modify_control(|mut value| {
value.set_irq_enable(true);
value
});
alarm_tim.write_enable_control(EnableControl::new_enable());
}
}
})
}
fn trigger_alarm(&self, cs: CriticalSection) {
Self::alarm_tim().modify_control(|mut value| {
value.set_irq_enable(false);
value.set_enable(false);
value
});
let alarm = &self.alarms.borrow(cs);
// Setting the maximum value disables the alarm.
alarm.timestamp.set(u64::MAX);
// Call after clearing alarm, so the callback can set another alarm.
let mut next = self
.queue
.borrow(cs)
.borrow_mut()
.next_expiration(self.now());
while !self.set_alarm(cs, next) {
next = self
.queue
.borrow(cs)
.borrow_mut()
.next_expiration(self.now());
}
}
fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
if SCALE.get().is_none() {
return false;
}
let mut alarm_tim = Self::alarm_tim();
alarm_tim.modify_control(|mut value| {
value.set_irq_enable(false);
value.set_enable(false);
value
});
let alarm = self.alarms.borrow(cs);
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).checked_mul(*SCALE.get().unwrap());
alarm_tim.write_reset_value(u32::MAX);
if timer_ticks.is_some_and(|v| v <= u32::MAX as u64) {
alarm_tim.write_count_value(timer_ticks.unwrap() as u32);
alarm_tim.modify_control(|mut value| {
value.set_irq_enable(true);
value.set_enable(true);
value
});
}
// If it's too far in the future, don't enable timer yet.
// It will be enabled later by `next_period`.
true
}
}
impl Driver for TimerDriver {
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 - Self::timekeeper_tim().read_count_value();
// 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;
}
}
}
fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
critical_section::with(|cs| {
let mut queue = self.queue.borrow(cs).borrow_mut();
if queue.schedule_wake(at, waker) {
let mut next = queue.next_expiration(self.now());
while !self.set_alarm(cs, next) {
next = queue.next_expiration(self.now());
}
}
})
}
} }

View File

@@ -8,20 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## Changed
- Move most library components to new [`vorago-shared-periphs`](https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs)
which is mostly re-exported in this crate.
- Overhaul and simplification of several HAL APIs. The system configuration and IRQ router
peripheral instance generally does not need to be passed to HAL API anymore.
- All HAL drivers are now type erased. The constructors will still expect and consume the PAC
singleton component for resource management purposes, but are not cached anymore.
- Refactoring of GPIO library to be more inline with embassy GPIO API.
## Added
- I2C clock timeout feature support.
## [v0.11.1] 2025-03-10 ## [v0.11.1] 2025-03-10
## Fixed ## Fixed

View File

@@ -12,11 +12,28 @@ categories = ["aerospace", "embedded", "no-std", "hardware-support"]
[dependencies] [dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"]} cortex-m = { version = "0.7", features = ["critical-section-single-core"]}
cortex-m-rt = "0.7"
nb = "1"
paste = "1"
vorago-shared-periphs = { git = "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs.git", features = ["vor1x"] } vorago-shared-periphs = { git = "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs.git", features = ["vor1x"] }
embedded-hal = "1"
embedded-hal-async = "1"
embedded-hal-nb = "1"
embedded-io = "0.6"
embedded-io-async = "0.6"
fugit = "0.3" fugit = "0.3"
typenum = "1"
critical-section = "1"
delegate = ">=0.12, <=0.13"
heapless = "0.8"
static_cell = "2"
thiserror = { version = "2", default-features = false } thiserror = { version = "2", default-features = false }
void = { version = "1", default-features = false }
once_cell = { version = "1", default-features = false }
va108xx = { version = "0.5", default-features = false, features = ["critical-section", "defmt"] } va108xx = { version = "0.5", default-features = false, features = ["critical-section", "defmt"] }
defmt = { version = "1", optional = true } embassy-sync = "0.6"
defmt = { version = "0.3", optional = true }
[target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies] [target.'cfg(all(target_arch = "arm", target_os = "none"))'.dependencies]
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] } portable-atomic = { version = "1", features = ["unsafe-assume-single-core"] }
@@ -26,11 +43,8 @@ portable-atomic = "1"
[features] [features]
default = ["rt"] default = ["rt"]
rt = ["va108xx/rt"] rt = ["va108xx/rt"]
defmt = ["dep:defmt", "vorago-shared-periphs/defmt"] defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03", "vorago-shared-periphs/defmt"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustdoc-args = ["--generate-link-to-definition"] rustdoc-args = ["--generate-link-to-definition"]
[package.metadata.cargo-machete]
ignored = ["cortex-m"]

View File

@@ -1,9 +1,29 @@
//! # API for clock related functionality //! # API for clock related functionality
//! //!
//! This also includes functionality to enable the peripheral clocks //! This also includes functionality to enable the peripheral clocks
use crate::time::Hertz;
use cortex_m::interrupt::{self, Mutex};
use once_cell::unsync::OnceCell;
pub use vorago_shared_periphs::gpio::FilterClkSel; pub use vorago_shared_periphs::gpio::FilterClkSel;
pub use vorago_shared_periphs::sysconfig::{disable_peripheral_clock, enable_peripheral_clock}; pub use vorago_shared_periphs::sysconfig::{disable_peripheral_clock, enable_peripheral_clock};
static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new());
/// The Vorago in powered by an external clock which might have different frequencies.
/// The clock can be set here so it can be used by other software components as well.
/// The clock can be set exactly once
pub fn set_sys_clock(freq: impl Into<Hertz>) {
interrupt::free(|cs| {
SYS_CLOCK.borrow(cs).set(freq.into()).ok();
})
}
/// Returns the configured system clock
pub fn get_sys_clock() -> Option<Hertz> {
interrupt::free(|cs| SYS_CLOCK.borrow(cs).get().copied())
}
pub fn set_clk_div_register(syscfg: &mut va108xx::Sysconfig, clk_sel: FilterClkSel, div: u32) { pub fn set_clk_div_register(syscfg: &mut va108xx::Sysconfig, clk_sel: FilterClkSel, div: u32) {
match clk_sel { match clk_sel {
FilterClkSel::SysClk => (), FilterClkSel::SysClk => (),

View File

@@ -18,3 +18,10 @@
//! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs) //! - [Blinky example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/blinky.rs)
//! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs) //! - [Async GPIO example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-gpio.rs)
pub use vorago_shared_periphs::gpio::*; pub use vorago_shared_periphs::gpio::*;
pub use vorago_shared_periphs::gpio::asynch;
/// Low-level GPIO access.
pub use vorago_shared_periphs::gpio::ll;
/// GPIO register definitions.
pub use vorago_shared_periphs::gpio::regs;

View File

@@ -17,13 +17,15 @@ pub mod time;
pub mod timer; pub mod timer;
pub mod uart; pub mod uart;
pub use vorago_shared_periphs::{ pub use vorago_shared_periphs::FunSel;
disable_nvic_interrupt, enable_nvic_interrupt, FunSel, InterruptConfig, PeripheralSelect,
};
/// This is the NONE destination reigster value for the IRQSEL peripheral. /// This is the NONE destination reigster value for the IRQSEL peripheral.
pub const IRQ_DST_NONE: u32 = 0xffffffff; pub const IRQ_DST_NONE: u32 = 0xffffffff;
pub use vorago_shared_periphs::{
disable_nvic_interrupt, enable_nvic_interrupt, InterruptConfig, PeripheralSelect,
};
#[derive(Debug, PartialEq, Eq, thiserror::Error)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("invalid pin with number {0}")] #[error("invalid pin with number {0}")]

View File

@@ -1,8 +1,8 @@
//! API for the SPI peripheral. //! API for the SPI peripheral.
//! //!
//! The main abstraction provided by this module is the [Spi] an structure. //! The main abstraction provided by this module is the [Spi] an structure.
//! It provides the [SpiBus trait](https://docs.rs/embedded-hal/latest/embedded_hal/spi/trait.SpiBus.html), //! It provides the [embedded_hal::spi] traits, but also offer a low level interface
//! but also offer a low level interface via the [SpiLowLevel] trait. //! via the [SpiLowLevel] trait.
//! //!
//! ## Examples //! ## Examples
//! //!
@@ -10,3 +10,5 @@
//! - [REB1 ADC example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/max11519-adc.rs) //! - [REB1 ADC example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/examples/max11519-adc.rs)
//! - [REB1 EEPROM library](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/src/m95m01.rs) //! - [REB1 EEPROM library](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/vorago-reb1/src/m95m01.rs)
pub use vorago_shared_periphs::spi::*; pub use vorago_shared_periphs::spi::*;
pub use vorago_shared_periphs::spi::pins_vor1x as pins;

View File

@@ -5,3 +5,5 @@
//! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/timer-ticks.rs) //! - [MS and second tick implementation](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/timer-ticks.rs)
//! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/cascade.rs) //! - [Cascade feature example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/cascade.rs)
pub use vorago_shared_periphs::timer::*; pub use vorago_shared_periphs::timer::*;
pub use vorago_shared_periphs::timer::regs;

View File

@@ -15,3 +15,6 @@
//! - [Async UART RX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-rx.rs) //! - [Async UART RX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-rx.rs)
//! - [Async UART TX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-tx.rs) //! - [Async UART TX example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy/src/bin/async-uart-tx.rs)
pub use vorago_shared_periphs::uart::*; pub use vorago_shared_periphs::uart::*;
pub use vorago_shared_periphs::uart::rx_asynch;
pub use vorago_shared_periphs::uart::tx_asynch;

View File

@@ -8,10 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [unreleased]
## [v0.5.1] 2025-07-22
defmt version v1
## [v0.5.0] 2025-02-17 ## [v0.5.0] 2025-02-17
- Re-generated PAC with `svd2rust` v0.35.0 and added optional `defmt` and `Debug` implementations - Re-generated PAC with `svd2rust` v0.35.0 and added optional `defmt` and `Debug` implementations
@@ -59,7 +55,7 @@ defmt version v1
### Fixed ### Fixed
- Generated with patched version of `svd2rust`: See - Generated with patched version of `svd2rust`: See
https://github.com/rust-embedded/svd2rust/pull/549 for more details. https://github.com/rust-embedded/svd2rust/pull/549 for more details.
Some bitmasks were missing from register reader definitions. Some bitmasks were missing from register reader definitions.
@@ -83,7 +79,3 @@ defmt version v1
- First version of the PAC which builds. Uses a patched version - First version of the PAC which builds. Uses a patched version
of `svd2rust`: https://github.com/rust-embedded/svd2rust of `svd2rust`: https://github.com/rust-embedded/svd2rust
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.5.1...HEAD
[v0.5.1]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.5.0...va108xx-v0.5.1
[v0.5.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.4.0...va108xx-v0.5.0

View File

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

View File

@@ -12,7 +12,7 @@ fn main() -> ! {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- Vorago Temperature Sensor and I2C Example --"); rprintln!("-- Vorago Temperature Sensor and I2C Example --");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let mut temp_sensor = let mut temp_sensor =
Adt75TempSensor::new(50.MHz(), dp.i2ca).expect("Creating temperature sensor struct failed"); Adt75TempSensor::new(50.MHz(), dp.i2ca).expect("Creating temperature sensor struct failed");
loop { loop {

View File

@@ -32,7 +32,7 @@ fn main() -> ! {
rprintln!("-- Vorago Accelerometer Example --"); rprintln!("-- Vorago Accelerometer Example --");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let pinsa = PinsA::new(dp.porta); let pinsa = PinsA::new(dp.porta);
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
let (sck, mosi, miso) = (pinsa.pa20, pinsa.pa19, pinsa.pa18); let (sck, mosi, miso) = (pinsa.pa20, pinsa.pa19, pinsa.pa18);
let cs_pin = pinsa.pa16; let cs_pin = pinsa.pa16;
let hw_cs_id = configure_pin_as_hw_cs_pin(cs_pin); let hw_cs_id = configure_pin_as_hw_cs_pin(cs_pin);
@@ -46,7 +46,7 @@ fn main() -> ! {
) )
.mode(MODE_3) .mode(MODE_3)
.slave_output_disable(true); .slave_output_disable(true);
let mut spi = Spi::new(dp.spib, (sck, miso, mosi), spi_cfg).unwrap(); let mut spi = Spi::new(50.MHz(), dp.spib, (sck, miso, mosi), spi_cfg).unwrap();
spi.cfg_hw_cs(hw_cs_id); spi.cfg_hw_cs(hw_cs_id);
let mut tx_rx_buf: [u8; 3] = [0; 3]; let mut tx_rx_buf: [u8; 3] = [0; 3];

View File

@@ -70,7 +70,7 @@ fn main() -> ! {
let mut led1 = Output::new(pins.pa10, PinState::Low); let mut led1 = Output::new(pins.pa10, PinState::Low);
let mut led2 = Output::new(pins.pa7, PinState::Low); let mut led2 = Output::new(pins.pa7, PinState::Low);
let mut led3 = Output::new(pins.pa6, PinState::Low); let mut led3 = Output::new(pins.pa6, PinState::Low);
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
for _ in 0..10 { for _ in 0..10 {
led1.set_low(); led1.set_low();
led2.set_low(); led2.set_low();
@@ -91,7 +91,7 @@ fn main() -> ! {
LibType::Bsp => { LibType::Bsp => {
let pinsa = PinsA::new(dp.porta); let pinsa = PinsA::new(dp.porta);
let mut leds = Leds::new(pinsa.pa10, pinsa.pa7, pinsa.pa6); let mut leds = Leds::new(pinsa.pa10, pinsa.pa7, pinsa.pa6);
let mut delay = CountdownTimer::new(dp.tim0, 50.MHz()); let mut delay = CountdownTimer::new(50.MHz(), dp.tim0);
for _ in 0..10 { for _ in 0..10 {
// Blink all LEDs quickly // Blink all LEDs quickly
for led in leds.iter_mut() { for led in leds.iter_mut() {

View File

@@ -110,7 +110,7 @@ fn main() -> ! {
rprintln!("-- Vorago ADC Example --"); rprintln!("-- Vorago ADC Example --");
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim0, SYS_CLK); let mut delay = CountdownTimer::new(SYS_CLK, dp.tim0);
unsafe { unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0); cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OC0);
} }
@@ -132,9 +132,9 @@ fn main() -> ! {
Output::new(pinsa.pa16, PinState::Low); Output::new(pinsa.pa16, PinState::Low);
let hw_cs_id = configure_pin_as_hw_cs_pin(pinsa.pa17); let hw_cs_id = configure_pin_as_hw_cs_pin(pinsa.pa17);
let spi = Spi::new(dp.spib, (sck, miso, mosi), spi_cfg).unwrap(); let spi = Spi::new(50.MHz(), dp.spib, (sck, miso, mosi), spi_cfg).unwrap();
let delay_spi = CountdownTimer::new(dp.tim1, SYS_CLK); let delay_spi = CountdownTimer::new(SYS_CLK, dp.tim1);
let spi_with_hwcs = SpiWithHwCs::new(spi, hw_cs_id, delay_spi); let spi_with_hwcs = SpiWithHwCs::new(spi, hw_cs_id, delay_spi);
match EXAMPLE_MODE { match EXAMPLE_MODE {
ExampleMode::NotUsingEoc => spi_example_externally_clocked(spi_with_hwcs, &mut delay), ExampleMode::NotUsingEoc => spi_example_externally_clocked(spi_with_hwcs, &mut delay),

View File

@@ -5,7 +5,7 @@ use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs; use embedded_hal::delay::DelayNs;
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{pac, spi::SpiClkConfig, time::Hertz, timer::CountdownTimer}; use va108xx_hal::{pac, time::Hertz, timer::CountdownTimer};
use vorago_reb1::m95m01::{M95M01, PAGE_SIZE}; use vorago_reb1::m95m01::{M95M01, PAGE_SIZE};
const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000); const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000);
@@ -17,9 +17,8 @@ fn main() -> ! {
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut delay = CountdownTimer::new(dp.tim0, CLOCK_FREQ); let mut timer = CountdownTimer::new(CLOCK_FREQ, dp.tim0);
let clk_config = SpiClkConfig::new(2, 4); let mut nvm = M95M01::new(CLOCK_FREQ, dp.spic);
let mut nvm = M95M01::new(dp.spic, clk_config);
let status_reg = nvm.read_status_reg().expect("reading status reg failed"); let status_reg = nvm.read_status_reg().expect("reading status reg failed");
if status_reg.zero_segment().value() == 0b111 { if status_reg.zero_segment().value() == 0b111 {
panic!("status register unexpected values"); panic!("status register unexpected values");
@@ -52,6 +51,6 @@ fn main() -> ! {
nvm.write(0, &orig_content).unwrap(); nvm.write(0, &orig_content).unwrap();
loop { loop {
delay.delay_ms(500); timer.delay_ms(500);
} }
} }

View File

@@ -47,6 +47,7 @@ pub mod regs {
use regs::*; use regs::*;
use va108xx_hal::{ use va108xx_hal::{
pac, pac,
prelude::*,
spi::{Spi, SpiClkConfig, SpiConfig, SpiLowLevel, BMSTART_BMSTOP_MASK}, spi::{Spi, SpiClkConfig, SpiConfig, SpiLowLevel, BMSTART_BMSTOP_MASK},
}; };
@@ -63,8 +64,13 @@ pub struct M95M01 {
pub struct PageBoundaryExceededError; pub struct PageBoundaryExceededError;
impl M95M01 { impl M95M01 {
pub fn new(spi: pac::Spic, clk_config: SpiClkConfig) -> Self { pub fn new(sys_clk: Hertz, spi: pac::Spic) -> Self {
let spi = RomSpi::new_for_rom(spi, SpiConfig::default().clk_cfg(clk_config)).unwrap(); let spi = RomSpi::new_for_rom(
sys_clk,
spi,
SpiConfig::default().clk_cfg(SpiClkConfig::new(2, 4)),
)
.unwrap();
let mut spi_dev = Self { spi }; let mut spi_dev = Self { spi };
spi_dev.clear_block_protection().unwrap(); spi_dev.clear_block_protection().unwrap();
spi_dev spi_dev

View File

@@ -52,8 +52,8 @@ impl Adt75TempSensor {
let mut sensor = Adt75TempSensor { let mut sensor = Adt75TempSensor {
// The master construction can not fail for regular I2C speed. // The master construction can not fail for regular I2C speed.
sensor_if: I2cMaster::new( sensor_if: I2cMaster::new(
i2ca,
sys_clk, sys_clk,
i2ca,
MasterConfig::default(), MasterConfig::default(),
I2cSpeed::Regular100khz, I2cSpeed::Regular100khz,
) )