stm32f4xx-hal
stm32f4xx-hal copied to clipboard
DMA Transfer consumes peripheral
Right now there aren't really any examples of both DMA and peripherals using this HAL, so I might be doing something wrong.
I'm able to both build a DMA Transfer
and initiate a peripheral such as the adc using this HAL, but not both at the same time.
// DMA init
let stream_0 = StreamsTuple::new(dp.DMA2).0;
let buf = singleton!(: [u16; 128] = [0; 128]).unwrap();
let dma_config = DmaConfig::default();
let adc_dma_transfer = Transfer::init(stream_0, dp.ADC1, buf, None, dma_config); //<-- consumes dp.ADC1
// adc init
let adc_config = hal::adc::config::AdcConfig::default();
let adc_periph = Adc::adc1(dp.ADC1, true, adc_config); //<-- cannot init this peripheral. ADC1 has already been moved
I haven't dug too much into the DMA
implementation but I don't think it would need ownership of the peripheral.
Reading more into it, I understand I could instead hand the dma Transfer
a copy of its address with something like
unsafe { &*ADC1::ptr() as *const _ as u32 }
But wouldn't it be more elegant for that to happen inside the dma module and not in the application code?
The stm32f1xx-hal
has dma implementations of peripherals within their respective peripheral crate, so this de/referencing happens there. Is that an approach this HAL is looking to move toward?
The idea is to implement the necessary abstraction and traits to the Adc HAL type, and pass it to the Transfer
API instead of the pac type. It seems that this was done already for serial, but other peripherals are still missing.
I just had a look: as of now (0.10.1) the Adc traits seem to be implemented for at least ADC1; nevertheless, the adc hal types are consumed themselves. This renders the calibration data inaccessible, as can be seen in the adc_dma example. The peripheral in the Transfer structs is passed as &mut to the closures of start,pause, so I don't think we get around that.
A way to fix this special issue could be to expose a reference to the peripheral. This allows us to use for example adc.sample_to_millivolts() wherever the sampled values are consumed.