Electronic – Synchronization mechanism suitable for bare metal applications

cembeddedmicrocontroller

I have been developing a bare metal control application on dsPIC33EP256MC506. My application consists of infinite loop in the background and three foreground "application" interrupt service routines (isr). Besides those application isrs there is also let's say system isr which services the SPI end of transaction interrupt requests. In each SPI interrupt new status of the remote digital inputs (state of contactors) is being read. This information is then used for the calculations (logic expressions determining when to close or open individual contactors) done in the background loop.

My problem is that I am not sure how to ensure that during one pass through the background loop the state of the remote digital inputs will be consistent. Better saying I have been looking for a mechanism how to avoid following situation

enter image description here

Can anybody recommend me a simple and robust solution for this kind of problem?.

EDIT:

Below given answers inspired me to following possible solution. I will define SPI driver:

enter image description here

The update function will be executed in the background loop and it will do following

if(new_data_ready){
    new_data_ready = false;
    transferDataToMirror();
}
startTransaction();

The SPI end of transaction interrupt will be serviced in following simple manner:

new_data_ready = true;

The client's code from the SPI driver point of view will access to the digital_ inputs_mirror via getInputsState function call. The digital_ inputs_mirror will be updated in synchronous manner in the background loop via transferDataToMirror() which will retrieve data from the SPI peripheral registers.

Best Answer

Pretty simply: don't directly work on the data the ISR modifies. Instead, in an atomic operation, copy over the potentially volatile variables from the ISR-modified location to your loop state.

Alternatively, if there's more data than you can copy atomically, you'll need to teach your ISR how to write into a ring buffer, and your main loop how to read from one, so that you're never modifying a piece of data that's still being used.

Remark: What you do sounds like 100% an application of a RTOS. These very slim pieces of operating systems are available for your CPU, too (promise! If you can run compiled C on it, someone has ported a small RTOS to it), and you should be using them, exactly because task synchronization is hard and it's a good idea to not do task juggling yourself. It's not any less "bare metal" (you can still write nearly exactly the same code if you want), you just get primitives for executing tasks, exchanging data etc. I don't know your MCU, but look into ChibiOS (if you want something really small) or FreeRTOS (if you want something small with a large user base).