diff --git a/.cargo/config b/.cargo/config index ad2c024..0682cd0 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,16 +1,11 @@ [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 = [ "-C", "link-arg=--nmagic", "-C", "link-arg=-Tlink.x", -# The target (below) defaults to cortex-m4 -# There currently are two different options to go beyond that: -# 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 + "-C", "link-arg=--nmagic", + "-C", "target-cpu=cortex-m7", ] [build] diff --git a/CHANGELOG.md b/CHANGELOG.md index 04aa2fe..331180f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +* Telemetry +* RTT logging + ### 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 ## [v0.5.0] - 2021-04-21 diff --git a/Cargo.lock b/Cargo.lock index 8cff2a7..f9f781b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,17 +139,6 @@ dependencies = [ "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]] name = "cortex-m-rt" version = "0.6.13" @@ -194,15 +183,6 @@ dependencies = [ "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]] name = "derive_miniconf" version = "0.1.0" @@ -218,7 +198,6 @@ name = "dsp" version = "0.1.0" dependencies = [ "easybench", - "generic-array 0.14.4", "libm", "miniconf", "ndarray", @@ -541,16 +520,6 @@ dependencies = [ "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]] name = "paste" version = "1.0.5" @@ -644,6 +613,26 @@ dependencies = [ "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]] name = "rustc_version" version = "0.2.3" @@ -745,7 +734,6 @@ dependencies = [ "asm-delay", "cc", "cortex-m 0.6.7", - "cortex-m-log", "cortex-m-rt", "cortex-m-rtic", "dsp", @@ -758,8 +746,9 @@ dependencies = [ "miniconf", "minimq", "nb 1.0.0", - "panic-semihosting", "paste", + "rtt-logger", + "rtt-target", "serde", "serde-json-core", "shared-bus", @@ -821,6 +810,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +[[package]] +name = "ufmt-write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" + [[package]] name = "unicode-xid" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 97b55f5..5bb7197 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,9 @@ members = ["ad9959", "dsp"] [dependencies] cortex-m = { version = "0.6", features = ["const-fn"] } cortex-m-rt = { version = "0.6", features = ["device"] } -cortex-m-log = { version = "0.7", features = ["log-integration"] } -log = "0.4" -panic-semihosting = { version = "0.5", optional = true } +log = { version = "0.4", features = ["max_level_trace", "release_max_level_info"] } +rtt-target = { version = "0.2.1", features = ["cortex-m"] } +rtt-logger = { version = "0.1" } serde = { version = "1.0", features = ["derive"], default-features = false } heapless = { version = "0.6", features = ["serde"] } cortex-m-rtic = "0.5.6" @@ -76,7 +76,6 @@ git = "https://github.com/quartiq/minimq.git" rev = "d2ec3e8" [features] -semihosting = ["panic-semihosting", "cortex-m-log/semihosting"] bkpt = [ ] nightly = ["cortex-m/inline-asm", "dsp/nightly"] pounder_v1_1 = [ ] diff --git a/README.md b/README.md index 80cda1d..d34d971 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ ## Applications -The Stabilizer firmware offeres a library of hardware and software functionality -exposing input/output, timing, and digital signal processing features. -An application can compose and configure these hardware and software components -to implement different use cases. Several applications are provides by default +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. +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 to implement different use cases. +Several applications are provides by default: ### Dual-IIR @@ -31,22 +31,34 @@ to implement different use cases. Several applications are provides by default ### 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 * Clone or download this * Get [rustup](https://rustup.rs/) -* `rustup target add thumbv7em-none-eabihf` -* `cargo build --release` +* Minimum supported Rust version (MSRV) is 1.52.0 +* 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. The added error checking code and missing optimizations may lead to the code missing deadlines and panicing. -### Using Cargo-embed +## Alternative flashing tools + +### Cargo-embed * Install `cargo-embed`: `cargo install cargo-embed` * 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 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 * `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`) * Connect to the Micro USB connector below the RJ45 * 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` -### Using ST-Link virtual mass storage +### ST-Link virtual mass storage -* 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` +* Prepare `dual-iir.bin` like above * 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 Stabilizer can be configured via MQTT. Refer to [`miniconf`](https://github.com/quartiq/miniconf) for more information about topics. A basic command line interface is available in [`miniconf.py`](miniconf.py). +Telemetry is published via MQTT as well. diff --git a/dsp/Cargo.toml b/dsp/Cargo.toml index 7b680d3..f9f680b 100644 --- a/dsp/Cargo.toml +++ b/dsp/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] libm = "0.2.1" serde = { version = "1.0", features = ["derive"], default-features = false } -generic-array = "0.14" num = { version = "0.4.0", default-features = false } miniconf = "0.1" diff --git a/dsp/benches/micro.rs b/dsp/benches/micro.rs index 22a2540..c3588df 100644 --- a/dsp/benches/micro.rs +++ b/dsp/benches/micro.rs @@ -1,7 +1,6 @@ use core::f32::consts::PI; use easybench::bench_env; -use generic_array::typenum::U4; use dsp::{atan2, cossin, iir, iir_int, Lowpass, PLL, RPLL}; @@ -72,13 +71,13 @@ fn iir_bench() { } fn lowpass_bench() { - let mut dut = Lowpass::::default(); + let mut dut = Lowpass::<4>::default(); println!( - "Lowpass::::update(x, k): {}", + "Lowpass::<4>::update(x, k): {}", bench_env((0x32421, 14), |(x, k)| dut.update(*x, *k)) ); println!( - "Lowpass::::update(x, 14): {}", + "Lowpass::<4>::update(x, 14): {}", bench_env(0x32421, |x| dut.update(*x, 14)) ); } diff --git a/dsp/src/lockin.rs b/dsp/src/lockin.rs index 613a133..a9f5e84 100644 --- a/dsp/src/lockin.rs +++ b/dsp/src/lockin.rs @@ -1,12 +1,11 @@ use super::{Complex, ComplexExt, Lowpass, MulScaled}; -use generic_array::ArrayLength; #[derive(Clone, Default)] -pub struct Lockin> { +pub struct Lockin { state: [Lowpass; 2], } -impl> Lockin { +impl Lockin { /// Update the lockin with a sample taken at a given phase. pub fn update(&mut self, sample: i32, phase: i32, k: u8) -> Complex { // Get the LO signal for demodulation and mix the sample; diff --git a/dsp/src/lowpass.rs b/dsp/src/lowpass.rs index 10d5838..265929b 100644 --- a/dsp/src/lowpass.rs +++ b/dsp/src/lowpass.rs @@ -1,16 +1,20 @@ -use generic_array::{ArrayLength, GenericArray}; - /// Arbitrary order, high dynamic range, wide coefficient range, /// lowpass filter implementation. DC gain is 1. /// /// Type argument N is the filter order. -#[derive(Clone, Default)] -pub struct Lowpass> { +#[derive(Clone)] +pub struct Lowpass { // IIR state storage - y: GenericArray, + y: [i32; N], } -impl> Lowpass { +impl Default for Lowpass { + fn default() -> Self { + Lowpass { y: [0i32; N] } + } +} + +impl Lowpass { /// Update the filter with a new sample. /// /// # Args diff --git a/hitl/run.sh b/hitl/run.sh index 2af4732..3eb3e35 100755 --- a/hitl/run.sh +++ b/hitl/run.sh @@ -15,9 +15,9 @@ python3 -m venv --system-site-packages py . py/bin/activate 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 # 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='"G1"' iir_ch/0/0=\ '{"y_min": -32767, "y_max": 32767, "y_offset": 0, "ba": [1.0, 0, 0, 0, 0]}' + +kill $(jobs -p) +wait || true diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index 9c4733b..72a3063 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -3,7 +3,6 @@ #![no_main] use embedded_hal::digital::v2::InputPin; -use generic_array::typenum::U4; use serde::Deserialize; @@ -92,7 +91,7 @@ const APP: () = { timestamper: InputStamper, pll: RPLL, - lockin: Lockin, + lockin: Lockin<4>, } #[init(spawn=[settings_update, telemetry])] diff --git a/src/hardware/configuration.rs b/src/hardware/configuration.rs index c8104f6..6efd576 100644 --- a/src/hardware/configuration.rs +++ b/src/hardware/configuration.rs @@ -145,19 +145,19 @@ pub fn setup( .pll2_q_ck(100.mhz()) .freeze(vos, &device.SYSCFG); - #[cfg(feature = "semihosting")] + // Set up RTT logging { - use cortex_m_log::log::{init as init_log, Logger}; - use cortex_m_log::printer::semihosting::{hio::HStdout, InterruptOk}; - use log::LevelFilter; - static mut LOGGER: Option>> = None; - let logger = Logger { - inner: InterruptOk::<_>::stdout().unwrap(), - level: LevelFilter::Info, - }; - let logger = unsafe { LOGGER.get_or_insert(logger) }; + // Enable debug during WFE/WFI-induced sleep + device.DBGMCU.cr.modify(|_, w| w.dbgsleep_d1().set_bit()); - 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. @@ -537,6 +537,7 @@ pub fn setup( &mut eeprom_i2c, &mut delay, )); + log::info!("EUI48: {}", mac_addr); let network_devices = { // Configure the ethernet controller @@ -673,6 +674,7 @@ pub fn setup( let pounder_pgood = gpiob.pb13.into_pull_down_input(); delay.delay_ms(2u8); let pounder = if pounder_pgood.is_high().unwrap() { + log::info!("Found Pounder"); let ad9959 = { let qspi_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!("Built on {}", build_info::BUILT_TIME_UTC); // info!("{} {}", build_info::RUSTC_VERSION, build_info::TARGET); + log::info!("setup() complete"); // Enable the instruction cache. core.SCB.enable_icache(); diff --git a/src/hardware/mod.rs b/src/hardware/mod.rs index b1c611c..98c12fa 100644 --- a/src/hardware/mod.rs +++ b/src/hardware/mod.rs @@ -4,9 +4,6 @@ use stm32h7xx_hal as hal; // Re-export for the DigitalInputs below: pub use embedded_hal::digital::v2::InputPin; -#[cfg(feature = "semihosting")] -use panic_semihosting as _; - mod adc; mod afe; mod configuration; @@ -59,17 +56,37 @@ pub use configuration::{setup, PounderDevices, StabilizerDevices}; #[inline(never)] #[panic_handler] -#[cfg(all(not(feature = "semihosting")))] -fn panic(_info: &core::panic::PanicInfo) -> ! { - let gpiod = unsafe { &*hal::stm32::GPIOD::ptr() }; - // Turn on both red LEDs, FP_LED_1, FP_LED_3 - gpiod.odr.modify(|_, w| w.odr6().high().odr12().high()); - loop { - // Halt - core::sync::atomic::compiler_fence( - core::sync::atomic::Ordering::SeqCst, - ); +fn panic(info: &core::panic::PanicInfo) -> ! { + use core::{ + fmt::Write, + sync::atomic::{AtomicBool, Ordering}, + }; + use cortex_m::asm; + use rtt_target::{ChannelMode, UpChannel}; + + 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]