Skip to main content
MJo.4
Associate
April 28, 2023
Question

ADC with external trigger source via a timer. STM32G431 with NUCLEO G431RB

Hello guys, I'm new to the ST controllers. My question would be how can I initialize an ADC that is waiting for an external signal from a timer. I have initialized a timer interrupt that is triggered every 1 ms at 170 Mhz clock frequency. The timer also works, but there is no ADC conversion, the conversion should be triggered each time via a timer. I work with direct access to the registers without using the hal library because I want to save memory. I've looked through the St examples a bit, but they're all made with the HAL library. I want to use Timer 2 and ADC channel 0 on GPIOA PA0. The timer is only running, my ADC(adc_value is empty) is not working can someone help me with what I have initialized incorrectly here or what is still missing. Thanks for your help guys, I'll post the code here.

Kind regards, Markus

void initADC()
{
 
	// Enable ADC clock
	RCC->AHB2ENR |= RCC_AHB2ENR_ADC12EN;
 
	// Configure GPIO pin as analog input
	GPIOA->MODER |= (0b11<<(0 * 2U));
 
	// Disable ADC deep power-down mode and enable ADC voltage regulator
	ADC1->CR &= ~ADC_CR_DEEPPWD;
	ADC1->CR |= ADC_CR_ADVREGEN;
	
	//wait for voltage 2ms
 for(uint32_t i = 0;i < 340000;i++);		//170Mhz ->340000 2ms
 
 // Configure ADC trigger source and mode
 ADC1->CFGR |= (ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_3); // Trigger on rising edge + Trigger TIM2_TRGO
 ADC2->CFGR |= (ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_3); // Trigger on rising edge + Trigger TIM2_TRGO
 
 ADC1->SQR1 |= (ADC_SQR1_SQ1_0 | ADC_SQR1_L_0 );
 
	// Enable ADC
	ADC1->CR |= ADC_CR_ADEN;
	// Start ADC conversion on Timer 2 TRGO event
	ADC1->CR |= ADC_CR_ADSTART;
 
 
 
}
 
void initCPU_Timer1()
{
 
 
	 RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;
 
	 TIM2->PSC = 169; 
	 TIM2->ARR = 999;
	 TIM2->CR1 = TIM_CR1_ARPE | TIM_CR1_URS; 
	 TIM2->DIER = TIM_DIER_UIE; // Enable Interrupt
	 TIM2->EGR = TIM_EGR_UG; // Update Event 
 
	 TIM2->CR2 |= TIM_CR2_MMS_2;
 
	 // Interrupt-Config
	 NVIC_SetPriority(TIM2_IRQn, 0);
	 NVIC_EnableIRQ(TIM2_IRQn); 
	 // Timer-start
	 TIM2->CR1 |= TIM_CR1_CEN;
 
}
 
int main(void)
{
 
 HAL_Init();
 
 SystemClock_Config();
 
 initADC();
 
 initCPU_Timer1();
 
 while (1)
 {
 
 }
 
}
 
 
volatile uint16_t adc_value = 0;
 
void TIM2_IRQHandler(void)
{
 if (TIM2->SR & TIM_SR_UIF) // Timer Overflow Event
 {
 ADC1->CR |= ADC_CR_ADSTART; // start ADC
 TIM2->SR &= ~TIM_SR_UIF; // Clear Timer Overflow Flag
 
 	 adc_value = ADC1->DR;
 
 }
 
}

This topic has been closed for replies.

10 replies

Senior III
April 28, 2023

Hmmm in timer handler you start adc again before read data from DR register ​

Dudo
MJo.4
MJo.4Author
Associate
May 2, 2023

Hello Kamil,

i removed line 79 from my timer handler but it doesn't work. I dont know whats wrong there no ADC conversion.

Senior III
May 2, 2023

Remove or move as last?​

Dudo
MJo.4
MJo.4Author
Associate
May 2, 2023

I tried both but without success. The timer handler works. Only no conversion is carried out. I think it's up to the ADC configuration, because if I just want to initialize the ADC and then set a software trigger, no conversion works for me either. I don't know how to properly configure the ADC.

MJo.4
MJo.4Author
Associate
May 2, 2023

do you have an example code how i have to configure the adc? I can't find any sample code with direct access to the registers on the STM controller

Senior III
May 2, 2023

You must wait for ADRDY flag after enable ADC. Its mandatory. This flag is ADC_ISR register ​

Dudo
Senior III
May 2, 2023

After line ​24

Dudo
Senior III
May 2, 2023

I think i found mistake in your code:

TIM2->CR2 |= TIM_CR2_MMS_2;

TIM_CR2_MMS_2 it equals 0x100 and in manual means :

0100: Compare - tim_oc1refc signal is used as trigger output (tim_trgo)

You have to use TIM_CR2_MMS_1:

0010: Update - The update event is selected as trigger output (tim_trgo). For instance a master timer can then be used as a prescaler for a slave timer. 

And you musn't use ADC start again in TIM IRQ handler :

Line 79: ADC1->CR |= ADC_CR_ADSTART; // start ADC

because trigger is automatically relaunch

Dudo