April, 2010Archive for

Atomic 8-bit integer operations

When executing code on many 8-bit CPUs (including the Atmel AVR ATmega168/328 chips popularized by Arduino), the only RAM operations guaranteed to be atomic are single byte reads and writes.  At the C/C++ level, therefore, the assignment and comparison operators cannot be treated as thread-safe for 16- or 32-bit (or larger) integers. Consider the common FIFO ringbuffer implementation below. For a Capacity_t of uint8_t, this implementation is thread-safe for a single writer and a single read...

Sparkfun AVC: Postmortem

ATR5 did not compete in the 2010 Sparkfun Autonomous Vehicle Competition (Apr. 17) as planned.  Pictured at left are several failed Electronic Speed Controllers which were the last in a series of hardware and software issues that led to the forfeit.  Though operating well within their stated capacities, two of the ESCs caught on fire; the third merely melted.  A more reliable (a.k.a. more expensive) backup model [Traxxas Velineon VXL-3s] turned out to be unusable for PID control.  [Reversing...

motorControllerServer: Routing graph

Below: The packet routing graph from the current version of the motorControllerServer, as implemented in both x86 and AVR (C++). For simplicity's sake, I have included only the data paths (which excludes PID setpoint and parameters control, dynamic routing management, nonvolatile state control, etc). Data enters through the serial UART incoming line and the ADC, both into ringbuffers via interrupts.  The UART data is MEP-decoded into MAP packets and the ADC data is collected and wrapped in MA...

Code78: Signed Implementation

Signed integers need a little massaging before Code78 transmission. In standard 2s-complement representation, the most significant bit (MSb) indicates sign. As Code78 normally transmits only the least significant bits, 2s-complement transmission is wildly inefficient when the integer value centers around 0 (i.e. small positive and negative values). For instance, a 32-bit integer with a value of 1 requires one byte to transmit, but a value of -1 sets the MSb and therefore requires five bytes.  ...

Code78: Implementation

The Code78 protocol implements easily in C++. // Sink a numeric value in C78-encoded big-endian format. // Transmits via a sinkData(uint8_t) function that can return false if the data // could not be transmitted. (An output buffer overflows, for instance.) bool sinkC78(const uint32_t value){ // Calculate extra C78 bytes required (before concluding byte, with its 0 MSb). // Will need an extra byte for each log (base 2^7) increment. uint8_t extraBytes = 0; for(uint32_t tmpValue = value...

Announcing the Micro Addressing Protocol (MAP)

The universal TCP/IP protocol and its less capable cousin, UDP/IP, both often delivered over MAC (ethernet), are venerable columns of the internet architecture. They are also too bloated for small packet applications: a 42 byte UDP/IP/MAC header set (14, 20, and 8 bytes, respectively) will consume 90% of the available communication bandwidth if the average packet contains 4 bytes of actual data. Over a 250kbps link (e.g. UART or XBee), this resolves to 3.1kB/s of actual data delivery. The Mic...