Andrew Que Sites list Photos
Projects Contact
Main

October 05, 2019

Emerald Dragon's Record Runtime Continues

Emerald Dragon Runtime
   The Emerald Dragon continues to have a flawless runtime record now over 800 days—that's two years and 80 days.  Zen informed me the battery pack is bulging.  This means the battery is physically decaying and needs to be replaced.  I have ordered a replacement.  This is the only physical maintenance it has required since it went online.
   Camping with Mary, her daughter Kate and several friends.  After sunset and dinner I did some night photography around the camp site.  I did get a few star shots, but clouds kept moving in and obstructing the sky.  Nonetheless I was able to get a few decent pictures.
   Pokie and I worked on replacing some rotten trim on the exterior of her new house.  The "quality" wood we were using was actually quite poor so we had to use a wood filler to patch some knots and planning marks.  It started raining before we could finish.  This should not have been an issue since we had a roof over our work area, but the wind off the lake make it a problem and we had to stop before sanding.

September 29, 2019

Poor Man's Semaphore Mistake

On small embedded systems that don’t use an operating system, there is often a mix of a main loop and system interrupts for controlling the system. One problem with interrupts is spelled out in their name: they interrupt normal code. This can change variables being used by other code, while they are being used. This can be useful if you are waiting for an event. For example:

bool volatile hasInterruptOccured = false;

void someInterruptFunction()
{
   hasInterruptOccured = true;
}

while ( ! hasInterruptOccured );

Assume someInterruptFunction is called by an interrupt routine and the while loop is in the program’s main function. One important note here is that hasInterruptOccured is marked volatile. That tells the compiler the value could change at any time. Otherwise, the optimizer will assume that since the while loop never changes hasInterruptOccured then it never needs to check it again. Being volatile means the optimizer will make no such assumptions.

The above is a useful example of variable being changed by interrupts, but it can be problematic.

Consider this code below. A function is called periodically to make calculations from x, but x is changed from an interrupt source.

y = a * x * x + b * x + c;

Now consider what happens if x can change at any time. The equation might actually result in the following:

y = a * x1 * x2 + b * x3 + c;

Where only two of the set of xn are equal. We never know when an interrupt might occur, and should plan that is can occur anywhere. One solution to the above is to use an intermediate to hold the value of x.

xHold = x;
y = a * xHold * xHold + b * xHold + c;

This would seem to solve all our problems, but it might not. Consider this code on an 8-bit processor:

uint16_t xHold = x;
y = a * xHold * xHold + b * xHold + c;

You might think that xHold will capture the value of x, but it may not. That is because on an 8-bit system, storing the value of a 16-bit integer takes 2x 8-bit operations, any one of which might be interrupted. This means xHold could change in horrible ways.

Consider x=256 or 0x0100, and an interrupt will change the value to 255 (0x00FF). Now if the assembly code starts the copy with the most-significant byte, then gets interrupted, the result in xHold will be 511 (0x01FF). That’s because it read the most-significant byte when that was set to 0x01, and after the interrupt read the least-significant byte which was now 0xFF.

The typical solution to avoiding such issues is simply to disable interrupts when reading volatile variables.

DisableInterrupts();
uint16_t xHold = x;
RestoreInterrupts();
y = a * xHold * xHold + b * xHold + c;

Now there is no way for x to change when reading.

There is a second way to accomplish the same thing without disabling interrupts.

uint16_x xHold;
do
{
   xHold = x;
} while ( xHold != x );

What’s going on here is that we check to see if x matches what we just read. If it doesn’t, x changed either during the storing, or the reading check. In either case, we simply try again. This works great for things such as system timers, and doesn’t require disabling every interrupt in the system just to get a value. It is my preferred way to fetch a single volatile value, and I usually call this the poor man’s semaphore as the same type of scenarios happens with threaded tasks. With threads you can simply use a semaphore or mutex to wrap the reading area, but you could use the same do-while trick.

Now for how to mess this up. In many projects I use a micro-controller timer as a system clock that counts in milliseconds or tens or hundreds of milliseconds per tick. The interrupt for the timer is very simple:

static uint32_t volatile systemTime = 0;
void timerInterrupt()
{
   systemTime += 1;
}

Then I make a function to get the system time.

uint32_t getSystemTime()
{
   uint32_t result;
   do
   {
      result = systemTime;
   }
   while ( result != systemTime );
   
   return result;
}

The other day I found I had made a mistake in implementing this function. Here is what I had instead:

uint32_t getSystemTime()
{
   uint32_t result;
   do
   {
      result = systemTime;
   }
   while ( result != systemTime );
   return systemTime;
}

The difference is very subtle, but messed up all the work done to ensure the value didn’t change. If the above code were to run on an 8-bit micro-controller, the function could return bad times. I got lucky. In my case, the system was a 32-bit micro-controller with 1 ms ticks and the system time was a 64-bit value. The timer only modifies the upper 32-bit once every 49 days. So the chances for reading an incorrect timer value is very low. Still, a stupid mistake.