-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Hi I'm new to rust and stm32s so please bare with me.
Main issue: I cannot find a way to access buffered data from a RTIC task triggered by a DMA transfer complete interrupt.
Preferred functionality from a stm32f4xx_hal example - https://github.com/stm32-rs/stm32f4xx-hal/blob/master/examples/rtic-adc-dma.rs
This example configures DMA to trigger an interrupt when its buffer is full (in this case a quantity of 2).
transfer
is set as a shared variable, and given a &'static mut [u16; 2]
buffer to fill.
In the dma
interrupt task (triggered when the first buffer is full), the task locks shared.transfer, and (from what I understand) passes ownership of the filled buffer from the transfer to the interrupt task, replacing it with a second buffer.
let (buffer, _) = transfer
.next_transfer(local.buffer.take().unwrap())
.unwrap();
I have attempted to do something similar with stm32g4xx_hal without success. There is no next_trasfer()
available.
I am not necessarily requiring a double buffer strategy, but simply a way to access the full buffer's data from the interrupt task utilizing the tools provided from this hal, avoiding unsafe blocks.
Side note:
I have developed a somewhat usable way using unsafe blocks to access static mut
array. This is not my preferred method.
In fact, rustc gives me this warning warning: creating a mutable reference to mutable static is discouraged
.
const BUFFER_SIZE: usize = 200;
type AdcDma = CircTransfer<
Stream0<stm32g4xx_hal::stm32::DMA1>,
Adc<stm32g4xx_hal::stm32::ADC1, DMA>,
&'static mut [u16; BUFFER_SIZE],
>;
#[app(device = stm32g4xx_hal::stm32, dispatchers = [EXTI0])]
mod app {
...
#[local]
struct Local {
...
adc_dma: AdcDma,
adc_buffer: &'static mut [u16; BUFFER_SIZE],
}
#[init]
fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) {
let dma_streams = dp.DMA1.split(&mut rcc);
let config = DmaConfig::default()
.transfer_complete_interrupt(true)
.circular_buffer(true)
.memory_increment(true)
.peripheral_increment(false); // Don't increment peripheral address
// 4) Prepare a buffer for the ADC samples
static mut ADC_BUFFER: [u16; BUFFER_SIZE] = [0; BUFFER_SIZE];
// Initialize ADC with delay for proper initialization timing
let mut adc_controller =
adc::AdcController::new(dp.ADC1, board_pins.adc1, &mut rcc, dma_streams, delay);
// Enable ADC DMA with local buffer
let (adc_dma_enabled, stream) = adc_controller.enable_dma();
let mut adc_dma = unsafe {
stream.into_circ_peripheral_to_memory_transfer(adc_dma_enabled, &mut ADC_BUFFER, config)
};
// Start DMA transfer and ADC conversion
adc_dma.start(|adc| adc.start_conversion());
(
Local {
adc_dma: adc_dma,
adc_buffer: unsafe { &mut ADC_BUFFER },
},
init::Monotonics(mono),
)
}
#[task(binds = DMA1_CH1, local = [adc_dma, adc_buffer])]
fn dma_isr(ctx: dma_isr::Context) {
if adc_dma.get_transfer_complete_flag() {
process_samples(&ctx.local.adc_buffer[BUFFER_SIZE / 2..]);
}
}
}
// From another local file.
pub fn enable_dma(&mut self) -> (Adc<ADC1, DMA>, Stream0<DMA1>) {
// Take ownership of ADC and stream
let adc = self.adc.take().unwrap();
let stream = self.stream.take().unwrap();
// Enable DMA mode first, then enable ADC
let adc_dma = adc.enable_dma(AdcDma::Continuous);
(adc_dma, stream)
}
Is there already a supported way to access the dma buffer data? Or is this functionality lacking.
Thanks for the help!