diff --git a/Cargo.lock b/Cargo.lock index edc2864..f7082af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -517,7 +517,7 @@ dependencies = [ [[package]] name = "stm32h7xx-hal" version = "0.8.0" -source = "git+https://github.com/quartiq/stm32h7xx-hal?branch=feature/number-of-transfers#e70a78788e74be5281321213b53e8cd1d213550e" +source = "git+https://github.com/stm32-rs/stm32h7xx-hal?branch=dma#25ee0f3a9ae27d1fd6bb390d6045aa312f29f096" dependencies = [ "bare-metal 1.0.0", "cast", diff --git a/Cargo.toml b/Cargo.toml index f1acbe0..7217589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,8 +53,8 @@ default-features = false [dependencies.stm32h7xx-hal] features = ["stm32h743v", "rt", "unproven", "ethernet", "quadspi"] -git = "https://github.com/quartiq/stm32h7xx-hal" -branch = "feature/number-of-transfers" +git = "https://github.com/stm32-rs/stm32h7xx-hal" +branch = "dma" [features] semihosting = ["panic-semihosting", "cortex-m-log/semihosting"] diff --git a/openocd.gdb b/openocd.gdb index e903a33..a96f8d4 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -18,6 +18,9 @@ load # tbreak cortex_m_rt::reset_handler monitor reset halt +source ../../PyCortexMDebug/cmdebug/svd_gdb.py +svd_load ~/Downloads/STM32H743x.svd + # cycle counter delta tool, place two bkpts around the section set var $cc=0xe0001004 define qq diff --git a/src/design_parameters.rs b/src/design_parameters.rs index 414a9e2..40be7b6 100644 --- a/src/design_parameters.rs +++ b/src/design_parameters.rs @@ -1,9 +1,11 @@ +use super::hal::time::MegaHertz; + /// The ADC setup time is the number of seconds after the CSn line goes low before the serial clock /// may begin. This is used for performing the internal ADC conversion. pub const ADC_SETUP_TIME: f32 = 220e-9; /// The maximum DAC/ADC serial clock line frequency. This is a hardware limit. -pub const ADC_DAC_SCK_MHZ_MAX: u32 = 50; +pub const ADC_DAC_SCK_MAX: MegaHertz = MegaHertz(50); /// The optimal counting frequency of the hardware timers used for timestamping and sampling. -pub const TIMER_FREQUENCY_MHZ: u32 = 100; +pub const TIMER_FREQUENCY: MegaHertz = MegaHertz(100); diff --git a/src/digital_input_stamper.rs b/src/digital_input_stamper.rs index 5843528..43ff9c5 100644 --- a/src/digital_input_stamper.rs +++ b/src/digital_input_stamper.rs @@ -24,7 +24,41 @@ ///! ///! This module only supports DI0 for timestamping due to trigger constraints on the DIx pins. If ///! timestamping is desired in DI1, a separate timer + capture channel will be necessary. -use super::{hal, timers}; +use super::{hal, timers, SAMPLE_BUFFER_SIZE, ADC_SAMPLE_TICKS}; + +/// Calculate the period of the digital input timestampe timer. +/// +/// # Note +/// The period returned will be 1 less than the required period in timer ticks. The value returned +/// can be immediately programmed into a hardware timer period register. +/// +/// The period is calcualted to be some power-of-two multiple of the batch size, such that N batches +/// will occur between each timestamp timer overflow. +/// +/// # Returns +/// A 32-bit value that can be programmed into a hardware timer period register. +pub fn calculate_timestamp_timer_period() -> u32 { + // Calculate how long a single batch requires in timer ticks. + let batch_duration_ticks: u64 = SAMPLE_BUFFER_SIZE as u64 * ADC_SAMPLE_TICKS as u64; + + // Calculate the largest power-of-two that is less than or equal to + // `batches_per_overflow`. This is completed by eliminating the least significant + // bits of the value until only the msb remains, which is always a power of two. + let batches_per_overflow: u64 = + (1u64 + u32::MAX as u64) / batch_duration_ticks; + let mut j = batches_per_overflow; + while (j & (j - 1)) != 0 { + j = j & (j - 1); + } + + // Once the number of batches per timestamp overflow is calculated, we can figure out the final + // period of the timestamp timer. The period is always 1 larger than the value configured in the + // register. + let period: u64 = batch_duration_ticks * j - 1u64; + assert!(period < u32::MAX as u64); + + period as u32 +} /// The timestamper for DI0 reference clock inputs. pub struct InputStamper { @@ -45,7 +79,7 @@ impl InputStamper { // Utilize the TIM5 CH4 as an input capture channel - use TI4 (the DI0 input trigger) as the // capture source. let input_capture = - timer_channel.to_input_capture(timers::tim5::CC4S_A::TI4); + timer_channel.into_input_capture(timers::tim5::CC4S_A::TI4); Self { capture_channel: input_capture, diff --git a/src/main.rs b/src/main.rs index 5ae2b0f..52c5650 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,8 +30,6 @@ extern crate panic_halt; #[macro_use] extern crate log; -use core::convert::TryInto; - // use core::sync::atomic::{AtomicU32, AtomicBool, Ordering}; use cortex_m_rt::exception; use rtic::cyccnt::{Instant, U32Ext}; @@ -294,10 +292,10 @@ const APP: () = { // Configure the timer to count at the designed tick rate. We will manually set the // period below. timer2.pause(); - timer2.set_tick_freq(design_parameters::TIMER_FREQUENCY_MHZ.mhz()); + timer2.set_tick_freq(design_parameters::TIMER_FREQUENCY); let mut sampling_timer = timers::SamplingTimer::new(timer2); - sampling_timer.set_period(ADC_SAMPLE_TICKS - 1); + sampling_timer.set_period_ticks(ADC_SAMPLE_TICKS - 1); sampling_timer }; @@ -313,32 +311,15 @@ const APP: () = { // Configure the timer to count at the designed tick rate. We will manually set the // period below. timer5.pause(); - timer5.set_tick_freq(design_parameters::TIMER_FREQUENCY_MHZ.mhz()); + timer5.set_tick_freq(design_parameters::TIMER_FREQUENCY); // The time stamp timer must run at exactly a multiple of the sample timer based on the - // batch size. To accomodate this, we manually set the period identical to the sample - // timer, but use a prescaler that is `BATCH_SIZE` longer. + // batch size. To accomodate this, we manually set the prescaler identical to the sample + // timer, but use a period that is longer. let mut timer = timers::TimestampTimer::new(timer5); - let period: u32 = { - let batch_duration: u64 = - SAMPLE_BUFFER_SIZE as u64 * ADC_SAMPLE_TICKS as u64; - let batches_per_overflow: u64 = - (1u64 + u32::MAX as u64) / batch_duration; - - // Calculate the largest power-of-two that is less than `batches_per_overflow`. - // This is completed by eliminating the least significant bits of the value until - // only the msb remains, which is always a power of two. - let mut j = batches_per_overflow; - while (j & (j - 1)) != 0 { - j = j & (j - 1); - } - - let period: u64 = batch_duration * j - 1u64; - period.try_into().unwrap() - }; - - timer.set_period(period); + let period = digital_input_stamper::calculate_timestamp_timer_period(); + timer.set_period_ticks(period); timer }; @@ -372,7 +353,7 @@ const APP: () = { let spi: hal::spi::Spi<_, _, u16> = dp.SPI2.spi( (spi_sck, spi_miso, hal::spi::NoMosi), config, - design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(), + design_parameters::ADC_DAC_SCK_MAX, ccdr.peripheral.SPI2, &ccdr.clocks, ); @@ -410,7 +391,7 @@ const APP: () = { let spi: hal::spi::Spi<_, _, u16> = dp.SPI3.spi( (spi_sck, spi_miso, hal::spi::NoMosi), config, - design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(), + design_parameters::ADC_DAC_SCK_MAX, ccdr.peripheral.SPI3, &ccdr.clocks, ); @@ -460,7 +441,7 @@ const APP: () = { dp.SPI4.spi( (spi_sck, spi_miso, hal::spi::NoMosi), config, - design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(), + design_parameters::ADC_DAC_SCK_MAX, ccdr.peripheral.SPI4, &ccdr.clocks, ) @@ -492,7 +473,7 @@ const APP: () = { dp.SPI5.spi( (spi_sck, spi_miso, hal::spi::NoMosi), config, - design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(), + design_parameters::ADC_DAC_SCK_MAX, ccdr.peripheral.SPI5, &ccdr.clocks, ) @@ -702,7 +683,7 @@ const APP: () = { // Ensure that we have enough time for an IO-update every sample. let sample_frequency = - (design_parameters::TIMER_FREQUENCY_MHZ as f32 + (design_parameters::TIMER_FREQUENCY.0 as f32 * 1_000_000.0) / ADC_SAMPLE_TICKS as f32; diff --git a/src/timers.rs b/src/timers.rs index 03bc0aa..8afa5cd 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -41,7 +41,7 @@ macro_rules! timer_channels { /// Manually set the period of the timer. #[allow(dead_code)] - pub fn set_period(&mut self, period: u32) { + pub fn set_period_ticks(&mut self, period: u32) { let regs = unsafe { &*hal::stm32::$TY::ptr() }; regs.arr.write(|w| w.arr().bits(period)); } @@ -136,7 +136,7 @@ macro_rules! timer_channels { /// # Args /// * `input` - The input source for the input capture event. #[allow(dead_code)] - pub fn to_input_capture(self, input: hal::stm32::tim2::[< $ccmrx _input >]::[< CC $index S_A >]) -> [< Channel $index InputCapture >]{ + pub fn into_input_capture(self, input: hal::stm32::tim2::[< $ccmrx _input >]::[< CC $index S_A >]) -> [< Channel $index InputCapture >]{ let regs = unsafe { &*<$TY>::ptr() }; regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));