now needs tests
All checks were successful
Rust/va108xx-rs/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2024-09-27 14:52:45 +02:00
parent f7ff74940a
commit 1f4d6f601d
Signed by: muellerr
GPG Key ID: A649FB78196E3849
6 changed files with 111 additions and 150 deletions

View File

@ -9,7 +9,7 @@ members = [
"examples/embassy", "examples/embassy",
"board-tests", "board-tests",
"bootloader", "bootloader",
# "flashloader", "flashloader",
] ]
exclude = [ exclude = [

View File

@ -9,11 +9,11 @@ cortex-m-rt = "0.7"
embedded-hal = "1" embedded-hal = "1"
embedded-io = "0.6" embedded-io = "0.6"
rtt-target = { version = "0.5" } rtt-target = { version = "0.5" }
panic-rtt-target = { version = "0.1" }
# Even though we do not use this directly, we need to activate this feature explicitely # 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"]}
panic-rtt-target = { version = "0.1" }
[dependencies.rtic] [dependencies.rtic]
version = "2" version = "2"

View File

@ -28,7 +28,7 @@ mod app {
use rtic_monotonics::Monotonic; use rtic_monotonics::Monotonic;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{ use va108xx_hal::{
gpio::PinsB, gpio::PinsA,
pac, pac,
prelude::*, prelude::*,
uart::{self, RxWithIrq, Tx}, uart::{self, RxWithIrq, Tx},
@ -38,8 +38,8 @@ mod app {
struct Local { struct Local {
data_producer: StaticProd<'static, u8, RX_RING_BUF_SIZE>, data_producer: StaticProd<'static, u8, RX_RING_BUF_SIZE>,
data_consumer: CachingCons<&'static StaticRb<u8, RX_RING_BUF_SIZE>>, data_consumer: CachingCons<&'static StaticRb<u8, RX_RING_BUF_SIZE>>,
rx: RxWithIrq<pac::Uartb>, rx: RxWithIrq<pac::Uarta>,
tx: Tx<pac::Uartb>, tx: Tx<pac::Uarta>,
} }
#[shared] #[shared]
@ -50,23 +50,29 @@ mod app {
#[init] #[init]
fn init(cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
rtt_init_print!(); rtt_init_print!();
rprintln!("-- VA108xx UART IRQ example application--"); rprintln!("-- VA108xx UART Echo with IRQ example application--");
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw()); Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let mut dp = cx.device; let mut dp = cx.device;
let gpiob = PinsB::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.portb); let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let tx = gpiob.pb21.into_funsel_1(); let tx = gpioa.pa9.into_funsel_2();
let rx = gpiob.pb20.into_funsel_1(); let rx = gpioa.pa8.into_funsel_2();
let irq_uart = let irq_uart = uart::Uart::new(
uart::Uart::new(&mut dp.sysconfig, 50.MHz(), dp.uartb, (tx, rx), 115200.Hz()); &mut dp.sysconfig,
SYSCLK_FREQ,
dp.uarta,
(tx, rx),
115200.Hz(),
);
let (tx, rx) = irq_uart.split(); let (tx, rx) = irq_uart.split();
let mut rx = rx.into_rx_with_irq(&dp.irqsel, pac::interrupt::OC3); let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC3);
rx.start(); rx.start();
let (data_producer, data_consumer) = unsafe { RINGBUF.split_ref() }; let (data_producer, data_consumer) = unsafe { RINGBUF.split_ref() };
echo_handler::spawn().unwrap();
( (
Shared {}, Shared {},
Local { Local {
@ -121,14 +127,16 @@ mod app {
async fn echo_handler(cx: echo_handler::Context) { async fn echo_handler(cx: echo_handler::Context) {
loop { loop {
let bytes_to_read = cx.local.data_consumer.occupied_len(); let bytes_to_read = cx.local.data_consumer.occupied_len();
let actual_read_bytes = cx if bytes_to_read > 0 {
.local let actual_read_bytes = cx
.data_consumer .local
.pop_slice(&mut cx.local.buf[0..bytes_to_read]); .data_consumer
cx.local .pop_slice(&mut cx.local.buf[0..bytes_to_read]);
.tx cx.local
.write_all(&cx.local.buf[0..actual_read_bytes]) .tx
.expect("Failed to write to TX"); .write_all(&cx.local.buf[0..actual_read_bytes])
.expect("Failed to write to TX");
}
Mono::delay(50.millis()).await; Mono::delay(50.millis()).await;
} }
} }

View File

@ -11,17 +11,22 @@ embedded-hal-nb = "1"
embedded-io = "0.6" embedded-io = "0.6"
panic-rtt-target = { version = "0.1.3" } panic-rtt-target = { version = "0.1.3" }
rtt-target = { version = "0.5" } rtt-target = { version = "0.5" }
rtt-log = "0.3"
log = "0.4" log = "0.4"
crc = "3" crc = "3"
rtic-sync = "1"
[dependencies.satrs] [dependencies.satrs]
version = "0.2" version = "0.2"
default-features = false default-features = false
[dependencies.rtt-log]
version = "0.3"
git = "https://github.com/us-irs/rtt-log-rs.git"
branch = "allow-usage-on-non-cas-systems"
[dependencies.ringbuf] [dependencies.ringbuf]
version = "0.4" version = "0.4"
git = "https://github.com/us-irs/ringbuf.git"
branch = "use-portable-atomic-crate"
default-features = false default-features = false
[dependencies.once_cell] [dependencies.once_cell]
@ -38,13 +43,26 @@ git = "https://github.com/robamu/cobs.rs.git"
branch = "all_features" branch = "all_features"
default-features = false default-features = false
[dependencies.va108xx-hal] # Even though we do not use this directly, we need to activate this feature explicitely
path = "../va108xx-hal" # so that RTIC compiles because thumv6 does not have CAS operations natively.
[dependencies.portable-atomic]
version = "1"
features = ["unsafe-assume-single-core"]
[dependencies.rtic] [dependencies.rtic]
version = "2" version = "2"
features = ["thumbv7-backend"] features = ["thumbv6-backend"]
[dependencies.rtic-monotonics] [dependencies.rtic-monotonics]
version = "2" version = "2"
features = ["cortex-m-systick"] features = ["cortex-m-systick"]
[dependencies.rtic-sync]
version = "1"
features = ["defmt-03"]
[dependencies.va108xx-hal]
path = "../va108xx-hal"
[dependencies.vorago-reb1]
path = "../vorago-reb1"

View File

@ -3,11 +3,15 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use once_cell::sync::OnceCell; use once_cell::sync::Lazy;
use panic_rtt_target as _; use panic_rtt_target as _;
use va108xx::{clock::Clocks, edac, pac, time::Hertz, wdt::Wdt}; use ringbuf::{
traits::{Consumer, Observer, Producer, SplitRef},
CachingCons, StaticProd, StaticRb,
};
use va108xx_hal::prelude::*;
const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000); const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
const MAX_TC_SIZE: usize = 1024; const MAX_TC_SIZE: usize = 1024;
const MAX_TC_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TC_SIZE); const MAX_TC_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TC_SIZE);
@ -23,25 +27,6 @@ pub enum ActionId {
CorruptImageA = 128, CorruptImageA = 128,
CorruptImageB = 129, CorruptImageB = 129,
} }
pub trait WdtInterface {
fn feed(&self);
}
pub struct OptWdt(Option<Wdt>);
impl WdtInterface for OptWdt {
fn feed(&self) {
if self.0.is_some() {
self.0.as_ref().unwrap().feed();
}
}
}
use once_cell::sync::Lazy;
use ringbuf::{
traits::{Consumer, Observer, Producer, SplitRef},
CachingCons, StaticProd, StaticRb,
};
// Larger buffer for TC to be able to hold the possibly large memory write packets. // Larger buffer for TC to be able to hold the possibly large memory write packets.
const BUF_RB_SIZE_TC: usize = 2048; const BUF_RB_SIZE_TC: usize = 2048;
@ -72,14 +57,12 @@ pub struct DataConsumer<const BUF_SIZE: usize, const SIZES_LEN: usize> {
pub sizes_cons: CachingCons<&'static StaticRb<usize, SIZES_LEN>>, pub sizes_cons: CachingCons<&'static StaticRb<usize, SIZES_LEN>>,
} }
static CLOCKS: OnceCell<Clocks> = OnceCell::new();
pub const APP_A_START_ADDR: u32 = 0x3000; pub const APP_A_START_ADDR: u32 = 0x3000;
pub const APP_A_END_ADDR: u32 = 0x11800; pub const APP_A_END_ADDR: u32 = 0x11800;
pub const APP_B_START_ADDR: u32 = APP_A_END_ADDR; pub const APP_B_START_ADDR: u32 = APP_A_END_ADDR;
pub const APP_B_END_ADDR: u32 = 0x20000; pub const APP_B_END_ADDR: u32 = 0x20000;
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])] #[rtic::app(device = pac, dispatchers = [OC20, OC21, OC22])]
mod app { mod app {
use super::*; use super::*;
use cortex_m::asm; use cortex_m::asm;
@ -93,18 +76,10 @@ mod app {
use spacepackets::ecss::{ use spacepackets::ecss::{
tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket, tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket,
}; };
use va416xx_hal::irq_router::enable_and_init_irq_router; use va108xx_hal::gpio::PinsA;
use va416xx_hal::uart::IrqContextTimeoutOrMaxSize; use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
use va416xx_hal::{ use va108xx_hal::{pac, uart};
clock::ClkgenExt, use vorago_reb1::m95m01::M95M01;
edac,
gpio::PinsG,
nvm::Nvm,
pac,
uart::{self, Uart},
};
use crate::{setup_edac, EXTCLK_FREQ};
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum CobsReaderStates { pub enum CobsReaderStates {
@ -116,10 +91,9 @@ mod app {
#[local] #[local]
struct Local { struct Local {
uart_rx: uart::RxWithIrq<pac::Uart0>, uart_rx: uart::RxWithIrq<pac::Uarta>,
uart_tx: uart::Tx<pac::Uart0>, uart_tx: uart::Tx<pac::Uarta>,
rx_context: IrqContextTimeoutOrMaxSize, rx_context: IrqContextTimeoutOrMaxSize,
rom_spi: Option<pac::Spi3>,
// We handle all TM in one task. // We handle all TM in one task.
tm_cons: DataConsumer<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>, tm_cons: DataConsumer<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
// We consume all TC in one task. // We consume all TC in one task.
@ -127,6 +101,7 @@ mod app {
// We produce all TC in one task. // We produce all TC in one task.
tc_prod: DataProducer<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>, tc_prod: DataProducer<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
verif_reporter: VerificationReportCreator, verif_reporter: VerificationReportCreator,
nvm: M95M01,
} }
#[shared] #[shared]
@ -138,34 +113,28 @@ mod app {
rtic_monotonics::systick_monotonic!(Mono, 10_000); rtic_monotonics::systick_monotonic!(Mono, 10_000);
#[init] #[init]
fn init(mut cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
//rtt_init_default!();
rtt_log::init(); rtt_log::init();
rprintln!("-- Vorago flashloader --"); rprintln!("-- Vorago flashloader --");
// Initialize the systick interrupt & obtain the token to prove that we did
// Use the external clock connected to XTAL_N.
let clocks = cx
.device
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
.freeze(&mut cx.device.sysconfig)
.unwrap();
enable_and_init_irq_router(&mut cx.device.sysconfig, &cx.device.irq_router);
setup_edac(&mut cx.device.sysconfig);
let gpiog = PinsG::new(&mut cx.device.sysconfig, cx.device.portg); Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let tx = gpiog.pg0.into_funsel_1();
let rx = gpiog.pg1.into_funsel_1();
let uart0 = Uart::new( let mut dp = cx.device;
cx.device.uart0, let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let tx = gpioa.pa9.into_funsel_2();
let rx = gpioa.pa8.into_funsel_2();
let irq_uart = uart::Uart::new(
&mut dp.sysconfig,
SYSCLK_FREQ,
dp.uarta,
(tx, rx), (tx, rx),
Hertz::from_raw(UART_BAUDRATE), UART_BAUDRATE.Hz(),
&mut cx.device.sysconfig,
&clocks,
); );
let (tx, rx) = uart0.split(); let (tx, rx) = irq_uart.split();
let mut rx = rx.into_rx_with_irq(&mut dp.sysconfig, &mut dp.irqsel, pac::interrupt::OC3);
let verif_reporter = VerificationReportCreator::new(0).unwrap(); let verif_reporter = VerificationReportCreator::new(0).unwrap();
@ -175,10 +144,6 @@ mod app {
let (buf_prod_tc, buf_cons_tc) = unsafe { BUF_RB_TC.split_ref() }; let (buf_prod_tc, buf_cons_tc) = unsafe { BUF_RB_TC.split_ref() };
let (sizes_prod_tc, sizes_cons_tc) = unsafe { SIZES_RB_TC.split_ref() }; let (sizes_prod_tc, sizes_cons_tc) = unsafe { SIZES_RB_TC.split_ref() };
Mono::start(cx.core.SYST, clocks.sysclk().raw());
CLOCKS.set(clocks).unwrap();
let mut rx = rx.to_rx_with_irq();
let mut rx_context = IrqContextTimeoutOrMaxSize::new(MAX_TC_FRAME_SIZE); let mut rx_context = IrqContextTimeoutOrMaxSize::new(MAX_TC_FRAME_SIZE);
rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context) rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context)
.expect("initiating UART RX failed"); .expect("initiating UART RX failed");
@ -195,7 +160,7 @@ mod app {
uart_rx: rx, uart_rx: rx,
uart_tx: tx, uart_tx: tx,
rx_context, rx_context,
rom_spi: Some(cx.device.spi3), // rom_spi: Some(cx.device.spi3),
tm_cons: DataConsumer { tm_cons: DataConsumer {
buf_cons: buf_cons_tm, buf_cons: buf_cons_tm,
sizes_cons: sizes_cons_tm, sizes_cons: sizes_cons_tm,
@ -209,6 +174,7 @@ mod app {
sizes_prod: sizes_prod_tc, sizes_prod: sizes_prod_tc,
}, },
verif_reporter, verif_reporter,
nvm,
}, },
) )
} }
@ -223,7 +189,7 @@ mod app {
// This is the interrupt handler to read all bytes received on the UART0. // This is the interrupt handler to read all bytes received on the UART0.
#[task( #[task(
binds = UART0_RX, binds = OC0,
local = [ local = [
cnt: u32 = 0, cnt: u32 = 0,
rx_buf: [u8; MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE], rx_buf: [u8; MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE],
@ -278,8 +244,8 @@ mod app {
.read_fixed_len_or_timeout_based_using_irq(cx.local.rx_context) .read_fixed_len_or_timeout_based_using_irq(cx.local.rx_context)
.expect("read operation failed"); .expect("read operation failed");
} }
if result.error() { if result.has_errors() {
log::warn!("UART error: {:?}", result.error()); log::warn!("UART error: {:?}", result.errors.unwrap());
} }
} }
Err(e) => { Err(e) => {
@ -295,7 +261,7 @@ mod app {
src_data_buf: [u8; 16] = [0; 16], src_data_buf: [u8; 16] = [0; 16],
verif_buf: [u8; 32] = [0; 32], verif_buf: [u8; 32] = [0; 32],
tc_cons, tc_cons,
rom_spi, nvm,
verif_reporter verif_reporter
], ],
shared=[tm_prod] shared=[tm_prod]
@ -355,19 +321,16 @@ mod app {
if pus_tc.service() == PusServiceId::Action as u8 { if pus_tc.service() == PusServiceId::Action as u8 {
let mut corrupt_image = |base_addr: u32| { let mut corrupt_image = |base_addr: u32| {
// Safety: We only use this for NVM handling and we only do NVM
// handling here.
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
let nvm = Nvm::new(
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
let mut buf = [0u8; 4]; let mut buf = [0u8; 4];
nvm.read_data(base_addr + 32, &mut buf); cx.local
.nvm
.read(base_addr + 32, &mut buf)
.expect("reading from NVM failed");
buf[0] += 1; buf[0] += 1;
nvm.write_data(base_addr + 32, &buf); cx.local
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg)); .nvm
.write(base_addr + 32, &buf)
.expect("writing to NVM failed");
let tm = cx let tm = cx
.local .local
.verif_reporter .verif_reporter
@ -440,16 +403,10 @@ mod app {
data_len, data_len,
offset offset
); );
// Safety: We only use this for NVM handling and we only do NVM cx.local
// handling here. .nvm
let mut sys_cfg = unsafe { pac::Sysconfig::steal() }; .write(offset, data)
let nvm = Nvm::new( .expect("writing to NVM failed");
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
nvm.write_data(offset, data);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
let tm = cx let tm = cx
.local .local
.verif_reporter .verif_reporter
@ -496,34 +453,4 @@ mod app {
Mono::delay(50.millis()).await; Mono::delay(50.millis()).await;
} }
} }
#[task(binds = EDAC_SBE, priority = 1)]
fn edac_sbe_isr(_cx: edac_sbe_isr::Context) {
// TODO: Send some command via UART for notification purposes. Also identify the problematic
// memory.
edac::clear_sbe_irq();
}
#[task(binds = EDAC_MBE, priority = 1)]
fn edac_mbe_isr(_cx: edac_mbe_isr::Context) {
// TODO: Send some command via UART for notification purposes.
edac::clear_mbe_irq();
// TODO: Reset like the vorago example?
}
#[task(binds = WATCHDOG, priority = 1)]
fn watchdog_isr(_cx: watchdog_isr::Context) {
let wdt = unsafe { pac::WatchDog::steal() };
// Clear interrupt.
wdt.wdogintclr().write(|w| unsafe { w.bits(1) });
}
}
fn setup_edac(syscfg: &mut pac::Sysconfig) {
// The scrub values are based on the Vorago provided bootloader.
edac::enable_rom_scrub(syscfg, 125);
edac::enable_ram0_scrub(syscfg, 1000);
edac::enable_ram1_scrub(syscfg, 1000);
edac::enable_sbe_irq();
edac::enable_mbe_irq();
} }

View File

@ -10,6 +10,7 @@ use va108xx::Uarta;
pub use crate::IrqCfg; pub use crate::IrqCfg;
use crate::{ use crate::{
clock::enable_peripheral_clock,
enable_interrupt, enable_interrupt,
gpio::pin::{ gpio::pin::{
AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30, AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30,
@ -744,10 +745,11 @@ impl<Uart: Instance> Rx<Uart> {
pub fn into_rx_with_irq( pub fn into_rx_with_irq(
self, self,
irqsel: &pac::Irqsel, sysconfig: &mut pac::Sysconfig,
irqsel: &mut pac::Irqsel,
interrupt: pac::Interrupt, interrupt: pac::Interrupt,
) -> RxWithIrq<Uart> { ) -> RxWithIrq<Uart> {
RxWithIrq::new(self, irqsel, interrupt) RxWithIrq::new(self, sysconfig, irqsel, interrupt)
} }
pub fn release(self) -> Uart { pub fn release(self) -> Uart {
@ -934,7 +936,13 @@ pub struct RxWithIrq<Uart> {
} }
impl<Uart: Instance> RxWithIrq<Uart> { impl<Uart: Instance> RxWithIrq<Uart> {
pub fn new(rx: Rx<Uart>, irqsel: &pac::Irqsel, interrupt: pac::Interrupt) -> Self { pub fn new(
rx: Rx<Uart>,
syscfg: &mut pac::Sysconfig,
irqsel: &mut pac::Irqsel,
interrupt: pac::Interrupt,
) -> Self {
enable_peripheral_clock(syscfg, PeripheralSelect::Irqsel);
irqsel irqsel
.uart0(Uart::IDX as usize) .uart0(Uart::IDX as usize)
.write(|w| unsafe { w.bits(interrupt as u32) }); .write(|w| unsafe { w.bits(interrupt as u32) });