cancel
Showing results for 
Search instead for 
Did you mean: 

ADC Sequence conversion not working on STM32G030. Only a single EOC and EOS event when CHSELR = 0b111.

deltronix
Associate II

I have tried multiple different configurations, software trigger, hardware trigger, the only way to read ADC channels in sequence is to use DISCONT=1 and trigger each reading individually. I have minimized my project to a testcase where a software trigger should initiate a sequence reading channel 0 through 2 and the EOC and EOS events are counted in the ISR then printed over usart. Am I missing something? Both EOS and EOC increment by 1 after each ADSTART...

// Main loop:
DelayCycles(1000000);
ADC1->CR |= ADC_CR_ADSTART;
DelayCycles(1000000);
 
if(EOS_COUNT != old_EOS_COUNT){
  old_EOS_COUNT = EOS_COUNT;
  etl::string<32>    text;
  etl::string_stream stream(text);
  stream << "EOS_COUNT:" << EOS_COUNT << "\tISR:\t" << etl::bin << ADC1->ISR << "\n";
  dbg << stream.str();
}
if(EOC_COUNT != old_EOC_COUNT){
    old_EOC_COUNT = EOC_COUNT;
      etl::string<32>    text;
    etl::string_stream stream(text);
    stream << "EOC_COUNT:" << EOC_COUNT << "\tDR:\t" << etl::dec << ADC1->DR << "\n";
    dbg << stream.str();
  }
}
// ADC and Timer configuration (Timer is unused in my test case)
  /* --------------------------------------------------------------- */
  //                        SET UP ADC
  /* --------------------------------------------------------------- */
 
  // select TIM3 trgo;
  // ADC1->CFGR1 |= ADC_CFGR1_EXTEN_0 | ADC_CFGR1_EXTSEL_1 | ADC_CFGR1_EXTSEL_0;
  
    // Set sample time
  // WRITE_REG(ADC1->SMPR,ADC_SMPR_SMP1_2);
 
  CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_DISCEN);
  CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_CONT);
 
  // Enable adc voltage regulator
  ADC1->CR |= ADC_CR_ADVREGEN;
  DelayCycles(16000);
 
  // Start adc cal sequence
  SET_BIT(ADC1->CR,ADC_CR_ADCAL);
  while(READ_BIT(ADC1->CR,ADC_CR_ADCAL)){}
  DelayCycles(16000);
 
  // Clear the ADRDY bit by writing '1'
  SET_BIT(ADC1->ISR,ADC_ISR_ADRDY); 
 
 
    // Set conversion channels
  ADC1->CHSELR |=  0b111;
  while(!READ_BIT(ADC1->ISR, ADC_ISR_CCRDY)){}
  SET_BIT(ADC1->ISR,ADC_ISR_CCRDY);
 
  // Enable ADC and wait till ready
  SET_BIT(ADC1->CR, ADC_CR_ADEN);
  while(!READ_BIT(ADC1->ISR, ADC_ISR_ADRDY)){}
  SET_BIT(ADC1->ISR, (ADC_ISR_ADRDY));
 
 
  // Enable end of conversion interrupt and start
  SET_BIT(ADC1->IER, ADC_IER_EOCIE);
  SET_BIT(ADC1->IER, ADC_IER_EOSIE);
  
  NVIC_SetPriority(ADC1_IRQn, 0x3);
  NVIC_EnableIRQ(ADC1_IRQn);
 
  SET_BIT(ADC1->CR, ADC_CR_ADSTART);
 
  /* --------------------------------------------------------------- */
  //                        SET UP TIM3
  /* --------------------------------------------------------------- */
  
  TIM3->PSC = 1999;
  TIM3->ARR = 3999;
  TIM3->CR2 |= TIM_CR2_MMS_1;
 
  NVIC_SetPriority(TIM3_IRQn, 0x1);
  NVIC_EnableIRQ(TIM3_IRQn);
 
  SET_BIT(TIM3->DIER, TIM_DIER_UIE);
  SET_BIT(TIM3->CR1, TIM_CR1_CEN);
// ISR
uint32_t EOS_COUNT;
uint32_t EOC_COUNT;
 
#ifdef __cplusplus
extern "C"{
#endif
void ADC1_IRQHandler(void){
    if(READ_BIT(ADC1->ISR, ADC_ISR_EOC){
        EOC_COUNT++;
        // (*adc_eoc_handler)(ADC1->DR);
    }
    if(READ_BIT(ADC1->ISR,ADC_ISR_EOS)){
        //(*adc_eos_handler)();
        EOS_COUNT++;
    }
 
    if(READ_BIT(ADC1->ISR,ADC_ISR_EOS))
        SET_BIT(ADC1->ISR,ADC_ISR_EOC);
    
    if(READ_BIT(ADC1->ISR,ADC_ISR_EOS))
        SET_BIT(ADC1->ISR,ADC_ISR_EOS);
 
  
 
}
#ifdef __cplusplus
}

 The usart output is as follows:

EOC_COUNT:189	DR:	2
EOS_COUNT:190	ISR:	0
EOC_COUNT:190	DR:	3
EOS_COUNT:191	ISR:	0
EOC_COUNT:191	DR:	1
EOS_COUNT:192	ISR:	0
EOC_COUNT:192	DR:	4
EOS_COUNT:193	ISR:	0
EOC_COUNT:193	DR:	2
EOS_COUNT:194	ISR:	0
EOC_COUNT:194	DR:	1

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Lead III

Right, you are missing something. What you are missing is the value of ADC conversion time compared to interrupt entry + service + return time. No chance to handle multiple channel conversion without DMA other than using WAIT mechanism - the next conversion starts after reading the previous result.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

3 REPLIES 3
gbm
Lead III

Right, you are missing something. What you are missing is the value of ADC conversion time compared to interrupt entry + service + return time. No chance to handle multiple channel conversion without DMA other than using WAIT mechanism - the next conversion starts after reading the previous result.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

I think you are partially correct. If I increase the sample time to 19.5 ADC Clock cycles 2 EOC events happen for each EOS event. I think there should be 3 EOC events, see the diagram, but it's an improvement. Also the data register now holds the data corresponding to the last channel in the sequence which is nice.

Actually, when the WAIT bit is set, 3 EOC events happen for each EOS, so that definitely solved the issue.

0693W00000Uo1NuQAJ.pngHowever if there previously was not enough time in the interrupt routine to reset the EOC flag the OVERRUN flag should have been set by hardware. It wasn't since I checked that by also printing out the ISR register... Strange business

I guess I can solve the issue reliably by using WAIT, or implementing DMA for this. Cheers!

gbm
Lead III

In any case 3 EOC events are generated but since the total interrupt handling time is now approx. > 2 x conversion time, you miss one event and the ISR is fired 2 times after the chage (was fired only once before).

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice