cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 Discovery - ADC Calibration Error

mattfox
Associate II
Posted on June 19, 2013 at 22:17

I'm trying to run the ADC Example code that came along with this board, but I keep getting stuck in a loop where the calibration bit (ADC1.CR - bit 31 of the control register) isn't getting set back to zero, and I'm getting stuck in this while loop:

while(ADC_GetCalibrationStatus(ADC1) != RESET )

{

printf(''No Reset\n\r'');

}

Any idea what the issue could be?  I read in the reference manual that once this bit is set, hardware will return in to 0, but this doesn't seem to be the case.  

My code looks like this:

&sharpinclude <stdint.h>

&sharpinclude ''stm32f30x_conf.h''

&sharpinclude ''peripherals.h''

&sharpinclude ''common.h''

__IO uint16_t calibration_value = 0;

__IO uint32_t TimingDelay = 0;

ADC_InitTypeDef       ADC_InitStructure;

ADC_CommonInitTypeDef ADC_CommonInitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

void ADC_Initialize(void)

{

/* Configure the ADC clock */

RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);

/* Enable ADC1 clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

/* Setup SysTick Timer for 1 �sec interrupts  */

if (SysTick_Config(SystemCoreClock / 1000000))

{

/* Capture error */

while (1)

{}

}

/* ADC Channel configuration */

/* GPIOC Periph clock enable */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

/* Configure ADC Channel7 as analog input */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

GPIO_Init(GPIOC, &GPIO_InitStructure);

ADC_StructInit(&ADC_InitStructure);

/* Calibration procedure */

ADC_VoltageRegulatorCmd(ADC1, ENABLE);

/* Insert delay equal to 10 �s */

Delay(10);

ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1) != RESET )

{

printf(''No Reset\n\r'');

}

calibration_value = ADC_GetCalibrationValue(ADC1);

ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;

ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;

ADC_CommonInit(ADC1, &ADC_CommonInitStructure);

ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;

ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;

ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;

ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;

ADC_InitStructure.ADC_NbrOfRegChannel = 1;

ADC_Init(ADC1, &ADC_InitStructure);

/* ADC1 regular channel7 configuration */

ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_7Cycles5);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

/* wait for ADRDY */

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY))

printf(''\fWaiting\n\r'');

}

/**

 * @brief  Inserts a delay time.

 * @param  nTime: specifies the delay time length, in milliseconds.

 * @retval None

 */

void Delay(__IO uint32_t nTime)

{

TimingDelay = nTime;

while(TimingDelay != 0);

}

#adc
15 REPLIES 15
raptorhal2
Lead
Posted on June 19, 2013 at 23:27

You can get at least one No Reset message. Try the same logic as the example:

while(ADC_GetCalibrationStatus(ADC1) != RESET );

printf(''Reset\n\r'');

Cheers, Hal

mattfox
Associate II
Posted on June 20, 2013 at 15:39

Yeah, I had tried that out originally, but it never passes the while loop, so nothing ever gets to the serial port.  I tried it again, just now, with the same results, unfortunately.  I understand why it would print No Reset a few times while it's calibrating, but it repeats it continually with my original code.

I also just changed the code to this:

float x = 0.0f;

while(ADC_GetCalibrationStatus(ADC1) != RESET )

{

x = ADC1->CR;

printf(''\fCR: %04f\n\r'', x);

}

I consistently get 0x90000000 for the critical register value, meaning it has a set calibration bit, the voltage regulator is enabled, and ADEN=0 just as they should be for calibration.  

Anyone have an idea what could be going on?

Thanks for the help!!

raptorhal2
Lead
Posted on June 20, 2013 at 16:29

Perhaps the library code is wrong. Step through it in debug mode to see if it's logic is reversed.

Cheers, Hal

raptorhal2
Lead
Posted on June 21, 2013 at 22:31

After a bit more investigation, there is a more plausible explanation.

Look at Figure 10 in the reference manual. There are two ADC prescalers, one running off the pll, the other from the AHB prescaler, with progammable logic (not shown on the figure) to select which prescaler to use. The example code assumes an EVAL board with an HSE, so the pll prescaler is used. Your discovery board has no HSE. The clock system then comes up on HSI and pll is off.

So the problem could simply be there is no ADC clock. Add code to switch to the AHB prescaler.

Cheers, Hal

mattfox
Associate II
Posted on June 24, 2013 at 16:50

Thanks for the help!  I've tried a few things, but to no avail.  I'm a bit confused why the f3 discovery board doesn't have a pll clock, because according to everything I can find online, it seems to have one.  I could just be confused though.

I did try a couple of things.  One thing I tried was:

RCC_ADCCLKConfig(RCC_SYSCLK_Div2)

though I don't think that is the correct way of setting it up without pll.  Either way when I loaded it onto the board, I had the same problem that I've been running into.   I also tried this:

RCC_HCLKConfig(RCC_SYSCLK_Div2);

RCC_PCLK2Config(RCC_HCLK_Div1);

RCC_ADCCLKConfig(RCC_PCLK2_Div2);

But, RCC_ADCCLIKConfig didn't like taking RCC_PCLK2_Div2 as an argument.  It seems like online, this is the way that people do it for the f1 discovery board but seem to use what I originally used for the f3 series. 

Am I just implementing the AHB prescaler incorrectly?  Or could this not be the problem?

raptorhal2
Lead
Posted on June 24, 2013 at 19:16

I am also a bit confused. The peripheral Library rcc.c has entries only for the pll source prescaler, and I can't find any supporting text in the reference manual for the AHB source in Figure 10.

The F303 does have a pll, but with no HSE, the chip is supposed to come up on HSI as SYSCLK.

I have an F3 Discovery, but I have modified it by swapping the chip for an F373 chip. It fails SDADC calibration. It comes up saying the HSE is ready, but there is no HSE. Can you put a breakpoint in the following statement of system_stm32f30x.c to see if yours has the same clock source problem?

     /* HCLK = SYSCLK / 1 */

     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

If the HSE is not ready, it shouldn't hit this statement.

Thanks, Hal

mattfox
Associate II
Posted on June 24, 2013 at 22:09

I just tried this out, and it doesn't look like it reached this statement.  That section of my code looks like this (I included signals.h at the top):

/* HCLK = SYSCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

    raise(SIGABRT);

I'm still getting the same printout from the loop that I've been stuck in.  Does this mean that I have the same clock source issue?

raptorhal2
Lead
Posted on June 24, 2013 at 23:25

The good news is that you are not getting a false HSE ready indication.

Your system_stm32F30x.c file is different from mine. Is it something supplied with an operating system such as RTOS ?

Check your system_stm32F30x.c for handling HSE not ready. To use pll as an ADC clock source, you will need code similar to the HSE section to set flash latency, pll source to HSI/2, pll multiplier, turn pll on, etc. Then put a breakpoint in that code to make sure it is being executed.

Cheers, Hal

mattfox
Associate II
Posted on June 25, 2013 at 18:41

I'm still fairly new to this board, so I want to make sure I'm not just making some stupid mistakes.

I had tried to use raise(SIGABRT); for a breakpoint because I found that online.  After that, I tried to just add a breakpoint in Eclipse by putting it in the IDE.  I'm not sure if this would effect a change in the board when I am running code or not, but either way, I got stuck in the same loop as I have been before.  Am i doing the breakpoint correctly?