cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 triggering ADC with TIM6 TRGO

n2wx
Senior

The ADC (ADC3 if that's relevant) provides for triggering by way of the TIM6 TRGO event. I have the ADC configured to convert with "ExternalTrigConv" pointing to ADC_EXTERNAL_TRIG_T6_TRGO, and the update event's rising edge. In no case am I able to get the thing to trigger though, not off of TIM6, only by software conversion start. I'm sure TIM6 is firing because when I intercept its ISR it's running on time, it's just not triggering the ADC.

The errata for the 32F4xx suggests that one has to enable the DAC RCC clock domain for it to work. This doesn't help on the H7 (and it's not mentioned in the H7 errata).

Has anyone managed to use TIM6 to trigger conversions of the ADC? I can start the s/w conversion in a roundabout way (roundabout because of the HAL locks if I do stuff in ISRs) after TIM6 fires its ISR but I'd rather not couple things so closely.

TIM6 when it's mentioned in the docs is always in relation to the DAC and not the ADC so I wonder if the connection just doesn't exist on the H7 part. Anyone? TIA

1 ACCEPTED SOLUTION

Accepted Solutions

Here, a fully functional example, tested on a NUCLEO-H743ZI2

void ADC3_IRQHandler() {
	ADC3->ISR = ADC_ISR_EOC; // clear interrupt flag
	GPIOB->ODR ^= 1; // toggle green
}
 
int main() {
	RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_ADC3EN;
	RCC->APB1LENR |= RCC_APB1LENR_TIM6EN;
	GPIOB->MODER &= ~((2u << 28u) | (2u << 0u)); // red, greed led output
	GPIOE->MODER &= ~(2u << 2u); // yellow led output
	TIM6->PSC = 0x3FF; // set some prescaler
	TIM6->EGR = TIM_EGR_UG; // load prescaler
	TIM6->CR2 = TIM_CR2_MMS_1; // master mode 010: update
	TIM6->ARR = 0xFFFF; // set period
	TIM6->SR = 0; // clear update status caused by TIM_EGR_UG
	ADC3_COMMON->CCR = ADC_CCR_CKMODE; // set a valid clock, hclk / 4
	ADC3->CR = 0; // clear sleep mode
	ADC3->CR;     // wait a bit
	ADC3->CR = ADC_CR_ADVREGEN; // enable ADC regulator
	some_delay();
	ADC3->CR |= ADC_CR_ADEN; // enable ADC
	while(!(ADC3->ISR & ADC_ISR_ADRDY)) // wait for ADC ready
		;
	ADC3->IER |= ADC_IER_EOCIE; // enable EOC interrupt, just for control
	ADC3->PCSEL = 1; // preselect channel 1
	ADC3->SQR1 = 0; //  convert channel 1 only
	ADC3->CFGR = ADC_CFGR_EXTEN_0 | // enable trigger on rising edge
			(13 << ADC_CFGR_EXTSEL_Pos); // trigger #13 is TIM6_TRGO
	ADC3->CR |= ADC_CR_ADSTART; // start ADC (in triggered mode)
	TIM6->CR1 = TIM_CR1_CEN;    // start timer
	NVIC_EnableIRQ(ADC3_IRQn);
	while(1) {
		some_delay();
		led_yellow(0); // just a heartbeat blink
		some_delay();
		led_yellow(1);
	}
}

The ADC interrupt handler is not actually needed, I just left it in as a visual indicator that the ADC is doing conversions roughly with the timer frequency.

View solution in original post

25 REPLIES 25

Read out and check the ADC and TIM6 registers' content. Have you set TRGO properly in TIM6_CR2?

JW

I have. I have the ADC trigger source set for ADC_EXTERNALTRIGCONV_T6_TRGO and the trigger edge set as ADC_EXTERNALTRIGCONVEDGE_RISING (I tried the other two settings too) . Maddeningly it doesn't work for TIM8 TRGO2 either, an ADC-specific trigger, so I must be doing something stupid. And I thought it was hard getting DMA to work, this one's totally difficult to troubleshoot. Obv I want the timer to trigger the DMA conversion so I don't have to spend any processor time on the silly ADC.

I could use an example somewhere. We seem to have few examples laying around for this speedy little big part. The F4 errata says to enable the clock for the DAC when using TIM6 as a trigger and that was promising but didn't help, perhaps I messed it up and need to try again now that I have an entire day in front of me

Okay so what's the content of the TIM6 and ADC registers?

JW

Here, a fully functional example, tested on a NUCLEO-H743ZI2

void ADC3_IRQHandler() {
	ADC3->ISR = ADC_ISR_EOC; // clear interrupt flag
	GPIOB->ODR ^= 1; // toggle green
}
 
int main() {
	RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_ADC3EN;
	RCC->APB1LENR |= RCC_APB1LENR_TIM6EN;
	GPIOB->MODER &= ~((2u << 28u) | (2u << 0u)); // red, greed led output
	GPIOE->MODER &= ~(2u << 2u); // yellow led output
	TIM6->PSC = 0x3FF; // set some prescaler
	TIM6->EGR = TIM_EGR_UG; // load prescaler
	TIM6->CR2 = TIM_CR2_MMS_1; // master mode 010: update
	TIM6->ARR = 0xFFFF; // set period
	TIM6->SR = 0; // clear update status caused by TIM_EGR_UG
	ADC3_COMMON->CCR = ADC_CCR_CKMODE; // set a valid clock, hclk / 4
	ADC3->CR = 0; // clear sleep mode
	ADC3->CR;     // wait a bit
	ADC3->CR = ADC_CR_ADVREGEN; // enable ADC regulator
	some_delay();
	ADC3->CR |= ADC_CR_ADEN; // enable ADC
	while(!(ADC3->ISR & ADC_ISR_ADRDY)) // wait for ADC ready
		;
	ADC3->IER |= ADC_IER_EOCIE; // enable EOC interrupt, just for control
	ADC3->PCSEL = 1; // preselect channel 1
	ADC3->SQR1 = 0; //  convert channel 1 only
	ADC3->CFGR = ADC_CFGR_EXTEN_0 | // enable trigger on rising edge
			(13 << ADC_CFGR_EXTSEL_Pos); // trigger #13 is TIM6_TRGO
	ADC3->CR |= ADC_CR_ADSTART; // start ADC (in triggered mode)
	TIM6->CR1 = TIM_CR1_CEN;    // start timer
	NVIC_EnableIRQ(ADC3_IRQn);
	while(1) {
		some_delay();
		led_yellow(0); // just a heartbeat blink
		some_delay();
		led_yellow(1);
	}
}

The ADC interrupt handler is not actually needed, I just left it in as a visual indicator that the ADC is doing conversions roughly with the timer frequency.

Thank you I can't wait to try it. Of course I was trying to make it work with the HAL which was my first mistake.

The ADC interrupt. I think you need to be doing the first thing you're doing, clearing the EOC, or else it'll get hung up in an infinite loop and the foreground will never run. I found that out with software triggering...

I don't mean to sound unappreciative but the contents are too voluminous to copy and unless you like interpreting bitmapped fields I don't think you'd enjoy viewing them. Likely Yet Another HAL bug. I need to rid myself of all HAL elements. I stuck to direct access and a little LL thrown in for my uart receive stuff and everything worked the first time through, I should know better

This is where I wanted to get you anyway... 😉

JW

It won't loop in the handler if you don't enable the interrupt.

If I don't enable the interrupt how am I going to get the end of sequence interrupt for the next triggered conversion?