TIMer triggers ADC which outputs via DMA just fires its DMA-ISR once
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(); ... }}#tim #dma #adc #stm32f765