diff --git a/.cargo/config b/.cargo/config index deffdfc51..82780fa5d 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,15 +1,10 @@ [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=-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 70665b450..331180fbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added * Telemetry +* RTT logging ### Changed -* Const generics bumping the MSRV to 1.51.0 +* 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 diff --git a/Cargo.lock b/Cargo.lock index 0d0f666f0..3cc8175fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,17 +133,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" @@ -191,15 +180,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 = "derivative" version = "2.2.0" @@ -562,16 +542,6 @@ dependencies = [ "syn", ] -[[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" @@ -671,6 +641,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" @@ -771,7 +761,6 @@ dependencies = [ "ad9959", "asm-delay", "cortex-m 0.6.7", - "cortex-m-log", "cortex-m-rt", "cortex-m-rtic", "dsp", @@ -783,8 +772,9 @@ dependencies = [ "minimq", "nb 1.0.0", "num_enum", - "panic-semihosting", "paste", + "rtt-logger", + "rtt-target", "serde", "serde-json-core", "shared-bus", @@ -846,6 +836,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 2f8054f25..d90f6825a 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" @@ -68,7 +68,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 b6c1af7f4..d34d971e0 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,23 +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.51.0 +* 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 @@ -57,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/hitl/run.sh b/hitl/run.sh index 2af47326a..3eb3e3510 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/hardware/configuration.rs b/src/hardware/configuration.rs index c8104f6e0..6efd57645 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()); + + use rtt_logger::RTTLogger; - init_log(logger).unwrap(); + 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 352c70d36..66152e062 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() }; +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()); - loop { - // Halt - core::sync::atomic::compiler_fence( - core::sync::atomic::Ordering::SeqCst, - ); + + // 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]