STM32H7 triggering ADC with TIM6 TRGO
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-15 7:33 AM
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
Solved! Go to Solution.
- Labels:
-
ADC
-
STM32H7 Series
-
TIM
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 10:00 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 4:08 AM
Read out and check the ADC and TIM6 registers' content. Have you set TRGO properly in TIM6_CR2?
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 5:56 AM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 7:59 AM
Okay so what's the content of the TIM6 and ADC registers?
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 10:00 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 3:06 PM
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...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 3:35 PM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 3:41 PM
This is where I wanted to get you anyway... ;)
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-16 9:35 PM
It won't loop in the handler if you don't enable the interrupt.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-02-17 6:49 AM
If I don't enable the interrupt how am I going to get the end of sequence interrupt for the next triggered conversion?
