Compare commits
1 Commits
va108xx-v0
...
4fb72ecba6
Author | SHA1 | Date | |
---|---|---|---|
4fb72ecba6 |
10
README.md
10
README.md
@@ -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.
|
||||||
|
@@ -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"
|
|
||||||
|
|
||||||
|
@@ -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()
|
||||||
|
}
|
||||||
|
@@ -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"
|
||||||
|
@@ -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 |
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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"]
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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),
|
||||||
)
|
)
|
||||||
|
@@ -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),
|
||||||
)
|
)
|
||||||
|
@@ -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,
|
||||||
);
|
);
|
||||||
|
@@ -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" }
|
||||||
|
@@ -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),
|
||||||
)
|
)
|
||||||
|
@@ -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"
|
||||||
|
@@ -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);
|
||||||
|
@@ -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
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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());
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
@@ -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"]
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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"]
|
||||||
|
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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"]
|
|
||||||
|
@@ -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 => (),
|
||||||
|
@@ -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;
|
||||||
|
@@ -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}")]
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
|
||||||
|
@@ -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"
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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];
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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),
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user