Addressing PR review

master
Ryan Summers 2021-01-04 17:12:24 +01:00
parent fc81f3d55d
commit 67b6990fc0
7 changed files with 60 additions and 40 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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"]

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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));