Logo Questions Linux Laravel Mysql Ubuntu Git Menu

STM32F4 - can I use delays in interrupt routines?

I'm using an STM32F4 discovery board for a project and am wondering if I'm approaching the problem correctly. When I press a button, an external interrupt is triggered which runs a routine; without using a delay, this part works fine. As the routine moves a servo then returns it to its original position, a delay is added to allow the servo to catch up with the new PWM output before returning to the original position. When I run the new interrupt routine with the delay, the board locks up. In debug the code appears to stall at the delay loop.

The delay is a simple systick routine. Is it bad practice (thus the reason for my crashes) to put this inside my interrupt, and should I use a different method? For example setting a one shot timer inside the external interrupt routine which returns the servo after a set time?


like image 396
Joe of Loath Avatar asked Mar 17 '23 22:03

Joe of Loath

2 Answers

As you've discovered, interrupt routines are intended to perform quick handling of an external event, and defer additional work to other facilities. This is why, in your case, the delay loop causes the board to lock up: no other work is being performed while the code is sleeping inside the interrupt handler. That is a typical characteristic of all interrupt handlers.

If you need to perform a separate task (moving the servo again), schedule it just like you described:

  • if the servo is guaranteed to have reached the intended position during a specified amount of time, set a timer to fire after that amount of time
  • if the servo mechanism can notify you, perhaps via another interrupt, when it reaches a specified position, use that to handle its movement back to the original position.
like image 167
Michael Foukarakis Avatar answered Mar 25 '23 07:03

Michael Foukarakis

Assuming you have a spare timer that can generate an interrupt, you can have the interrupt handler setup a timer interrupt handler that starts the next step. I use pointers to functions that are setup and later called by interrupt handlers to advance an interrupt driven process through a sequence of logical steps. In some cases, I'll have a set of hierarchical pointers to functions, where each pointer to function is used to call an end action handler for a logical function. For example, the end action function pointer for a high level function (like a wait for ready function) is set, and the high level function is called. That high level function in turn sets an end action function pointer for a low level function, and calls the low level function to start it. The low level function then sets the interrupt end action function pointer, and starts some type of interrupt driven sequence, advancing the low level interrupt function pointer through a series of interrupt functions to follow a sequence, then calling the high level end action function pointer when the sequence is complete to return back to a step in the high level sequence.

To maintain accurate timing and avoid drift over a period of time, you need to base all "delays" off an original reading of the timer. For each step, you add a fixed count to a variable that was initialized with a original reading of the timer in order to determine the next delay point. For frequencies that aren't an exact multiple of the timer, you can use division to produce a quotient and remainder, accumulating the remainder to round up the quotient as needed for each interval step.

like image 45
rcgldr Avatar answered Mar 25 '23 09:03