2020-02-15 07: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.
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.
2020-02-16 04:08 AM
Read out and check the ADC and TIM6 registers' content. Have you set TRGO properly in TIM6_CR2?
JW
2020-02-16 05: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
2020-02-16 07:59 AM
Okay so what's the content of the TIM6 and ADC registers?
JW
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.
2020-02-16 03: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...
2020-02-16 03: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
2020-02-16 03:41 PM
This is where I wanted to get you anyway... ;)
JW
2020-02-16 09:35 PM
It won't loop in the handler if you don't enable the interrupt.
2020-02-17 06: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?