Adding documentation

This commit is contained in:
Ryan Summers 2021-01-06 14:42:36 +01:00
parent 3899848815
commit 8a98428ed4
2 changed files with 55 additions and 2 deletions

View File

@ -1,13 +1,40 @@
///! ADC sample timestamper using external Pounder reference clock. ///! ADC sample timestamper using external Pounder reference clock.
///!
///! # Design
///!
///! The pounder timestamper utilizes the pounder SYNC_CLK output as a fast external reference clock
///! for recording a timestamp for each of the ADC samples.
///!
///! To accomplish this, a timer peripheral is configured to be driven by an external clock input.
///! Due to the limitations of clock frequencies allowed by the timer peripheral, the SYNC_CLK input
///! is divided by 4. This clock then clocks the timer peripheral in a free-running mode with an ARR
///! (max count register value) configured to overflow once per ADC sample batch.
///!
///! Once the timer is configured, an input capture is configured to record the timer count
///! register. The input capture is configured to utilize an internal trigger for the input capture.
///! The internal trigger is selected such that when a sample is generated on ADC0, the input
///! capture is simultaneously triggered. This results in the input capture triggering identically
///! to when the ADC samples the input.
///!
///! Once the input capture is properly configured, a DMA transfer is configured to collect all of
///! timestamps. The DMA transfer collects 1 timestamp for each ADC sample collected. In order to
///! avoid potentially losing a timestamp for a sample, the DMA transfer operates in double-buffer
///! mode. As soon as the DMA transfer completes, the hardware automatically swaps over to a second
///! buffer to continue capturing. This alleviates timing sensitivities of the DMA transfer
///! schedule.
use stm32h7xx_hal as hal; use stm32h7xx_hal as hal;
use hal::dma::{dma::DmaConfig, PeripheralToMemory, Transfer}; use hal::dma::{dma::DmaConfig, PeripheralToMemory, Transfer};
use crate::{timers, SAMPLE_BUFFER_SIZE}; use crate::{timers, SAMPLE_BUFFER_SIZE};
// Three buffers are required for double buffered mode - 2 are owned by the DMA stream and 1 is the
// working data provided to the application. These buffers must exist in a DMA-accessible memory
// region. Note that AXISRAM is not initialized on boot, so their initial contents are undefined.
#[link_section = ".axisram.buffers"] #[link_section = ".axisram.buffers"]
static mut BUF: [[u16; SAMPLE_BUFFER_SIZE]; 3] = [[0; SAMPLE_BUFFER_SIZE]; 3]; static mut BUF: [[u16; SAMPLE_BUFFER_SIZE]; 3] = [[0; SAMPLE_BUFFER_SIZE]; 3];
/// Software unit to timestamp stabilizer ADC samples using an external pounder reference clock.
pub struct Timestamper { pub struct Timestamper {
next_buffer: Option<&'static mut [u16; SAMPLE_BUFFER_SIZE]>, next_buffer: Option<&'static mut [u16; SAMPLE_BUFFER_SIZE]>,
timer: timers::PounderTimestampTimer, timer: timers::PounderTimestampTimer,
@ -20,6 +47,21 @@ pub struct Timestamper {
} }
impl Timestamper { impl Timestamper {
/// Construct the pounder sample timestamper.
///
/// # Note
/// The DMA is immediately configured after instantiation. It will not collect any samples
/// until the sample timer begins to cause input capture triggers.
///
/// # Args
/// * `timestamp_timer` - The timer peripheral used for capturing timestamps from.
/// * `stream` - The DMA stream to use for collecting timestamps.
/// * `capture_channel` - The input capture channel for collecting timestamps.
/// * `sampling_timer` - The stabilizer ADC sampling timer.
/// * `_clock_input` - The input pin for the external clock from Pounder.
///
/// # Returns
/// The new pounder timestamper in an operational state.
pub fn new( pub fn new(
mut timestamp_timer: timers::PounderTimestampTimer, mut timestamp_timer: timers::PounderTimestampTimer,
stream: hal::dma::dma::Stream7<hal::stm32::DMA1>, stream: hal::dma::dma::Stream7<hal::stm32::DMA1>,
@ -51,8 +93,8 @@ impl Timestamper {
Transfer::init( Transfer::init(
stream, stream,
input_capture, input_capture,
// Note(unsafe): The BUF[0] and BUF[1] is "owned" by this peripheral. // Note(unsafe): BUF[0] and BUF[1] are "owned" by this peripheral.
// It shall not be used anywhere else in the module. // They shall not be used anywhere else in the module.
unsafe { &mut BUF[0] }, unsafe { &mut BUF[0] },
unsafe { Some(&mut BUF[1]) }, unsafe { Some(&mut BUF[1]) },
config, config,
@ -63,10 +105,14 @@ impl Timestamper {
Self { Self {
timer: timestamp_timer, timer: timestamp_timer,
transfer: data_transfer, transfer: data_transfer,
// Note(unsafe): BUF[2] is "owned" by this peripheral. It shall not be used anywhere
// else in the module.
next_buffer: unsafe { Some(&mut BUF[2]) }, next_buffer: unsafe { Some(&mut BUF[2]) },
} }
} }
/// Update the period of the underlying timestamp timer.
pub fn update_period(&mut self, period: u16) { pub fn update_period(&mut self, period: u16) {
self.timer.set_period_ticks(period); self.timer.set_period_ticks(period);
} }

View File

@ -1,6 +1,7 @@
///! The sampling timer is used for managing ADC sampling and external reference timestamping. ///! The sampling timer is used for managing ADC sampling and external reference timestamping.
use super::hal; use super::hal;
/// The source of an input capture trigger.
#[allow(dead_code)] #[allow(dead_code)]
pub enum CaptureTrigger { pub enum CaptureTrigger {
Input13 = 0b01, Input13 = 0b01,
@ -8,6 +9,7 @@ pub enum CaptureTrigger {
TriggerInput = 0b11, TriggerInput = 0b11,
} }
/// The event that should generate an external trigger from the peripheral.
#[allow(dead_code)] #[allow(dead_code)]
pub enum TriggerGenerator { pub enum TriggerGenerator {
Reset = 0b000, Reset = 0b000,
@ -20,6 +22,7 @@ pub enum TriggerGenerator {
Ch4Compare = 0b111, Ch4Compare = 0b111,
} }
/// Selects the trigger source for the timer peripheral.
#[allow(dead_code)] #[allow(dead_code)]
pub enum TriggerSource { pub enum TriggerSource {
Trigger0 = 0, Trigger0 = 0,
@ -28,6 +31,7 @@ pub enum TriggerSource {
Trigger3 = 0b11, Trigger3 = 0b11,
} }
/// Prescalers for externally-supplied reference clocks.
pub enum Prescaler { pub enum Prescaler {
Div1 = 0b00, Div1 = 0b00,
Div2 = 0b01, Div2 = 0b01,
@ -116,6 +120,8 @@ macro_rules! timer_channels {
self.timer.resume(); self.timer.resume();
} }
/// Configure the timer peripheral to generate a trigger based on the provided
/// source.
#[allow(dead_code)] #[allow(dead_code)]
pub fn generate_trigger(&mut self, source: TriggerGenerator) { pub fn generate_trigger(&mut self, source: TriggerGenerator) {
let regs = unsafe { &*hal::stm32::$TY::ptr() }; let regs = unsafe { &*hal::stm32::$TY::ptr() };
@ -125,6 +131,7 @@ macro_rules! timer_channels {
} }
/// Select a trigger source for the timer peripheral.
#[allow(dead_code)] #[allow(dead_code)]
pub fn set_trigger_source(&mut self, source: TriggerSource) { pub fn set_trigger_source(&mut self, source: TriggerSource) {
let regs = unsafe { &*hal::stm32::$TY::ptr() }; let regs = unsafe { &*hal::stm32::$TY::ptr() };