This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Debugger hangs on Float instruction

When I run this code on my STM32L1 board, the debugger hangs once it reaches to a Float (in this case the variable 'Distance') or Delay, I mean it seems like it's processing, however it never goes through, and I have to close it and run the debugger again, which hangs of course again. Note that the code builds without errors or warnings.
Is there's any special configuration for float ?

The following is the related part of the code:


void Delay(int x){
    //input milliseconds, delay that number of milliseconds
    int a,b;
    for(a=0; a<x; a++){
        for(b=0; b<1000; b++){
        }
    }
}
                .
                .
                .

volatile int timespan = 0;                      // Total pulse width

int main(void){

                float Distance;     // actual distance in cm
                .
                .
                .

    while(1){

        TIM4_Echo_Read();

    Distance = (timespan / 58.0);

        if (Distance <= 100){

            GPIOB->BSRRL = (1<<7);
        }
            else {
            GPIOB->BSRRH = (1<<7);

            }
                Delay(10);
        }

timespan is declared as a global int.
Note that none of this happens when I declare Distance as int instead of float.

Any idea why the debugger keeps getting stuck on float instructions?

  • #include <stdio.h>
    #include "stm32l1xx.h"                  // Keil::Device:Startup
    
            //Initialize the timers variables.
        volatile int timespan = 0;      // Total pulse width
        volatile int lastcounter = 0;   // Timer counter value of the last event
        volatile int newcounter = 0;    // Timer counter value of the current event
        volatile int overflow = 0;      // Count the number of overflows
    
        void SetHSI(void);
        void Delay(int);
        void GPIO_config(void);
        void TIM2_Trigger(void);
        void TIM4_Init(void);
        void TIM4_Echo_Read(void);
        void LED (void);
    
    
            int main(void){
    
                SetHSI();
                GPIO_config();
                TIM2_Trigger();
                TIM4_Init();
    
    
              while(1){
    
                 TIM4_Echo_Read();
                 LED();
    
                 Delay(100);
          }
       }
    
    void Delay(int x){
        //input milliseconds, delay that number of milliseconds
        int a,b;
        for(a=0; a<x; a++){
            for(b=0; b<1000; b++){
            }
        }
    }
    
      //set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)//
    
    void SetHSI(void) {
    
    // Turn on HSI (16MHz)
    RCC->CR |= RCC_CR_HSION;
    // Wait until HSI is ready
    while( (RCC->CR & RCC_CR_HSIRDY) == 0);
    // Select HSI as system clock
    RCC->CFGR &= ~RCC_CFGR_SW_HSI;
    RCC->CFGR |= RCC_CFGR_SW_HSI;
    while( (RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI ); // Wait till HSI
    }
    
    // Configure GPIO Port B
    void GPIO_config(void){
    
        RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST;   // Reset GPIOB clock
        RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST;  // Clear Reset
        RCC->AHBENR |= RCC_AHBENR_GPIOBEN;      // Enable GPIOB clock
    
        //PB6 Echo Pin
        GPIOB->MODER   &=   ~(0x03 << 12);    // Clear bit 12 & 13 Alternate function mode
        GPIOB->MODER   |=   (0x02 << 12);    // set as Alternate function mode
        GPIOB->OSPEEDR &=   ~(0x03<< 12);   // 40 MHz  speed
        GPIOB->OSPEEDR |=   (0x03<< 12);    // 40 MHz  speed
        GPIOB->PUPDR &=         ~(0X3<<12); // NO PULL-UP PULL-DOWN
        GPIOB->OTYPER &=        ~(1<<6);    // PUSH-PULL
        GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6;  // Clear pin 6 for alternate function
        GPIOB->AFR[0] |=        0x2 << (4*6);   // set PB pin 6 as AF2 (TIM4_CH1)
    
    //PB10 Pluse Generating Pin
        GPIOB->MODER   &=   ~(0x03 << (2*10));  // Clear bit 12 & 13 Alternate function mode
        GPIOB->MODER   |=   0x02 << (2*10);     // set as Alternate function mode
        GPIOB->OSPEEDR &=   ~(0x03<< (2*10));   // 40 MHz  speed
        GPIOB->OSPEEDR |=   0x03<< (2*10);      // 40 MHz  speed
        GPIOB->PUPDR &=         ~(1<<10);       // NO PULL-UP PULL-DOWN
        GPIOB->OTYPER &=        ~(1<<10);       // PUSH-PULL
        GPIOB->AFR[1] |=        0x1 << (4*2);   // set PB pin 10 as AF1 (TIM2_CH3)
    
    //PB7 LED ON/OFF
        GPIOB->MODER   |=   GPIO_MODER_MODER7_0;   // General purpose output mode
      GPIOB->OSPEEDR |=   GPIO_OSPEEDER_OSPEEDR7;  // Max High speed 50MHz
    
    
    }
    
    // CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
    void TIM2_Trigger(void){
        RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
        TIM2->PSC = 159;                    // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
        TIM2->ARR = 0XFFFF;         // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
    
        TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // 111: PWM mode 1
        TIM2->CCMR2 |= TIM_CCMR2_OC3PE;         // CH3 Output Preload Enable
        TIM2->CR1 |= TIM_CR1_ARPE;              // Auto-reload Prelaod Enable
        TIM2->CCER |= TIM_CCER_CC3E;            // Enable Output for CH3
        TIM2->EGR |= TIM_EGR_UG;                // Force Update
        TIM2->SR &= ~TIM_SR_UIF;                // Clear the Update Flag
        TIM2->DIER |= TIM_DIER_UIE;             // Enable Interrupt on Update
        TIM2->CR1 &= ~TIM_CR1_DIR;              // Set upcounting counter direction
        TIM2->CCR3 &= ~(TIM_CCR3_CCR3);         // Clear CCR3 (Channel 3)
        TIM2->CCR3 |= 0x1;                      // Load the register
        TIM2->CR1 |= TIM_CR1_CEN;               // Enable the counter
    }
    
    
    // CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
    void TIM4_Init(void){
        RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;         // ENABLE TIM4 CLOCK
        TIM4->PSC = 15;                             // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
        TIM4->ARR = 0xFFFF;                         // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
        TIM4->CCMR1 &= ~TIM_CCMR1_CC1S;             // CLEAR CAPTURE/COMPARE REGISTER
        TIM4->CCMR1 |= 0X1;                         // SELECT CH1 INPUTE CAPTURE
        TIM4->CCMR1 &= ~TIM_CCMR1_IC1F;             // DISABLE DIGITAL FILTERING
        TIM4->CCER |= (1<<1 | 1<<3);                // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
        TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC);         // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
        TIM4->DIER |= TIM_DIER_UIE;                 // UPDATE INTERRUPT ENABLE
        TIM4->CCER |= TIM_CCER_CC1E;                // ENABLE COUNTER CAPTURE
        TIM4->DIER |= TIM_DIER_CC1IE;               // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
        TIM4->CR1 |= TIM_CR1_CEN;                   // Enable the counter
        NVIC_SetPriority(TIM4_IRQn, 1);             // SET PRIORITY TO 1
        NVIC_EnableIRQ(TIM4_IRQn);                  //ENABLE TIM4 INTERRUPT IN NVIC
    
    
    }
    
    void TIM4_Echo_Read(void){
    
        if ((TIM4->SR & TIM_SR_UIF) != 0){          // Check the update event flag
            overflow++;                             // if UIF = 1, increment overflow counter
            TIM4->SR &= ~TIM_SR_UIF;                // clear UIF
        }
        if ((TIM4->SR & TIM_SR_CC1IF) != 0){        // Check capture event flag
        newcounter = TIM4->CCR1;                    // read capture value, store as newcounter
        timespan = (newcounter - lastcounter)+(65536 * overflow); // calculate the total pulse width
        lastcounter = newcounter;                   // save the value of newcounter as lastcounter to be used for the next cycle
        overflow = 0;                               // clear overflow counter
        }
    
    }
    
    void LED (void){
    
        float Distance;               // actual distance in cm
        Distance = (timespan / 58.0);
    
        if (Distance <= 100.0){
    
            GPIOB->BSRRL = (1<<7);
        }
            else {
            GPIOB->BSRRH = (1<<7);
    
            }
        }
    
    

  • After it "crashes" press the RED STOP icon and take a screen shot of the code/disassembly window so you can see where it is stuck.

  • You enable interrupts that you don't service, that's unlikely to end well.

  • Can you be more specific. I'm using Timer interrupt to detect signal rising and falling edges and read the counter values at both ends. At least that's what I think I'm doing.

  • You can't just randomly enable interrupts without the TIMx_IRQHandler() code to service them. Code you don't show, so assuming it is missing.

    Your code is stuck in the Default_Handler code because you don't deal with the interrupt with your own routine.

    The TIM will work without the interrupt being enabled.

    When you first published your code none of this detail was presented, it is important to make a complete presentation.

  • I thought I already enabled TIM4 interrupt via the following lines:

    TIM4->DIER |= TIM_DIER_UIE; // UPDATE INTERRUPT ENABLE

    TIM4->CCER |= TIM_CCER_CC1E; // ENABLE COUNTER CAPTURE

    TIM4->DIER |= TIM_DIER_CC1IE; // ENABLE CH1 CAPTURE/COMPARE INTERRUPT

    TIM4->CR1 |= TIM_CR1_CEN; // Enable the counter

    NVIC_SetPriority(TIM4_IRQn, 1); // SET PRIORITY TO 1

    NVIC_EnableIRQ(TIM4_IRQn); //ENABLE TIM4 INTERRUPT IN NVIC

    What I'm I missing here..

  • void TIM4_IRQHandler(void)
    {
      // Handle and clear the interrupt you've caused.
    
      if (TIM4->SR & TIM_SR_UIF)
      {
        TIM4->SR = ~TIM_SR_UIF;
    
        // Perhaps read registers or do something related to why you wanted interrupt?
      }
    }
    

    I don't believe these concepts are entirely unique to ARM or STM32 parts.

  • I can't believe I missed that. I changed the function name from TIM4_IRQHandler to TIM4_Echo_Read without changing it on the NVIC_EnableIRQ() line.
    just changed the function name and everything worked, well the debugger doesn't hang anymore, however I still don't get the Distance value, I guess (according to the guys in Stackoverflow) it's because STM32L1 doesn't have FPU, But the LED did turn on when an object closer that 1 meter is detected, even with the float declaration.

    @Westonsupermare Pier thank you for your patience & knowledge, you sure have a lot of both.