Rick Swift & Apple & Embedded I make things. Sometimes, I’ll talk about it here.

My Gorram Frakking Blog

Best WFH Email, Ever

This just hit my inbox:

From: Anton S. [mailto:xxx@yyy.com]
Sent: Monday, August 29, 2011 9:42 AM
To: dept@yyyy.com
Subject: Anton WFH Today

There was a shooting Saturday night in SF where my car was parked. When I was walking to my car I got hit by a ricochet bullet. Luckily it hit the side of my neck and didn’t enter the body (just a flesh wound). I am fully functional, but my neck is a little sore. Working from home today.

Related local news links
http://www.ktvu.com/news/29005645/detail.html
http://www.sfexaminer.com/blogs/law-and-disorder/2011/08/two-wounded-san-francisco-soma-shooting-early-sunday-morning

-Anton

Ice Twisters

I'm watching this scientific train wreck of a movie called Ice Twisters, about a government-funded cloud-seeding experiment gone wrong. The EPG gives it three out of four stars, a rating clearly not awarded, in any part, based on scientific accuracy.

Here's the worst bit of science so far. The research team developed a Predator-like drone that flies a swarm formation, creating rain clouds (the drones are called SERIFs, but I don't remember the exact acronym). The first test run of the swarm of 2000 drones is initially successful, causing the expected rain. But soon, violent, brief storms begin to form in the surrounding areas, accompanied by dramatic drops in temperature, and icy tornadoes. Anyone caught a tornado is instantly frozen. And that's not the bad science. Read on.

The team brings in Charlie, a former scientist (now a science calamity fiction author) to "think outside the box". The principal investigator is Joanne. Other scientists include Damon, Gary, and Phil. Here's the dialogue from the scene, with the worst parts in italics.

Charlie: "There was a very loud sonic boom during the storm."

Damon: "You, uh, heard thunder."

Charlie: "No, no, it wasn't thunder, it was something else. These SERIFs, you say they make the clouds, then seed them with silver iodide? How, exactly, are they doing this?"

(Cut to CG shot of the drones doing their thing in the sky.)

Joanne: "They use tiny wind turbines to supply power to their propulsion systems, so there's no limit to how long they can stay airborne.

Once up, each one has a revolutionary moisture evaporator designed to condense liquid nitrogen out of the upper atmosphere."

Charlie: "Upper atmosphere? I thought these were in the troposphere."

Joanne: "They are, right at the ceiling, just below the tropopause."

(Charlie walks over to a large diagram of the atmosphere, gestures toward it.)

Charlie: "Your SERIFs are here, taking any moisture in the atmosphere, and processing it into liquid nitrogen, right? Making this area extremely dry at first, right? Correct me if I'm wrong."

Joanne: "No, you're right."

Charlie: "All right. There's a subatomic reaction happening. It's drawing moisture from the upper atmosphere. The effect of this process is creating…vertical weather."

What kills me is that it's not necessary to create such bullshit. Movies are better when they're more believable, and "science" movies like this have to be on their best behavior when creating their disasters.

Anyway, enough procrastinating. Project time!

The Nissan LEAF Finally Arrived

On Friday, May 20, 2011, I finally took delivery of the Nissan LEAF I had on order for so long. I reserved it in April of 2010, and ordered it September 23, 2010.

My New LEAF

Overall, I quite like it. My only other car is a 1995 Acura Integra GS-R that I bought new. It was a basic car, but well engineered, and very fun to drive.

The LEAF is a huge step up in luxury. Much quieter, about a thousand more airbags, computerized, cool. It has a range of about 100 miles, which is fine for my daily commute. It's smooth, and has excellent fit and finish. The traction motor control is excellent. It has a really cool backup camera that draws lines predicting where you'll go based on steering angle input. It has an excellent Bluetooth hands-free system, and it can play music directly off my iPhone via A2DP.

The computer systems leave a lot to be desired, though. I don't think they're generally any worse than those of other cars, but now that I own one, I see lots of places where they really failed to create a great product. I'll write an article about that later.

Trouble with Static C++ Constructors in ChibiOS/ARM

For the last few days I've been troubleshooting a problem with a C++ thread class I created to aid in the static allocation of threads under ChibiOS.

The problem boiled down to the fact that the ChibiOS ARM port (specifically, the ARM7 port, but it's probably true for most ports) isn't properly executing the constructors for statically (globally) allocated class objects. To clean up the other post, I moved the troubleshooting material to this post.

Note: I've discussed this with the author of ChibiOS, and he hopes to resolve the issue in ChibiOS version 2.3.2.

When any object with a vtable pointer is allocated on the stack (i.e. at run time), it works. But when it is allocated as a global variable, the vtable pointer is NULL. Here's the test code and output:

[cpp]
class FooParent
{
public:
FooParent();

virtual void doSomething();

uint32_t mField1;
uint32_t mField2;
};

FooParent::FooParent()
:
mField1(0xBEEFBA55),
mField2(0xDEADFACE)
{
}

void
FooParent::doSomething()
{
}

class
Foo : public FooParent
{
public:
Foo();
virtual void doSomething();

uint32_t mField3;
};

Foo::Foo()
:
mField3(0xFEEDABCD)
{
}

void
Foo::doSomething()
{
}

Foo f;

void
dumpObjects
{
uint32_t* p = reinterpret_cast<uint32_t*> (&f);
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;

Foo g;
p = reinterpret_cast<uint32_t*> (&g);
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
}
[/cpp]

[cpp]
f dump @ 0x00203090: 0x00000000
f dump @ 0x00203094: 0x00000000
f dump @ 0x00203098: 0x00000000
f dump @ 0x0020309c: 0x00000000

g dump @ 0x00202a60: 0x0010a0a8
g dump @ 0x00202a64: 0xbeefba55
g dump @ 0x00202a68: 0xdeadface
g dump @ 0x00202a6c: 0xfeedabcd
[/cpp]

As you can see, the constructor isn't getting called, (and vtable initialization isn't happening) for the statically-allocated object f, but does get called for object g, allocated on the stack.

This is a GCC issue. It needs to call static ctors (and dtors, theoretically), but it's failing to do so. It could be a mis-configured build of the toolchain, or a bug in the run-time library, or something else along those lines.

Thoughts While Troubleshooting

It currently fails on ARM (on an AT91SAM7X). The symptom is typical of exceeding the allocated stack space: the processor appears to reset (that is, it re-starts execution from the start of code).

There are two failure modes: in the first, it fails in ThreadEntry(), where the the thread context is cast to a pointer to the BaseThread class, and the virtual entry() method is called, executing the CThread subclass' implementation. If I remove the call to entry() and just implement some code directly in ThreadEntry(), it works fine.

The second failure mode has to do with what I put in the modified ThreadEntry(). Although it executes, subsequent execution later in the program fails (by failure, it is meant that the processor appears to reset).

At this point, I'm not sure what is wrong. Code seems well-enough aligned, when the GCC .map file is examined. The self/this pointer in ThreadEntry() has the correct value. I've tried with very large stacks to ensure I'm not overrunning the stack. I've tried a non-template class hierarchy to be sure virtual method dispatch works correctly (it does).

I'm going to try twiddling some outputs on the MCU (instead of calling the stdlib routines I have been). Without JTAG debugging, it's going to be difficult to figure this out.

Using Templates to Statically Allocate Thread Working Area in ChibiOS

On both 8-bit AVR and 32-bit ARM (AT91SAM7X and SAM3S), I've been using ChibiOS. It's a nifty little OS that supports fully-static operation. That is to say, it's possible to allocate all OS structures statically, at compile time, so none need be allocated dynamically at run-time, an operation that can possibly fail. This also allows the exact memory requirements to be known before loading the code onto the target.

I wrote a CThread class (so named to avoid conflict with the OS Thread object) that wraps the allocation of the thread working area and OS thread creation. To do this, CThread is a template class, parameterizing the stack size. Clients subclass CThread and implement the virtual msg_t entry() method.

Note: If you're looking for the description of what goes wrong when the compiler fails to properly initialize static C++ object instances, I moved that material to a new post, Trouble with Static C++ Constructors in ChibiOS/ARM.

ChibiOS Threads

In ChibiOS, to create a thread, you allocate the thread working area with a macro provided by the OS, and call chThdCreateStatic():

[cpp]
WORKING_AREA(sMyThreadWA, 512);

msg_t
MyThreadEntry(void* inArg)
{
// …do work

return 0;
}

void
MyProgram::startAThread()
{
Thread* t = chThdCreateStatic(sThreadWA, sizeof (sMyThreadWA), NORMALPRIO, MyThreadEntry, NULL);
}
[/cpp]

The last parameter to chThdCreateStatic() is passed into the thread's entry point. We use it later to pass a reference to the thread class.

As soon as chThdCreateStatic() is called, the thread begins executing. ChibiOS provides numerous synchronization primitives, but we won't get into those here.

CThread Class

The idea with the CThread wrapper is to provide a class to be subclassed to tidy up the creation of a thread. It would be used like this:

[cpp]
class
MyThread : public CThread<512>
{
protected:
virtual msg_t entry();
};
[/cpp]

And the implementation:

[cpp]
msg_t
MyThread::entry()
{
// …do work

return 0;
}
[/cpp]

Finally, the thread is allocated as a global (as before), and started:

[cpp]
MyThread sMyThread;

void
MyProgram::startAThread()
{
sMyThread.start(NORMALPRIO);
}
[/cpp]

Considerably tidier, isn't it?

Pulling this off requires two classes: A non-template BaseThread class that provides the basic thread functionality, and the CThread template class that derives from it. Note that I do this to try to avoid redundant code generation, which can probably be done using partial specialization or a smart compiler, but I wasn't sure how much luck I would have. The approach does result in a an extra member variable in the base class: the working area size from construction to be used when the thread is started.

BaseThread::entry() should be pure virtual, but I had link errors on AVR with that.

Here's the complete implementation.

CThread.h:

[cpp]
/**
CThread.h

Created by Roderick Mann on 2/3/11.
Copyright 2011 Latency: Zero. All rights reserved.

*/

#ifndef __CThread_h__
#define __CThread_h__

#include "ch.h"

/**
*/

class
BaseThread
{
public:
BaseThread(void* inWorkingArea, size_t inWorkingAreaSize);

void start(tprio_t inPriority = NORMALPRIO);

msg_t sendMessage(msg_t inMsg, void* inContext);
Thread* getSysThread() { return mSysThread; }

protected:
virtual msg_t entry();

private:
static msg_t ThreadEntry(void* inArg);

void* mWorkingArea;
uint32_t mWorkingAreaSize;
Thread* mSysThread;
};

inline
msg_t
BaseThread::ThreadEntry(void* inArg)
{
BaseThread* self = reinterpret_cast<BaseThread*> (inArg);
return self->entry();
}

/**
*/

template<size_t inStackSize>
class
CThread : public BaseThread
{
public:
CThread()
:
BaseThread(mWorkingArea, sizeof(mWorkingArea))
{
}

protected:
virtual stkalign_t* getWorkingArea() { return mWorkingArea; }

private:
WORKING_AREA(mWorkingArea, inStackSize);
};

#endif // __CThread_h__
[/cpp]

And the implementation:

[cpp]
/**
CThread.cpp

Created by Roderick Mann on 2/3/11.
Copyright 2011 Latency: Zero. All rights reserved.
*/

#include "CThread.h"

#include "ch.h"

BaseThread::BaseThread(void* inWorkingArea, size_t inWorkingAreaSize)
:
mWorkingArea(inWorkingArea),
mWorkingAreaSize(inWorkingAreaSize),
mSysThread(NULL)
{
}

msg_t
BaseThread::entry()
{
return 0;
}

void
BaseThread::start(tprio_t inPriority)
{
mSysThread = chThdCreateStatic(mWorkingArea,
mWorkingAreaSize,
inPriority,
ThreadEntry,
this);
}
[/cpp]

What you see above is a little messier than it could be, given a number of issues I ran into while developing it, and concerns about code bloat. But it works reasonably well.