This commit is contained in:
parent
f7ff74940a
commit
1f4d6f601d
@ -9,7 +9,7 @@ members = [
|
||||
"examples/embassy",
|
||||
"board-tests",
|
||||
"bootloader",
|
||||
# "flashloader",
|
||||
"flashloader",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
@ -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"
|
||||
|
@ -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,14 +127,16 @@ mod app {
|
||||
async fn echo_handler(cx: echo_handler::Context) {
|
||||
loop {
|
||||
let bytes_to_read = cx.local.data_consumer.occupied_len();
|
||||
let actual_read_bytes = cx
|
||||
.local
|
||||
.data_consumer
|
||||
.pop_slice(&mut cx.local.buf[0..bytes_to_read]);
|
||||
cx.local
|
||||
.tx
|
||||
.write_all(&cx.local.buf[0..actual_read_bytes])
|
||||
.expect("Failed to write to TX");
|
||||
if bytes_to_read > 0 {
|
||||
let actual_read_bytes = cx
|
||||
.local
|
||||
.data_consumer
|
||||
.pop_slice(&mut cx.local.buf[0..bytes_to_read]);
|
||||
cx.local
|
||||
.tx
|
||||
.write_all(&cx.local.buf[0..actual_read_bytes])
|
||||
.expect("Failed to write to TX");
|
||||
}
|
||||
Mono::delay(50.millis()).await;
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) });
|
||||
|
Loading…
Reference in New Issue
Block a user