Team,
Since we have a few new developers, I thought it might be a good idea to review the concept of atomic operations.
An atomic operation is an operation that proceeds without the possibility of being interrupted. Moving 8 bit and 16 bit values around in memory is atomic because the move is accomplished by a single instruction. Moving a 32 bit value is not guaranteed to be atomic, because the code that the compiler generates usually moves it as two 16 bit values using more than one instruction, so it could get interrupted between the instructions involved in the move. As a result, the value that is being moved good get changed while it is being moved, which can cause problems.
Many of the computations in MatrixPilot involve several inputs and several outputs. These computations are hardly every achieved atomically, because the inputs are continually changing. But the lack of atomicity usually does not matter much when all of the inputs and outputs are 16 bit values, because the inputs do not change very much from sample to sample.
However, sometimes atomicity matters very much. Two examples come to mind. One of them is the A/D sampling, and the other is the EM406 communications handler.
One of the steps in the A/D conversion is to divide running totals by the number of samples. It is critical that the number of terms in the total exactly corresponds to the number of samples used to do the division. It just will not do for the number to be off by one. So, we must guarantee that the division is achieved atomically. That is, the total and the number of samples must be consistent. This is achieved by doing the division in the A/D ISAR instead of by the client of the samples. Take a look at the
code.
The way that the atomicity of numerator and denominator of the division is achieved is by doing the division in the A/D ISAR. However, because the division is done there, we do not know exactly when it should be done, since the result is used in a different ISAR. But we can estimate the earliest it will be needed, and continually revise it during a short time window when it might be read by the client.
Another example is in the communications handler for the EM406. The data comes through from the EM406 in 8 bit bytes. So 16 bit and 32 bit values are at risk of becoming inconsistent when read by the clients, if they are read while the data is coming in. Not good. Atomicity is achieved in the EM406 communications handler by using two techniques.
First, everything is double buffered in the EM406 communications handler. As the data is coming in from the EM406, a slow process, it is stored in the first buffer. When all of the data has arrived, the data is then copied over to a second buffer (a fast process), and the downstream computations are kicked off.
The second technique used to achieve atomicity in the EM406 comm handler is to time the downstream computations to happen between sets of messages. One of the things I did in developing EM406 handler was to determine the sequence of the several message types sent by EM406, and then make sure that the data copying started only after the last message in the sequence is complete.
I get the uneasy feeling that atomicity has not always been achieved where it is needed in the newer software that has been developed over the past year or so, particularly communications software, such as telemetry and MAVLINK. 16 bit values are fine, but any 32 bit values are at risk. So, if you are seeing "glitches" in any 32 bit values, such as longitude or latitude, you might want to suspect violation of atomicity.
Regarding 32 bit values, it turns out that both the dsPIC30 and the dsPIC33 have atomic 32 bit move instructions, it is just that the compiler does not use them, which is too bad.
I took a look at the 32 bit move instructions, I think it would be possible to write a routine to achieve an atomic 32 bit move.
If any of you suspect that some of the glitching you see in the 32 bit values in code that you have developed recently, let me know, I will give you a hand in making the transfer atomic. There are several ways we could do it:
1. Restructure the code to guarantee the 32 bit value read and write cannot interrupt each other.
2. Write a 32 bit atomic move routine.
3. Turn interrupts off for a few instructions.
4. Use the features of the RTOS for interprocess transfer of 32 bit values.
Best regards,
Bill