STM32G0 ADC AWD2/AWD3 does not work
Hello everyone,
we have a STM32G070CBT6 microcontroller and we want to use the ADC in the following configuration:
- Channels: 1,2,3
- Continuous Measurement, automatically restart at channel 1 after measuring channel 3
- Transfer measured analog values via DMA to an array
- Monitor Channel 1 with Analog Window Watchdog 1
- Monitor Channel 2 and 3 with Analog Window Watchdog 2 or 3
Since I wasn't able to configure Scan conversion mode in combination with continuous conversion in STM32CubeMX (CubeMX always disables continuous conversion mode and enables dicontinuous mode as soon as I enable Scan conversion mode), I configured the ADC myself with the following code:
static void ADC_Init(void)
{
/** Configure the ADC with CMSIS since the HAL can not configure the ADC as intended**/
//Reset ADC
RCC->APBRSTR2 |= RCC_APBRSTR2_ADCRST;
RCC->APBRSTR2 &= ~RCC_APBRSTR2_ADCRST;
//Activate ADC Clock
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
//Run calibration
ADC1->CR |= ADC_CR_ADCAL; //Start calibration
while((ADC1->CR & ADC_CR_ADCAL) == ADC_CR_ADCAL); //Wait for completion
//After reset, the resolution is already set to 12 bit
//After reset, the ADC uses the asynchronous clock with a prescaler of 1.
//Configure the DMA Requests from the ADC
ADC1->CFGR1 |= ADC_CFGR1_DMACFG; //Configure DMA in circular mode
ADC1->CFGR1 |= ADC_CFGR1_DMAEN; //Enable DMA Requests
//Enable the ADC
ADC1->ISR |= ADC_ISR_ADRDY; //Clear ADRDY-Bit
ADC1->CR |= ADC_CR_ADEN; //Activate ADC
while((ADC1->ISR & ADC_ISR_ADRDY) != ADC_ISR_ADRDY); //Wait until ADC is ready
//Configure the Channels and the sequencer
ADC1->ISR |= ADC_ISR_CCRDY; //Clear CCRDY Flag
ADC1->CFGR1 |= ADC_CFGR1_CHSELRMOD; //Enable the sequencer
ADC1->CHSELR = 0xF321; //Scan direction: CH1->CH2->CH3
while((ADC1->ISR & ADC_ISR_CCRDY) != ADC_ISR_CCRDY); //Wait until new configuration is established
//Configure the ADC for continuous conversion
ADC1->CFGR1 |= ADC_CFGR1_CONT;
/** Configure the Analog Watchdogs**/
//Analog Watchdog 1 monitors Channel 1
ADC1->CFGR1 |= ADC_CFGR1_AWD1SGL; //Monitor only a single channel
ADC1->CFGR1 |= 1<<ADC_CFGR1_AWD1CH_Pos; //Monitor Channel 1
ADC1->CFGR1 |= ADC_CFGR1_AWD1EN; //Enable the Analog Window Watchdog
ADC1->IER |= ADC_IER_AWD1IE; //Enable Analog Window Watchdog 1 interrupt
ADC1->AWD1TR = 2000<<ADC_AWD1TR_HT1_Pos; //Program upper threshold
//Lower threshold stays at reset value (0)
//Analog Watchdog 2 monitors Channel 2 and 3
ADC1->AWD2CR = ADC_AWD2CR_AWD2CH_2 | ADC_AWD2CR_AWD2CH_3; //The second watchdog monitors Channels 2 and 3
ADC1->IER |= ADC_IER_AWD2IE; //Enable Analog Watchdog 2 interrupt
ADC1->AWD2TR = 700<<ADC_AWD2TR_HT2_Pos; //Program upper threshold
//Lower threshold stays at reset value (0)
NVIC_EnableIRQ(ADC1_IRQn); //Enable ADC interrupts in the NVIC
}I have separate functions for initilaizing the DMA and setting up the GPIO pins, but since everything works except for the AWD2, I am not showing this part of the code.
If I initialize the ADC with the code above, everything works except for the Analog Watchdog 2. I have the following code in my ISR:
void ADC1_IRQHandler(void)
{
adc_isr_flag = 1;
if((ADC1->ISR & ADC_ISR_AWD1) == ADC_ISR_AWD1)
{
HAL_GPIO_WritePin(STATUS_LED_1_GPIO_Port, STATUS_LED_1_Pin, GPIO_PIN_SET); //Turn on an LED to indicate that the upper threshold is reached
ADC1->IER &= ~ADC_IER_AWD1IE; //Disable the interrupt to avoid calling the ISR repeatedly
ADC1->ISR |= ADC_ISR_AWD1; //Clear Interrupt flag
}
else if((ADC1->ISR & ADC_ISR_AWD2) == ADC_ISR_AWD2)
{
HAL_GPIO_WritePin(STATUS_LED_2_GPIO_Port, STATUS_LED_2_Pin, GPIO_PIN_SET); //Turn on an LED to indicate that the upper threshold is reached
ADC1->AWD2CR = 0x00000000; //Disable the AWD2 to avoid calling the ISR repeatedly
ADC1->ISR |= ADC_ISR_AWD2; //Clear Interrupt flag
}
}When I connect at potentiometer to the analog input 1, than the Status LED 1 turns on if I turn the potentiometer beyond a certain position. This shows that the AWD1 and the ISR are working as expected.
If I however connect the same potentiometer to channels 2 and 3 and turn it, the LED never turns off, even if I turn the potentiometer from one end to the other.
I already tried polling the AWD2 flag in the main loop and disabling ADC interrupts, but this did not work either. It seems like the flag is never set. I also tried sending a message over UART instead of turning on LEDs, but this did not change the situation.
I checked the HAL driver to see how the initilization is done there, but the only difference is that the HAL resets the AWD2 flag after setting up the channels. I tried resetting the flag as well after setting up the channels, but this did not work.
I also created a separate test project in the STM32CubeIDE. I configured a single channel, enabled continuous measurement and set up the AWD2. What I find strange is that I can not specify the channel to be monitored by the AWD2. I still tried it but it did not work as well. After checking the code, I realized that CubeMX does not call the HAL_ADC_AnalogWDGConfig() function, which should configure the Analog Watchdog, thus the AWD does not get configured. If I check the AWD2CR register, I can see that it only contains zeros (reset value), thus the AWD does not monitor any channels.
I even tried using the AWD3 instead of the AWD2, but still no luck.
At this point, I do not know what the problem is. Does anyone have a test code for the AWD2 or was able to configure it correctly using CubeMX?
We need the AWD in our application to react to a voltage change as fast as possible.
According to the Errata, there are no known limitations regarding the AWD2.
I would appreciate any help. Thanks in advance.
Best Regards
