AnsweredAssumed Answered

STM32F3 ADC in differential mode

Question asked by davy.nigel on Oct 15, 2014
Latest reply on Oct 15, 2014 by davy.nigel

Hi

I have used the STM32 F3 Discovery board to perform ADC in differential mode. I used all four AD modules (ADC1/2 and ADC3/4). There is an external 2.5V reference voltage. All four AD modules work independently in regular and continuous mode. Generally the device works correctly except randomly there is a spike and AD channel instead of reading e.g. 0.8V reads max value (2.5V). I scoped these channels and there was no spike on the oscilloscope. That situation happens only for channels connected to ADC1 and ADC3 (masters are in dual mode, but I did not use dual mode). Channels connected to ADC2 and 4 works perfectly fine. Is there any difference between these AD modules that may cause this problem? I read AN4195 Application notes and of course STM32F303 reference manual but could not find any solution. Here is my code for ADC1 and ADC2 initialisation. I used the CooCox compiler. Thanks for any advice.

void calibrate_Diff_ADC1 (void)

{

       uint32_t calibration_value=0;

//ADC1 voltage regulator enabled

       ADC1 ->CR &= ~ADC_CR_ADVREGEN_1; 

       ADC1 ->CR |= ADC_CR_ADVREGEN_0;

//ADC1 voltage regulator startup time

       uSec_Delay(10);

       //single mode for calibration                                

       ADC1 ->CR &= ~ADC_CR_ADCALDIF;          

//start the calibration of the ADC1

       ADC1 ->CR |= ADC_CR_ADCAL;

       //wait until calibration done    

       while (ADC1 ->CR & ADC_CR_ADCAL){} 

//differential mode for calibration

       ADC1 ->CR |= ADC_CR_ADCALDIF;

       //start the calibration of the ADC1     

       ADC1 ->CR |= ADC_CR_ADCAL;

       //wait until calibration done           

       while (ADC1 ->CR & ADC_CR_ADCAL){} 

       //read calibrations value

       calibration_value = ADC1 ->CALFACT;

 

//common register: independent mode

       ADC1_2 ->CCR &= ~ADC12_CCR_MULTI;

       //common register: asynchronous clock mode

       ADC1_2 ->CCR &= ~ADC12_CCR_CKMODE;

       //common register: direct memory access mode disabled

       ADC1_2 ->CCR &= ~ADC12_CCR_MDMA; 

//common register: one shot mode selected

       ADC1_2 ->CCR &= ~ADC12_CCR_DMACFG;

       //common register: 1*TADC_CLK delay between 2 sampling phases

       ADC1_2 ->CCR &= ~ADC12_CCR_DELAY;

 

//continuous conversion mode

       ADC1 ->CFGR |= ADC_CFGR_CONT;

       //12-bit data resolution  

       ADC1 ->CFGR &= ~ADC_CFGR_RES;

       //hardware trigger detection disabled   

       ADC1 ->CFGR &= ~ADC_CFGR_EXTEN;

       //right data alignment    

       ADC1 ->CFGR &= ~ADC_CFGR_ALIGN;      

       //preserves ADC_DR with the old data when an overrun is detected

       ADC1 ->CFGR &= ~ADC_CFGR_OVRMOD;

       //auto-delayed conversion mode off

       ADC1 ->CFGR &= ~ADC_CFGR_AUTDLY;

       //automatic injected group conversion disabled

       ADC1 ->CFGR &= ~ADC_CFGR_JAUTO;

       //1 regular channels to be converted in discontinuous mode   

       ADC1 ->CFGR &= ~ADC_CFGR_DISCNUM;

       //601.5 ADC clock cycles for ADC1_channel1 ()

       ADC1 ->SMPR1 |= ADC_SMPR1_SMP1_0

                           | ADC_SMPR1_SMP1_1

                           | ADC_SMPR1_SMP1_2;

       ADC1 ->SMPR1 |= ADC_SMPR1_SMP2_0

                           | ADC_SMPR1_SMP2_1

                           | ADC_SMPR1_SMP2_2;

//1st conversion in regular sequence with channel1

       ADC1 ->SQR1  |= ADC_SQR1_SQ1_0;

       //the total number of conversions: 1

       ADC1 ->SQR1 |= ADC_SQR1_L_0;            

//differential mode for channel1

       ADC1 ->DIFSEL |= ADC_DIFSEL_DIFSEL_0;

//enable ADC1

       ADC1 ->CR |= ADC_CR_ADEN;

       //wait for ADC1 to be ready to start conversion       

       while (!ADC1 ->ISR & ADC_ISR_ADRD){}

//start conversions in continuous mode

       ADC1 ->CR |= ADC_CR_ADSTART;

}

void calibrate_Diff_ADC2 (void)

{

       uint32_t calibration_value=0;

 

       ADC2 ->CR &= ~ADC_CR_ADVREGEN_1;     //ADC1 voltage regulator enabled

       ADC2 ->CR |= ADC_CR_ADVREGEN_0;

       uSec_Delay(10);                      //ADC1 voltage regulator startup time

       ADC2 ->CR &= ~ADC_CR_ADCALDIF;       //single mode for calibration

       ADC2 ->CR |= ADC_CR_ADCAL;           //start the calibration of the ADC1

       while (ADC2 ->CR & ADC_CR_ADCAL){}  //wait until calibration done

 

       ADC2 ->CR |= ADC_CR_ADCALDIF;        //differential mode for calibration

       ADC2 ->CR |= ADC_CR_ADCAL;           //start the calibration of the ADC1

       while (ADC2 ->CR & ADC_CR_ADCAL){}  //wait until calibration done

       calibration_value = ADC2 ->CALFACT;

 

       ADC2 ->CFGR |= ADC_CFGR_CONT;        //continuous conversion mode

 

       ADC2 ->CFGR &= ~ADC_CFGR_RES;        //12-bit data resolution

       ADC2 ->CFGR &= ~ADC_CFGR_EXTEN;      //hardware trigger detection disabled

       ADC2 ->CFGR &= ~ADC_CFGR_ALIGN;      //right data alignment

      //preserves ADC_DR with the old data when an overrun is detected

       ADC2 ->CFGR &= ~ADC_CFGR_OVRMOD;    

       ADC2 ->CFGR &= ~ADC_CFGR_AUTDLY;     //auto-delayed conversion mode off

      //automatic injected group conversion disabled

       ADC2 ->CFGR &= ~ADC_CFGR_JAUTO;

       //1 regular channels to be converted in discontinuous mode   

       ADC2 ->CFGR &= ~ADC_CFGR_DISCNUM;

//601.5 ADC clock cycles for ADC2_channel7  

       ADC2 ->SMPR1 |= ADC_SMPR1_SMP7_0

                     | ADC_SMPR1_SMP7_1

                     | ADC_SMPR1_SMP7_2;

       ADC2 ->SMPR1 |= ADC_SMPR1_SMP8_0

| ADC_SMPR1_SMP8_2  

                     | ADC_SMPR1_SMP8_2;

      //1st conversion in regular sequence with channel7

       ADC2 ->SQR1 |= ADC_SQR1_SQ1_0           

                            | ADC_SQR1_SQ1_1

                            | ADC_SQR1_SQ1_2;

      //the total number of conversions: 1

       ADC2 ->SQR1 &= ~ADC_SQR1_L_0;                  

 

       ADC2 ->DIFSEL|= ADC_DIFSEL_DIFSEL_6;   //differential mode for channel7

       ADC2 ->CR |= ADC_CR_ADEN;                //enable ADC2

      //wait for ADC2 to be ready to start conversion

       while (!ADC2 ->ISR & ADC_ISR_ADRD){}

      //start conversions in continuous mode

       ADC2 ->CR |= ADC_CR_ADSTART;        

}

Outcomes