How to split tasks between interrupts and the main loop on a bare metal controller?

I'm working on a robotics project where I have 3 services running. I have my sensor DAQ, my logic ISR (motor controller at 20kHz) and my EtherCAT slave controller.

DAQ and EtherCAT run in the idle and the logic runs during an interrupt. The logic does some calculations and controls the motor. The EtherCAT service (kinda like CANbus) runs together with my DAQ in the idle loop. I can not run the DAQ in the interrupt because that leaves me with less than 100ns for the EtherCAT service to run.

I'm not sure whether this is the right way to do this especially considering all the scary things i've read regarding data corruption when using interrupts.

Does anyone have some nice ideas on how to handle these services?

I'm running all my code on a Zynq 7020 (on the ARM Cortex) and it's written in C++.

Here is an example of my code:

/**
* Get all sensor data
*/
void Supervisor::communication(void) {
// Get all the sensors data
dispatchComm.getData(&motorAngle, &motorVelocity, &jointAngle, &springAngle, &tuningParameter);

}

/**
* Run all the logic
*/
void Supervisor::logic(void) {

dispatchLogic.calculate(tuningParameter, motorAngle, motorVelocity, jointAngle, springAngle);

dispatchLogic.getData(&angle, &magnitude);

// Dispatch values to the motor drive
dispatchComm.setMotorDriveSetpoint(angle, magnitude);
dispatchComm.writeToPiggyback((uint32_t) (tuningParameter), motorAngle, motorVelocity);
}

• Embedded programming, especially when it comes to hard real time requirements is a tricky and complicated topic, yet you only mention "an interrupt". Are you working with only one interrupt? I bet that chip has dozens of interrupts and many other features that help to stay within a certain time boundary. "logic runs during an interrupt" as far as I remember, the rule of thumb is to keep the interrupt routine as short as possible. It would likely be helpful if you included some of your code. – Bending Unit 22 May 23 '16 at 22:07
• You will have the best luck asking this question on a product specific forum or to the application engineers of the supplier you got the board from. – hauptmech May 24 '16 at 3:02
• @BendingUnit22 Yes I only run a single interrupt. In that interrupt I run my controllers (motor controller and joint position controller). Within that interrupt I need the data from the sensors which is acquired during idle state. I have included my code. The reason I do my calculations in the interrupt is because I have been told that the motor controller always has to run at a fixed frequency. – Ortix92 May 24 '16 at 8:56
• I agree with @hauptmech, chances are Electrical Engineering will also provide better answers. Because your question is not really related to robotics. – Bending Unit 22 May 24 '16 at 9:20

My first impression from your question is that you are struggling with the fact that no hardware provides infinite resources. You can either slow down your control loops or look for better hardware (which may not exist).

If your control has nested loops, then run each one a slow as possible. Are you controlling position at 20kHz? Pull that out and run that at 500Hz (A little faster if your mechanical mechanism is designed for high performance). Is you DAQ measuring current for the controller? Try running your current control at 5kHz but commutating at 20kHz.

All those numbers are assuming a meso scale device using electro-magnetic actuators.

Regarding interrupts, the rule of thumb is to do as little as possible, as quickly as possible, inside the interrupt and everything else outside it. However it feels like you might be using a timer interrupt to substitute for a real-time task scheduler (nothing wrong with that), in which case, you will want to do everything needed for that cycle in the interrupt. Add a time-overrun check at the end so that if your interrupt is taking longer than 50us you know about it and can adjust your strategy or optimize code.

If you are writing interrupts then you need to go learn the details about data corruption issues. They are not scary and they are straightforward to manage on all modern processors. You can protect data in your idle loop by disabling interrupts in critical sections or using higher level synchronization constructs if you really need to.

A final thought; even though you are coding in C++, you should read the processor datasheet and instruction set so that you have an idea of the capabilities and limitations of the hardware if you have not already.

EDIT:

From the limited code you added it looks like high level control for a series elastic actuator. The spring will dominate the mechanical time constant of the actuator system and you probably do not need that loop to run at 20kHz in lockstep with your motor commutation.

• Very good advice from @Hauptmech. I would also suggest the use of a code profiler to see what tasks are occupying CPU time for various events, and optomize where needed. You may need to embed some C or ASM code in the ISRs, but unless you profile the code, you are just guessing. – SteveO May 24 '16 at 4:18
• I'm having a hard time visualizing how the structure of this code will look. You are correct to assume that this is regarding a series elastic actuator (for an exoskeleton). From what I can understand now is that I do all non critical tasks at lower frequencies (so I will need multiple interrupts). At 20kHz I am supposed to commutate the motor and generate the PWM signal. For that I need the motor encoder values acquired over SPI. Any example which is similar to my system would be greatly beneficial. – Ortix92 May 24 '16 at 12:16
• I took a look at your software on github (saw the mechanicals too). I don't have an easy example for you. If your skill is in low level, go for multiple nested interrupts if the hardware supports it, if your skill is in high-level, put a realtime OS on your system. You could probably put your low frequency calculation in the idle loop and check the timer for when to run the calculation and when to run soem() but if your application complexity grows you will have to do one of the above approaches. – hauptmech May 24 '16 at 23:28