STM32, ADCs, Timing Problem

Started by Mike Kaufmann October 9, 2009
Hello Everyone,

these days I encountered a serious timing problem using the ADCs, twice.
Because of this the ADC interrupt used up all computing power, leading
to a not or *very* slow running application and, if activated, a
watchdog reset.

What happend:
The first time the error occured sometimes when I tried to write new
parameters into the flash, just after erasing the page. After I
disabled the watchdog is was just a bit harder to get the error. And
every time I stopped the device I landed somewhere in the ADC
interrupt. Other interrupts or the main loop where not serviced.
Sometimes, after restarting the device, it worked propper again.

The second time the error occured at nearly every startup, after I added
some lines of code. After commenting them out everything was fine
again, but these lines where never called before the error. Also,
commenting out some old line fixed the problem. Ok, I disabled the
watchdog to figure out, what the program is doing, but guess what -
yes, everything worked fine. So I replaced the watchdog code by code
writing to SFRs of some unused peripherals, same amount of code, same
timing, and the error occured again. Stopping the device now also led
to the ADC interrupt. But this time the application was *very* slow, a
heartbeat LED, normaly lit for something between 100ms and 200ms, now
was lit for about 30s.

Ok, both times I did a workaround which at least seems to work, but I
never found the reason for the error, so I can't be sure that it will
not happen again. And now, in the hope of getting some hint, I'm
posting here.

For those who are still interested, some technical data:
- I'm using all 3 ADCs,
- triggered by timer 1 with a frequency of 10kHz,
- only the injected conversion is used.
- ADC clock is 12MHz
- Core clock is 72MHZ
- ADC1 sampling 3 channels with sampling times of 28.5, 28.5, and 239.5
  ADC clock cycles, overall conversion time 334 (27.8us)
- ADC2 and ADC3 each samling 4 channels with sampling times of 3 * 7.5
  and 239.5 ADC clock cycles, overall converion time 312 (26us)
- after I first encountered the error, I changed the sampling time for
  the last channel of ADC2 and ADC3 to 71.5 clock cycles (sum: 144,
- I implemented some cod to measure the time used by the ADC interrupt
  using timer 4, running with the core clock frequency
- the interrupt is generated by ADC1
- at the beginning the ADC interrupt waits for the other ADCs

Times measured the first time (using gcc 4.1.1, in core clock cycles,
values rounded):
- when everything was ok:
  whole interrupt:     min:     1050     (14.6us)
                       max:     4100     (56.9us)
  waiting for ADCs:    min:       30     ( 0.24us)
                       max:       32     ( 0.26us)
- when the error occured:
  whole interrupt:     min:     4030     (56.0us)
                       max:    10100    (140.3us)
  waiting for ADCs:    min:     3000     (41.7us)
                       max:     6050     (84.0us)
The second time (using gcc 4.3.3, in core clock cycles):
- when everything was ok:
  whole interrupt:     min:     1042     (14.5us)
                       max:     3554     (49.4us)
  waiting for ADCs:    min:       30     ( 0.24us)
                       max:       32     ( 0.26us)
- when the error occured:
  whole interrupt:     min:     4662     (64.8us)
                       max:     9352    (129.9us)
  waiting for ADCs:    min:     3620     (50.3us)
                       max:     5932     (82.4us)

The only thing I can ascertain out of these numbers is, that the
additional time is spent waiting for ADC2. I check the ADCs
configuration, they where always ok.

Some code:
void init1_ADCs(void)
    // ADC1
    ADC1->CR1   = 0x00000180;   // scan mode, interrupt injected on
    ADC1->CR2   = 0x00808000;   // temp sensor on,
                                // start inj. group with ext. trigger
    ADC1->SMPR1 = 0x001C0000;   // sample times
    ADC1->SMPR2 = 0x006C0000;
    ADC1->JOFR1 = 0x00008000;   // offsets
    ADC1->JSQR  = 0x00281CC0;   // sampling sequence

    // ADC2
    ADC2->CR1   = 0x00000100;   // scan mode
    ADC2->CR2   = 0x00808000;   // temp sensor on,
                                // start inj. group with ext. trigger
    ADC2->SMPR1 = 0x00000E00;   // sample times
    ADC2->SMPR2 = 0x00000000;
    ADC2->JOFR1 = 0x00000800 + offset1;  // offsets
    ADC2->JOFR2 = 0x00000800 + offset2;
    ADC2->JOFR3 = 0x00000800 + offset3;
    ADC2->JSQR  = 0x0036B16A;   // sampling sequence

    // ADC3
    ADC3->CR1   = 0x00000100;   // scan mode
    ADC3->CR2   = 0x00808000;   // temp sensor on
                                // start inj. group with ext. trigger
    ADC3->SMPR1 = 0x00000000;   // sample times
    ADC3->SMPR2 = 0x00000E00;
    ADC3->JOFR1 = 0x00000800 + offset4;  // offsets
    ADC3->JOFR2 = 0x00000800 + offset5;
    ADC3->JOFR3 = 0x00000800 + offset6;
    ADC3->JSQR  = 0x00318820;   // sampling sequence

// switch ADCs on and calibrate
void enable_ADCs(void)
    ADC1->CR2 |= ADC_CR2_ADON;
    ADC1->CR2 |= ADC_CR2_CAL;
    ADC2->CR2 |= ADC_CR2_ADON;
    ADC2->CR2 |= ADC_CR2_CAL;
    ADC3->CR2 |= ADC_CR2_ADON;
    ADC3->CR2 |= ADC_CR2_CAL;
    while(ADC1->CR2 & ADC_CR2_CAL) { }
    while(ADC2->CR2 & ADC_CR2_CAL) { }
    while(ADC3->CR2 & ADC_CR2_CAL) { }

void adc_irq(void)
    u16 te;

    TIM4->PSC = 0;  // for time measurement
    TIM4->CNT = 0;
    TIM4->CR1 = 1;

    while((ADC2->SR & ADC_SR_JEOC) == 0) { }
//  TIM4->CR1 = 0;  // activated to measure time for waiting on ADC2
    while((ADC3->SR & ADC_SR_JEOC) == 0) { }
    ADC1->SR = 0x00000000;         // resetting flags
    ADC2->SR = 0x00000000;
    ADC3->SR = 0x00000000;
    NVIC->ICPR[0] |= 0x00040000;

/* skipped lots of calculation stuff */

    TIM4->CR1 = 0;  // activated to measure time of whole interrupt
    te = TIM4->CNT;
    if(te > sums->time)
        sums->maxtime = te;
    if(te < sums->time)
        sums->mintime = te;

The workarounds:
Due to the findings during debugging it looks like the error occures
after ADC interrupts could not be serviced for some reason.

So in the first case I just deactivated the ADC interrupt and timer 1
before erasing the flash page and reenabled them afterwards.
I also decreased the sampling time for the 4th channel of ADCs 2 and 3.
But this probably doesn't do the trick, because the error occured

In the second case ADCs and timer were enabled before initialising
variables and so long before enabling the interrupts. Now ADCs and
timer are enabled just after the interrupts.

Thanks in advance for any hint realy solving the problem.

By, Mike