diff --git a/bluepill-rs/src/dmx.rs b/bluepill-rs/src/dmx.rs index d5cbba8..8823699 100644 --- a/bluepill-rs/src/dmx.rs +++ b/bluepill-rs/src/dmx.rs @@ -1,57 +1,142 @@ -use cortex_m::singleton; -use stm32f1xx_hal::{dma, pac, prelude::*, rcc, serial}; +use stm32f1xx_hal::{afio, dma, gpio, pac, prelude::*, rcc, serial}; -const DMX_LEN_MAX: usize = 512; type TxDma = dma::TxDma, dma::dma1::C4>; type DMXUniverse = &'static mut [u8; DMX_LEN]; type DMXTransfer = dma::Transfer, TxDma>; -pub enum DMX { - Idle(Option, Option>), - Busy(Option>), +struct TxDMAIdle { + tx: TxDma, + buffer: DMXUniverse, +} + +struct TxDMABusy { + transfer: DMXTransfer, +} + +enum TxDMA { + Idle(Option>), + Busy(Option>), +} + +impl TxDMA { + fn new(tx: TxDma, buffer: DMXUniverse) -> Self { + TxDMA::Idle(Some(TxDMAIdle { tx, buffer })) + } + + fn start_sending(&mut self, tx_universe: &[u8]) { + let TxDMA::Idle(idle) = self else { + return; + }; + + let Some(TxDMAIdle { tx, buffer }) = idle.take() else { + panic!(); + }; + + buffer.copy_from_slice(tx_universe); + *self = TxDMA::Busy(Some(TxDMABusy { + transfer: tx.write(buffer), + })); + } + + fn wait(&mut self) { + let TxDMA::Busy(busy) = self else { + return; + }; + + let Some(TxDMABusy { transfer }) = busy.take() else { + panic!(); + }; + + let (buffer, tx) = transfer.wait(); + + *self = TxDMA::Idle(Some(TxDMAIdle { tx, buffer })); + } + + fn is_idle(&mut self) -> bool { + match self { + TxDMA::Idle(_) => true, + + TxDMA::Busy(busy) => { + let Some(TxDMABusy { transfer }) = busy.take() else { + panic!(); + }; + + let is_done = transfer.is_done(); + busy.replace(TxDMABusy { transfer }); + if is_done { + self.wait(); + } + + is_done + } + } + } +} + +#[allow(clippy::upper_case_acronyms)] +pub struct DMX { + tx_universe: DMXUniverse, + sender: TxDMA, } impl DMX { - pub fn new( - mut serial: serial::Serial, - channel: dma::dma1::C4, + pub fn new( + mem: &'static mut [u8], + mut dma_channel: dma::dma1::C4, + pa9: gpio::PA9, + pa10: gpio::PA10, + acrh: &mut gpio::Cr<'A', true>, + mapr: &mut afio::MAPR, clocks: &rcc::Clocks, - ) -> Self - where - PINS: serial::Pins, - { - assert!(DMX_LEN <= DMX_LEN_MAX); + ) -> Self { + // use provided memory region + assert!(mem.len() >= DMX_LEN * 2); - serial.reconfigure(250_000.bps(), &clocks).unwrap(); + let (tx_universe, tx_buffer) = { + let (tx_universe, rest) = mem.split_at_mut(DMX_LEN); + let (tx_buffer, _) = rest.split_at_mut(DMX_LEN); - Self::Idle(Some(serial.tx.with_dma(channel)), None) - } + let tx_universe: DMXUniverse = tx_universe.try_into().unwrap(); + let tx_buffer: DMXUniverse = tx_buffer.try_into().unwrap(); - pub fn send(&mut self, data: &[u8]) { - if let Self::Busy(_) = self { - self.wait(); - } - - let Self::Idle(tx, txbuffer) = self else { - panic!("Broken DMX State!") + (tx_universe, tx_buffer) }; - let txbuffer = txbuffer.take().unwrap_or_else(|| { - let foo = singleton!(: [u8; DMX_LEN_MAX] = [0u8; DMX_LEN_MAX]).unwrap(); - (&mut foo[..DMX_LEN]).try_into().unwrap() - }); - let tx = tx.take().unwrap(); + // setup DMA1_CHANNEL4 interrupt on TransferComplete + dma_channel.listen(dma::Event::TransferComplete); + unsafe { + pac::CorePeripherals::steal() + .NVIC + .set_priority(pac::Interrupt::DMA1_CHANNEL4, 1); + } - txbuffer.copy_from_slice(&data[..DMX_LEN]); - *self = Self::Busy(Some(tx.write(txbuffer))); + // Serial config + let serial = serial::Serial::new( + unsafe { pac::Peripherals::steal() }.USART1, + ( + pa9.into_alternate_open_drain(acrh), + pa10, //.into_pull_up_input(acrh), + ), + mapr, + 250_000.bps(), + clocks, + ); + + Self { + tx_universe, + sender: TxDMA::new(serial.tx.with_dma(dma_channel), tx_buffer), + } } - pub fn wait(&mut self) { - let Self::Busy(xfer) = self else { return }; + pub fn start_tx(&mut self) { + self.sender.start_sending(self.tx_universe); + } - let xfer = xfer.take().unwrap(); - let (txbuffer, tx) = xfer.wait(); + pub fn wait_tx(&mut self) { + self.sender.wait(); + } - *self = Self::Idle(Some(tx), Some(txbuffer)); + pub fn tx_is_idle(&mut self) -> bool { + self.sender.is_idle() } } diff --git a/bluepill-rs/src/dmx2.rs b/bluepill-rs/src/dmx2.rs deleted file mode 100644 index 8823699..0000000 --- a/bluepill-rs/src/dmx2.rs +++ /dev/null @@ -1,142 +0,0 @@ -use stm32f1xx_hal::{afio, dma, gpio, pac, prelude::*, rcc, serial}; - -type TxDma = dma::TxDma, dma::dma1::C4>; -type DMXUniverse = &'static mut [u8; DMX_LEN]; -type DMXTransfer = dma::Transfer, TxDma>; - -struct TxDMAIdle { - tx: TxDma, - buffer: DMXUniverse, -} - -struct TxDMABusy { - transfer: DMXTransfer, -} - -enum TxDMA { - Idle(Option>), - Busy(Option>), -} - -impl TxDMA { - fn new(tx: TxDma, buffer: DMXUniverse) -> Self { - TxDMA::Idle(Some(TxDMAIdle { tx, buffer })) - } - - fn start_sending(&mut self, tx_universe: &[u8]) { - let TxDMA::Idle(idle) = self else { - return; - }; - - let Some(TxDMAIdle { tx, buffer }) = idle.take() else { - panic!(); - }; - - buffer.copy_from_slice(tx_universe); - *self = TxDMA::Busy(Some(TxDMABusy { - transfer: tx.write(buffer), - })); - } - - fn wait(&mut self) { - let TxDMA::Busy(busy) = self else { - return; - }; - - let Some(TxDMABusy { transfer }) = busy.take() else { - panic!(); - }; - - let (buffer, tx) = transfer.wait(); - - *self = TxDMA::Idle(Some(TxDMAIdle { tx, buffer })); - } - - fn is_idle(&mut self) -> bool { - match self { - TxDMA::Idle(_) => true, - - TxDMA::Busy(busy) => { - let Some(TxDMABusy { transfer }) = busy.take() else { - panic!(); - }; - - let is_done = transfer.is_done(); - busy.replace(TxDMABusy { transfer }); - if is_done { - self.wait(); - } - - is_done - } - } - } -} - -#[allow(clippy::upper_case_acronyms)] -pub struct DMX { - tx_universe: DMXUniverse, - sender: TxDMA, -} - -impl DMX { - pub fn new( - mem: &'static mut [u8], - mut dma_channel: dma::dma1::C4, - pa9: gpio::PA9, - pa10: gpio::PA10, - acrh: &mut gpio::Cr<'A', true>, - mapr: &mut afio::MAPR, - clocks: &rcc::Clocks, - ) -> Self { - // use provided memory region - assert!(mem.len() >= DMX_LEN * 2); - - let (tx_universe, tx_buffer) = { - let (tx_universe, rest) = mem.split_at_mut(DMX_LEN); - let (tx_buffer, _) = rest.split_at_mut(DMX_LEN); - - let tx_universe: DMXUniverse = tx_universe.try_into().unwrap(); - let tx_buffer: DMXUniverse = tx_buffer.try_into().unwrap(); - - (tx_universe, tx_buffer) - }; - - // setup DMA1_CHANNEL4 interrupt on TransferComplete - dma_channel.listen(dma::Event::TransferComplete); - unsafe { - pac::CorePeripherals::steal() - .NVIC - .set_priority(pac::Interrupt::DMA1_CHANNEL4, 1); - } - - // Serial config - let serial = serial::Serial::new( - unsafe { pac::Peripherals::steal() }.USART1, - ( - pa9.into_alternate_open_drain(acrh), - pa10, //.into_pull_up_input(acrh), - ), - mapr, - 250_000.bps(), - clocks, - ); - - Self { - tx_universe, - sender: TxDMA::new(serial.tx.with_dma(dma_channel), tx_buffer), - } - } - - pub fn start_tx(&mut self) { - self.sender.start_sending(self.tx_universe); - } - - pub fn wait_tx(&mut self) { - self.sender.wait(); - } - - pub fn tx_is_idle(&mut self) -> bool { - self.sender.is_idle() - } -} diff --git a/bluepill-rs/src/main.rs b/bluepill-rs/src/main.rs index 1105167..2a26297 100644 --- a/bluepill-rs/src/main.rs +++ b/bluepill-rs/src/main.rs @@ -4,15 +4,14 @@ // mod i2c_reg_slave; // mod i2c_slave; -// mod dmx; -mod dmx2; +mod dmx; // extern crate panic_halt; extern crate panic_semihosting; #[rtic::app(device = stm32f1xx_hal::pac, dispatchers = [SPI1, SPI2, SPI3])] mod app { - use crate::dmx2::DMX; + use crate::dmx::DMX; use stm32f1xx_hal::{ gpio::{self, ExtiPin}, pac,