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:
extern int Q, I;
void ADC1_Init(void) {
// Enable clock for GPIOA and ADC1
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
RCC->AHBENR |= RCC_AHBENR_ADC12EN;
// Configure GPIOA pins 0 (PA0) and 1 (PA1) as analog mode
GPIOA->MODER |= (3U << (0 * 2)) | (3U << (1 * 2));
// Set ADC1 clock prescaler and clock source
RCC->CFGR2 |= RCC_CFGR2_ADCPRE12_DIV4; // Set ADC clock prescaler
ADC12_COMMON->CCR &= ~ADC12_CCR_CKMODE; // Select synchronous clock mode (HCLK/1)
// Enable ADC1 voltage regulator
ADC1->CR &= ~ADC_CR_ADVREGEN;
ADC1->CR |= ADC_CR_ADVREGEN_0;
// Configure ADC resolution and alignment
ADC1->CFGR &= ~ADC_CFGR_RES; // 12-bit resolution
ADC1->CFGR &= ~ADC_CFGR_ALIGN; // Right alignment
ADC1->CFGR &= ~ADC_CFGR_CONT; // Ensure single conversion mode
// Enable ADC1
ADC1->ISR |= ADC_ISR_ADRDY;
ADC1->CR |= ADC_CR_ADEN;
while (!(ADC1->ISR & ADC_ISR_ADRDY)); // Wait for ADC to be ready
ADC1->IER |= 1<<2; // Interrupt enable on EOC
NVIC_SetPriority(ADC1_2_IRQn, 2);
NVIC_EnableIRQ(ADC1_2_IRQn);
}
void ADC1_Read(uint8_t channel) {
ADC1->SQR1 = 0; // Clear previous selection
if (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 flag
if(ADC1->SQR1 & 1<<6) Q = ADC1->DR;
if(ADC1->SQR1 & 1<<7) I = ADC1->DR;
}
TIM6 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 in
frequency if the Q signal LOWERS while it lowers in frequency otherwise.
The signal is outputed on pin PA5 and its generation is gated by
the 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 ARR
in order to decrease the frequency.
If we choose a PSC = 10 we get a Ftick of 6.4MHz -> Ttick = 156.25ns
This means that we can place our ARR at 9696 for a 660Hz toggle.
We can change the tone going up by simply adding the difference
of the ADC reading from its steady value (2048) multiplied by
four 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 enable
GPIOA->MODER &= ~(1<<11); // GPIOA5 in output mode
GPIOA->MODER |= 1<<10;
GPIOA->PUPDR |= 1<<11; // GPIOA5 internal pulldown enable
TIM6->DIER |= 1<<0; // Interrupt on update event
TIM6->SR |= 0; // Interrupt flags registers
TIM6->ARR = ARRbaseLow;
TIM6->PSC = 9696;
TIM6->CR1 |= 1; // TIM6 enabled
NVIC_SetPriority(TIM6_DAC1_IRQn, 5);
NVIC_EnableIRQ(TIM6_DAC1_IRQn);
}
void TIM6_IRQHandler(){
TIM6->SR = 1<<0; // Clear pending interrupt flag
if(Q <= 2048-Qthreshold || Q >= 2048+Qthreshold){ // If we are above threshold
GPIOA->ODR ^= 1<<5; // We toggle the tone pin
}
else GPIOA->ODR &= ~(1<<5); // If not we turn it off
}
A PIECE OF MAIN:
/* ********** 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 conversion
ADC1_Read(1); // Q channel acquisition
TIM6->ARR = ARRbaseLow + (Q - 2048)*4; // Value to generate the low frequency tone
conversionFlag = 1;
}
if(conversion == 1 && conversionFlag == 1){ // I channel conversion
ADC1_Read(2); // I channel acquisition
//TIM7->ARR = ARRbaseHigh + (I - 2048)*24; // Value to generate the high frequency tone
conversionFlag = 0;
}
}