Addressing PR review
This commit is contained in:
parent
fc81f3d55d
commit
67b6990fc0
|
@ -517,7 +517,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stm32h7xx-hal"
|
name = "stm32h7xx-hal"
|
||||||
version = "0.8.0"
|
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 = [
|
dependencies = [
|
||||||
"bare-metal 1.0.0",
|
"bare-metal 1.0.0",
|
||||||
"cast",
|
"cast",
|
||||||
|
|
|
@ -53,8 +53,8 @@ default-features = false
|
||||||
|
|
||||||
[dependencies.stm32h7xx-hal]
|
[dependencies.stm32h7xx-hal]
|
||||||
features = ["stm32h743v", "rt", "unproven", "ethernet", "quadspi"]
|
features = ["stm32h743v", "rt", "unproven", "ethernet", "quadspi"]
|
||||||
git = "https://github.com/quartiq/stm32h7xx-hal"
|
git = "https://github.com/stm32-rs/stm32h7xx-hal"
|
||||||
branch = "feature/number-of-transfers"
|
branch = "dma"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
|
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
|
||||||
|
|
|
@ -18,6 +18,9 @@ load
|
||||||
# tbreak cortex_m_rt::reset_handler
|
# tbreak cortex_m_rt::reset_handler
|
||||||
monitor reset halt
|
monitor reset halt
|
||||||
|
|
||||||
|
source ../../PyCortexMDebug/cmdebug/svd_gdb.py
|
||||||
|
svd_load ~/Downloads/STM32H743x.svd
|
||||||
|
|
||||||
# cycle counter delta tool, place two bkpts around the section
|
# cycle counter delta tool, place two bkpts around the section
|
||||||
set var $cc=0xe0001004
|
set var $cc=0xe0001004
|
||||||
define qq
|
define qq
|
||||||
|
|
|
@ -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
|
/// 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.
|
/// may begin. This is used for performing the internal ADC conversion.
|
||||||
pub const ADC_SETUP_TIME: f32 = 220e-9;
|
pub const ADC_SETUP_TIME: f32 = 220e-9;
|
||||||
|
|
||||||
/// The maximum DAC/ADC serial clock line frequency. This is a hardware limit.
|
/// 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.
|
/// 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);
|
||||||
|
|
|
@ -24,7 +24,41 @@
|
||||||
///!
|
///!
|
||||||
///! This module only supports DI0 for timestamping due to trigger constraints on the DIx pins. If
|
///! 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.
|
///! 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.
|
/// The timestamper for DI0 reference clock inputs.
|
||||||
pub struct InputStamper {
|
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
|
// Utilize the TIM5 CH4 as an input capture channel - use TI4 (the DI0 input trigger) as the
|
||||||
// capture source.
|
// capture source.
|
||||||
let input_capture =
|
let input_capture =
|
||||||
timer_channel.to_input_capture(timers::tim5::CC4S_A::TI4);
|
timer_channel.into_input_capture(timers::tim5::CC4S_A::TI4);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
capture_channel: input_capture,
|
capture_channel: input_capture,
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -30,8 +30,6 @@ extern crate panic_halt;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
// use core::sync::atomic::{AtomicU32, AtomicBool, Ordering};
|
// use core::sync::atomic::{AtomicU32, AtomicBool, Ordering};
|
||||||
use cortex_m_rt::exception;
|
use cortex_m_rt::exception;
|
||||||
use rtic::cyccnt::{Instant, U32Ext};
|
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
|
// Configure the timer to count at the designed tick rate. We will manually set the
|
||||||
// period below.
|
// period below.
|
||||||
timer2.pause();
|
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);
|
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
|
sampling_timer
|
||||||
};
|
};
|
||||||
|
@ -313,32 +311,15 @@ const APP: () = {
|
||||||
// Configure the timer to count at the designed tick rate. We will manually set the
|
// Configure the timer to count at the designed tick rate. We will manually set the
|
||||||
// period below.
|
// period below.
|
||||||
timer5.pause();
|
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
|
// 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
|
// batch size. To accomodate this, we manually set the prescaler identical to the sample
|
||||||
// timer, but use a prescaler that is `BATCH_SIZE` longer.
|
// timer, but use a period that is longer.
|
||||||
let mut timer = timers::TimestampTimer::new(timer5);
|
let mut timer = timers::TimestampTimer::new(timer5);
|
||||||
|
|
||||||
let period: u32 = {
|
let period = digital_input_stamper::calculate_timestamp_timer_period();
|
||||||
let batch_duration: u64 =
|
timer.set_period_ticks(period);
|
||||||
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);
|
|
||||||
|
|
||||||
timer
|
timer
|
||||||
};
|
};
|
||||||
|
@ -372,7 +353,7 @@ const APP: () = {
|
||||||
let spi: hal::spi::Spi<_, _, u16> = dp.SPI2.spi(
|
let spi: hal::spi::Spi<_, _, u16> = dp.SPI2.spi(
|
||||||
(spi_sck, spi_miso, hal::spi::NoMosi),
|
(spi_sck, spi_miso, hal::spi::NoMosi),
|
||||||
config,
|
config,
|
||||||
design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(),
|
design_parameters::ADC_DAC_SCK_MAX,
|
||||||
ccdr.peripheral.SPI2,
|
ccdr.peripheral.SPI2,
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
);
|
);
|
||||||
|
@ -410,7 +391,7 @@ const APP: () = {
|
||||||
let spi: hal::spi::Spi<_, _, u16> = dp.SPI3.spi(
|
let spi: hal::spi::Spi<_, _, u16> = dp.SPI3.spi(
|
||||||
(spi_sck, spi_miso, hal::spi::NoMosi),
|
(spi_sck, spi_miso, hal::spi::NoMosi),
|
||||||
config,
|
config,
|
||||||
design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(),
|
design_parameters::ADC_DAC_SCK_MAX,
|
||||||
ccdr.peripheral.SPI3,
|
ccdr.peripheral.SPI3,
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
);
|
);
|
||||||
|
@ -460,7 +441,7 @@ const APP: () = {
|
||||||
dp.SPI4.spi(
|
dp.SPI4.spi(
|
||||||
(spi_sck, spi_miso, hal::spi::NoMosi),
|
(spi_sck, spi_miso, hal::spi::NoMosi),
|
||||||
config,
|
config,
|
||||||
design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(),
|
design_parameters::ADC_DAC_SCK_MAX,
|
||||||
ccdr.peripheral.SPI4,
|
ccdr.peripheral.SPI4,
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
)
|
)
|
||||||
|
@ -492,7 +473,7 @@ const APP: () = {
|
||||||
dp.SPI5.spi(
|
dp.SPI5.spi(
|
||||||
(spi_sck, spi_miso, hal::spi::NoMosi),
|
(spi_sck, spi_miso, hal::spi::NoMosi),
|
||||||
config,
|
config,
|
||||||
design_parameters::ADC_DAC_SCK_MHZ_MAX.mhz(),
|
design_parameters::ADC_DAC_SCK_MAX,
|
||||||
ccdr.peripheral.SPI5,
|
ccdr.peripheral.SPI5,
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
)
|
)
|
||||||
|
@ -702,7 +683,7 @@ const APP: () = {
|
||||||
|
|
||||||
// Ensure that we have enough time for an IO-update every sample.
|
// Ensure that we have enough time for an IO-update every sample.
|
||||||
let sample_frequency =
|
let sample_frequency =
|
||||||
(design_parameters::TIMER_FREQUENCY_MHZ as f32
|
(design_parameters::TIMER_FREQUENCY.0 as f32
|
||||||
* 1_000_000.0)
|
* 1_000_000.0)
|
||||||
/ ADC_SAMPLE_TICKS as f32;
|
/ ADC_SAMPLE_TICKS as f32;
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ macro_rules! timer_channels {
|
||||||
|
|
||||||
/// Manually set the period of the timer.
|
/// Manually set the period of the timer.
|
||||||
#[allow(dead_code)]
|
#[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() };
|
let regs = unsafe { &*hal::stm32::$TY::ptr() };
|
||||||
regs.arr.write(|w| w.arr().bits(period));
|
regs.arr.write(|w| w.arr().bits(period));
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ macro_rules! timer_channels {
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `input` - The input source for the input capture event.
|
/// * `input` - The input source for the input capture event.
|
||||||
#[allow(dead_code)]
|
#[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() };
|
let regs = unsafe { &*<$TY>::ptr() };
|
||||||
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
|
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue