Author Topic: STM32F103 interrupt problems  (Read 4107 times)

0 Members and 1 Guest are viewing this topic.

Offline anda3243Topic starter

  • Contributor
  • Posts: 44
  • Country: cn
  • Product development professional, still learning
    • Check out our ThreadTitan product
STM32F103 interrupt problems
« on: May 04, 2022, 07:40:45 am »
Hello Forum

It seems that I am asking for some help every day. Feel free to move this to the beginner section if you feel it is more appropriate.

I have my STM32 board running. And I have implemented some basic functions. I have a blinking LED, I can detect when a button is pushed, I have a PWM signal out to one of the pins. I had some issues previously, you helped me here.
https://www.eevblog.com/forum/microcontrollers/stm32f103t8u6-not-recognized-by-cubeide-as-genuine/

Now I have problems getting the interrupt functions to work.
Firstly I wanted the buttons to be managed by interrupt. There are many guides out there, here is one of them.


When I follow this example, as soon as I push the button the MCU will freeze. I have a blinking LED going, if the button is pushed when the LED is on, it stays on, of LED is of it stays of.
I can use the NRST and try again, this issue can be repeated again and again.

I can have a IF function in the main while loop for the buttons, and there it will work without issue.

I could live with having the buttons in the while loop.

But then I needed a timer. I need one of the buttons provide a different function if it is pressed for a long time. And the best solution I could find would be to use a timer
Similar to this example. https://deepbluembedded.com/stm32-timer-interrupt-hal-example-timer-mode-lab/
First I get it to blink a LED, later I can use it to count time and detect how long the button has been pressed.

But when the function to start timer is added in main.c the board will not work.
I can remove this line, and it will work
HAL_TIM_Base_Start_IT(&htim4);

It is in this section in main.c:

  /* USER CODE BEGIN 2 */

  //Start PWM timer
 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);

 //Start the timekeeping timer
 HAL_TIM_Base_Start_IT(&htim4);

 int pulse = 0 ;
 
  /* USER CODE END 2 */
 
I dont know if something is wrong with my chip, or if there is some small setting that I have wrong

Help would be much appreciated.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6938
  • Country: es
Re: STM32F103 interrupt problems
« Reply #1 on: May 04, 2022, 08:41:50 am »
What's the timer4 config? Have you enabled the timer4 interrupt under CubeMX timer settings?
When those things happen, debug the code, then you will see where is it stalling at, probably polling a flag.
Better you post the rest of the code!

There're lots of ways to time a button. You can use HAL_GetTick() to get the systick (1ms steps).
Will be more efficient this way than having a timer interrupt running all the time.
Ex.
Code: [Select]
// Assume button is read low when pressed
#define BTN()    HAL_GPIO_Read(Button_GPIO_Port, Button_Pin)

uint32_t btn_time;
uint8_t last_btn=1; // 0=previously pushed, 1=released, 2=pushed, but long press action already done, so ignore until released

void main (void){ 

  if(BTN()==0){                     // Button pushed
    if(last_btn==0){                // Was previously pushed (continuously pressed)
      uint32_t push=HAL_GetTick()-btn_time;   // Get elapsed time
      if( push>5000 ){              // Very long press, >5seconds, we can take action now if required, before it's released
        last_btn=2;                 // Set last_btn=2 to avoid any more button action until it's released (And set to 1)
      }     
    }
    else if(last_btn==1){           // Wasn't previously pushed (Ignore if button=2)
      last_btn=0;                   // Update value
      btn_time=HAL_GetTick();       // Save push time
    }
  }
  else{                             // Button released
    if(last_btn==0){                // Was previously pushed
      uint32_t push=HAL_GetTick()-btn_time;   // Get elapsed time
      if( push>1000 ){              // Button was pushed for >1 second       
      }
      else if( push>500 ){          // Button was pushed for >0.5 second       
      }
      else if( push>100 ){          // Button was pushed for >0.1 second           
      }                             // Shorter button presses can be ignored, probably just noise.
    }
    last_btn=1;                     // Update value
  }
}

And, instead of while(), use if() to avoid blocking the program flow. The program gets more complex, as you have to track all states, but execution is extremely more efficient.

while() loops are only ok for events expected to finish in a very short time, ex. a flag happening in few us, but if it's going to take milliseconds, better you use a state machine, so every time the function is called, it checks the last state and does whatever it needs based on that, and updates the state if required.

Another example:
Code: [Select]
const char * hello = "Hello, this is a message\n";
void send_message(const char * msg){
  while(*msg){
    while(!UART_READY);     // Wait until UART is ready (Pseudo code)
    UART_send(*msg++);      // Send next char
  }
}
void main (void){
  send_message(hello);
  do_something();           // This will be blocked until the message is completely sent
}

Code: [Select]
uint8_t send_busy;
const char * hello = "Hello, this is a message\n";
const char * send_ptr;

uint8_t send_is_busy(){      // Return current state
  return send_busy;
}
void send_message(const char * msg){
  send_ptr=msg;             // Store pointer to message
  send_busy=1;              // Set busy flag
}
void handle_message(void){
  if(!send_busy){           // Nothing to do
    return;
  } 
  if(!*send_ptr){           // Done sending
    send_busy=0;
    return;   
  } 
  if(UART_READY){           // If UART ready (pseudo code)
    UART_send(*send_ptr++); // Send next char
  }
}

void main (void){
  if(!send_is_busy()){      // Send message if ready
    send_message(hello);
  }
  handle_message();         // Always call handler
  do_something();           // This will never be blocked by sending the message
}
« Last Edit: May 04, 2022, 11:18:31 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline anda3243Topic starter

  • Contributor
  • Posts: 44
  • Country: cn
  • Product development professional, still learning
    • Check out our ThreadTitan product
Re: STM32F103 interrupt problems
« Reply #2 on: May 04, 2022, 10:27:17 am »

Thank you DavidAlfa, you have helped me more than once! I will buy you a beer sometime!

I am slowly learning to code. Moving from just copying in example code, to at least a little bit understanding what each line does.

I will digest the post you wrote, it will take some time. I will think about posting the rest of the code.

Yes, timer4 is configured for interrupt. I will make more attempts at debugging. For now, as soon as I use anything interrupt related, the chip will freeze. I suspect that there is some setting that is overlooked or managed differently in CrossWorks and CubeIDE.

I did read about the GetTick function, i will try to use it next. 


What's the timer4 config? Have you enabled the timer4 interrupt under CubeMX timer settings?
When those things happen, debug the code, then you will see where is it stalling at, probably polling a flag.
Better you post the rest of the code!

There're lots of ways to time a button. You can use HAL_GetTick() to get the systick (1ms steps).
Will be more efficient this way than having a timer interrupt running all the time.
Ex.
Code: [Select]
#define BTN_1()    HAL_GPIO_Read(Button1_GPIO_Port, Button1_Pin)

uint32_t btn_time;
uint8_t last_btn;

void main (void){ 

  if(!BTN){                         // Button pushed
    if(!last_btn){                  // Was previously pushed (continuously pressed)
      uint32_t push=HAL_GetTick()-btn_time;   // Get elapsed time
      if( push>5000 ){              // Very long press, >5seconds, we can take action now if required, before it's released
        last_btn=2;                 // Set last_btn=2 to avoid any more button action until it's released (And set to 1)
      }     
    }
    else{                           // Wasn't previously pushed
      last_btn=0;                   // Update value
      btn_time=HAL_GetTick();       // Save push time
    }
  }
  else{                             // Button released
    if(!last_btn){                  // Was previously pushed
      uint32_t push=HAL_GetTick()-btn_time;   // Get elapsed time
      if( push>1000 ){              // Button was pushed for >1 second       
      }
      else if( push>500 ){          // Button was pushed for >0.5 second       
      }
      else if( push>100 ){          // Button was pushed for >0.1 second           
      }                             // Shorter button presses can be ignored, probably just noise.
      last_btn=1;                   // Update value
    }
    else{                           // Wasn't previously pressed (Or button=2)
      last_btn=0;                   // Update value
    }
  }
}

And, instead of while(), use if() to avoid blocking the program flow. The program gets more complex, as you have to track all states, but execution is extremely more efficient.

while() loops are only ok for events expected to finish in a very short time, ex. a flag happening in few us, but if it's going to take milliseconds, better you use a state machine, so every time the function is called, it checks the last state and does whatever it needs based on that, and updates the state if required.

Another example:
Code: [Select]
const char * hello "Hello, this is a message\n";
send_message(const char * msg){
  while(*msg){
    while(!UART_READY);     // Wait until UART is ready
    UART_send(*msg++);      // Send next char
  }
}
void main (void){
  send_message(hello);
  do_something();           // This will be blocked until the message is completely sent
}

Code: [Select]
uint8_t send_busy;
const char * hello "Hello, this is a message\n";
const char * send_ptr;

send_is_busy(){             // Return current state
  return send_busy;
}
send_message(const char * msg){
  send_ptr=msg;             // Store pointer to message
  send_busy=1;              // Set busy flag
}
handle_message(void){
  if(!send_busy){           // Nothing to do
    return;
  } 
  if(!*send_ptr){           // Done sending
    send_busy=0;
    return;   
  } 
  if(UART_READY){           // If UART ready
    UART_send(*send_ptr++); // Send next char
  }
}

void main (void){
  if(!send_is_busy()){      // Send message if ready
    send_message(hello);
  }
  handle_message();         // Always call handler
  do_something();           // This will never be blocked by sending the message
}
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6938
  • Country: es
Re: STM32F103 interrupt problems
« Reply #3 on: May 04, 2022, 11:10:23 am »
Check the button code, there were few mistakes.
So you don't blow your brains trying to understand why it isn't working :D.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline anda3243Topic starter

  • Contributor
  • Posts: 44
  • Country: cn
  • Product development professional, still learning
    • Check out our ThreadTitan product
Re: STM32F103 interrupt problems
« Reply #4 on: May 05, 2022, 04:56:19 am »
Check the button code, there were few mistakes.
So you don't blow your brains trying to understand why it isn't working :D.

I am in middle of checking it.
I think I get the basic idea of what it is supposed to do, I just need it to get it working.
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 5399
  • Country: nl
Re: STM32F103 interrupt problems
« Reply #5 on: May 06, 2022, 12:19:30 am »
I like sprinkling debug code through my sourcecode that sends out data through some unused peripheral and/or some I/O pins.

Several unused peripherals are fit for this such as an UART, or SPI.

Sending out a byte via a UART is very lightweight for the uC. It is just a few instructions.
With this info you can catch the data with a Logic Analyser, and then also back track where it's been before some fault happened.

For example, if your application toggles an I/O pin every time the main loop executes, you already have a log of how quick that loop executes, and of when ISR's happen, because the pin stops toggling.

the first instruction of an ISR can be to set another I/O pin high, and the last instruction to set it low again. This gets you a log of how many times an ISR is executed, and how long it takes to execute it.

By making a little library for this you can wrap it up to easily remove the code with a single #define.

It's not a perfect method but I find it quite useful.
 

Offline anda3243Topic starter

  • Contributor
  • Posts: 44
  • Country: cn
  • Product development professional, still learning
    • Check out our ThreadTitan product
Re: STM32F103 interrupt problems
« Reply #6 on: May 07, 2022, 12:36:59 am »
Thank you for the tip.
What I have started doing is having moving around toggle LED commands to see what part of the code works properly, and what doesn't. Without any such feedback one is truly blind.

For the next iteration of the board I will add some LED just for this feedback purpose, and something from a unused CPU pin where oscilloscope probe can be connected.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6938
  • Country: es
Re: STM32F103 interrupt problems
« Reply #7 on: May 07, 2022, 08:31:56 am »
Sending out a byte via a UART is very lightweight for the uC. It is just a few instructions.
Loading the char into the uart buffer doesn't take any CPU power, but waiting for the data to be sent is a different story, unless you provide some non-blocking mechanism.
At 72MHz and 115200baud the CPU will stall for 625 cycles for each char. That's why I made that example!
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->