coding help (interrupts)

hi guys- just a quick question.

i want in my program to run 2 separate loops - a control loop - running at 120Hz with a runtime of ~6ms, and a communications loop - running at 25Hz with a runtime of ~3ms.

to do this i set up 2 timers (using the Atmega2560) to run at these speeds... now here comes the tricky part- i cant run the loops inside the ISR since the arduino framework doesnt allow nested interrupts which is required to read the digital sensors and receive incoming serial data and PPM data... the only solution i found was to raise flags in the ISR's and then run the loops inside the main Loop... this causes some problems such as inconsistent run frequencies (problematic for the PID).

how can i design the infrastructure of my program so that i run these loop at fixed constant speeds? ( please elaborate with code, i'm no AVR expert...)

Thanks, Edi

What are you trying to control and communicate with? Is there really a need to be so rigid about timing, or can you have the arduino react when it needs to?

its a quadrotor- [u]control[/u] is key. communications are with a ground station - very important.

since the arduino framework doesnt allow nested interrupts

You don't have to restrict yourself to what the Arduino allows. The AVR does support nested interrupts (to the extent that you want to use here anyways), and you're free to use any of the AVR LibC library capabilities even within the Arduino IDE. Nothing prevents you from doing so.

a control loop - running at 120Hz with a runtime of ~6ms, and a communications loop - running at 25Hz with a runtime of ~3ms.

120 * 6 = 720; 25 * 3 = 75; That's a total of 795ms of processing every second, or nearly 80% CPU load. Precise timing with that much loading is only going to be possible within ISRs. Alternatively, try to optimize your PID routine. Switch any floating point operations to fixed point math. If you can cut that processing time in half, your timing consistency will improve significantly.

here's the full picture: i have: 1. Serial data constantly being shot at me. 2. a vital external interrupt ISR constantly running in the background. 3. 2 sofware ISR's generated with 16-bit timers.

how do i work around the disabled interrupts (some code please) so that i can put my control loop inside a ISR without 'interfering' the stuff stated above? how do i set the priority of all the interrupts and how do i enable the nested ones? if i enable nested interrupts on the control loop ISR, do i need to 'fix' all the priorities so that nothing gets ran over? how do i do all these thing? im no avr expert, please elaborate on code...

Thanks, Edi

  1. a vital external interrupt ISR constantly running in the background.

No, you don't. It is essential that you get your terminology straight. The Arduino runs one process. There is no background/foreground distinction possible when you have one process.

The ISR, when it is running, is the foreground process. When it is not running, it simply waits to be triggered again.

It seems to me that you either need multiple Arduinos or you need to define the priorities of the one that you have. Keeping the quadcopter flying, and not hitting stuff or crashing, is highest priority. Communicating with the ground station happens when there is time.

Just like in real life.

  1. when i say background i mean in an asynchronous ISR.

True, those are the priorities when you look at the system in that way…
but its much more complex when you dive into it:
this is a full list of the ISR’s going on that need to be prioritized:

  1. 2 software timers (1 & 5) running at separate frequencies running the control loop and the comm’s loop.
  2. external (background) ISR for incoming PPM signal data.
  3. incoming Serial data from the ground station
  4. other core Ardunio ISR’s.

all of that needs to be prioritized, and when it does- can someone please show me some code of how to enable interrups inside the control ISR and prioritize the interrupts?

Thank you,
Edi

I haven't built a quad copter, so I may be off base here, but from basic principles, I don't think you need to worry so much about nesting interrupts. Conventionally, you just set a flag in each of your interrupts and process it in loop. You may have to do some clever coding in loop to ensure that it reacts fast enough and implements the priority you need. If each interrupt service routine is lengthy, you may need to break them into steps and manage those steps through a state machine so that you can move through loop quickly to see if a higher priority event needs your attention.

Serial in is buffered, so you just need to get to it eventually. Serial out blocks, so you may want to put a buffering wrapper on it that only does one character at a time, so you can get back to loop asap.

You should end up with a loop that looks at three or four flags in priority order, picks an action and does it, perhaps in several separate steps, with a side order of serial processing when you have nothing else to do. This offers you more flexibility in the way the 'copter is controlled, though it may be harder to debug.

The things you are asking to be performed (nested interrupts, configuring individual interrupt priorities, etc) can all be accomplished by using low level register commands and the specific information is all documented in the AVR datasheet for the specific chip. There are commands to enable and disable interrupts globaly and individual interrupt sources can be disabled and enabled. However the complexity of this kind of control is usually performed in a OS rather then in user code and is probably within the capabilities of only the most experienced and knowledgeable AVR programmers.

You might be better off running individual tasks in dedicated arduino modules and have a master arduino module coordinate the whole application. Otherwise don't expect to find off the shelf code or libraries to solve your problems, as it would be so very specific to your actual hardware setup and user functions.

Lefty

edigotlieb:
a vital external interrupt ISR constantly running in the background.

  1. when i say background i mean in an asynchronous ISR.

Your terminology is confusing me. An ISR “running constantly” is a bit of a contradiction of terms. If it is running constantly, it’s not an ISR.

Your main loop runs constantly, interrupts interrupt it, hopefully briefly.

… can someone please show me some code of how to enable interrups inside the control ISR …

You can enable interrupts inside an ISR:

void myisr ()
  {
  sei ();  // enable interrupts
  }

However I think you really have to straighten out your design. Once you enable interrupts, the interrupt routine might be called again, thus recursing.

There is a fixed priority of interrupts (the order in which the hardware checks them). You can’t change this.

how do i work around the disabled interrupts (some code please) so that i can put my control loop inside a ISR without ‘interfering’ the stuff stated above?

You just don’t want to do this, trust me. You don’t have a “control loop inside an ISR” - it just doesn’t make sense.

You want a control loop outside an ISR, and when interrupts happen they set flags that the loop then checks. The loop can check those in the priority order you decide is best. The loop should be written in such a way that it checks frequently (eg. so you don’t crash into a tree while you are busy taking a nice photo).

The best solution depends on what what the priorites are. When a control timer interrupt occurs, can you afford the execution of the control code to be delayed by 3ms if a comms timer interrupt has just occurred? Likewise, when a comms timer interrupt occurs, can you afford the execution of the comms code to be delayed by 6ms if a control timer interrupt has just occurred? if the answer to both of the above is yes, then you can just sets flags in the timer ISRs and execute the control code and comms code in loop() when it sees those flags set.

Your CPU load does appear to be high and you should probably look at optimizing your control code.