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",
"board-tests",
"bootloader",
# "flashloader",
"flashloader",
]
exclude = [

View File

@ -9,11 +9,11 @@ cortex-m-rt = "0.7"
embedded-hal = "1"
embedded-io = "0.6"
rtt-target = { version = "0.5" }
panic-rtt-target = { version = "0.1" }
# Even though we do not use this directly, we need to activate this feature explicitely
# so that RTIC compiles because thumv6 does not have CAS operations natively.
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
panic-rtt-target = { version = "0.1" }
[dependencies.rtic]
version = "2"

View File

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

View File

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

View File

@ -3,11 +3,15 @@
#![no_main]
#![no_std]
use once_cell::sync::OnceCell;
use once_cell::sync::Lazy;
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_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TC_SIZE);
@ -23,25 +27,6 @@ pub enum ActionId {
CorruptImageA = 128,
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.
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>>,
}
static CLOCKS: OnceCell<Clocks> = OnceCell::new();
pub const APP_A_START_ADDR: u32 = 0x3000;
pub const APP_A_END_ADDR: u32 = 0x11800;
pub const APP_B_START_ADDR: u32 = APP_A_END_ADDR;
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 {
use super::*;
use cortex_m::asm;
@ -93,18 +76,10 @@ mod app {
use spacepackets::ecss::{
tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket,
};
use va416xx_hal::irq_router::enable_and_init_irq_router;
use va416xx_hal::uart::IrqContextTimeoutOrMaxSize;
use va416xx_hal::{
clock::ClkgenExt,
edac,
gpio::PinsG,
nvm::Nvm,
pac,
uart::{self, Uart},
};
use crate::{setup_edac, EXTCLK_FREQ};
use va108xx_hal::gpio::PinsA;
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
use va108xx_hal::{pac, uart};
use vorago_reb1::m95m01::M95M01;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum CobsReaderStates {
@ -116,10 +91,9 @@ mod app {
#[local]
struct Local {
uart_rx: uart::RxWithIrq<pac::Uart0>,
uart_tx: uart::Tx<pac::Uart0>,
uart_rx: uart::RxWithIrq<pac::Uarta>,
uart_tx: uart::Tx<pac::Uarta>,
rx_context: IrqContextTimeoutOrMaxSize,
rom_spi: Option<pac::Spi3>,
// We handle all TM in one task.
tm_cons: DataConsumer<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
// We consume all TC in one task.
@ -127,6 +101,7 @@ mod app {
// We produce all TC in one task.
tc_prod: DataProducer<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
verif_reporter: VerificationReportCreator,
nvm: M95M01,
}
#[shared]
@ -138,34 +113,28 @@ mod app {
rtic_monotonics::systick_monotonic!(Mono, 10_000);
#[init]
fn init(mut cx: init::Context) -> (Shared, Local) {
//rtt_init_default!();
fn init(cx: init::Context) -> (Shared, Local) {
rtt_log::init();
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);
let tx = gpiog.pg0.into_funsel_1();
let rx = gpiog.pg1.into_funsel_1();
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
let uart0 = Uart::new(
cx.device.uart0,
let mut dp = cx.device;
let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
let gpioa = PinsA::new(&mut dp.sysconfig, Some(dp.ioconfig), dp.porta);
let tx = gpioa.pa9.into_funsel_2();
let rx = gpioa.pa8.into_funsel_2();
let irq_uart = uart::Uart::new(
&mut dp.sysconfig,
SYSCLK_FREQ,
dp.uarta,
(tx, rx),
Hertz::from_raw(UART_BAUDRATE),
&mut cx.device.sysconfig,
&clocks,
UART_BAUDRATE.Hz(),
);
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();
@ -175,10 +144,6 @@ mod app {
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() };
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);
rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context)
.expect("initiating UART RX failed");
@ -195,7 +160,7 @@ mod app {
uart_rx: rx,
uart_tx: tx,
rx_context,
rom_spi: Some(cx.device.spi3),
// rom_spi: Some(cx.device.spi3),
tm_cons: DataConsumer {
buf_cons: buf_cons_tm,
sizes_cons: sizes_cons_tm,
@ -209,6 +174,7 @@ mod app {
sizes_prod: sizes_prod_tc,
},
verif_reporter,
nvm,
},
)
}
@ -223,7 +189,7 @@ mod app {
// This is the interrupt handler to read all bytes received on the UART0.
#[task(
binds = UART0_RX,
binds = OC0,
local = [
cnt: u32 = 0,
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)
.expect("read operation failed");
}
if result.error() {
log::warn!("UART error: {:?}", result.error());
if result.has_errors() {
log::warn!("UART error: {:?}", result.errors.unwrap());
}
}
Err(e) => {
@ -295,7 +261,7 @@ mod app {
src_data_buf: [u8; 16] = [0; 16],
verif_buf: [u8; 32] = [0; 32],
tc_cons,
rom_spi,
nvm,
verif_reporter
],
shared=[tm_prod]
@ -355,19 +321,16 @@ mod app {
if pus_tc.service() == PusServiceId::Action as u8 {
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];
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;
nvm.write_data(base_addr + 32, &buf);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
cx.local
.nvm
.write(base_addr + 32, &buf)
.expect("writing to NVM failed");
let tm = cx
.local
.verif_reporter
@ -440,16 +403,10 @@ mod app {
data_len,
offset
);
// 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(),
);
nvm.write_data(offset, data);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
cx.local
.nvm
.write(offset, data)
.expect("writing to NVM failed");
let tm = cx
.local
.verif_reporter
@ -496,34 +453,4 @@ mod app {
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;
use crate::{
clock::enable_peripheral_clock,
enable_interrupt,
gpio::pin::{
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(
self,
irqsel: &pac::Irqsel,
sysconfig: &mut pac::Sysconfig,
irqsel: &mut pac::Irqsel,
interrupt: pac::Interrupt,
) -> RxWithIrq<Uart> {
RxWithIrq::new(self, irqsel, interrupt)
RxWithIrq::new(self, sysconfig, irqsel, interrupt)
}
pub fn release(self) -> Uart {
@ -934,7 +936,13 @@ pub struct 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
.uart0(Uart::IDX as usize)
.write(|w| unsafe { w.bits(interrupt as u32) });