STM32F103 interrupt problems - Page 1
Forum section: electronics / general

author: anda3243
author_rank: Contributor
timestamp: May 04, 2022, 07:40:45 am
content: Hello ForumIt 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 timerSimilar 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 workHAL_TIM_Base_Start_IT(&htim4);It is in this section in main.c:/* USER CODE BEGIN 2 *///Start PWM timerHAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);//Start the timekeeping timerHAL_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 wrongHelp would be much appreciated.

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 04, 2022, 08:41:50 am
content: 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:// 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 releasedvoid main (void){if(BTN()==0){ // Button pushedif(last_btn==0){ // Was previously pushed (continuously pressed)uint32_t push=HAL_GetTick()-btn_time; // Get elapsed timeif( push>5000 ){ // Very long press, >5seconds, we can take action now if required, before it's releasedlast_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 valuebtn_time=HAL_GetTick(); // Save push time}}else{ // Button releasedif(last_btn==0){ // Was previously pusheduint32_t push=HAL_GetTick()-btn_time; // Get elapsed timeif( 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: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:uint8_t send_busy;const char * hello = "Hello, this is a message\n";const char * send_ptr;uint8_t send_is_busy(){ // Return current statereturn send_busy;}void send_message(const char * msg){send_ptr=msg; // Store pointer to messagesend_busy=1; // Set busy flag}void handle_message(void){if(!send_busy){ // Nothing to doreturn;}if(!*send_ptr){ // Done sendingsend_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 readysend_message(hello);}handle_message(); // Always call handlerdo_something(); // This will never be blocked by sending the message}

author: anda3243
author_rank: Contributor
timestamp: May 04, 2022, 10:27:17 am
content: 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.Quote from: DavidAlfa on May 04, 2022, 08:41:50 am

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 04, 2022, 11:10:23 am
content: Check the button code, there were few mistakes.So you don't blow your brains trying to understand why it isn't working.

author: anda3243
author_rank: Contributor
timestamp: May 05, 2022, 04:56:19 am
content: Quote from: DavidAlfa on May 04, 2022, 11:10:23 amI 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.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: May 06, 2022, 12:19:30 am
content: 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.

author: anda3243
author_rank: Contributor
timestamp: May 07, 2022, 12:36:59 am
content: 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.

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 07, 2022, 08:31:56 am
content: Quote from: Doctorandus_P on May 06, 2022, 12:19:30 amLoading 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!