cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 Analog Watchdog too slow

vincent.baille
Associate II

Hello, I am working on a project in which the AWD must react quickly (less than 500 us).

But when using the oscilloscope, it takes around 70 ms to react.

The project is big, so i can't give everything, but the ADC are configured like following :

uint32_t adc_value[4];
 
// Some code...
 
static void MX_ADC1_Init(void)
{
	ADC_MultiModeTypeDef multimode;
	ADC_InjectionConfTypeDef sConfigInjected;
 
	/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	 */
	hadc1.Instance = ADC1;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.ScanConvMode = ENABLE;
	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 = DISABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
		Error_Handler();
	}
 
	/**Configure the ADC multi-mode
	 */
	multimode.Mode = ADC_DUALMODE_INJECSIMULT;
	multimode.DMAAccessMode = ADC_DMAACCESSMODE_2;
	multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
	if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
	{
		Error_Handler();
	}
 
	/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
	 */
	sConfigInjected.InjectedChannel = ADC_CHANNEL_14;
	sConfigInjected.InjectedRank = 1;
	sConfigInjected.InjectedNbrOfConversion = 3;
	sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
	sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_NONE;
	sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
	sConfigInjected.AutoInjectedConv = DISABLE;
	sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
	sConfigInjected.InjectedOffset = 0;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
 
	/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
	 */
	sConfigInjected.InjectedChannel = ADC_CHANNEL_7;
	sConfigInjected.InjectedRank = 2;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
 
	/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
	 */
	sConfigInjected.InjectedChannel = ADC_CHANNEL_15;
	sConfigInjected.InjectedRank = 3;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
}
 
static void MX_ADC2_Init(void)
{
	ADC_AnalogWDGConfTypeDef AnalogWDGConfig;
	ADC_InjectionConfTypeDef sConfigInjected;
 
	/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	 */
	hadc2.Instance = ADC2;
	hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc2.Init.Resolution = ADC_RESOLUTION_12B;
	hadc2.Init.ScanConvMode = ENABLE;
	hadc2.Init.ContinuousConvMode = ENABLE;
	hadc2.Init.DiscontinuousConvMode = DISABLE;
	hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
	hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc2.Init.NbrOfConversion = 1;
	hadc2.Init.DMAContinuousRequests = DISABLE;
	hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	if (HAL_ADC_Init(&hadc2) != HAL_OK)
	{
		Error_Handler();
	}
 
        /* Configure the Analog Watchdog */
	AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_INJEC;
	AnalogWDGConfig.HighThreshold = 0x7FF;
	AnalogWDGConfig.LowThreshold = 0x0;
	AnalogWDGConfig.Channel = ADC_CHANNEL_6;
	AnalogWDGConfig.ITMode = ENABLE;
	if (HAL_ADC_AnalogWDGConfig(&hadc2, &AnalogWDGConfig) != HAL_OK)
	{
		Error_Handler();
	}
 
        /* Configure the injected channel */
	sConfigInjected.InjectedChannel = ADC_CHANNEL_6;
	sConfigInjected.InjectedRank = 1;
	sConfigInjected.InjectedNbrOfConversion = 1;
	sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
	sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_NONE;
	sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
	sConfigInjected.AutoInjectedConv = ENABLE;
	sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
	sConfigInjected.InjectedOffset = 0;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
 
	HAL_ADCEx_InjectedStart(&hadc2);
	HAL_ADC_Start_IT(&hadc2);
	HAL_ADCEx_MultiModeStart_DMA(&hadc1, adc_value, sizeof(adc_value));
}

What i want is to have the Analog watchdog always ready to call the interruption without the need to call a function every x us. (I know it's working, I tried, but calling a function more than 1000 times per second is a waste of resources and slow the program)

I already did some tests, I know the Analog Watchdog works, I enabled the continuous mode and for the ADC 2 the AutoInjectedConv (if I enable it on the ADC 1, the injected channels don't work anymore...), but the ADC doesn't seem to do a conversion just after the previous one finished or the Analog Watchdog doesn't constantly watch... I'm not sure what is the problem, but the reaction time is too slow...

I often read that something like this was possible, so I suppose it's my code which have a problem, something I don't do correctly...

If you have questions about something, just ask.

4 REPLIES 4

I don't understand - can't you simply set aside one of the ADCs for the watchdog, ie. that you don't attempt to use it for any other purposes, just to watch one input?

JW

vincent.baille
Associate II

This is what I did, the first ADC was already here when i started to work and I need it for others values, but the ADC2 is here only for the watchdog, it only watch the channel6, nothing else.

VB

Then what's the problem? Set up the ADC2 for the given channel, set up the watchdog (WD), enable the WD interrupt and start conversion in continuous mode. There's only one interrupt for the whole ADC, so if you want to it really fast you won't be using it for anything else (or you would make sure that handling the non-WD rest is fast enough, dropping priority for lengthy processing or deferring it to some other-priority task if you run an OS). And of course you'd give the interrupt high enough priority so that nests into any other potentially lengthy interrupts.

Start with a minimal code, without the other ADC running, so that you are confident in the WD; then gradually add the other ADC and then mix in the rest of the code, while constantly stirring.

JW

vincent.baille
Associate II

The ADC2 is set up only for the channel 6 (line 110), and the WD watch this channel (line 102), the interrupt is enable (line 103), it is in continuous mode (line 85) and I start it in interrupt mode (line 125) and the priority is high enough.

I also tried with a minimal code, only one ADC with the watchdog and removing most of the thread, but it doesn't work (I linked the pins of the STM to the ADC1 in "HAL_ADC_MspInit()" and "HAL_ADC_MspDeInit()") :

static void MX_ADC1_Init(void)
{
        ADC_AnalogWDGConfTypeDef AnalogWDGConfig;
	ADC_InjectionConfTypeDef sConfigInjected;
 
	/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	 */
	hadc1.Instance = ADC1;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.ScanConvMode = ENABLE;
	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 = DISABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
		Error_Handler();
	}
 
       sConfigInjected.InjectedChannel = ADC_CHANNEL_6;
	sConfigInjected.InjectedRank = 1;
	sConfigInjected.InjectedNbrOfConversion = 1;
	sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
	sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_NONE;
	sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
	sConfigInjected.AutoInjectedConv = ENABLE;
	sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
	sConfigInjected.InjectedOffset = 0;
	if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
 
        AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_INJEC;
	AnalogWDGConfig.HighThreshold = 0x14E;//14E;//333;
	AnalogWDGConfig.LowThreshold = 0x0;
	AnalogWDGConfig.Channel = ADC_CHANNEL_6;
	AnalogWDGConfig.ITMode = ENABLE;
	if (HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_ADCEx_InjectedStart(&hadc1);
	HAL_ADC_Start_IT(&hadc1);
}

But by removing the other threads I saw that the only reason the watchdog could throw an interruption is because we call the function "HAL_ADCEx_InjectedStart(&hadc1);" in a thread, without it we receive only one value with the initialization when we "HAL_ADC_Start_IT()".

But it's strange because we call this only 3 time per second (333 ms) when the WD can trow an interrupt in 70 ms. And this is the only place in the code where this function is called...

So I suppose my real problem is not that the WD is slow but that the sampling doesn't do a loop.

But with this code it should do a new sample just after the previous one no? Or is there something which is not correctly configured? I think I did what you are telling, ADC1 only for the channel6 with the watchdog interrupt enable in continuous mode and I start the conversion. If something is not configured correctly please tell me, I tried different things but it never worked.

VB