From d236ea94c476aa74edcfee1985134d098daa954c Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 24 Nov 2020 17:21:14 +0100 Subject: [PATCH] Updating DAC SPI structures to own HAL SPI structure for safety guarantees --- src/adc.rs | 2 ++ src/dac.rs | 81 +++++++++++++++++++++++++++--------------------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/adc.rs b/src/adc.rs index 9b2c53b..552d210 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -307,6 +307,8 @@ impl Adc1Input { Transfer::init( trigger_stream, SPI3::new(trigger_channel), + // Note(unsafe). This transaction is read-only and SPI_START is a dont-care value, + // so it is always safe to share. unsafe { &mut SPI_START }, None, trigger_config, diff --git a/src/dac.rs b/src/dac.rs index c567bf2..89a31bf 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -24,19 +24,24 @@ static mut DAC1_BUF0: [u16; SAMPLE_BUFFER_SIZE] = [0; SAMPLE_BUFFER_SIZE]; #[link_section = ".axisram.buffers"] static mut DAC1_BUF1: [u16; SAMPLE_BUFFER_SIZE] = [0; SAMPLE_BUFFER_SIZE]; -/// SPI4 is used as a ZST (zero-sized type) for indicating a DMA transfer into the SPI4 TX FIFO +/// SPI4 is used as a type for indicating a DMA transfer into the SPI4 TX FIFO struct SPI4 { + spi: hal::spi::Spi, _channel: sampling_timer::tim2::Channel3, } + impl SPI4 { - pub fn new(_channel: sampling_timer::tim2::Channel3) -> Self { - Self { _channel } + pub fn new( + _channel: sampling_timer::tim2::Channel3, + spi: hal::spi::Spi, + ) -> Self { + Self { _channel, spi } } } // Note(unsafe): This is safe because the DMA request line is logically owned by this module. -// Additionally, it is only safe if the SPI TX functionality is never used, which is managed by the -// Dac0Output. +// Additionally, the SPI is owned by this structure and is known to be configured for u16 word +// sizes. unsafe impl TargetAddress for SPI4 { /// SPI2 is configured to operate using 16-bit transfer words. type MemSize = u16; @@ -46,25 +51,28 @@ unsafe impl TargetAddress for SPI4 { /// Whenever the DMA request occurs, it should write into SPI4's TX FIFO. fn address(&self) -> u32 { - // Note(unsafe): This is only safe as long as no other users write to the SPI TX FIFO. - let regs = unsafe { &*hal::stm32::SPI4::ptr() }; - ®s.txdr as *const _ as u32 + &self.spi.inner().txdr as *const _ as u32 } } /// SPI5 is used as a ZST (zero-sized type) for indicating a DMA transfer into the SPI5 TX FIFO struct SPI5 { _channel: sampling_timer::tim2::Channel4, + spi: hal::spi::Spi, } + impl SPI5 { - pub fn new(_channel: sampling_timer::tim2::Channel4) -> Self { - Self { _channel } + pub fn new( + _channel: sampling_timer::tim2::Channel4, + spi: hal::spi::Spi, + ) -> Self { + Self { _channel, spi } } } // Note(unsafe): This is safe because the DMA request line is logically owned by this module. -// Additionally, it is only safe if the SPI TX functionality is never used, which is managed by the -// Dac1Output. +// Additionally, the SPI is owned by this structure and is known to be configured for u16 word +// sizes. unsafe impl TargetAddress for SPI5 { /// SPI5 is configured to operate using 16-bit transfer words. type MemSize = u16; @@ -74,9 +82,7 @@ unsafe impl TargetAddress for SPI5 { /// Whenever the DMA request occurs, it should write into SPI5's TX FIFO fn address(&self) -> u32 { - // Note(unsafe): This is only safe as long as no other users write to the SPI TX FIFO. - let regs = unsafe { &*hal::stm32::SPI5::ptr() }; - ®s.txdr as *const _ as u32 + &self.spi.inner().txdr as *const _ as u32 } } @@ -121,7 +127,6 @@ impl DacOutputs { pub struct Dac0Output { next_buffer: Option<&'static mut [u16; SAMPLE_BUFFER_SIZE]>, // Note: SPI TX functionality may not be used from this structure to ensure safety with DMA. - _spi: hal::spi::Spi, transfer: Transfer< hal::dma::dma::Stream4, SPI4, @@ -153,16 +158,6 @@ impl Dac0Output { .memory_increment(true) .peripheral_increment(false); - // Construct the trigger stream to write from memory to the peripheral. - let transfer: Transfer<_, _, MemoryToPeripheral, _> = Transfer::init( - stream, - SPI4::new(trigger_channel), - // Note(unsafe): This buffer is only used once and provided for the DMA transfer. - unsafe { &mut DAC0_BUF0 }, - None, - trigger_config, - ); - // Listen for any potential SPI error signals, which may indicate that we are not generating // update codes. let mut spi = spi.disable(); @@ -175,11 +170,20 @@ impl Dac0Output { spi.inner().cr1.modify(|_, w| w.spe().set_bit()); spi.inner().cr1.modify(|_, w| w.cstart().started()); + // Construct the trigger stream to write from memory to the peripheral. + let transfer: Transfer<_, _, MemoryToPeripheral, _> = Transfer::init( + stream, + SPI4::new(trigger_channel, spi), + // Note(unsafe): This buffer is only used once and provided for the DMA transfer. + unsafe { &mut DAC0_BUF0 }, + None, + trigger_config, + ); + Self { transfer, // Note(unsafe): This buffer is only used once and provided for the next DMA transfer. next_buffer: unsafe { Some(&mut DAC0_BUF1) }, - _spi: spi, first_transfer: true, } } @@ -216,8 +220,6 @@ impl Dac0Output { /// Represents the data output stream from DAC1. pub struct Dac1Output { next_buffer: Option<&'static mut [u16; SAMPLE_BUFFER_SIZE]>, - // Note: SPI TX functionality may not be used from this structure to ensure safety with DMA. - _spi: hal::spi::Spi, transfer: Transfer< hal::dma::dma::Stream5, SPI5, @@ -250,16 +252,6 @@ impl Dac1Output { .peripheral_increment(false) .circular_buffer(true); - // Construct the stream to write from memory to the peripheral. - let transfer: Transfer<_, _, MemoryToPeripheral, _> = Transfer::init( - stream, - SPI5::new(trigger_channel), - // Note(unsafe): This buffer is only used once and provided to the transfer. - unsafe { &mut DAC1_BUF0 }, - None, - trigger_config, - ); - // Listen for any SPI errors, as this may indicate that we are not generating updates on the // DAC. let mut spi = spi.disable(); @@ -272,11 +264,20 @@ impl Dac1Output { spi.inner().cr1.modify(|_, w| w.spe().set_bit()); spi.inner().cr1.modify(|_, w| w.cstart().started()); + // Construct the stream to write from memory to the peripheral. + let transfer: Transfer<_, _, MemoryToPeripheral, _> = Transfer::init( + stream, + SPI5::new(trigger_channel, spi), + // Note(unsafe): This buffer is only used once and provided to the transfer. + unsafe { &mut DAC1_BUF0 }, + None, + trigger_config, + ); + Self { // Note(unsafe): This buffer is only used once and provided for the next DMA transfer. next_buffer: unsafe { Some(&mut DAC1_BUF1) }, transfer, - _spi: spi, first_transfer: true, } }