diff --git a/Cargo.toml b/Cargo.toml index 98cf9a9..34c1302 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "examples/embassy", "board-tests", "bootloader", - # "flashloader", + "flashloader", ] exclude = [ diff --git a/examples/rtic/Cargo.toml b/examples/rtic/Cargo.toml index b24a1ab..5e1dc90 100644 --- a/examples/rtic/Cargo.toml +++ b/examples/rtic/Cargo.toml @@ -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" diff --git a/examples/rtic/src/bin/uart-echo-rtic.rs b/examples/rtic/src/bin/uart-echo-rtic.rs index 98e8e4f..7392470 100644 --- a/examples/rtic/src/bin/uart-echo-rtic.rs +++ b/examples/rtic/src/bin/uart-echo-rtic.rs @@ -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>, - rx: RxWithIrq, - tx: Tx, + rx: RxWithIrq, + tx: Tx, } #[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; } } diff --git a/flashloader/Cargo.toml b/flashloader/Cargo.toml index 4b5e9c5..4f6ce9a 100644 --- a/flashloader/Cargo.toml +++ b/flashloader/Cargo.toml @@ -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" diff --git a/flashloader/src/main.rs b/flashloader/src/main.rs index c4ee6ff..1042bfe 100644 --- a/flashloader/src/main.rs +++ b/flashloader/src/main.rs @@ -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); - -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 { pub sizes_cons: CachingCons<&'static StaticRb>, } -static CLOCKS: OnceCell = 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, - uart_tx: uart::Tx, + uart_rx: uart::RxWithIrq, + uart_tx: uart::Tx, rx_context: IrqContextTimeoutOrMaxSize, - rom_spi: Option, // We handle all TM in one task. tm_cons: DataConsumer, // We consume all TC in one task. @@ -127,6 +101,7 @@ mod app { // We produce all TC in one task. tc_prod: DataProducer, 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(); } diff --git a/va108xx-hal/src/uart.rs b/va108xx-hal/src/uart.rs index e0f4b25..623347b 100644 --- a/va108xx-hal/src/uart.rs +++ b/va108xx-hal/src/uart.rs @@ -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 Rx { pub fn into_rx_with_irq( self, - irqsel: &pac::Irqsel, + sysconfig: &mut pac::Sysconfig, + irqsel: &mut pac::Irqsel, interrupt: pac::Interrupt, ) -> RxWithIrq { - RxWithIrq::new(self, irqsel, interrupt) + RxWithIrq::new(self, sysconfig, irqsel, interrupt) } pub fn release(self) -> Uart { @@ -934,7 +936,13 @@ pub struct RxWithIrq { } impl RxWithIrq { - pub fn new(rx: Rx, irqsel: &pac::Irqsel, interrupt: pac::Interrupt) -> Self { + pub fn new( + rx: Rx, + 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) });