Merge branch 'rj/log' into rj/itcm

* rj/log:
  refine panic handler and add some logging info
  hitl: kill probe-run cleanly
  set target-cpu=cortex-m7, MSRV 1.52.0, use probe-run
  README: document lockin, cleanup instructions, use probe-run
  CHANGELOG: update
  README: streamline docs a bit, add probe-run
  update hitl script
  remove rtt feature
  use rtt logging
  dsp/lowpass,lockin: const generics
master
Robert Jördens 2021-05-13 15:20:20 +02:00
commit 8eef23da6b
13 changed files with 134 additions and 103 deletions

View File

@ -1,16 +1,11 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))'] [target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "gdb-multiarch -q -x openocd.gdb" runner = "probe-run --chip STM32H743ZITx --speed 30000"
# runner = "gdb-multiarch -q -x openocd.gdb"
rustflags = [ rustflags = [
"-C", "link-arg=--nmagic", "-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tlink.x",
# The target (below) defaults to cortex-m4 "-C", "link-arg=--nmagic",
# There currently are two different options to go beyond that: "-C", "target-cpu=cortex-m7",
# 1. cortex-m7 has the right flags and instructions (FPU) but no instruction schedule yet
# "-C", "target-cpu=cortex-m7",
# 2. cortex-m4 with the additional fpv5 instructions and a potentially
# better-than-nothing instruction schedule
"-C", "target-feature=+fp-armv8d16",
# When combined they are equivalent to (1) alone
] ]
[build] [build]

View File

@ -9,8 +9,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added ### Added
* Telemetry
* RTT logging
### Changed ### Changed
* Const generics, bumping the MSRV to 1.51.0
* `lockin-internal` and `lockin-external` have been merged into `lockin`
* Set target CPU to cortex-m7, effectively bumping the MSRV to 1.52.0
### Fixed ### Fixed
## [v0.5.0] - 2021-04-21 ## [v0.5.0] - 2021-04-21

61
Cargo.lock generated
View File

@ -139,17 +139,6 @@ dependencies = [
"volatile-register", "volatile-register",
] ]
[[package]]
name = "cortex-m-log"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e202d2eac4e34adf7524a563e36623bae6f69cc0a73ef9bd22a4c93a5a806fa"
dependencies = [
"cortex-m 0.7.2",
"cortex-m-semihosting",
"log",
]
[[package]] [[package]]
name = "cortex-m-rt" name = "cortex-m-rt"
version = "0.6.13" version = "0.6.13"
@ -194,15 +183,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "cortex-m-semihosting"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc"
dependencies = [
"cortex-m 0.7.2",
]
[[package]] [[package]]
name = "derive_miniconf" name = "derive_miniconf"
version = "0.1.0" version = "0.1.0"
@ -218,7 +198,6 @@ name = "dsp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"easybench", "easybench",
"generic-array 0.14.4",
"libm", "libm",
"miniconf", "miniconf",
"ndarray", "ndarray",
@ -541,16 +520,6 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "panic-semihosting"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec"
dependencies = [
"cortex-m 0.7.2",
"cortex-m-semihosting",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.5" version = "1.0.5"
@ -644,6 +613,26 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "rtt-logger"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d082d3a20a5d4f69ad509720de1777fe5aa2092ea1af51b254ff79113d46d2ea"
dependencies = [
"log",
"rtt-target",
]
[[package]]
name = "rtt-target"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0869b4c5b6a6d8c5583fc473f9eb3423a170f77626b8c8a7fb18eddcda5770e2"
dependencies = [
"cortex-m 0.6.7",
"ufmt-write",
]
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.2.3" version = "0.2.3"
@ -745,7 +734,6 @@ dependencies = [
"asm-delay", "asm-delay",
"cc", "cc",
"cortex-m 0.6.7", "cortex-m 0.6.7",
"cortex-m-log",
"cortex-m-rt", "cortex-m-rt",
"cortex-m-rtic", "cortex-m-rtic",
"dsp", "dsp",
@ -758,8 +746,9 @@ dependencies = [
"miniconf", "miniconf",
"minimq", "minimq",
"nb 1.0.0", "nb 1.0.0",
"panic-semihosting",
"paste", "paste",
"rtt-logger",
"rtt-target",
"serde", "serde",
"serde-json-core", "serde-json-core",
"shared-bus", "shared-bus",
@ -821,6 +810,12 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "ufmt-write"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.1"

View File

@ -30,9 +30,9 @@ members = ["ad9959", "dsp"]
[dependencies] [dependencies]
cortex-m = { version = "0.6", features = ["const-fn"] } cortex-m = { version = "0.6", features = ["const-fn"] }
cortex-m-rt = { version = "0.6", features = ["device"] } cortex-m-rt = { version = "0.6", features = ["device"] }
cortex-m-log = { version = "0.7", features = ["log-integration"] } log = { version = "0.4", features = ["max_level_trace", "release_max_level_info"] }
log = "0.4" rtt-target = { version = "0.2.1", features = ["cortex-m"] }
panic-semihosting = { version = "0.5", optional = true } rtt-logger = { version = "0.1" }
serde = { version = "1.0", features = ["derive"], default-features = false } serde = { version = "1.0", features = ["derive"], default-features = false }
heapless = { version = "0.6", features = ["serde"] } heapless = { version = "0.6", features = ["serde"] }
cortex-m-rtic = "0.5.6" cortex-m-rtic = "0.5.6"
@ -76,7 +76,6 @@ git = "https://github.com/quartiq/minimq.git"
rev = "d2ec3e8" rev = "d2ec3e8"
[features] [features]
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
bkpt = [ ] bkpt = [ ]
nightly = ["cortex-m/inline-asm", "dsp/nightly"] nightly = ["cortex-m/inline-asm", "dsp/nightly"]
pounder_v1_1 = [ ] pounder_v1_1 = [ ]

View File

@ -10,10 +10,10 @@
## Applications ## Applications
The Stabilizer firmware offeres a library of hardware and software functionality This firmware offers a library of hardware and software functionality targeting the use of the Stabilizer hardware in various digital signal processing applications commonly occurring in Quantum Technology.
exposing input/output, timing, and digital signal processing features. It provides abstractions over the fast analog inputs and outputs, time stamping, Pounder DDS interfaces and a collection of tailored and optimized digital signal processing algorithms (IIR, FIR, Lockin, PLL, reciprocal PLL, Unwrapper, Lowpass, Cosine-Sine, Atan2).
An application can compose and configure these hardware and software components An application can compose and configure these hardware and software components to implement different use cases.
to implement different use cases. Several applications are provides by default Several applications are provides by default:
### Dual-IIR ### Dual-IIR
@ -31,22 +31,34 @@ to implement different use cases. Several applications are provides by default
### Lockin ### Lockin
* Up to 800 kHz sampling
* Up to 400 kHz modulation frequency
* Reciprocal PLL for external reference
* Internal reference
* Adjustable PLL and locking time constants
* Adjustable phase offset and harmonic index
* Different output modes (in-phase, quadrature, magnitude, log2 power, phase, frequency)
## Minimal bootstrapping documentation ## Minimal bootstrapping documentation
* Clone or download this * Clone or download this
* Get [rustup](https://rustup.rs/) * Get [rustup](https://rustup.rs/)
* `rustup target add thumbv7em-none-eabihf` * Minimum supported Rust version (MSRV) is 1.52.0
* `cargo build --release` * Install target support: `rustup target add thumbv7em-none-eabihf`
* Install `probe-run`: `cargo install probe-run`
* `cargo run --release --bin dual-iir`
* When using debug (non `--release`) mode, increase the sample interval significantly. * When using debug (non `--release`) mode, increase the sample interval significantly.
The added error checking code and missing optimizations may lead to the code The added error checking code and missing optimizations may lead to the code
missing deadlines and panicing. missing deadlines and panicing.
### Using Cargo-embed ## Alternative flashing tools
### Cargo-embed
* Install `cargo-embed`: `cargo install cargo-embed` * Install `cargo-embed`: `cargo install cargo-embed`
* Program the device: `cargo embed --bin dual-iir --release` * Program the device: `cargo embed --bin dual-iir --release`
### Using GDB/OpenOCD ### GDB/OpenOCD
* Get a recent openocd, a JTAG adapter ("st-link" or some clone) and * Get a recent openocd, a JTAG adapter ("st-link" or some clone) and
everything connected and permissions setup. Most everything connected and permissions setup. Most
@ -56,24 +68,24 @@ to implement different use cases. Several applications are provides by default
* `openocd -f stabilizer.cfg` and leave it running * `openocd -f stabilizer.cfg` and leave it running
* `cargo run --release` * `cargo run --release`
### Using USB-DFU ### USB-DFU
* Get [cargo-binutils](https://github.com/rust-embedded/cargo-binutils/)
* `cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin` or `arm-none-eabi-objcopy -O binary target/thumbv7em-none-eabihf/release/dual-iir dual-iir.bin`
* Install the DFU USB tool (`dfu-util`) * Install the DFU USB tool (`dfu-util`)
* Connect to the Micro USB connector below the RJ45 * Connect to the Micro USB connector below the RJ45
* Short JC2/BOOT * Short JC2/BOOT
* Get [cargo-binutils](https://github.com/rust-embedded/cargo-binutils/)
* `cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin` or `arm-none-eabi-objcopy -O binary target/thumbv7em-none-eabihf/release/dual-iir dual-iir.bin`
* `dfu-util -a 0 -s 0x08000000:leave -D dual-iir.bin` * `dfu-util -a 0 -s 0x08000000:leave -D dual-iir.bin`
### Using ST-Link virtual mass storage ### ST-Link virtual mass storage
* Get [cargo-binutils](https://github.com/rust-embedded/cargo-binutils/) * Prepare `dual-iir.bin` like above
* `cargo objcopy --release --bin dual-iir -- -O binary dual-iir.bin` or `arm-none-eabi-objcopy -O binary target/thumbv7em-none-eabihf/release/dual-iir dual-iir.bin`
* Connect the ST-Link debugger * Connect the ST-Link debugger
* copy `dual-iir.bin` to the `NODE_H743ZI` USB disk * Copy `dual-iir.bin` to the `NODE_H743ZI` virtual mass storage device
## Protocol ## Protocol
Stabilizer can be configured via MQTT. Refer to Stabilizer can be configured via MQTT. Refer to
[`miniconf`](https://github.com/quartiq/miniconf) for more information about topics. [`miniconf`](https://github.com/quartiq/miniconf) for more information about topics.
A basic command line interface is available in [`miniconf.py`](miniconf.py). A basic command line interface is available in [`miniconf.py`](miniconf.py).
Telemetry is published via MQTT as well.

View File

@ -7,7 +7,6 @@ edition = "2018"
[dependencies] [dependencies]
libm = "0.2.1" libm = "0.2.1"
serde = { version = "1.0", features = ["derive"], default-features = false } serde = { version = "1.0", features = ["derive"], default-features = false }
generic-array = "0.14"
num = { version = "0.4.0", default-features = false } num = { version = "0.4.0", default-features = false }
miniconf = "0.1" miniconf = "0.1"

View File

@ -1,7 +1,6 @@
use core::f32::consts::PI; use core::f32::consts::PI;
use easybench::bench_env; use easybench::bench_env;
use generic_array::typenum::U4;
use dsp::{atan2, cossin, iir, iir_int, Lowpass, PLL, RPLL}; use dsp::{atan2, cossin, iir, iir_int, Lowpass, PLL, RPLL};
@ -72,13 +71,13 @@ fn iir_bench() {
} }
fn lowpass_bench() { fn lowpass_bench() {
let mut dut = Lowpass::<U4>::default(); let mut dut = Lowpass::<4>::default();
println!( println!(
"Lowpass::<U4>::update(x, k): {}", "Lowpass::<4>::update(x, k): {}",
bench_env((0x32421, 14), |(x, k)| dut.update(*x, *k)) bench_env((0x32421, 14), |(x, k)| dut.update(*x, *k))
); );
println!( println!(
"Lowpass::<U4>::update(x, 14): {}", "Lowpass::<4>::update(x, 14): {}",
bench_env(0x32421, |x| dut.update(*x, 14)) bench_env(0x32421, |x| dut.update(*x, 14))
); );
} }

View File

@ -1,12 +1,11 @@
use super::{Complex, ComplexExt, Lowpass, MulScaled}; use super::{Complex, ComplexExt, Lowpass, MulScaled};
use generic_array::ArrayLength;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Lockin<N: ArrayLength<i32>> { pub struct Lockin<const N: usize> {
state: [Lowpass<N>; 2], state: [Lowpass<N>; 2],
} }
impl<N: ArrayLength<i32>> Lockin<N> { impl<const N: usize> Lockin<N> {
/// Update the lockin with a sample taken at a given phase. /// Update the lockin with a sample taken at a given phase.
pub fn update(&mut self, sample: i32, phase: i32, k: u8) -> Complex<i32> { pub fn update(&mut self, sample: i32, phase: i32, k: u8) -> Complex<i32> {
// Get the LO signal for demodulation and mix the sample; // Get the LO signal for demodulation and mix the sample;

View File

@ -1,16 +1,20 @@
use generic_array::{ArrayLength, GenericArray};
/// Arbitrary order, high dynamic range, wide coefficient range, /// Arbitrary order, high dynamic range, wide coefficient range,
/// lowpass filter implementation. DC gain is 1. /// lowpass filter implementation. DC gain is 1.
/// ///
/// Type argument N is the filter order. /// Type argument N is the filter order.
#[derive(Clone, Default)] #[derive(Clone)]
pub struct Lowpass<N: ArrayLength<i32>> { pub struct Lowpass<const N: usize> {
// IIR state storage // IIR state storage
y: GenericArray<i32, N>, y: [i32; N],
} }
impl<N: ArrayLength<i32>> Lowpass<N> { impl<const N: usize> Default for Lowpass<N> {
fn default() -> Self {
Lowpass { y: [0i32; N] }
}
}
impl<const N: usize> Lowpass<N> {
/// Update the filter with a new sample. /// Update the filter with a new sample.
/// ///
/// # Args /// # Args

View File

@ -15,9 +15,9 @@ python3 -m venv --system-site-packages py
. py/bin/activate . py/bin/activate
python3 -m pip install -r requirements.txt python3 -m pip install -r requirements.txt
cargo flash --elf target/thumbv7em-none-eabihf/release/dual-iir --chip STM32H743ZITx probe-run --chip STM32H743ZITx target/thumbv7em-none-eabihf/release/dual-iir &
# Before attempting to ping the device, sleep to allow Stabilizer to boot. # Sleep to allow flashing, booting, DHCP, MQTT
sleep 30 sleep 30
# Test pinging Stabilizer. This exercises that: # Test pinging Stabilizer. This exercises that:
@ -30,3 +30,6 @@ ping -c 5 -w 20 stabilizer-hitl
python3 miniconf.py dt/sinara/dual-iir/04-91-62-d9-7e-5f afe/0='"G2"' python3 miniconf.py dt/sinara/dual-iir/04-91-62-d9-7e-5f afe/0='"G2"'
python3 miniconf.py dt/sinara/dual-iir/04-91-62-d9-7e-5f afe/0='"G1"' iir_ch/0/0=\ python3 miniconf.py dt/sinara/dual-iir/04-91-62-d9-7e-5f afe/0='"G1"' iir_ch/0/0=\
'{"y_min": -32767, "y_max": 32767, "y_offset": 0, "ba": [1.0, 0, 0, 0, 0]}' '{"y_min": -32767, "y_max": 32767, "y_offset": 0, "ba": [1.0, 0, 0, 0, 0]}'
kill $(jobs -p)
wait || true

View File

@ -3,7 +3,6 @@
#![no_main] #![no_main]
use embedded_hal::digital::v2::InputPin; use embedded_hal::digital::v2::InputPin;
use generic_array::typenum::U4;
use serde::Deserialize; use serde::Deserialize;
@ -92,7 +91,7 @@ const APP: () = {
timestamper: InputStamper, timestamper: InputStamper,
pll: RPLL, pll: RPLL,
lockin: Lockin<U4>, lockin: Lockin<4>,
} }
#[init(spawn=[settings_update, telemetry])] #[init(spawn=[settings_update, telemetry])]

View File

@ -145,19 +145,19 @@ pub fn setup(
.pll2_q_ck(100.mhz()) .pll2_q_ck(100.mhz())
.freeze(vos, &device.SYSCFG); .freeze(vos, &device.SYSCFG);
#[cfg(feature = "semihosting")] // Set up RTT logging
{ {
use cortex_m_log::log::{init as init_log, Logger}; // Enable debug during WFE/WFI-induced sleep
use cortex_m_log::printer::semihosting::{hio::HStdout, InterruptOk}; device.DBGMCU.cr.modify(|_, w| w.dbgsleep_d1().set_bit());
use log::LevelFilter;
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
let logger = Logger {
inner: InterruptOk::<_>::stdout().unwrap(),
level: LevelFilter::Info,
};
let logger = unsafe { LOGGER.get_or_insert(logger) };
init_log(logger).unwrap(); use rtt_logger::RTTLogger;
static LOGGER: RTTLogger = RTTLogger::new(log::LevelFilter::Info);
rtt_target::rtt_init_print!(NoBlockSkip, 1024);
log::set_logger(&LOGGER)
.map(|()| log::set_max_level(log::LevelFilter::Trace))
.unwrap();
log::info!("starting...");
} }
// Set up the system timer for RTIC scheduling. // Set up the system timer for RTIC scheduling.
@ -537,6 +537,7 @@ pub fn setup(
&mut eeprom_i2c, &mut eeprom_i2c,
&mut delay, &mut delay,
)); ));
log::info!("EUI48: {}", mac_addr);
let network_devices = { let network_devices = {
// Configure the ethernet controller // Configure the ethernet controller
@ -673,6 +674,7 @@ pub fn setup(
let pounder_pgood = gpiob.pb13.into_pull_down_input(); let pounder_pgood = gpiob.pb13.into_pull_down_input();
delay.delay_ms(2u8); delay.delay_ms(2u8);
let pounder = if pounder_pgood.is_high().unwrap() { let pounder = if pounder_pgood.is_high().unwrap() {
log::info!("Found Pounder");
let ad9959 = { let ad9959 = {
let qspi_interface = { let qspi_interface = {
// Instantiate the QUADSPI pins and peripheral interface. // Instantiate the QUADSPI pins and peripheral interface.
@ -935,6 +937,7 @@ pub fn setup(
// info!("Version {} {}", build_info::PKG_VERSION, build_info::GIT_VERSION.unwrap()); // info!("Version {} {}", build_info::PKG_VERSION, build_info::GIT_VERSION.unwrap());
// info!("Built on {}", build_info::BUILT_TIME_UTC); // info!("Built on {}", build_info::BUILT_TIME_UTC);
// info!("{} {}", build_info::RUSTC_VERSION, build_info::TARGET); // info!("{} {}", build_info::RUSTC_VERSION, build_info::TARGET);
log::info!("setup() complete");
// Enable the instruction cache. // Enable the instruction cache.
core.SCB.enable_icache(); core.SCB.enable_icache();

View File

@ -4,9 +4,6 @@ use stm32h7xx_hal as hal;
// Re-export for the DigitalInputs below: // Re-export for the DigitalInputs below:
pub use embedded_hal::digital::v2::InputPin; pub use embedded_hal::digital::v2::InputPin;
#[cfg(feature = "semihosting")]
use panic_semihosting as _;
mod adc; mod adc;
mod afe; mod afe;
mod configuration; mod configuration;
@ -59,17 +56,37 @@ pub use configuration::{setup, PounderDevices, StabilizerDevices};
#[inline(never)] #[inline(never)]
#[panic_handler] #[panic_handler]
#[cfg(all(not(feature = "semihosting")))] fn panic(info: &core::panic::PanicInfo) -> ! {
fn panic(_info: &core::panic::PanicInfo) -> ! { use core::{
let gpiod = unsafe { &*hal::stm32::GPIOD::ptr() }; fmt::Write,
// Turn on both red LEDs, FP_LED_1, FP_LED_3 sync::atomic::{AtomicBool, Ordering},
gpiod.odr.modify(|_, w| w.odr6().high().odr12().high()); };
loop { use cortex_m::asm;
// Halt use rtt_target::{ChannelMode, UpChannel};
core::sync::atomic::compiler_fence(
core::sync::atomic::Ordering::SeqCst, cortex_m::interrupt::disable();
);
// Recursion protection
static PANICKED: AtomicBool = AtomicBool::new(false);
while PANICKED.load(Ordering::Relaxed) {
asm::bkpt();
} }
PANICKED.store(true, Ordering::Relaxed);
// Turn on both red LEDs, FP_LED_1, FP_LED_3
let gpiod = unsafe { &*hal::stm32::GPIOD::ptr() };
gpiod.odr.modify(|_, w| w.odr6().high().odr12().high());
// Analogous to panic-rtt-target
if let Some(mut channel) = unsafe { UpChannel::conjure(0) } {
channel.set_mode(ChannelMode::BlockIfFull);
writeln!(channel, "{}", info).ok();
}
// Abort
asm::udf();
// Halt
// loop { core::sync::atomic::compiler_fence(Ordering::SeqCst); }
} }
#[cortex_m_rt::exception] #[cortex_m_rt::exception]