cancel
Showing results for 
Search instead for 
Did you mean: 

ADC with multiple interrupts

terence-b
Associate II
Posted on October 26, 2012 at 09:46

Is it possible to have more than one ADC interrupt source? Because I am trying to program ADC3 so that the interrupt can be caused both from an end of conversion (EOC) event and from the analogue watchdog (AWD) event. Is this possible?  

9 REPLIES 9
frankmeyer9
Associate II
Posted on October 26, 2012 at 15:40

Of course it's possible.

But apart from distinguishing the cause at the start of the interrupt handler, do not forget to clear the pending-flag.

While the EOC flag is cleared implicitely by reading the ADC->DR register, the others are not.

Semantically, having both the EOC and the AWD interrupt makes not too much sense, you could check the analog limit also when handling an EOC interrupt.

However, dropping EOC for the AWD interrupt makes more sense IMHO. It would significantly reduce interrupt load.

terence-b
Associate II
Posted on November 02, 2012 at 10:02

Good morning!

Thanks for your help. I have managed to achieve this. But yes, you're right, I can do without the AWD by configuring two pins to indicate when I reach my upper and the lower thresholds in the EOC event handler.

Currently, I'm having another problem. I am generating other pulses in the EOC so as to confirm that I have the expected ADC frequency. The resulting frequency is not as expected. In fact, I confirmed that the ADC IRQ Handler is coming into effect even when there is no an EOC or AWD event by generating pulses outside the EOC and AWD blocks. It seems that there is another source causing an ADC interrupt. My supervisor told be that the high ADC frequency (10.5 MHz) might be causing the havoc. Hence he suggested to obtain a lower clocking frequency by using for example Timer 1 as the ADC clock source, since the highest value of APB2 prescaler is only 8. What do you think about this and can you give me some hints? The only think that I think I understood is that TIM_SelectOutputTrigger can be used to configure the timer to clock some other peripheral.

frankmeyer9
Associate II
Posted on November 02, 2012 at 10:22

Thanks for your help. I have managed to achieve this. But yes, you're right, I can do without the AWD by configuring two pins to indicate when I reach my upper and the lower thresholds in the EOC event handler.

I would have skipped the EOC instead, because the AWD interrupt would do the additional work of comparing the ADC input to your threshold ... Currently, I'm having another problem. I am generating other pulses in the EOC so as to ... When you configure the ADC in continuous mode, the sampling frequency (for one channel) depends only on the ADC clock speed, the configured sampling time (ADC_SampleTime_xxxCycles), and the number of channel scanned. This is obviously not what you want. First step is to turn continuous mode off. For low sampling frequencies, you can trigger each sample individually by SW. For higher rates, a timer is the best solution.

/* TIM3 Configuration */
TIM_DeInit (TIM3);
TIM_TimeBaseStructInit (&TIM_TimeBaseStructure);
TIM_OCStructInit (&TIM_OCInitStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 0x4E1; 
// try to get 125 us
TIM_TimeBaseStructure.TIM_Prescaler = 0x2; 
// update rate of 625us (2.560 kHz)
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; 
// at a 16MHz timer clock
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* TIM3 TRGO selection */
TIM_SelectOutputTrigger (TIM3, TIM_TRGOSource_Update);
/* -------- ADC1 Configuration -------- */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; 
/* Don't do continuous conversions - do them on demand */
/* trigger on Timer 3 instead */
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; 
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
/* 12 bit, right aligned */
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init (ADC1, &ADC_InitStructure);
/* ADC Ch10 ... CH13 configuration */
ADC_ChannelConfig (ADC1, ADC_Channel_10, ADC_SampleTime_28_5Cycles);
ADC_ChannelConfig (ADC1, ADC_Channel_11, ADC_SampleTime_28_5Cycles);
ADC_ChannelConfig (ADC1, ADC_Channel_12, ADC_SampleTime_28_5Cycles);
ADC_ChannelConfig (ADC1, ADC_Channel_13, ADC_SampleTime_28_5Cycles);
/* configure one transfer after each conversion sequence, and enable */
#ifdef DMA_INT_ON_EOT
ADC_DMARequestModeConfig (ADC1, ADC_DMAMode_Circular);
ADC_DMACmd (ADC1, ENABLE);
#endif
/* Enable DMA1 Channel Transfer Complete interrupt */
#ifdef DMA_INT_ON_EOT
DMA_ITConfig (DMA1_Channel1, DMA_IT_TC, ENABLE);
#else
ADC_ITConfig (ADC1, ADC_IT_EOC, ENABLE); 
/* ADC Interrupt enable */
// ADC_ITConfig (ADC1, ADC_IT_EOC | ADC_IT_EOSEQ, ENABLE); /* ADC Interrupt enable, alternatively... */
#endif
/* no explicit calibration required for F0 ADC, load calibration constants */
ADC_GetCalibrationFactor(ADC1);
ADC_Cmd (ADC1, ENABLE); 
/* Enable ADC1 */
while
(!ADC_GetFlagStatus (ADC1, ADC_FLAG_ADEN)); 
/* Wait the ADCEN flag */
TIM_Cmd (TIM3, ENABLE); 
/* TIM3 enable counter */
/* Software Start Conv - enables the selected hardware trigger */
ADC_StartOfConversion(ADC1);

This is example code for the STM32F0, which uses DMA additionally. It contains the configuration to trigger the ADC from a timer, the rest is skipped. For available triggers, you might need to consult the reference manual.
terence-b
Associate II
Posted on November 05, 2012 at 08:55

Good morning!

Thanks a lot. I managed to get TIM1 triggering ADC3. As regards EOC and AWD, I need them both, because in the EOC I'm calculating a voltage level based on the ADC converted value and in the AWD I'm checking that the thresholds are not exceeded (although this can be done in the EOC event handler as already said). But for sure, in my case I need EOC event handler.

Lately I realised that I have another problem, that was present before doing the last modification. The program is getting into the ADC IRQ handler, but its not getting in the EOC block. That is, when I'm checking if there was an EOC by using

 if (ADC_GetITStatus(ADC3, ADC_IT_EOC) != RESET) , it seems that the EOC status bit is never being set. In fact, the pulse I'm generating at the start of the ADC IRQ handler can be visualised on the oscilloscope, while the pulse I'm generating in the EOC block is not being displayed. By this I came to the conclusion that there is something wrong with the EOC status bit.

Regards,

Terence

frankmeyer9
Associate II
Posted on November 05, 2012 at 10:27

If you are in the ADC interrupt routine, there should be some flag set.

Can't you run it in the debugger, and check what flag is set upon entry ? On a F0 example, I used the following code to configure for an EOC interrupt:

/* NVIC ADC interrupt setup */
NVIC_InitStructure.NVIC_IRQChannel = ADC1_COMP_IRQn; 
// ADC1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init (&NVIC_InitStructure);
...
ADC_ITConfig (ADC1, ADC_IT_EOC, ENABLE); 
/* ADC Interrupt enable, */

terence-b
Associate II
Posted on November 06, 2012 at 08:00

Good morning!

Actually I should have everything set right for the ADC. I also enabled the ADC interrupt in the NVIC (like you showed in your last reply). 

My ADC is using the DMA controller, and my supervisor told me that this might be the source of problem. He advised me to use a DMA interrupt instead of ADC interrupt. In fact, now I have created a DMA IRQ handler, and programmed it to occur at every Transfer complete. However, the DMA interrupt is not occuring at the ADC sampling and conversion frequency, but at another frequency.

frankmeyer9
Associate II
Posted on November 06, 2012 at 08:43

However, the DMA interrupt is not occuring at the ADC sampling and conversion frequency, but at another frequency.

 

Of course.

It depends on how you configured your DMA. Cyclic mode makes most sense with the ADC. Usually, one configures an DMA TC interrupt (Transmission Complete), which is triggered after the configured number of items is transferred. And this number of items uses to match the number of channels.

There is a section in the reference manual, dealing with ADC usage in DMA mode, which I recommend to digest

terence-b
Associate II
Posted on November 07, 2012 at 10:31

Good morning!

I've finally managed to get DMA interrupt working correctly. 

What is still unclear is how come without the following, T1_CC1 is still being used as the source of triggering for my ADC:

TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);  //this one was used by you in the code you gave me last week

TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_OC1Ref); //this one was the one I tried to use

Regards,

Terence

frankmeyer9
Associate II
Posted on November 08, 2012 at 09:01

I'm not sure what the problem is.

In reference to the source code posted, I used an example which I adapted to my requirements.  I think I changed the timer unit and the counter/prescaler values for the timer.

It is several weeks ago, but I believe it was from the F0 firmware examples...