cancel
Showing results for 
Search instead for 
Did you mean: 

What is the accuracy of the ADC watchdog [STM32F303]?

Tobe
Senior III

I have successfully configured the adc watchdog. But i am a bit dissapointed of the accuracy. I set the bounds to 1000 and 3000, but when i read the values of the adc from the watchdog interrupt, i get also values from within the window (up to 1025/2975).

The signal is 10Hz Triangular. I already measured the time from beeing outside of the window until the interrupt is executed (4us). So there is no timing issue.

In the manual it says:

The analog watchdog feature allows very precise monitoring of the converted voltage of one, some or all selected channels. An interrupt is generated when the converted voltage is outside the programmed thresholds.

25 of 4096 at 3.3V is 20mV... I would not call that very precise, not even precise....

Is it a safety margin?

I could compensate this, but i wonder if it could change somehow (temperature etc.)?

I made a diagram, to visualize it and added a cap to smooth out the signal:


_legacyfs_online_stmicro_images_0693W00000bijYFQAY.png x-axis shows the value from the ADC, and the y-axis is the number of measures values. The window has been changed to 3000/3200.

1 ACCEPTED SOLUTION

Accepted Solutions
Tobe
Senior III

I think i found the problem (probably, as there is a lot of code just for the ADC) in my case: The EOC interrupt cleared the EOC flag, which itself reset the preservation of the ADC dataregister. And i thought this would only happen when i would read the dataregister.

I found this int the datasheet, which is not clearly stating this:

"EOC flag is cleared by the software either by writing 1 to it or by reading ADCx_DR."

At the relevant point in the datasheet there is no information about this:

It is possible to configure if data is preserved or overwritten when an overrun event occurs
by programming the control bit OVRMOD:
• OVRMOD=0: The overrun event preserves the data register from being overrun: the
old data is maintained and the new conversion is discarded and lost. If OVR remains at
1, any further conversions will occur but the result data will be also discarded.

View solution in original post

11 REPLIES 11
Tobe
Senior III

I could now improve my measurements a tiny bit. As i did forget about my signal i used, there were some artifacts (valleys and mountains in the signal). Those came from the DAC that was generating the signal.

But still the values when the watchdog fires are not precise. My test setup is on a breadboard. The increasing numbers to the right are, because the signal curve flattens at higher level, and produces more measured values. The signal is a 2Hz triangular (somewhat) waveform.
_legacyfs_online_stmicro_images_0693W00000bin3PQAQ.png

The watchdog is digital, so its accuracy is the same as any ADC readout.

I don't know how do you determine the value in the interrupt, but if the latency is too high and you have continuous conversions, you may read out not the value which triggered the interrupt, but value from some subsequent conversion.

JW

No, i have set the option to preserve the data in the register. I thought "well thats it" but i was quite dissapointed as it didnt change much. Or maybe there is more to it?
_legacyfs_online_stmicro_images_0693W00000bioLoQAI.png

Tobe
Senior III

I have now checked on the preserve option in particular. It works as expected. But the watchdog is still not working as it should. I have read in the manual:

The watchdog comparison is performed on the raw converted data before any alignment calculation and before applying any offsets (the data which is compared is not signed).

When it says "Data", there should be no watchdog interrupt that has a value of between 3000 and 3200.
_legacyfs_online_stmicro_images_0693W00000biqCtQAI.png

Tobe
Senior III

This is the code currently used:

static void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  /* USER CODE END ADC1_Init 0 */
 
  ADC_MultiModeTypeDef multimode = {0};
  ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC1_Init 1 */
 
  /* USER CODE END ADC1_Init 1 */
 
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** B_Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Analog WatchDog 1
  */
  AnalogWDGConfig.WatchdogNumber = ADC_ANALOGWATCHDOG_1;
  AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
  AnalogWDGConfig.HighThreshold = 3200;
  AnalogWDGConfig.LowThreshold = 3000;
  AnalogWDGConfig.Channel = ADC_CHANNEL_1;
  AnalogWDGConfig.ITMode = ENABLE;
  if (HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
void HAL_ADC_LevelOutOfWindowCallback(struct __ADC_HandleTypeDef* hadc){
//create delay
	for(int i = 0; i < 100; i++){
		if(lastStart < 0){
			print("WTF",3);
		}
	}
 
	uint32_t value = hadc->Instance->DR;
 
	if(value >= 2900 && value < 3300){
		BSP_LED_Toggle(LED3);
		outLevelCount[value-2900]++;
	}
 
	if(HAL_GetTick() - lastStart > 30000){
		HAL_ADC_Stop_IT(&hadc1);
	}
}

> No, i have set the option to preserve the data in the register.

That has nothing to do with the watchdog. That setting means, that in case of overflow (i.e. if new conversion finishes and previous conversion's data have not been read) the new conversion's data are not thrown away, but replace the old data.

You not only don't read the value which caused the interrupt, by adding deliberate delay in the ISR you more-less make sure you read an entirely different data, converted much later than the data which caused the interrupt.

JW

Yes, it does not have much to do with the watchdog, but with my watchdoginterrupt. I added this delay, to check if something else would be wrong.

When i read the register, it should be the value from what the watchdog triggered as i understand. And with preserving the data i would make sure, i dont get other values written into it before i have read them.

> When i read the register, it should be the value from what the watchdog triggered as i understand.

No. Why would it be? Where do you see this written?

> And with preserving the data i would make sure, i dont get other values written into it before i have read them.

No. As I've said, that option has nothing to do with watchdog.

There's no such functionality as "preserve converted value which triggered the watchdog" in the ADC.

JW

In the manual (RM0316), under 15.3.28 table 97 it says:

The watchdog comparison is performed on the raw converted data before any alignment calculation and before applying any offsets (the data which is compared is not signed).

That is what i wrote already above. Do you actually have some facts or sources?

Have you actually read my posts?