Enabling TIM6 ISR makes ADC1 not working - STM32F303 - Page 1
Forum section: electronics / general

author: ppTRN
author_rank: Regular Contributor
timestamp: March 26, 2025, 06:37:17 pm
content: Hi all,as my journey in peripherals programming continues, i am facing a whole new problem. I want to generate a square wave which period depends on some data read by the ADC. First I tested the ADC acquisition and works perfectly. I sample two channels in single conversion mode, where each conversion is triggered by a function called by the Systick. The ADC resouls are retrived from its ISR. Again, it works just fine.On the same code we have also TIM15, TIM16 and TIM17 that does other jobs.Now, when I enable the interrupts of TIM6, the ADC stops working. I tought it was about interrupt priorities, but it appears to be complitely unlinked. I also tought that it was due to my messing with the TIM6 ARR "on the fly", but it was not.Would you please help me?As always I thank you for the time you spent for me until now.ADC CODE:Code:extern int Q, I;void ADC1_Init(void) {// Enable clock for GPIOA and ADC1RCC->AHBENR |= RCC_AHBENR_GPIOAEN;RCC->AHBENR |= RCC_AHBENR_ADC12EN;// Configure GPIOA pins 0 (PA0) and 1 (PA1) as analog modeGPIOA->MODER |= (3U << (0 * 2)) | (3U << (1 * 2));// Set ADC1 clock prescaler and clock sourceRCC->CFGR2 |= RCC_CFGR2_ADCPRE12_DIV4; // Set ADC clock prescalerADC12_COMMON->CCR &= ~ADC12_CCR_CKMODE; // Select synchronous clock mode (HCLK/1)// Enable ADC1 voltage regulatorADC1->CR &= ~ADC_CR_ADVREGEN;ADC1->CR |= ADC_CR_ADVREGEN_0;// Configure ADC resolution and alignmentADC1->CFGR &= ~ADC_CFGR_RES; // 12-bit resolutionADC1->CFGR &= ~ADC_CFGR_ALIGN; // Right alignmentADC1->CFGR &= ~ADC_CFGR_CONT; // Ensure single conversion mode// Enable ADC1ADC1->ISR |= ADC_ISR_ADRDY;ADC1->CR |= ADC_CR_ADEN;while (!(ADC1->ISR & ADC_ISR_ADRDY)); // Wait for ADC to be readyADC1->IER |= 1<<2;// Interrupt enable on EOCNVIC_SetPriority(ADC1_2_IRQn, 2);NVIC_EnableIRQ(ADC1_2_IRQn);}void ADC1_Read(uint8_t channel) {ADC1->SQR1 = 0;// Clear previous selectionif (channel == 1) ADC1->SQR1 |= 1<<6; // Select channel 1 (PA0)if (channel == 2) ADC1->SQR1 |= 1<<7; // Select channel 2 (PA1)ADC1->CR |= ADC_CR_ADSTART;// Start conversion}void ADC1_2_IRQHandler(){ADC1->ISR = 1<<2;// Clear EOC interrupt flagif(ADC1->SQR1 & 1<<6) Q = ADC1->DR;if(ADC1->SQR1 & 1<<7) I = ADC1->DR;}TIM6 CODE:Code:/*This function uses TIM6 in order to generate the low frequency tone.The tone is linked to the Q signal sampled by the ADC and it rises infrequency if the Q signal LOWERS while it lowers in frequency otherwise.The signal is outputed on pin PA5 and its generation is gated bythe reach of a predetermined threshold, in order to avoid a noisy search.FREQUENCY DYNAMIC: 330Hz to 630Hz (means toggle at 660Hz and 1260Hz)We can set the PSC in order to generate exactly 330Hz and then move the ARRin order to decrease the frequency.If we choose a PSC = 10 we get a Ftick of 6.4MHz -> Ttick = 156.25nsThis means that we can place our ARR at 9696 for a 660Hz toggle.We can change the tone going up by simply adding the differenceof the ADC reading from its steady value (2048) multiplied byfour in order to increase sensitivity.ARR = ARRbase + (Q - 2048)*4;*/#include "stm32f303x8.h"extern int Q, Qthreshold, ARRbaseLow;void QtoneInit(){RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;RCC->AHBENR |= RCC_AHBENR_GPIOAEN;// GPIOA clock enableGPIOA->MODER &= ~(1<<11);// GPIOA5 in output modeGPIOA->MODER |= 1<<10;GPIOA->PUPDR |= 1<<11;// GPIOA5 internal pulldown enableTIM6->DIER |= 1<<0;// Interrupt on update eventTIM6->SR |= 0;// Interrupt flags registersTIM6->ARR = ARRbaseLow;TIM6->PSC = 9696;TIM6->CR1 |= 1;// TIM6 enabledNVIC_SetPriority(TIM6_DAC1_IRQn, 5);NVIC_EnableIRQ(TIM6_DAC1_IRQn);}void TIM6_IRQHandler(){TIM6->SR = 1<<0;// Clear pending interrupt flagif(Q <= 2048-Qthreshold || Q >= 2048+Qthreshold){// If we are above thresholdGPIOA->ODR ^= 1<<5;// We toggle the tone pin}else GPIOA->ODR &= ~(1<<5);// If not we turn it off}A PIECE OF MAIN:Code:/* ********** INVERTING CHARGE PUMP SIGNAL GENERATION ********* */timer16Init();/* ********** QUADRATURE AND PHASE SIGNAL GENERATION ********** */timer15Init();/* ************* FREQUENCY MEASURE INITIALIZATION ************* */timer17Init();EXTI0Config();/* ************* ROTARY ENCODER INITIALIZATION ************* */EXTI1Config();EXTI2Config();/* ******************* 10ms SysTick CONFIGURATION ****************** */SysTick->CTRL |= 1<<1 | 1<<0;SysTick->LOAD = 640000;/* ************* ANALOG TO DIGITAL CONVERSION ************ */ADC1_Init();/* ************* TONE GENERATION INITIALIZATION ************* *///QtoneInit();//ItoneInit();/* ************************************************************ */while (1){if(conversion == 0 && conversionFlag == 0){// Q channel conversionADC1_Read(1);// Q channel acquisitionTIM6->ARR = ARRbaseLow + (Q - 2048)*4;// Value to generate the low frequency toneconversionFlag = 1;}if(conversion == 1 && conversionFlag == 1){// I channel conversionADC1_Read(2);// I channel acquisition//TIM7->ARR = ARRbaseHigh + (I - 2048)*24;// Value to generate the high frequency toneconversionFlag = 0;}}

author: ajb
author_rank: Super Contributor
timestamp: March 26, 2025, 07:15:17 pm
content: Can you be a little more specific with "when I enable the interrupts of TIM6, the ADC stops working"?What happens exactly when the ADC "stops working" -- do you get incorrect results, does the ISR not run, or something else?If you comment/uncomment just the NVIC_EnableIRQ call for the timer, does that toggle the ADC failure?

author: ppTRN
author_rank: Regular Contributor
timestamp: March 26, 2025, 07:38:01 pm
content: Hi,the fault disappears when i comment one of the following:Code:TIM6->DIER |= 1<<0;// Interrupt on update eventorNVIC_EnableIRQ(TIM6_DAC1_IRQn);Both clearely in charge of enabling the interrupt.When I say that the ADC stops working I mean that it no longer performs conversions because the lines of code inside the while(1) are never executed.Those lines performs alternatively the conversion of CH1 and CH2, and they are triggered bu the SystickCode:void SysTick_Handler(void){conversion = 1-conversion;HAL_IncTick();}The systick ISR is reached every time, so it always updates the variable "conversion". But it is like the only thing alive in the system. The code inside the while(1) is never executed.I am noticing one more thing tho. After executing the systick ISR the code jumps to aCode:B .instruction on the startup .s file. That's why it gets stuck. But why? This instruction is at the end of the ISR names exports.It is like it never returns form the ISR maybe? But again, why do it only when the TIM6 interrutps are enabled?I hope I answared clearely, thank you

author: ppTRN
author_rank: Regular Contributor
timestamp: March 26, 2025, 07:39:58 pm
content: Oh my... I think I called the ISR TIM6_IRQHandler while its name is supposed to be TIM6_DAC1_IRQHandler.... Let me try it

author: Dan N
author_rank: Contributor
timestamp: March 26, 2025, 08:09:29 pm
content: Quote from: ppTRN on March 26, 2025, 06:37:17 pmYou have to carefully read the reference manual for these flags. This one is cleared by writing a 0 (writing 1 has no effect):Code:TIM6->SR = ~(1<<0);// Clear pending interrupt flagmore readable if you use the defines in the cmsis headers:TIM6->SR = ~TIM_SR_UIF

author: ppTRN
author_rank: Regular Contributor
timestamp: March 26, 2025, 09:31:16 pm
content: Damn, here's another mistake.Why do they do this? Why in the same chip there are peripherals whose interrupt flag is cleared by writing a 1 and others in which it is the opposite?Thanks tho, I sometimes feel like this errors are really stupid, I guess I need to put more attention in what I do, and I do not want to abuse of your help and patience. Tomorrow I will fix it and see if it works.Thanks a lot for your help