From adaca88a50e11cd98899d0269f18e9ca8867eb57 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Tue, 3 Nov 2020 09:41:14 +0100 Subject: [PATCH] Adding ADC/DAC modules --- src/adc.rs | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dac.rs | 64 ++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 src/adc.rs create mode 100644 src/dac.rs diff --git a/src/adc.rs b/src/adc.rs new file mode 100644 index 0000000..15d2f63 --- /dev/null +++ b/src/adc.rs @@ -0,0 +1,187 @@ +use super::{hal, DmaConfig, PeripheralToMemory, MemoryToPeripheral, TargetAddress, Transfer, DMAReq, +Stream}; + +const INPUT_BUFFER_SIZE: usize = 1; + +#[link_section = ".axisram.buffers"] +static mut SPI_START: [u16; 1] = [0x00]; + +#[link_section = ".axisram.buffers"] +static mut ADC0_BUF0: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; + +#[link_section = ".axisram.buffers"] +static mut ADC0_BUF1: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; + +#[link_section = ".axisram.buffers"] +static mut ADC1_BUF0: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; + +#[link_section = ".axisram.buffers"] +static mut ADC1_BUF1: [u16; INPUT_BUFFER_SIZE] = [0; INPUT_BUFFER_SIZE]; + +struct SPI2 {} + +impl SPI2 { + pub fn new() -> Self { + Self {} + } +} + +unsafe impl TargetAddress for SPI2 { + type MemSize = u16; + + const REQUEST_LINE: Option = Some(DMAReq::TIM2_UP as u8); + + fn address(&self) -> u32 { + let regs = unsafe { &*hal::stm32::SPI2::ptr() }; + ®s.txdr as *const _ as u32 + } +} + +struct SPI3 {} + +impl SPI3 { + pub fn new() -> Self { + Self {} + } +} + +unsafe impl TargetAddress for SPI3 { + type MemSize = u16; + + const REQUEST_LINE: Option = Some(DMAReq::TIM2_UP as u8); + + fn address(&self) -> u32 { + let regs = unsafe { &*hal::stm32::SPI3::ptr() }; + ®s.txdr as *const _ as u32 + } +} + +pub struct Adc0Input { + next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>, + transfer: Transfer< + hal::dma::dma::Stream1, + hal::spi::Spi, + PeripheralToMemory, + &'static mut [u16; INPUT_BUFFER_SIZE]>, +} + +impl Adc0Input { + pub fn new( + spi: hal::spi::Spi, + trigger_stream: hal::dma::dma::Stream0, + data_stream: hal::dma::dma::Stream1, + ) -> Self { + let trigger_config = DmaConfig::default() + .memory_increment(false) + .peripheral_increment(false) + .circular_buffer(true); + + let mut trigger_transfer: Transfer<_, _, MemoryToPeripheral, _ > = Transfer::init( + trigger_stream, + &SPI2::new(), + unsafe { &mut SPI_START }, + None, + trigger_config); + + let data_config = DmaConfig::default() + .memory_increment(true) + .transfer_complete_interrupt(true) + .peripheral_increment(false); + + let mut spi = spi.disable(); + spi.listen(hal::spi::Event::Error); + + let mut data_transfer: Transfer<_, _, PeripheralToMemory, _ > = Transfer::init( + data_stream, + &spi, + unsafe { &mut ADC0_BUF0 }, + None, + data_config); + + spi.enable_dma_rx(); + spi.enable_dma_tx(); + + let spi = spi.enable(); + spi.inner().cr1.modify(|_, w| w.cstart().started()); + + data_transfer.start(); + trigger_transfer.start(); + + Self { + next_buffer: unsafe { Some(&mut ADC0_BUF1) }, + transfer: data_transfer, + } + } + + pub fn transfer_complete_handler(&mut self) -> &[u16; INPUT_BUFFER_SIZE] { + let next_buffer = self.next_buffer.take().unwrap(); + let (prev_buffer, _) = self.transfer.next_transfer(next_buffer).unwrap(); + self.next_buffer.replace(prev_buffer); + self.next_buffer.as_ref().unwrap() + } +} + +pub struct Adc1Input { + next_buffer: Option<&'static mut [u16; INPUT_BUFFER_SIZE]>, + transfer: Transfer< + hal::dma::dma::Stream3, + hal::spi::Spi, + PeripheralToMemory, + &'static mut [u16; INPUT_BUFFER_SIZE]>, +} + +impl Adc1Input { + pub fn new( + spi: hal::spi::Spi, + trigger_stream: hal::dma::dma::Stream2, + data_stream: hal::dma::dma::Stream3, + ) -> Self { + let trigger_config = DmaConfig::default() + .memory_increment(false) + .peripheral_increment(false) + .circular_buffer(true); + + let mut trigger_transfer: Transfer<_, _, MemoryToPeripheral, _ > = Transfer::init( + trigger_stream, + &SPI3::new(), + unsafe { &mut SPI_START }, + None, + trigger_config); + + let data_config = DmaConfig::default() + .memory_increment(true) + .transfer_complete_interrupt(true) + .peripheral_increment(false); + + let mut spi = spi.disable(); + spi.listen(hal::spi::Event::Error); + + let mut data_transfer: Transfer<_, _, PeripheralToMemory, _ > = Transfer::init( + data_stream, + &spi, + unsafe { &mut ADC1_BUF0 }, + None, + data_config); + + spi.enable_dma_rx(); + spi.enable_dma_tx(); + + let spi = spi.enable(); + spi.inner().cr1.modify(|_, w| w.cstart().started()); + + data_transfer.start(); + trigger_transfer.start(); + + Self { + next_buffer: unsafe { Some(&mut ADC1_BUF1) }, + transfer: data_transfer, + } + } + + pub fn transfer_complete_handler(&mut self) -> &[u16; INPUT_BUFFER_SIZE] { + let next_buffer = self.next_buffer.take().unwrap(); + let (prev_buffer, _) = self.transfer.next_transfer(next_buffer).unwrap(); + self.next_buffer.replace(prev_buffer); + self.next_buffer.as_ref().unwrap() + } +} diff --git a/src/dac.rs b/src/dac.rs new file mode 100644 index 0000000..fb5f4ab --- /dev/null +++ b/src/dac.rs @@ -0,0 +1,64 @@ + +use super::hal; +use heapless::consts; + +pub struct Dac0Output { + outputs: heapless::spsc::Queue, + spi: hal::spi::Spi, +} + +impl Dac0Output { + pub fn new(spi: hal::spi::Spi) -> Self { + spi.inner().cr1.modify(|_, w| w.cstart().started()); + Self { spi, outputs: heapless::spsc::Queue::new() } + } + + pub fn push(&mut self, value: u16) { + self.outputs.enqueue(value).unwrap(); + } + + pub fn update(&mut self) { + match self.outputs.dequeue() { + Some(value) => self.write(value), + None => {}, + } + } + + pub fn write(&mut self, value: u16) { + unsafe { + core::ptr::write_volatile(&self.spi.inner().txdr as *const _ as *mut u16, value); + } + } +} + +pub struct Dac1Output { + outputs: heapless::spsc::Queue, + spi: hal::spi::Spi, +} + +impl Dac1Output { + pub fn new( + spi: hal::spi::Spi, + ) -> Self { + spi.inner().cr1.modify(|_, w| w.cstart().started()); + + Self { spi, outputs: heapless::spsc::Queue::new() } + } + + pub fn push(&mut self, value: u16) { + self.outputs.enqueue(value).unwrap(); + } + + pub fn update(&mut self) { + match self.outputs.dequeue() { + Some(value) => self.write(value), + None => {}, + } + } + + pub fn write(&mut self, value: u16) { + unsafe { + core::ptr::write_volatile(&self.spi.inner().txdr as *const _ as *mut u16, value); + } + } +}