Search code examples
cstm32bare-metalstm32f0

Program stop working as I activated ADC interrupt on STM32


I wrote code for generation square pulse. Everything works fine till I activate ADC Interrupt by NVIC commands. Is ADC IRQ Handler wrote correctly?(I am specious on Handler). ADC Sets on continuous mode by only one channel is using. End_of_Conversion and End_of_Sequence Interrupt flag have been set.

#include <stdint.h>
#include "stm32f0xx.h"

//static __IO uint32_t RPM;
//uint32_t RPM=1000;
#define DUTY_CYCLE 0.1

void SysTick_Handler(void);
void ADC1_IRQHandler(void);

void Delay_10us(__IO uint32_t nTime);
static __IO uint32_t TimingDelay;
static __IO uint32_t adcValue;
//int calibration_factor;
uint32_t rpm;
int global_counter=0;

int main(void)
{
    //  Set SysTick for create 10 microsecond delay
    if(SysTick_Config(80))
    {
        while(1);
    }
    //CLOCK
    RCC->CR|=RCC_CR_HSEON;
    while(!(RCC->CR&RCC_CR_HSERDY));
    RCC->CR|=RCC_CR2_HSI14ON;
    while(!(RCC->CR2|=RCC_CR2_HSI14RDY));
    RCC->CFGR|=RCC_CFGR_SW_HSE;
    while(!(RCC->CFGR&=RCC_CFGR_SWS_HSE));
    RCC->APB2ENR|=RCC_APB2ENR_ADCEN;
    //  ADC1->CFGR2|=ADC_CFGR2_CKMODE_1;
    RCC->AHBENR|=RCC_AHBENR_GPIOAEN;
    //GPIO
    GPIOA->MODER|=GPIO_MODER_MODER4_0;
    GPIOA->PUPDR|=GPIO_PUPDR_PUPDR4_0;
    GPIOA->ODR|=GPIO_ODR_4;
    GPIOA->MODER|=GPIO_MODER_MODER5;
    //NVIC
    NVIC_EnableIRQ(ADC1_COMP_IRQn);/*if I comment this two lines everything works*/
    NVIC_SetPriority(ADC1_COMP_IRQn,0);/*if I comment this two lines everything works*/
    //ADC
    ADC1->CR&=~ADC_CR_ADEN;
    ADC1->SMPR|=ADC_SMPR1_SMPR;
    ADC1->CFGR1|=ADC_CFGR1_CONT;
    ADC1->IER|=ADC_IER_EOSIE|ADC_IER_EOCIE;
    ADC1->CHSELR|=ADC_CHSELR_CHSEL5;
    //  for(int i=0;i<10;i++);
    //  ADC1->CR|=ADC_CR_ADCAL;
    //  while(ADC1->CR&ADC_CR_ADCAL);
    //  calibration_factor=ADC1->DR;
    for(int i=0;i<10;i++);
    ADC1->ISR|=ADC_ISR_ADRDY;
    ADC1->CR|=ADC_CR_ADEN;
    while(!(ADC1->ISR&=ADC_ISR_ADRDY));
    ADC1->CR|=ADC_CR_ADSTART;
    /* Loop forever */
    int counter=0;
    while(1){
        if(rpm<250){rpm=250;}
        int T=10000/rpm;
        int OnDelay=T*DUTY_CYCLE;
        int OffDelay=T*(1-DUTY_CYCLE);
        GPIOA->ODR &=~GPIO_ODR_4;
        Delay_10us(OffDelay);
        GPIOA->ODR|=GPIO_ODR_4;
        Delay_10us(OnDelay);
        counter++;
        if(counter==59)
        {
            GPIOA->ODR &=~GPIO_ODR_4;
            Delay_10us(2*T);
            counter=0;
            continue;
        }
    }
}
void Delay_10us(__IO uint32_t nTime)
{
    TimingDelay = nTime;

    while(TimingDelay != 0);
}

void SysTick_Handler(void){
    if (TimingDelay != 0x00)
    {
        TimingDelay--;
    }
}
void ADC1_IRQHandler()
{
//  
}

Solution

  • Your program enters ADC1_IRQHandler and stays there forever, since the handler is empty.

    If you've enabled an interrupt, you must handle it - at least clear the interrupt source. And don't look at the SysTick_Handler it is a special case with autoreset. For other interrupts the corresponding status bit must be reset, or a special sequence of operations performed. Details are usually found in the description of a status register, in your case it is ADC_ISR.

    With End_Of_Conversion and End_Of_Sequence enabled, the interrupt could be triggered by the EOC and EOSEQ status bits. Both could be cleared by writing 1 to it. The handler should look something like this:

    void ADC1_IRQHandler()
    {
        if(ADC1->ISR & ADC_ISR_EOC)
        {
            //Handle end of conversion
            ADC1->ISR = ADC_ISR_EOC;
        }
        if(ADC1->ISR & ADC_ISR_EOSEQ)
        {
            //Handle end of sequence
            ADC1->ISR = ADC_ISR_EOSEQ;
        }
    }
    

    The name of a handler depends on the startup used, it must match name of a placeholder in the interrupt vector table of the startup file. In Cube-generated projects this is an assembler file (.s) in Startup folder (eg. /Core/Startup/startup_stm32f407zgtx.s)