According to my understanding, the best way to implement a PID handler is inside an Interrupt Service Routine which is usually a timer ISR with configurable frequency rate. Here we calculate the process output as a function of setpoint and process input, along with other calculations.

I have the following confusions about what needs to be included inside the ISR and main function.

1) Since the frequency of some PID loops is very high, it is a good idea to read the inputs, setpoint and other values from outside the ISR and calculate only the output inside ISR. In this case what will happen if some of my debug functions(usually a printf) delay the reading of an input or setpoint from the main function? What if the ISR calculated a perfect output value but the main program delays the output to the outside world because of the same debug functions? Here the program behaves in a slightly different manner(Sometimes noticeable differences) with and without the debug code.

2) Another option is to implement input and setpoint reading functions inside the ISR. In this case, both input and output may take a significant amount of time to read the values which will affect the ISR timing. For instance, setpoint can be a serial packet which can become a problem for the ISR execution time. Same happens when we output the calculated value to the outside world.

I am a little bit confused which approach to follow while designing a PID controller. What needs to be included inside the ISR(input, setpoint or output routines) and what needs to be included in the main function?

Implementation Details :- The experimentation setup consists of a 60RPM geared DC motor, an H bridge(VNH5019) and a magnetic rotary encoder(AS5048B). The H bridge has a PWM input for speed control and 2 other pins for direction control. AS5048B is an absolute encoder which gives a 14Bit output corresponding to 0 - 360-degree rotation of the motor shaft and the same act as a feedback signal for the plant. I am trying to implement a PID position control setup for this motor. Right now the PID Update function is written inside a timer ISR which runs at a frequency of 10KHz(may be an overkill for this particular application). The input comes from a rotary encoder which will be replaced by a serial packet in future. My plan is to read input and setpoint from a main function, access the values from PID Update ISR , calculate the output PWM value corresponding to the error just like the arduino PID library implementation as shown below


The variables are shared with the PID Update ISR using pointers. So all the inputs read from within the main is available in the ISR and the output value calculated is available in the main function. The PWM value thus calculated is given to the input of the H bridge IC.

Note : Reading input, setpoint and output to H-bridge is not a part of any ISR right now. Only the calculation is done inside PID Update ISR.

  • \$\begingroup\$ 10kHz cyclic interrupts is very tough real-time for a cyclic interrupt. What makes you think a hobbyist Arduino can keep up with that? Why not use hardware PWM. The only thing that's important for the PID is usually that the calculation is carried out cyclically. To update it with every PWM cycle ain't gonna happen with a corn flakes MCU. \$\endgroup\$
    – Lundin
    Dec 5, 2018 at 16:27
  • \$\begingroup\$ Also, using printf on a small MCU is almost certainly horrible design. Roll out your own serial debugging routines. Might want to mention which MCU you are using. Did I interpret you correctly and it's an Arduino AVR? \$\endgroup\$
    – Lundin
    Dec 5, 2018 at 16:31
  • \$\begingroup\$ @Lundin : I am using Tiva C Series LaunchPad for prototyping (Based on TM4C123GH6PM). Using sprintf along with custom string out functions for monitoring the setpoint, input and tuning parameter values. \$\endgroup\$
    – Supreeth
    Dec 6, 2018 at 3:10
  • \$\begingroup\$ Ok then there's hope, but you ought to look into hardware PWM no matter, unless you truly need the regulator to respond at 10kHz. Might be sufficient to run the PID regulator on a multiple of the actual PWM period time. Depends on how much other work the MCU has perform simultaneously. The PID must absolutely run on a fixed periodic time though. Regarding the debug interface, you should probably use something more suitable for real-time, like raw values over SPI or CAN. Or perhaps UART with DMA if that's available. Busy-wait printf UART is not an option, you aren't programming for MS DOS. \$\endgroup\$
    – Lundin
    Dec 6, 2018 at 8:46

2 Answers 2


1) If the debug functions change the behavior of the system, then you're debugging for Schrodinger bugs. You won't know if there is a bug or not because you are looking for it.
That is an issue that needs to be addressed.

You should use a fifo to output data asynchronous from the print call location. Have the print function output to the fifo, and use the TX complete interrupt to fetch a new byte to transmit. Make sure you do not overflow this fifo buffer, and that you're not interrupting the print functions with those in interrupts.
You need to treat it as log, with a low frequency of lines (like dmesg). Only on state changes, not for continuous plotting of measurement data.

2) If the setpoint arrives asynchronous, then you cannot wait for in in the PID thread. You have to cache it somewhere else.
If the measurements are also asynchronous, then you have another problem. It makes no sense to recalculate PID when:
- there is no new measurement.
- the previous output was not processed yet.
You might need to lower the frequency of PID calculation.

It looks like what you describe is a simple tasker system. You have an superloop (main `while(1)) with idle priority tasks, and a few ISR with high priority or regular tasks. For example, performing DSP on the ADC samples is such a regular high priority task. If you're late, the data is irrelevant and overwritten.
Things that are lower priority, for example, is communicating with a user or reading received setpoint message frames.

The priority of the various interrupts define the task priority, and if they can preempt. This is an extremely simple way of scheduling. But it has drawbacks. Tasks should not take longer then their interval, this included possible preempted tasks.
Make sure to setup the priorities correctly.

If you put the only watchdog reset in the superloop, you will know when any thread hung itself.
You should also watch for missed interrupts, for example, when you're still doing A, and the A IRQ is set again.

See also if an (RT)OS is of added value to your system.


There will not be a specific answer available for your question because there is not a enough information about what you are trying to control. The behavior of your system will be key to understanding how you code it, how you debug it and how you tune it.

The only things I can get out of what you wrote are:

  1. Using I/O such as printf for debugging in a real time system is typically not a suitable approach, especially if the output of such is routed to some slow interface like a UART port. You may very well need to devise other debug methods.
  2. You need to look at your set point reading process. How fast can it change? From what you describe that it arrives via serial input should immediately tell you that it should not be read from serial inside your timer ISR.

In the end every thing in a real time control system is a balancing act of finding the correct way parcel out the available CPU cycles in a way to maximize the computational efficiency. Every time you find the CPU waiting for something at the same time that it needs to be taking care of something else it means you do not have the correct design.

  • \$\begingroup\$ If the debug is DMA-able, it might get closer to real results (by keeping out of the way). \$\endgroup\$ Dec 5, 2018 at 15:20
  • \$\begingroup\$ @MichaelKaras: I have edited the post with implementation details for more clarity \$\endgroup\$
    – Supreeth
    Dec 5, 2018 at 15:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.