AnsweredAssumed Answered

TIMer triggers ADC which outputs via DMA just fires its DMA-ISR once

Question asked by Gahlen Feld on Jul 14, 2017
Latest reply on Jul 17, 2017 by Gahlen Feld

Hello,

 

in my STM32F765 project I am using a timer (TIM6) which is set to a constant frequency. The update event of the timer triggers an ADC (ADC2&3) which is configured to start conversion of a regular group of channels on the TRGO of the timer.

DMA2Stream2_IrqHandler clears the TC&HT flags of both DMA2-Streams (2&0) but is called only once and then never again.

I have done any number of combinations for different ADC/DMA settings but it behaves always the same. I suspect the DMA controller but I did not got it working right. Can somebody give me a hint, please?

 

Thank you in  advance,

Gahlen

 

Here is my code for configuring the hardware:

void Timer6::Init(void) {
    hardware.rcc.EnableClock(APB1, RCC_APB1ENR_TIM6EN);
        hardware.timer.SetPrescaler   (TIM6, prescaler-1);
        hardware.timer.SetPeriod      (TIM6, period-1);
        hardware.timer.SetMasterMode  (TIM6, TIMER_MASTER_MODE_UPDATE); // TRGO on update event
}

void Timer6::Start(void) { // initiates the Adc conversion
    hardware.timer.Enable(TIM6);
}

void Adc::GeneralConfig(void) {
    EnableDigitalClock();
    SetAnalogClock(ADC_APB2_DIV4); // => 27MHz (1.8MS/s max.)
    SetResolution(ADC_RESOLUTION_12BIT);
    if ((adc_number == 2) || (adc_number == 3)) {
        SetExternalRegularTrigger(ADC_TRIGGER_RISING);
        SetExternalRegularTriggerSource(ADC_EXTERNAL_TRIGGER_REGULAR_TIM6_TRGO); // ADC1 is triggered manually in systemick ISR
    }
    SetAlignmentRight();
    ClearContinuousMode(); // look at application note AN3116 for selection of ADC modes
    ClearDiscontinuousMode();
    SetScanMode();         // in this mode the ADC converts all channels of the group one time until it is retriggered by timer6 for the next group of conversion
    //ClearScanMode();
    SetEocForSequence();
}

void Adc::GpioConfig(void) {
    GPIO_TypeDef* gpio;

    for (u16 i=0; i<number_of_channels; i++) {
        gpio = config->channel_sequence[i].gpio;
        if (gpio != (GPIO_TypeDef*)0) hardware.gpio.InitPin(gpio, (GpioPinNumberType)Position(config->channel_sequence[i].pin), GPIO_MODE_ANALOG);
    }
}

void Adc::DmaConfig(void) {
    DMA_TypeDef*   dma    = config->dma.hardware;
    DmaStreamsType stream = config->dma.stream;

    SetContinuousDMA(); // ADCn DMA is running continuously on every sampled value
    //SetSingleGroupDMA();
    hardware.rcc.EnableClock (AHB1, RCC_AHB1ENR_DMA2EN);
    hardware.dma.SetChannel  (dma, stream, config->dma.channel);
    hardware.dma.SetPriority (dma, stream, config->dma.priority);
    hardware.dma.SetMode     (dma, stream, config->dma.mode);
    hardware.dma.SetDirection(dma, stream, DMA_PERIPH2MEMORY);
    hardware.dma.SetIncrement(dma, stream, DMA_PERIPHERAL_INCREMENT_NONE, DMA_MEMORY_INCREMENT);
    hardware.dma.SetDataSize (dma, stream, DMA_PERIPHERAL_SIZE_16BIT, DMA_MEMORY_SIZE_16BIT);
    hardware.dma.EnableIrq   (dma, stream, DMA_IRQ_TRANSFER_COMPLETE);
    hardware.dma.SetLength   (dma, stream, number_of_channels);
    hardware.dma.SetAddresses(dma, stream, (u32)&adc->DR, (u32)dma_memory);
    hardware.dma.EnableStream(dma, stream);
    if (config->irq.priority != IRQ_PRIORITY_NONE) hardware.cortex_m.nvic.InitIrq(config->irq.line, config->irq.priority, ENABLE);
}

void Adc::ChannelsConfig(void) {
    u16 i;

    for (i=0; i<number_of_channels; i++) {
        AdcChannelType channel = config->channel_sequence[i].adc_input_channel;
        SetSampleTime(channel, config->channel_sequence[i].sampletime);
        SetRegularSequenceChannel((AdcSequenceType)i, channel);
        if ((adc_number == 1) && ((channel == ADC_CHANNEL17) || (channel == ADC_CHANNEL18))) EnableTemperatureAndBandgapMeasurement();
    }
    SetRegularSequenceLength(i);
}

void Adc::Start(void) {
    switch (adc_number) {
        case 2  :
        case 3  : hardware.timer6.Start();
            break;
        default :                          break;
    }
}

void Adc::Init(ADC_TypeDef* ADCx) {
...
    DisableDMA();
    Disable();
    GpioConfig();
    DmaConfig();
    GeneralConfig();
    ChannelsConfig();
    Enable();
    EnableDMA();
    
    Start();
}

void DMA2_Stream2_IRQHandler(void) {
    if (hardware.dma.GetFlagStatus(DMA2, DMA_STREAM_2, DMA_FLAG_TRANSFER_COMPLETE)) {
        ClearDma2Stream2TcFlag(); // this is mandatory
        ClearDma2Stream0TcFlag();
        ...
    }
}

Outcomes