391: setup: use a best-effort lock for rprintln r=ryan-summers a=jordens

close #382

* [x] tested with very long log messages that would otherwise cause the DMA deadline to be missed. (use cargo-embed git to make it work with stlink v3)


Co-authored-by: Robert Jördens <rj@quartiq.de>
master
bors[bot] 2021-06-24 08:49:36 +00:00 committed by GitHub
commit b7e2a3dbca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 35 additions and 7 deletions

View File

@ -1,6 +1,8 @@
///! Stabilizer hardware configuration ///! Stabilizer hardware configuration
///! ///!
///! This file contains all of the hardware-specific configuration of Stabilizer. ///! This file contains all of the hardware-specific configuration of Stabilizer.
use core::sync::atomic::{self, AtomicBool, Ordering};
use core::{ptr, slice};
use stm32h7xx_hal::{ use stm32h7xx_hal::{
self as hal, self as hal,
ethernet::{self, PHY}, ethernet::{self, PHY},
@ -149,8 +151,6 @@ fn load_itcm() {
static mut __eitcm: u32; static mut __eitcm: u32;
static mut __siitcm: u32; static mut __siitcm: u32;
} }
use core::{ptr, slice, sync::atomic};
// NOTE(unsafe): Assuming the address symbols from the linker as well as // NOTE(unsafe): Assuming the address symbols from the linker as well as
// the source instruction data are all valid, this is safe as it only // the source instruction data are all valid, this is safe as it only
// copies linker-prepared data to where the code expects it to be. // copies linker-prepared data to where the code expects it to be.
@ -163,7 +163,7 @@ fn load_itcm() {
ptr::write_volatile(ITCMCR, ptr::read_volatile(ITCMCR) | 1); ptr::write_volatile(ITCMCR, ptr::read_volatile(ITCMCR) | 1);
// Ensure ITCM is enabled before loading. // Ensure ITCM is enabled before loading.
atomic::fence(atomic::Ordering::SeqCst); atomic::fence(Ordering::SeqCst);
let len = let len =
(&__eitcm as *const u32).offset_from(&__sitcm as *const _) as usize; (&__eitcm as *const u32).offset_from(&__sitcm as *const _) as usize;
@ -174,7 +174,7 @@ fn load_itcm() {
} }
// Ensure ITCM is loaded before potentially executing any instructions from it. // Ensure ITCM is loaded before potentially executing any instructions from it.
atomic::fence(atomic::Ordering::SeqCst); atomic::fence(Ordering::SeqCst);
cortex_m::asm::dsb(); cortex_m::asm::dsb();
cortex_m::asm::isb(); cortex_m::asm::isb();
} }
@ -224,10 +224,38 @@ pub fn setup(
// Enable debug during WFE/WFI-induced sleep // Enable debug during WFE/WFI-induced sleep
device.DBGMCU.cr.modify(|_, w| w.dbgsleep_d1().set_bit()); device.DBGMCU.cr.modify(|_, w| w.dbgsleep_d1().set_bit());
use rtt_logger::RTTLogger; // Set up RTT channel to use for `rprintln!()` as "best effort".
// This removes a critical section around the logging and thus allows
// high-prio tasks to always interrupt at low latency.
// It comes at a cost:
// If a high-priority tasks preempts while we are logging something,
// and if we then also want to log from within that high-preiority task,
// the high-prio log message will be lost.
static LOGGER: RTTLogger = RTTLogger::new(log::LevelFilter::Info); let channels = rtt_target::rtt_init_default!();
rtt_target::rtt_init_print!(); // Note(unsafe): The closure we pass does not establish a critical section
// as demanded but it does ensure synchronization and implements a lock.
unsafe {
rtt_target::set_print_channel_cs(
channels.up.0,
&((|arg, f| {
static LOCKED: AtomicBool = AtomicBool::new(false);
if LOCKED.compare_exchange_weak(
false,
true,
Ordering::Acquire,
Ordering::Relaxed,
) == Ok(false)
{
f(arg);
LOCKED.store(false, Ordering::Release);
}
}) as rtt_target::CriticalSectionFunc),
);
}
static LOGGER: rtt_logger::RTTLogger =
rtt_logger::RTTLogger::new(log::LevelFilter::Info);
log::set_logger(&LOGGER) log::set_logger(&LOGGER)
.map(|()| log::set_max_level(log::LevelFilter::Trace)) .map(|()| log::set_max_level(log::LevelFilter::Trace))
.unwrap(); .unwrap();