stm32-rs / stm32f4xx-hal

A Rust embedded-hal HAL for all MCUs in the STM32 F4 family

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ADC DMA blocked by another interrupt

vinsynth opened this issue · comments

I'm using an STM32F411 chip via WeAct's Blackpill and am trying to read an analog input through one pin while outputting an unrelated PWM signal through another.

The PWM signal is successfully outputted via interrupt TIM1_UP_TIM10().

The ADC can be read over DMA when DMA2_STREAM0() is the only active interrupt. The ADC can also be read directly via the ADC() interrupt while also outputting PWM the same way as before; however, trying to read ADC via DMA2_STREAM0() while outputting PWM apparently blocks the DMA2_STREAM0() interrupt after one cycle (when ADC and its DMA initialized before PWM) or several cycles (when ADC and its DMA initialized after PWM).

Here's the gist of the initialization code:

    // init adc
    let adc_config = adc_cfg::AdcConfig::default()
        .scan(adc_cfg::Scan::Enabled)
        .continuous(adc_cfg::Continuous::Continuous)
        .dma(adc_cfg::Dma::Continuous);
    let mut adc = hal::adc::Adc::adc1(dp.ADC1, true, adc_config);

    let x_pin = gpioa.pa0.into_analog();

    adc.configure_channel(
        &x_pin,
        adc_cfg::Sequence::One,
        adc_cfg::SampleTime::Cycles_480
    );
    adc.enable();

    let dma = hal::dma::StreamsTuple::new(dp.DMA2);
    let dma_config = hal::dma::config::DmaConfig::default()
        .memory_increment(true)
        .fifo_enable(true)
        .fifo_error_interrupt(true)
        .transfer_complete_interrupt(true);

    let buf = cortex_m::singleton!(: [u16; 2] = [0; 2]).unwrap();

    let mut transfer = Transfer::init_peripheral_to_memory(
        dma.0,
        adc,
        buf,
        None,
        dma_config
    );

    unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::DMA2_STREAM0) };
    cs::with(|cs| {
        ADC_TRANS.borrow(cs).replace(Some(transfer));
        ADC_TRANS
            .borrow_ref_mut(cs)
            .as_mut()
            .unwrap()
            .start(|adc| adc.start_conversion())
    });

    // init pwm
    let channel = hal::timer::Channel3::new(gpioa.pa10);
    let mut pwm = dp.TIM1.pwm_hz(channel, 32.kHz(), &clocks);

    pwm.enable(hal::timer::Channel::C3);
    pwm.listen(hal::timer::Event::Update);

    cs::with(|cs| PWM_TIM.borrow(cs).replace(Some(pwm)));
    unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::TIM1_UP_TIM10) };

From looking at this library, I'm under the impression that PWM also leverages DMA; is this causing a conflict, or is there something else I'm missing?