cancel
Showing results for 
Search instead for 
Did you mean: 

ADC noisy with external clock on Nucleo F303RE ??

David Pekin
Senior

Hello,

I have an application that reads a couple of ADC channels. each time through the main loop. There's no It's a blocking ADC read so nothing else is going on when I'm reading the 2 channels.

For testing purposes I have a 3V battery attached to both inputs so the input signal is clean and stable. When I take multiple samples over time the two channels are within a couple of ADC counts of each other ( 3783 ADC ****) and range of the ADC acquisitions are typically +- 6 or 7 counts. An outlier might be 10 or 12 counts out. That's OK for what we're doing.

The problem occurs when I change from using the default Nucleo 8Mhz clock and use an external 20Mhz clock. I've modified the SystemClock_Config to use the external clock and have divided it down so the RCC/PLL is the same 4Mhz that the onboard clock was generating. Everything works correctly with the external clock - serial baud rates, timers, PWM generation, etc.

What doesn't work correctly is the ADC! Using the same stable battery source into the 2 ADC channels I get noise all over the place! Sometimes the 2 channels are close within a couple of ADC counts of each other. The next time they might be 100 ADC counts different! What used to be 3783 +- 7 is now 3780 +- 75 or 80! That's not even good enough for gov't work!

Below is my ADC config. The ADC clock is set to derived from AHB clock divided by a prescaler of 4. Would the AHB clock be different if the PLL is running the same as in the default case?

Any thoughts appreciated.

static void ADC_Config(void)

{

  ADC_ChannelConfTypeDef  sConfig;

// ADC_AnalogWDGConfTypeDef AnalogWDGConfig;

  /* Configuration of ADCx init structure: ADC parameters and regular group */

  AdcHandle.Instance = ADCx;

  AdcHandle.Init.ClockPrescaler    = ADC_CLOCK_SYNC_PCLK_DIV4;

  AdcHandle.Init.Resolution      = ADC_RESOLUTION_12B;

  AdcHandle.Init.DataAlign       = ADC_DATAALIGN_RIGHT;

  AdcHandle.Init.ScanConvMode     = DISABLE;            /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */

  AdcHandle.Init.EOCSelection     = ADC_EOC_SINGLE_CONV;

  AdcHandle.Init.LowPowerAutoWait   = DISABLE;

  AdcHandle.Init.NbrOfConversion    = 1;               /* Parameter discarded because sequencer is disabled */

  AdcHandle.Init.DiscontinuousConvMode = DISABLE;            /* Parameter discarded because sequencer is disabled */

  AdcHandle.Init.NbrOfDiscConversion = 0;  /* Parameter discarded because sequencer is disabled */

  AdcHandle.Init.NbrOfConversion = 2;  /* Parameter discarded because sequencer is disabled */

  AdcHandle.Init.ScanConvMode = ENABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */

  AdcHandle.Init.EOCSelection = DISABLE; 

  AdcHandle.Init.ContinuousConvMode = ENABLE;  /* Continuous mode disabled to have only 1 conversion at each conversion trig */

  AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Trig of conversion start done by external event */

  AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;

  AdcHandle.Init.DMAContinuousRequests = DISABLE;

  AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

  if (HAL_ADC_Init(&AdcHandle) != HAL_OK)

  {

    /* ADC initialization error */

    Error_Handler(__FILE__, __LINE__);

  }

  /* Configuration of channel on ADCx regular group on sequencer rank 1 */

  /* Note: Considering IT occurring after each ADC conversion if ADC     */

  /*    conversion is out of the analog watchdog widow selected (ADC IT  */

  /*    enabled), select sampling time and ADC clock with sufficient    */

  /*    duration to not create an overhead situation in IRQHandler.    */

  sConfig.Channel = ADCx_CHANNELa;

  sConfig.Rank = ADC_REGULAR_RANK_1;

  sConfig.SamplingTime = ADC_SAMPLETIME_601CYCLES_5;

  sConfig.SingleDiff = ADC_MODE;

  sConfig.OffsetNumber = ADC_OFFSET_NONE;

  sConfig.Offset = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)

  {

    /* Channel Configuration Error */

    Error_Handler(__FILE__, __LINE__);

  }

  sConfig.Channel = ADCx_CHANNELb;

  sConfig.Rank = ADC_REGULAR_RANK_2;

  sConfig.SamplingTime = ADC_SAMPLETIME_601CYCLES_5;

  sConfig.SingleDiff = ADC_MODE;

  sConfig.OffsetNumber = ADC_OFFSET_NONE;

  sConfig.Offset = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)

  {

    /* Channel Configuration Error */

    Error_Handler(__FILE__, __LINE__);

  }

}

1 REPLY 1
David Pekin
Senior

I still don't understand why the ADC is more noisy with the external clock but by changing the ADC clock source from the AHB clock to the PLL, I get a little more stable ADC reading. It's now just a little more noisy than the original on board Nucleo clock. With a bit of averaging I can use the ADC readings for my purposes. (The signal I'm measuring doesn't change rapidly.) Below is the change to ADC_Config.

#if EXTERNAL_CLOCK

  AdcHandle.Init.ClockPrescaler    = ADC_CLOCK_ASYNC_DIV1;    // use PLL clock

#else

  AdcHandle.Init.ClockPrescaler    = ADC_CLOCK_SYNC_PCLK_DIV4;  // use AHB clock

#endif