Skip to content

Access DMA buffered data from RTIC task #171

@jismithc

Description

@jismithc

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions