Posts Tagged ‘gadget’

Tim Tears It Apart: Kidde KN-COB-B Carbon Monoxide Alarm

Of course it happens this way: stuff works for you, but breaks as soon as you have guests and drives them crazy. In this case, the missus and I were out of the house having a baby and her folks were in to hold down the fort. A carbon monoxide detector had failed in the most irritating possible way, emitting a very short low-battery chirp just often enough to drive everyone batty, but intermittently enough to be very time-consuming to track down. My poor father-in-law eventually managed to find the source of the racket, and changed the batteries.

The chirping continued.

He then trashed those batteries and put in another set of fresh batteries, from a new package.

The chirping continued.

And then took the damn thing off the ceiling and removed the batteries for good.

The chirping continued.

Oh yeah, it turns out that not one, but TWO detectors had failed simultaneously. And not for want of batteries, either.

It turns out the detector elements in most modern CO detectors have an indeterminate-but-finite lifespan, and are programmed to self-destruct when their time’s up. The actual sensor lifespan depends on the usual factors like operating temperature, humidity, CO exposure, etc., but most manufacturers take the easy way out and simply define a conservative time value where it may need replacing. In this case, it is 7 years. (I bought the house about 7 years ago, hmmm…)

Self-destruct timer disclaimer on back of detector

Self-destruct timer disclaimer on back of detector

Although design-to-fail schemes are occasionally on legally shaky ground, this product-death-timer is actually required by UL for CO detector products whose detector has a limited lifespan (which is most of them).

While they still power-on and blink (it’s not clear if the timer expiration also explicitly disables CO detection, but the labeling on the back suggests so), these units are basically landfill fodder now. I think you know what that means…

Front of detector with battery door removed. The marking indicating the direction to pull to release it from the nails in the ceiling is NOT factory stock :-)

Front of detector with battery door removed. The marking indicating the direction to pull to release it from the nails in the ceiling is NOT factory stock :-)

Top side of PCB

Top side of PCB

Top side of PCB with piezo horn removed

Top side of PCB with piezo horn removed

Bottom side of PCB

Bottom side of PCB

Main parts:
CPU: PIC16LCE625 – One-time programmable 8-bit microcontroller with 2k ROM / 128 byte RAM, 128 byte EEPROM.

MCP6042I/P – Dual Low power (0.6uA) opamp – guard ring attached to pin 7

LM385-1.2 (package marking 385B12) – 1.2V voltage reference with minimum operating current of 15uA.

Noisemaker: Ningbo East Electronics EFM-290ED piezoelectric horn claiming 90dB(A) sound output @ 9V/10mA @ 30cm.
Has GND, main and feedback connection.

Ningbo East Electronics ELB-38 or ELB-74 (?) – 3-terminal inductor (autotransformer) generating a stepped-up AC voltage to drive the horn.

A scattering of bog-standard transistors (2n3904/3906) rounds out the silicon ensemble.

The detector is a large metal cylinder marked with a Kidde part number and has a silica gel (dessicant) package shrink-wrapped to the front of the detection end. The detector is soldered to the board and not replaceable.

Business end of CO sensor showing silica gel dessicant covering aperture

Business end of CO sensor showing silica gel dessicant covering aperture

Some points of interest:

Idiot resistance: One thing to notice even before taking the unit apart are the little red spring-loaded tabs underneath each battery socket. I couldn’t find anything on the purpose of these in a quick web search, but my guess is they are there to block you from putting the battery door back on with no batteries in, e.g. after pulling them to silence a chirping alarm at 3am, and then forget to put new ones in.

Horn drive: Piezo horns are resonant systems with a very high Q; they must be driven at resonance to produce anywhere near their maximum sound output. However, due to manufacturing tolerances the exact resonant frequency may differ significantly between individual units. Another issue for this device is that piezo horns need comparatively high voltages to operate: this one has a rated voltage of 9V, but can probably go a fair amount higher (>100V drive signals for larger piezo sounders are not uncommon). But, the 3x AA batteries in this device can deliver a maximum of only ~4.5V. The self-resonant oscillator formed by Q2 and L1 efficiently solves both problems. The ‘feedback’ pin connects to a small patch of piezo material on the horn that acts as a sensor, translating deflection to voltage (more or less). Using this as the control signal for a simple oscillator allows it to automatically pull in to the piezo’s resonant frequency. The autotransformer coil, L1, is basically a step-up transformer with one end of its primary and secondary windings tied together and connecting to the 2nd pin. (You can think of it as a single winding with an asymmetric center-tap if you prefer.)

Detector analog frontend: The FR4 material the PCB is made of is a pretty good insulator, but its resistance is not infinite. With sensitive high impedance signals in the tens of Megaohm or more, even the tiny leakage currents across the PCB can induce a measurement error – especially when dust, finger oils from manufacture, other residue and humidity from the air combine on the surface. Notice the exposed silver trace that completely circumscribes the PCB area occupied by the sensor, with its green soldermask covering purposely omitted. This is almost certainly a guard ring intended to intercept such PCB leakage currents before they reach the connection points of the chemical CO sensor. The trace will be attached to a low-impedance circuit node whose voltage is as close to the sensor terminal voltage as possible, minimizing the voltage difference between them, and thus the current that can leak across. The trace is tied to pin 7 of the opamp.

Closeup of guard ring trace surrounding analog frontend

Closeup of guard ring trace surrounding analog frontend

End-of-life-lockout: As mentioned previously, this device is programmed to commit suicide after 7 years. There is no battery backup inside the device, nor any discrete realtime clock or other means of telling the time. How does it know when 7 years have elapsed? The CPU is clocked by a 32.768KHz crystal oscillator, otherwise known just as a “watch crystal” due to their ubiquitous use in watches, clocks and other timekeeping applications. While running the CPU at such a low speed also has certain power advantages relevant to a battery-powered system, this crystal is providing an accurate timebase. Needless to say, it is counting 7 years of power-on time, not wall time (even if it sat on the shelf quite a while, your alarm will not be dead and chirping the moment you remove it from the package). The CPU sports 128 bytes of EEPROM, which are used to store the peak CO reading (over the product’s lifetime or since the last alarm; not sure which) and most likely periodically count down its remaining lifetime. Basic operation of a CO detector is to stick batteries in and forget about it (unexpected powercycles will be infrequent), so the timekeeping can be very coarse, e.g. decrementing a couple-byte EEPROM countdown every time a very long counter rolls over some preprogrammed value.

I pulled the CPU, hooked it up to an ancient PIC programmer and tried dumping the firmware to see exactly how this worked, just in case they had left it unprotected, but no such luck. The code protect fuses are all set and readout attempts return all 0s. The EEPROM in this particular chip is actually implemented as a separate I2C “part”, either on the same die or a separate die copackaged with the CPU die, with the two I2C control pins and a power control line memory-mapped into a register. So there is no access to the EEPROM contents through a PIC programmer either.

Enclosure: At first glance, it’s about what you expect from a low cost consumer product that is designed to be thrown away periodically. There is not a screw to be found anywhere – everything, from the PCB to the enclosure halves themselves, clicks together via little plastic tabs. But wait a minute… hold this up to the light just right, and you can see hand-finishing marks where extra plastic (e.g. overmold) from the injection molding process has been filed or sanded off. On the *inside* of the enclosure, where nobody will see it! And yes, these marks appear to be from work applied to the finished enclosure itself, not the master mold it came from – the sanded portions go slightly in, not out.

Manual finishing marks on inside of plastic enclosure

Manual finishing marks on inside of plastic enclosure

Hidden Features: There are a few hidden features suggesting this same PCB, CPU and firmware are used for several models of alarm, including a fancier one. The most obvious is a non-stuffed footprint for another pushbutton switch, marked ‘PEAK’. When pressed, it causes the green test LED to flash a number of times in a row (presumably corresponding to the peak CO level ever measured by this detector – my 2 dead units show 9 and 10 blinks, respectively). Near the center of the board is a non-stuffed 6-pin header, with the outer two being power & ground, and the middle four signals going straight to CPU pins. Scoping these reveals unidirectional SPI signalling on 3 of the pins (CS\, CLK, DATA) that would probably drive an LCD readout on a more expensive version of this detector. Capturing the data in various modes doesn’t produce any obvious pattern (e.g. ASCII, numeric, BCD or raw 7-segment data). Finally, there are two mystery pads on the back of the PCB. Shorting them causes both the alarm and test LEDs to light, and the green LED to produce 5 extremely rapid blinks every few seconds. Doing this does not reset the timer-of-death, clear the PEAK reading or have any other long-term effects that I can ascertain. Both the PEAK switch and mystery jumper noticeably change the data pattern sent to the nonexistent LCD.

BUT… I did find a sequence of inputs that put the detector into some kind of trick mode permanently (persisting across powercycles). I believe the exact sequence of events that triggered it was to have S2 shorted at powerup, then short PEAK once the blinking sequence starts. It’s not clear if S2 must remain shorted during this time or only at powerup. The unit this sequence occurred on is now permanently in a mode where it emits long, repeating rapid blink sequences on the green LED (red lit continuously) and draws some 40mA continuously. The repeating sequence is 1 (pause) 63 (pause) 68 (pause) 24 (pause) 10 (last blink is longer) (pause) 21 (pause) 82 (pause) 82 (pause) 14 (long pause).

Tim Tears It Apart: Honeywell R8184 Oil-fired boiler controller

Honeywell R8184G oil burner control

Honeywell R8184G oil burner control

Its official designation is “R8184 Intermittent Ignition Oil Primary”.

“But Tiiiim! That sounds booooorrrring. Why this thing, and not one of those fancy cloud-enabled thermostats containing more RAM than the desktop computer you had in college and not less than five processors capable of running Angry Birds at a playable framerate?”

Yes, excitement-wise this one sounds right up there with having your toenails waxed, but there are a few interesting bits regardless. Also, I have a broken one sitting in my basement right now, and what do we do with broken gadgets?…

Underside of oil burner controller

Underside of oil burner controller

Here is the underside showing the PCB. This should give some sense as to the age of this design. These curvacious traces are something you just don’t see in the era of computer-aided PCB design. This board may very well have been laid out literally by hand, the master trace pattern drawn in magic marker. Speaking of which, I drew an arrow in marker pointing to the likely culprit for this unit’s failure: a cold solder joint on one of the relay terminals, specifically, the one that energizes the orange wire leading to the burner and motor. You can also see some strategic cuts in the board itself, providing a physical air gap to isolate the low-voltage stuff from the line-powered sections nearby.

Oil burner topside

Oil burner topside

Here is the topside. There’s really nothing much to it! You can probably take a stab at how this all works just by inspection, but in case not, Honeywell provides the actual schematic on their website.

The fat transformer at top-left steps the 120VAC from the line down to around 24VAC to drive its own circuitry and the thermostat (red and white wire normally connected to the “T” terminals). I peeled back the tape on the primary winding a bit so you can see the difference in wire diameter, allowing for many more turns on the primary side. Without documentation or proper test equipment, you could use this to visually determine its function as a step-down transformer and maybe even make a loose guesstimate of the turns ratio.

Oil burner 24VAC relay

Oil burner 24VAC relay

Kitty-corner from this transformer is a big honkin’ relay, armed with a similarly fat bundle of wire. This coil is powered right from the AC off the transformer; notice the large metal weight clamped to the top end of the part that actually moves. I suspect this is to provide added inertia to keep the contactor in-place and prevent buzzing during the low periods in the AC cycle where the magnetic force ordinarily holding it drops out. Energizing this relay closes two separate pairs of contacts; one (with the cold solder joint) powers up the boiler via the orange wire, and the other completes the circuit (transformer center tap, or ~12VAC) for the safety lockout logic, which I’ll get to in a moment.

In an oil burning boiler, turning on the boiler engages a large motor that both blows air into the combustion chamber and forces oil through an atomizing nozzle. The oil is ignited by a spark plug of sorts, formed by a high voltage transformer and a conductor near the nozzle. Home heating oil is otherwise known as diesel fuel. Needless to say, you want this atomized fuel to burn away in a quick and controlled way, not let large quantities of it accumulate and then go up suddenly.

To prevent your basement turning into a Super Mario Bros. boss level if the fuel doesn’t ignite in a timely fashion, there is a “flame sensor” (photocell) and lockout timer built in. The label on the front of the unit specifies a lockout time of 45 seconds. As you probably noticed, there are no microcontrollers, quartz crystals, counters or any other obvious timing devices on this board, so how does this work?

The answer may wow you, either with its ghetto-ness or its ingenious simplicity. Much like the electric stove guts described in an earlier post, the timer is thermal. The top-right component contains a heating element attached to a bimetallic strip, which in turn connects to some contacts and a mechanical latch. This is attached to the bit of circuitry at the bottom-left, which connects to the photocell (flame sensor) normally connected at the ‘F’ terminals. For the grisly details, look at the schematic linked above. Ordinarily, when the thermostat is on 24VAC flows through R1 and R2 to the “bilateral switch” (there’s a symbol and part you don’t see everyday), which trips the TRIAC and ultimately begins warming the heating element, eventually curling the metallic strip inside the lockout mechanism enough to trip and cut power to the boiler. Note, the schematic shows the gate of the “bilateral switch” not connected to anything, but in reality it is shorted back to the first terminal (at R2), turning this device into basically a voltage threshold detector. Light falling on the sensor lowers its resistance from near-infinite down to the k-Ohm range or less, forming a resistor divider with R1. This lowers the voltage at the bilateral switch below its turn-on threshold, cutting power to the heating element before it trips the lockout.

Protectorelay thermal safety / lockout switch with latching feature

Protectorelay(R) thermal safety / lockout switch with latching feature

A look through the clear plastic case of this device shows the heating element is an ordinary 1W flameproof resistor. A metal slug, no doubt carefully sized to provide the right thermal inertia for the desired lockout time, is clamped around it. On the side of the device is an access hole for a setscrew, which applies pressure to a spring-loaded plate behind the bimetallic element. This most likely sets the initial position/tension of the strip against the pushbutton latch, and so allows fine-tuning the trip time.

Here is a video of the mechanism in action.

If the previous TTIA installment was any indication, the burning question is how much the thing cost to manufacture. As before, the off-the-shelf parts are pretty cheap but the presence of complex custom parts makes it hard to pin down a number. A comparable step-down transformer can be had for about $5-8 bucks on Digikey. The discretes would run probably another buck total, and give another $3-5 bucks for wiring, the solder-on screw terminals and the blank PCB itself. The transformer is a bit harder – it’s a custom Honeywell part and can’t be sourced off the shelf – but comparably sized transformers might run in the $20 range in onesies. Now for that lockout switch assembly, that’s a real piece of work. Not heavy on any expensive metals, but plenty of NRE sunk into this part, and plenty of mechanical parts to assemble (possibly some or all by hand). I’ll pull a $15 out of my ass for that component.

Tim Tears It Apart: Sensitech TempTale4(R) data logger

One of these devices appeared in a large shipment of temperature-sensitive raw materials at my work, amid a pile of dry ice chips. While I don’t know the MSRP or actual retail price of this gadget, the shipper packs one in with every order and tacks on $60-70 for it as a line-item; nonreturnable as far as I know.

So, we can’t return it and we can’t read it out, so what do we do?

I think you know what we do :p

TempTale4 Front Panel

TempTale4 Front Panel

The device is aimed at exactly this application – telling if your temperature-sensitive stuff stayed within a defined temperature band during all phases of shipping and handling. With timestamps, you could probably tell exactly which party in the shipment chain screwed the pooch. There is a fancy term for this kind of tracking – cold chain certification.

As far as interfaces go, it doesn’t get much more simple. A button to start logging, a button to stop logging, a simple LCD display, and a couple blanks to enter a shipper’s name and the PO# of the shipment. The current temperature and recording status (started / stopped) is displayed on the LCD. If the temperature went outside the allowed band while recording, an alarm symbol (bell) also appears. A pair of LEDs exposed through the front panel allow the device to be configured and recorded data to be read out to a PC via an optical doohicky (more on this later).

TempTale4 rear cover removed, showing the plastic 'cage' that holds the battery pack in place

TempTale4 rear cover removed, showing the plastic ‘cage’ that holds the battery pack in place

The enclosure is a basic 2-piece sandwich, with the half-thickness (.031″) PCB fixed into the front by 3 screws. A separate plastic ‘cage’ holds the battery pack in place; fingers on the backside clip around the edges of the PCB. The entire weight of the battery pack – and impact loads it imparts during rough shipping – are borne solely by the PCB and ultimately those 3 screw points. They might not anticipate extremely rough shipping for cold-chain cargoes (although a broken logger could be spun as a rough-shipping-detection “feature”).

On the plus side, note the O-ring ensuring a water-resistant seal between the case halves. Any other case openings are covered by the front overlay “sticker”, eliminating any fluid intrusion paths.

Battery cage removed

Battery cage removed

Battery pack removed. That piece of double-stick tape really ties the room together.

Battery pack removed. That piece of double-stick tape really ties the room together.

The battery pack is Zip-tied to the plastic “cage”, although not to the PCB or any part of the case. A piece of foamy double-stick tape helps hold and cushion the battery pack where it sits against the PCB. This and the overlay sticker on the front suggest this device is intended for enforcing low temperatures. High-temperature overlays and even double-stick tape exist, but it’s pretty fancy stuff. This tape isn’t fancy.

The battery pack consists of two series-connected Tadiran lithium primary cells (AA size), with a nominal 7.2V output. Now, in an industry that is constantly pushing toward ever lower voltages to reduce power consumption, this is weird! Especially for a gadget that needs to go a long time without a battery change. A single 3.6V cell will easily power a 1.8-3.3V device, and maintain this output voltage until nearly depleted. Some wild guesses at the reason behind the unusually high voltage:

1) High-current operation at very low temperatures. This shouldn’t be an issue during normal operation (just datalogging should use very little current on average), but if someone wanted to read it out over the optical interface in the Arctic, it may be another story. This may provide extra headroom against the inevitable cold-battery voltage sags that would occur as the transmit LED fires.

2) Voltage-happy LCD? Some LCDs require a higher voltage such as this to operate (usually generated by an onboard charge pump circuit), but these are typically graphical matrix LCDs (many independent rows/columns) – the rows/cols are typically energized one at a time, and to refresh the entire display faster than the eye can perceive flicker, each one is on for only a very short time – higher voltages help them reach their final dark/light state within that time and retain it until the next refresh. I can’t imagine this little segment LCD having such a requirement.

3) They needed 2 batteries to get the milliamp-hours up regadless, and wiring them in series was easier/cheaper (no worries about cell balancing). This is not an ideal way to get more mAh (increasing resistive losses in the series-connected pair, and conversion losses in any regulator, especially linear/LDO), but I suppose it works well-enough, and the price is right.

Bottom side of PCB exposed

Bottom side of PCB exposed

With the battery pack out of the way, we can see the bottom side of the PCB. Not much there! A couple things to note though:

1) A secret button hidden inside the device. As it turns out, this button resets/clears the device for reuse. The entire LCD will blink every segment for a couple minutes, then the device is factory-fresh again (probably).

2) No components apart from the secret button, but a fair number of empty pads (non-stuffed components).

PCB removed - rear of LCD accessible

PCB removed – rear of LCD accessible

Top of PCB. Notable points incude "secret" magnetic switch, accessible programming header, and an overall dearth of actual components.

Top of PCB. Notable points incude “secret” magnetic switch, accessible programming header, and an overall dearth of actual components.

Finally, we get to the topside of the PCB, the actual meat of the device! Erm, wait a minute, where’s all the meat?

The $70 pricetag notwithstanding, it should be becoming clear that this device is cheap-cheap-cheap to make. The bill of materials consists mainly of a few pushbuttons, a small handful of discretes and a glob-top MCU/ASIC. The segment LCD and an EEPROM in the top-left of the photo (a note on the manufacturer’s web site says it could be 2KB or even a whopping 16KB of storage) complete the ensemble. I have to snicker a bit about that after testing a 32GByte uSD card in my own day-job datalogger design the same day, but again, this device is designed to be throwaway cheap, and 640k (ahem, 16k) ought to be enough for anybody – for temperature data, anyway. (The astute reader will see “32K” stamped on the chip; either a clever misdirection or these loggers have grown more spacious than the web site lets on.)

Some notable points:

1) The temperature sensing element appears to be a simple RTD – no thermocouple or even brand-name digital sensor, but probably accurate enough.

2) The glass tube designated S3 is a magnetic reed switch. This almost certainly is used to trigger entry into the download/configure mode, either with a magnetic wand or a magnet built into a monolithic reader device that aligns to the LEDs.

3) The LCD is affixed to the top shell, not the PCB, and contact is made by an elastomer strip (zebra strip). Don’t lose this!

4) The neat row of capacitors at the bottom of the photo (C2, C3, C10 ~ 13) are probably part of a charge pump circuit for the LCD. There goes that theory about the battery voltage.

5) As with the bottom side, note the prevalence of non-stuffed component pads. Aside from a good handful of discretes, there are spots that appear to accept a second RTD temperature sensor and a humidity sensor. Most likely, this same board and ASIC become the “TempTale4 Humidity” with the addition of these components.

6) Besides the holes for extra sensors, pay particular attention to the two – two! – sets of non-stuffed headers (J1, J2). The latter pins directly into the globtop, suggesting the likely possibility of an in-circuit programming header (or even JTAG, holiest of holy grails).

See-thru view of front case, showing button flexures and a small opening in the plastic to bring the temperature sensor closer to the outside environment.

See-thru view of front case, showing button flexures and a small opening in the plastic to bring the temperature sensor closer to the outside environment.

In this final photo, you can see the shell cutouts as they relate to the overlay sticker. The temperature sensor normally sits in the small notch in the middle, leaving only the thin bit of sticker between the sensor and the outside environment.

A new feature: “Tim Tears It Apart”!

So, as you might have guessed, I’m an electronics engineer, and I like to tear things apart – especially gadgets. I don’t usually post about it, because a) someone else has probably already posted a teardown of that gadget, and b) I’m lazy as balls.

But then I realized a good teardown is not all about the pretty pictures, but reverse-engineering the mind and intentions of the original designer. After about a deca*cough* some time in the industry, at the age where I tell kids to get off my lawn*cough* pull up their damn pants, I’m getting a pretty decent feel for not just how a gadget works, but why it works the way it does – i.e. the budgetary constraints, schedule pressures and technical constraints behind specific design decisions. So maybe it is worth posting those teardowns after all :p

I can’t guarantee it’ll be a frequent feature, but there are a few torn-apart gadgets I could throw my 2 cents in on.

AllElectronics “Mystery Infrared Device” with LIRC

NOTE: This device is no longer sold; rescuing this information before it disappears from various caches.

Description of the device from AllElectronics:
Our best guess is this is an infrared receiver/ transmitter for use with televisions or other remote-controlled equipment. Made for OnCommand™, it consists of a small black box, 2″ x 1.95″ x 0.6″ with a dark-red plastic IR window on one side. Inside is a small pc board with four clear LEDs and a module that looks like an IR receiver. There is a 3.5mm phone jack and a 6′ 6-conductor phone cord with a modular phone plug.
CAT# IR-13

Various information on modification for use with a PC: (pulled from cache of AllElectronics product review page)

Reviewer: Seth Marks from CRYSTAL LAKE, IL US
This circuit can be used with one minor modification to make a serial IR receiver for use with LIRC. http://lnx.manoweb.com/lirc/?partType=section&partName=circuit Connect the following: White Wire to DCD (Pin 1), Red Wire to RTS (Pin 7), Blue Wire – GND (Pin 5) The only modification you must perform is to add a pullup resistor between the output pin on the IR transmittor (connected to the white wire) and “In” on the 78l05 (the pin on the main IC closest to the red wire). Seems to work great.

Note: I (Tim) have personally used these instructions and can confirm that they work. With the white/data wire tied to DCD as above, make sure to select “DCD Device” rather than “Rx Device” in the (Win)LIRC serial receiver settings.

Reviewer: Mike from SAN ANTONIO, TX US
Just received this module and started playing around with it. This is what i figured out for the wiring. Yellow and Blue- ground, Red and Green- positive(around 9-12VDC), White- IR out, Black- IR in, 3.5mm jack- External IR emitter If you jumper the white and black together whatever is received from the ir receiver is transmitted out the four IR emitters on the board.(IR amplifier)Or plug in an IR emitter to the jack and controll hard to reach equipment.I have thought up many ways of using these modules.

Fun with cheap TV-tuner dongles and Software Defined Radio (SDR)

So, last week I joined the bandwagon of exploring software-defined radio (SDR) via one of those super-cheap Chinese TV tuner USB sticks. In a nutshell, the idea of SDR is that, rather than the traditional approach of building dedicated radio receiver hardware for each possible RF band and modulation type (here’s your AM radio, here’s your FM radio, here’s your TV receiver…), each of which can only do one thing, we can simply make an extremely *wide* bandwidth receiver frontend that captures ALL the signals, shovel the raw waveform into a computer, and emulate all the desired radio receiver frontends and tuning in software via digital filtering. New type of radio scheme just got invented? You don’t have to buy/build a new radio receiver, just download this update! Historically, this ‘universal receiver’ has been somewhat hairy and expensive to build. The most well-known (and open-source!) is probably the Universal Software Radio Peripheral, most commonly associated with the gnuradio project. Recently though, Antti Palosaari and other clever folks discovered that a $20 USB TV tuner can be pressed into service as a ‘universal enough’ receiver for many purposes.

There are many ‘flavors’ of the sticks that work for this. These sticks consist of two parts (as far as you’re concerned): a frontend tuner chip, and the Realtek RTL2832U demodulator chip. The latter also includes the USB interface. RTL2832U-based sticks are popular because, while it is officially intended to output TV/FM signal data, it is easy to put this IC into a mode where it dumps the raw tuner output directly to the USB port at high speed. This allows user software to bend, fold, mutilate and decode arbitrary radio signals as it sees fit.

The ‘tuner’ part of this stick is somewhat interchangeable; they all do pretty much the same thing (although some are better or worse at the job for our purposes). A large list of tuners, and the products they appear in, is being maintained here. The Elonics E4000 tuner is regarded as the ‘best’ as it can tune over a wider range (64-1700MHz, with a small coverage gap in the middle) compared to the others. Note however, because of the ‘interchangeable’ nature of the tuners, the stick you receive is not at all guaranteed to contain the tuner you wanted – it will most likely contain whichever flavor was cheapest in China at the time this batch was manufactured. The Realtek IC is much less likely to be substituted with another part since all the USB drivers (or at least USB VID/PID codes) would have to be rewritten.

Case in point; the one I bought was the ezcap DVB-T/DAB/FM stick; upon cracking it open I found an FC0013 tuner rather than the E4000 others have reported.

Some Software

Several SDR software packages (other than, of course, gnuradio) have now been written or updated to accept data from the RTL2832U, and present it in a user-friendly manner. These consist generally of a frequency/tuning setting, spectral plot, waterfall plot (sort of a stripchart of the time-varying spectrum over the last 30 seconds or so), and various options for demodulating a user-specified portion of the spectrum (usually to the form of audio played back on the speakers).
Some that I have tested so far are:

Gqrx SDR receiver – For Linux; supports several common modulations including AM, FM (wide/narrow), and SSB. At the time of this writing, you have to pull an experimental source tree and compile it yourself to get the (very recently added) support for RTL dongles. Luckily, this (for me at least) went painlessly following this tutorial (Gqrx portion begins on page 2; warning: annoying float-over ads); it just takes a while.

HDSDR – For Windows; supports even more modulations (AM, FM, ECSS, single sideband (lower, upper), CW, DRM) and allows the filter bandwidth to be adjusted in most cases. This program is freeware, but not open-source.

SDR# (SDR-Sharp) – For Windows; supported modulations include AM, FM (narrow/wide), single (lower/upper) and dual sideband, CW (lower, upper). This is my personal favorite so far, as the filter bandwidth can be arbitrarily set and easily fine-tuned by simply clicking and dragging the filter envelope shown on the waterfall plot. Tuning can also be accomplished by dragging the spectrum plot as a ‘radio dial’ besides the usual typing/mousewheeling in the Frequency field.

Note that the RTL support in these programs (and in some cases the programs themselves) are very new; they may be much evolved from the anecdotes above by the time you read this.

Some Oddities

Heat issues
When my shiny new tuner stick arrived I wasted no time building gqrx and firing it up. I was rather dismayed to find that the tuner frequency set in the software seemed to have absolutely no correlation to the frequency actually tuned (confirmed by finding some local FM radio stations and comparing their spoken station identifications to the frequency displayed). Same story on other software. It turns out that these chips run pretty warm, and mine arrived on about the hottest day of the year – after a few minutes of being plugged in, the stick was overheating and the tuner IC was no longer responding to commands. This has been mostly solved by removal of the stick’s plastic case and cooler overall temperatures. It seems others have seen the same problem on similar sticks; this user (original Romanian) (English translation) solved it by cutting a hole in the case and bonding a small heatsink to the IC.

Aliasing and other ghosts
With the overheating issue sorted, I confirmed some ‘known’ FM radio stations were where they belonged… but noticed strong FM stations also popping up at truly bizarre locations on the dial. It turns out these sticks are prone to showing you aliased signals and other forms of ‘ghost’ signals. Aliasing occurs when a high-frequency signal is undersampled. As I understand it, these sticks ‘demodulate’ a signal by multiplying the incoming signal with a reference frequency (the ‘local oscillator’, or LO), causing it to be frequency-shifted down to something more manageable. (In most SDR software, the ‘center frequency’ adjustment for tuning adjusts the LO.) Poor filtering of strong signals can cause accidental demodulation of those signals even at far-away local oscillator frequencies, probably most noticeable at integer multiples of the signal’s carrier. The result is that a spurious alias of that signal will show up, ‘folded over’ to an unexpected frequency.

A sure giveaway that you are looking at an alias and not the real signal is that it moves in the ‘wrong’ direction if the tuner center frequency is altered slightly. That is, while authentic signals should appear at a consistent frequency regardless of small tuning changes, an alias will appear to change frequencies as the tuner center frequency (LO) is adjusted.

I have also noticed other ‘ghost’ signals repeated at multiple frequencies, but without the giveaway folding. I don’t have an explanation for these. However, the false-frequency copies seem to vary widely in amplitude, to the extent of appearing and disappearing, as the LO is adjusted.

NOTE: Specific alias/ghost behavior may be (and probably is) tuner IC specific; your results may vary depending on the type of tuner in your particular stick.

I/Q imbalance (DC Offset)
Another issue common to these cheap TV sticks is an imbalance between the I and Q components (we’ll get to that in a minute) of the returned signal. This typically manifests as a continuous false ‘signal’ peak always at the center (LO) frequency.

Primer on some digital RF basics (e.g. what is all this ‘I/Q’ stuff?)

This paper from Agilent is a good overview of how these tuner sticks and similar digital radios are implemented under-the-hood, as well as covering many basic digital modulation schemes and how to identify them.

What’s Out There?
Oh, the fun you can have. So far I have read the entire neighborhood’s pager messages, eavesdropped on bored rent-a-cops’ walkie-talkie chatter, gotten weather reports, and found many more things I can’t even begin to identify. Here is a quick link-dump for some specific cool stuff people have managed to find, and how to do it yourself.

Read pager messages
Plot the courses of aircraft via their radio identification messages
Acquiring GPS (scroll down a bit)
Receive weather satellite images

I might try to cobble together a visual identification guide (or links to same, if this already exists) as a Part 2.

PS. Action shot of sniffing pager data out of the air in my hometown. Click for fullsize:

Screenshot of capturing pager data using the SDR-Sharp and PDW software

Screenshot of capturing pager data using the SDR-Sharp and PDW software

Notes to myself: Using EnergyMicro EFM32 with GCC open-source toolchain

The EFMs can be used with many different toolchains after installing EnergyMicro’s “Simplicity Studio” package, which includes board/chip support packages and some code examples.

EnergyMicro’s application note AN0023 has an overall good overview of setting up an Eclipse + GCC (CodeSourcery) toolchain. Nevertheless, in attempting to replicate this process on my Win7 system (work PC; not my first choice of OS) I ran into a few particular time-wasting issues. The appnote recommends to find and install specific (“old” / current at the time of writing) versions and see it work, then take the risk of updating versions – I just installed the current version of everything (including Eclipse). This might be part of my problems. Installing toolchain components to a slightly unexpected location (i.e. not on the C:\ drive, let alone “C:\progra~1”) may add a bit of uncertainty too.

Some quick notes / “problemlet” observations:
The Simplicity Studio code examples install to one of your OS/version-specific “home” folders, regardless of where you told it to install the application proper. On Win7 there are many variations of a “home” folder; they get installed to the Windows “%appdata%” path (which expands to something like C:\Users\yourname\AppData\Roaming). Assuming you’ve performed the necessary voodoo to bring back some kind of ‘Run’ dialog / command line in Win7, you should be able to type %appdata% at the prompt and thereby obtain the actual path it expands to on your flavor.

During installation of Simplicity Studio you are prompted to install the SEGGER J-Link (JTAG / debug client emulator) drivers. In my case, I was prompted to install them about 30 times (wtf?). After the first installation appeared to succeed, I canceled out of the numerous repeat prompts (holding down ESC key works well for this) without any apparent ill effects.

Otherwise, installation and setup of Simplicity, Eclipse and the various other bits went pretty smoothly, up until…

Problem #1: Broken handling of PATH in Eclipse (Juno)
Attempting to build the ‘blink’ example, eclipse barfs out the following error:
program “cs-make” not found in path
So, dig down to Windows Environment Variables, confirm the path to the build tools has been correctly added…sure enough, there it is. Open a command prompt (defaults to C:\Users\myusername) and type cs-make … Windows can find it too, apparently. Just for fun, copy the CodeSourcery build tools’ path from the system path variable to the *user* path variable, close and re-open Eclipse… same problem. Finally, digging deep in the Eclipse build setup (Project -> Settings -> C/C++ Build -> Environment and manually adding the $path$ variable to the Eclipse-specific environment variables shows that it appears to have taken the “user” environment path, and injected several Java-related paths, apparently overwriting the first several path entries (including the one for the build tools). Manually adding the OS-provided “path” variable here (it expands to a plain text string once added) and hand-adding the build tool path (in my case, “d:\CodeSourcery\Sourcery_CodeBench_Lite_for_ARM_EABI\bin”) is ugly, but it works and I don’t have a better idea.

Problem #2: Install Path Assumptions; Wide Open Spaces
As mentioned earlier, I installed Eclipse and the build tools to my dedicated non-installed-by-the-IT-department-by-default apps partition, D:\. Apparently that is a minor nono – the Makefiles in the Simplicity Studio examples have a hard-coded expectation that you installed everything in “C:\Program Files\” (or your OS-flavor equivalent). After hacking around in the blink example’s makefile a bit to remove all traces of this assumption, I ran into the 2nd problem:

cs-make: *** [build/system_efm32lg.o] Error 1

This incredibly helpful error message from cs-make means that a failure occurred in some upstream tool. Clicking on the ‘Console’ tab at the bottom of the Eclipse window discloses the actual problem:

11:37:58 **** Build of configuration Default for project blink ****
cs-make all
“Building file: ../../../../../Device/EnergyMicro/EFM32LG/Source/system_efm32lg.c”
“D:/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_EABI /bin/arm-none-eabi-gcc”
(…etc, etc…)
The system cannot find the path specified.
cs-make: *** [build/system_efm32lg.o] Error 1

Note the two, yes two, superfluous and unwanted spaces in the middle of the GCC path string, between “Sourcery_CodeBench_Lite_for_ARM_EABI” and “/bin/arm-none-eabi-gcc”. I have absolutely no idea where those are coming from (they aren’t in any of the strings used to build this path string in the Makefile), or whether this is a specific bug of cs-make, Windows ports of make, or make in general. Lacking any kind of better idea, I “solved” this by wrapping every possible piece of data that may be used to generate a path with the makefile ‘strip’ directive (discovered via yet more googling in circles, yay), e.g. a string definition blah becomes $(strip blah), and $(QUOTE)$(TOOLDIR)/bin/arm-none-eabi-gcc$(QUOTE) becomes $(QUOTE)$(strip $(TOOLDIR))$(strip /bin/arm-none-eabi-gcc)$(QUOTE), etc. Note that it appears any piece of string variable which has already been ‘strip’ped must again be re-‘strip’ped when using it to build another string (e.g. in the above, I’ve already defined TOOLDIR = $(strip $(WINDOWSCS)) , and WINDOWSCS = $(strip D:/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_EABI) , to no apparent effect.

Once every susceptible substring in the Makefile has been flushed out and dealt with (this may take a few builds), eclipse builds the project without failures and produces a .bin file. Whee!

Now, the next step is to actually download this fresh new executable to the target board and run it. As I understand it, this requires cooperation of several tools. GDB (GNU Debugger) is used to (besides debug) interact with the vendor-specific JTAG device and actually burn code onto a device. There is also some sort of TCP/IP loopback server (gdbproxy? J-Link apparently performs this function) in the mix somehow.

Aside: This is where everything seemed to sh*t the bed when I tried to set up a similar Eclipse+GCC toolchain for msp430 microcontrollers – building went smoothly, but the whole matryoshka of uneasy agreements between gdb, gdbproxy, and the proprietary binary-blob (.dll) JTAG tool could only be jostled into working occasionally, with a lot of gdb-related process-killing and potentially rebooting between build attempts.

Sure enough, the next problem occurs here.

‘Launching blink Default’ encountered a problem

Error creating session
Cannot run program “arm-none-eabi-gdb”: Launching failed
Cannot run program “arm-none-eabi-gdb”: Launching failed
Cannot run program “arm-none-eabi-gdb”: Launching failed

As a quick sanity-check, typing arm-none-eabi-gdb at a command prompt successfully launches GDB, so this is probably more Eclipse-specific path BS. Since I don’t have infinite time to burn on this, another hacky ‘solution’: manually ‘Browse’-ing to and thus hardcoding the path to arm-none-eabi-gdb in Eclipse’s debug configuration dialog, under (green ‘bug’ button dropdown arrow) -> Debug Configurations -> Debugger. This done, launching debug dumps a healthy amount of gibberish (raw GDB commands and responses) to the console, along with several errors/warnings from gdb and several inexplicable red lines of text (that do not, outwardly, appear to be error messages, but rather echoes of send commands), but the gdb stream seems to suggest that bytes were successfully pushed to the dev board.

Success! I think. I guess. Maybe.
Switching over to the “Segger J-Link GDB Server” program (remember, the appnote says to start this before Eclipse and leave it running) shows GDB “Connected to 127.0.0.1” along with another green mark, which it did not before. Good sign, I suppose.

…OK, maybe not. Attempting to set a breakpoint and run the application does nothing. Attempting to restart the “Debug” process from the beginning just causes Eclipse to hang. With some dicking about (close Eclipse, manually kill all *gdb processes in Windows task manager, restart) I can get as far as “Starting target CPU…” and “4 KB downloaded” appearing in J-Link, but no apparent activity on the target board. But, uploading the freshly built ‘blink.bin’ binary using the ‘energyAware Commander’ DOES work! So, at least the compiler / build environment is sane. Something is going wonky between Eclipse/J-Link/GDB/board. If “Show log window” and “Verify download” are enabled in J-Link GDB Server, download lines have “Verify failed” after them.

After a reboot and starting over with the recommended versions of Eclipse (2.7.3 / Indigo) and its plugins… it works! Then switching back to the current version… it works! It is possible the PC and/or board were just in a wonky state and fixed by a good old-fashioned powercycle. Aaaanyway, downloading code to the development board thru Eclipse seems to be OK now.

Last little niggles:

  • Upon starting a debug session, a large page shows up with the following in bright red scary text: No source available for “__cs3_interrupt_vector_em() “. This is not any kind of error message, really. It just means that the interrupt vector table(?) (which it wants to show you for some reason) has no source code available to show you. (You are instead given the option to view an assembler dump.)
  • The “EmbSys Registers” tab shown in the appnote screen shots does not appear. Solution: This tab is not enabled by default – enable it using Window->Show View->Other->Debug->EmbSys Registers
  • . Once this is done, the tab will appear with a note to set your chip. Now go into Window -> Preferences -> C/C++ -> Debug -> EmbSys Register Viewer and select the appropriate architecture/vendor/chip. For the EFM32LG-STK3600 (Leopard Gecko Starter Kit), this is ARM3, EnergyMicro, and EFM32LG990F256, respectively. Close out of there and the EmbSys tab should contain a list of viewable registers in a folder hierarchy by association (e.g. those associated with the ADC, WDT, etc.).

  • Unresolvable symbol errors: On my setup, several error messages appear under “problems” when debugging is started: “Symbol ‘cmuClock_CORE’ could not be resolved” and “Type ‘uint32_t’ could not be resolved”, for example. They don’t seem to be hurting anything (and I have not found/ looked for any fix for this), but I’d bet real money that this is a stupid paths problem again.
  • Well, Future Tim, there you have it. Working EFM32 debugging on an open-source toolchain!

Computer-controlled RGB LED Buckyball

Everyone and his brother has built LED cubes before, and while they are unmitigatedly awesome, I wanted to try something a little different. As far as I can tell, nobody has made an LED buckyball before!

Completed ball running some cheesy visualizations

And of course, the requirements for such a large, sparse shape are a little different. In a typical LED cube design, the leads of the LEDs themselves form the structural members and support base of the cube – the lead lengths more-or-less set the size and density of the cube, and since it sits on a large surface area, there’s plenty of room to bring out plenty of signals and drive them from a single many-pinned microcontroller (usually via Charlieplexing). In a large, sparse hollow sphere, the wiring for Charlieplexed LEDs would get unwieldly pretty fast. So instead, I used a bussed approach where each LED sits with its own tiny microcontroller on a serial bus, with a unique address programmed into each one. Such addressable “smart pixel” LED nodes have been around for a while and available off-the-shelf, but for various reasons (outlined below), I opted to design my own open source (GPL) version, dubbed das Blinkenlichten, and used these for the project. These nodes sit on a 3-wire (power, data, gnd) bus and speak over a self-clocking bit protocol. The ball contains 90 such nodes; one for each of the 60 junctions of the buckyball, plus 30 more in the “long” beams of the ball (more on that later too).


Sidebar: Addressable RGB LED nodes
Addressable “smart pixels” or RGB LED nodes have been around for a while; in the hobbyist community, BlinkM is probably the most well-known. However, at close to $13 a pop, a deployment of any significant number of these adds up very fast. In addition, the code was/is very much proprietary – not only closed source with dire warning against reverse-engineering, but only allowed for noncommercial applications at that. As of late 2004, there was really not much in the way of very inexpensive nodes or open-source designs to pick up and build on one’s own. Add to that patent issues surrounding many of these products (including pretty much all I2C-based designs), and the situation for open blinky hardware was bleak indeed. So I rolled my own that was dirt-cheap, minimal wire count and GPL’ed. By happy coincidence, it also avoids all the RGB LED control patents that I am aware of. Luckily, as of late 2011 there are many more inexpensive, open-source and even microcontrollerless (shift-register based) blinkies available in single or strips, so go nuts!

Buckyballs:
In real life, buckyballs are spherical molecules composed entirely of carbon. The LED ball models the most well-known of these molecules, carbon-60 (buckminsterfullerene), consisting of 60 carbon atoms. These atoms are arranged such that their bonds form 12 polygons and 20 hexagons, with one carbon atom at each vertex. The stitching, and often coloring, of soccer balls (footballs outside the US) mimics this structure.

Construction details:
I wanted the ball to consist of basically nothing but light – i.e. a bare minimum of visible wiring, electronics or any other opaque portions. Thus the light from the tiny LEDs would have to be well diffused throughout the entire structure. Playing around, I found that hot-glue sticks make almost perfect LED diffusers, and wasted no time cleaning out the local art&craft store’s supply for the ball’s structural elements. In retrospect, this was not the ideal solution: despite anything you might hear about the buckyball being a magically strong shape, it’s still not enough to hold the weight of 90 hot-glue sticks and electronics without sagging into more of a pear shape. In the end I had to add some internal “guy wires” (monofilament fishing line) to help it hold a spherical shape. As you can see, it’s still not perfect, so I’ll have some adjusting to do!

The ball consists of 12 pentagonal sections totaling 60 sticks, and 20 hexagonal sections formed by connecting 3 sticks between each neighboring trio of pentagons.

To create the physical ball, I needed some kind of scaffolding to hold the ball in shape during various stages of (in)completion, and ideally serve as a construction guide. For this, I bought a cheap inflatable soccer ball on eBay, blew it up, and assembled the ball around it in pieces. The markings on this ball (a promotional item for a foul-tasting yet inexplicitly popular domestic beer) are not 100% faithful to a real C60 molecule; the pentagonal sections are a bit small, resulting in the spokes between them (forming the hexagons) being a bit longer than the pentagon segments. I’ll just refer to these as the “long” sticks from now on.

First, I assembled all the Blinkenlichten boards with a 5mm LED. Each board is about 10mm square and can sit flush against the end of a glue stick with only the solder tabs sticking out. Each of the 60 sticks forming the pentagons are end-lit, with the LED node installed by drilling a hole in one end the diameter of the LED and shoving it in. The remaining 30 “long” sticks (to form the hexagonal sections) have a hole drilled in its middle and the LED inserted perpendicular to the stick. I’ve found that using a drill bit a tiny bit smaller than the LED itself works well: the drilling action heats up the stick enough to partially melt the inner walls of the hole; quickly shoving in the LED after this allows the walls to stretch slightly to accommodate it, then glues it tightly in place.

Template for cutting pentagon sticks to size/shape

"Long" (hexagonal) sticks with the LED perpendicular

I first built the required number of pentagonal sections, with the length of each side matching that printed on the soccer ball. To do this, I made two simple templates in Inkscape and printed them out. One consists of two lines intersecting at 108 degrees (the interior angle of a pentagon), indicating the length to cut each stick to and the angle to cut the end at so that the 5 sticks will sit flush against each other when assembled. The other is a template for laying up the pentagon itself. A box cutter knife made short work of cutting the sticks to the right size and shape. With all the sticks cut to shape, I used more hot glue (for its intended purpose this time) to assemble the sticks into pentagons, being sure to fill in any gaps where the sticks mated.

Stack of assembled pentagons

With all 12 pentagons assembled, I wired their power, data and ground terminals together using 3 runs of color-coded magnet wire. I made a complete ring with each – although this was not strictly necessary, it provides two parallel current paths between any two points around the pentagon. Not a bad idea since the ones nearest where the power/data cable will plug in will be passing a lot of current. To avoid any surprises later, I quickly clipped the Arduino (running a simple test loop) to each assembled pentagon to make sure they were working. Finally, I tacked the wires together and onto the backside of each pentagon with hot glue. While I had the magnet wire handy, I took this opportunity to solder lengths of wire to each of the 30 “long” sticks as well.

Testing the pre-assembled segments to avoid surprises later

With the pentagons assembled and wired, I began assembling them onto on the inflated beach ball, adding the “long” sticks in between as needed. For this I just kind of winged it to avoid tolerance stack-up, marking and cutting one stick at a time for a good fit. After cutting to length, I cut a V-shaped notch in both ends of each stick so that they would mesh well with the pentagon corners they attached to. These were similarly glued into place, squeezing in extra hot glue to fill in any voids.

Sections being assembled on the beachball

Ball structurally completed, but not wired up

Finally! The buckyball looks like a buckyball. The beach ball was deflated and removed. By this stage each pentagon was already bussed together, so wiring consisted of using all the pre-wired “long” sticks to bridge neighboring pentagons together, folding or trimming any excess magnet wire and tacking it to the back of each stick (i.e. the inside surface of the ball.) After a final electrical test with the whole ball assembled, I sealed in all the LED boards and solder points with (you guessed it) more hot glue, made a hanger out of metal rod and cut two pieces of plexiglass to serve as the top and bottom supports for the rod. Bends in the hanging rod prevent the ball from sliding free of the rod or stretching out of shape.

Making endcaps for the top/bottom, which will support its weight when the hanging rod is passed through.

Completed ball running some cheesy visualizations

Electronics & Programming:
After some brief forays writing effects code in Processing and C (to run directly on the Arduino), I decided to write the visual effects script in Python for the most flexibility. The effects script outputs serial data to an Arduino (for the blog cred, yo), which serves as the bridge between the PC and the RGB LED array. Commands are sent as 3-byte packets to the Arduino consisting of a sync byte (0x55) followed by the Blinkenlichten address and command bytes. The Arduino clocks these out to the ball in the native Blinkenlichten single-wire format (not to be confused with Dallas 1-Wire(R) Protocol). See the Blinkenlichten page(s) for a full description of this protocol, but it basically consists of bits encoded as the ratio of ON-time to OFF-time on the wire (if the high “half” of the bit is longer than the low half, it is decoded as a 1 and vice versa), endcapped by a START (high for longer than the maximum bit ON-time) and END (low for longer than the maximum bit OFF-time) condition. Special commands exist for address discovery, address grouping, low-power mode and a couple other handy features.

Obviously, with 90 tiny microcontrollers and 270 unique LED dice potentially drawing power at the same time, there’s no way an Arduino / USB port can supply sufficient power on its own. A small perfboard mates the Arduino (running off the USB supply) to a 5V/4A wall wart for power to the ball electronics. The USB and wall-wart power are *not* bridged together (although the grounds are). Even at 4A (claimed) output capability, the wall wart struggles to keep the ball lit at full tilt – currently (hah!) it takes on a reddish hue if all the LEDs are going near full brightness, because the power supply output drops below the 4V or so it takes to light the blue LEDs. Also, the “3-wire” cable through my window now consists of 5 strands of rainbow wire (power and ground doubled up) because it was getting a tad warm with only one power and one ground strand.

Arduino supplies the data, while a 5V/4A wall-wart (black cable) supplies the power. The flat rainbow wire, is the perfect shape for sneaking around a closed window and to the ball outside.

When I assembled the Blinkenlichten nodes, I just programmed them serially and threw the finished ones in a box. Needless to say, by the time nodes were pulled from this box and the ball assembled, the node IDs are in no particular order. To make things easier on myself, I numbered all the locations in a logical way by writing them on the beachball with marker, then map the “human-readable” number to the actual node ID at that location in software. If you noticed various numbers scrawled on the beachball, this is what they are for (red: pentagon locations, black: “long” stick locations, green: actual node ID at that spot, in hexadecimal).

As of this writing, the effects script has only a tiny handful of effects I could throw together quickly – one pays homage the well-known “snake” games of yore, a couple others simulate paint splotches or crystal growth in various ways, and one just fades the primary colors in and out. Obviously, many of these require the software to have knowledge of the physical structure and relationships of the LED array. For this, the script includes a “neighbor table” consisting of a 2D list of each (human-readable) node number’s immediate neighbors. A couple more tables identify other relationships, such as which nodes are in the same pentagon or hexagon section. The script makes (or will make ;-) extensive use of das Blinkenlichten’s address-grouping features to run high-speed complementary effects on different logical groups with a minimum of bus traffic.

Downloads:
Blinkenlichten schematics/PCB, firmware and Arduino library – see the Blinkenlichten page
Buckyball effects script and Arduino serial-to-blinken script

Fixing an Acer AL2216W LCD Monitor (Delta DAC-19M010 power supply, bad caps)

There are several dozen of this model of monitor at my work since last year or so; the other day I found one on top of the dead electronics plunder pile recycling bin, looking brand new. Googling the model # and terms such as “problems” or “repair” or “won’t turn on” revealed pages of discussion on the badcaps.net forums: it seems this model of monitor is yet another victim of the bad capacitor plague that somehow continues to sweep the electronics world. Upon opening the monitor, this suspicion was confirmed by several visibly bulging capacitors in the low-voltage section of the power supply.

Probable Symptoms:

  • Monitor won’t turn on, no apparent power, black screen
  • Blinking power LED
  • Turns on but shuts itself off without warning*

Note: This power supply board (or very similar model) appears to be used in a variety of monitors from different manufacturers. Depending on which one you have, your symptoms may differ to what I have observed on the AL2216W. In particular, the monitor may simply not turn on (too-low logic voltage or software-controlled shutdown), may blink its power LED to indicate a fault, or may turn on for a few seconds and switch off again. In my case, the monitor showed absolutely no external signs of life (power LED dark and no response to the power switch), but a very brief flash of the backlight could be seen just as the unit was unplugged, confirming it did indeed have power but “chose” not to switch on (likely as a safety feature).

Obligatory Butt Covering Warnings

This is a wall-powered electronic gadget. Opening it and poking around inside carries a small, but non-zero, risk of electric shock even when unplugged. (There is a 100K bleeder resistor across the mains filter cap, but this could fail.) For your safety, wait at least one full minute after unplug to go near the supply board, and use a screwdriver with an insulated handle to short across the leads of the filter cap to be sure it is discharged. If you see a fat spark and blinding flash of light, the safety bleeder resistor has probably failed, and you might want to reconsider poking around in here.

(Opening it and poking around inside while it’s plugged in carries a guarantee of electric shock, just FYI.)

Disassembly

This is fairly straightforward. Pop off the plastic cover hiding the screws that attach the base. Unscrew them and any other visible screws, then carefully pry at the seam where the two halves of the monitor “shell” come together. Once inside, more screws. Note that to get the final metal shields off, the backlight connectors and the ribbon cable to the button panel must be disconnected, then the scew-in posts for the video connectors and two screws concealed in the mains cord socket must be removed.

What’s inside?

Surprisingly little, it turns out. There is one large power supply board (made by Delta Electronics, Inc.) and a much smaller display controller board (marked A220Z1-Z01-H-S6) with only two highly-integrated Realtek ICs and some discrete components. My educated guess is that the controller boards are very unlikely to fail, so start by looking at the Delta board.

Fault Finding

By all accounts, bad capacitors are usually the underlying cause of these problems. Due either to being under-rated or a sordid tale of corporate espionage (see Wikipedia link above), the capacitors will gradually vaporize their electrolyte (and sometimes not so gradually, with a bang) until they can no longer perform their capacitorly duties, causing the monitor to go haywire.

First, inspect all the electrolytic (“tin-can”) capacitors for visible problems. Their tops normally have a score pattern on them, but should otherwise be flat. They should not bulge upward, even a little. Visible bulging, ruptured tops or signs of leakage (e.g. brown goo around the top or seams) are sure signs they need replacing. Note that failed or failing caps will not always show visible signs.

On the Delta DAC-19M010 board, things are divided up into 3 logical sections: the bottom half is a switching power supply that steps your 120/240V wall power down to a 13.8V and 5V rail. Roughly speaking, everything to the left of the large center transformer is its primary (high-voltage) side, and everything to the right is the low-voltage secondary side (the high side may also be marked off by cutouts and/or a line on the underside of the board). The upper half of the board (more or less) is the backlight inverter, with another large transformer to step this low voltage up to the 1kV or so needed to feed the CCFL backlights.

I’m sure you noticed the large, high voltage cap on the high side, right near where the power cord plugs in. You did short it, right? This is the one that can make your skeleton glow even if the monitor is unplugged. Luckily, consensus from the internet is that this filter cap on the primary side rarely fails, so unless it is showing visible signs you can probably leave it alone.

There are seven electrolytic caps on the low-voltage side, all of which should be replaced if you even slightly suspect a capacitor problem. (Technically, the topmost one connects to the backlight inverter, but you should change it anyway.) On my monitor, the 13.8V rail read a tad high (14.x) and the 5V rail showed only 4.1V. There is likely an undervoltage lockout circuit on the controller that prevents operation at this voltage, although there may have been significant voltage ripple due to the bad caps that was resetting or otherwise fouling up the logic directly.

Collateral Damage

With the caps replaced, it’s a good idea to check for any obvious collateral damage. There are several surface-mount fuses (denoted Fxxx) on the bottom of the board which might have been affected (zero-ohm resistors may have been stuffed in place of some fuses; check these too). After you triple-check that the mains filter cap is discharged, also check the through-hole fusible resistor to the immediate left (high voltage side) of the switching transformer. There is also a surface-mount fuse on the controller board near the power entry connector.

Cap List

Here are suitable replacement parts currently available on Digikey. Be careful when removing the old ones, as some of them are near very brittle powdered-core inductors and tacked down with some kind of glue. Note, one of the parts below has a higher voltage rating than the original (this is OK).

Quantity Part# Value Lead Spacing Height
2x 565-1546-ND (220u/25V) 3.50mm 11.5mm
1x 338-2342-ND (2200u/10V) 5.00mm 21.00mm
3x 493-1065-ND (1000uF/25V) 5.00mm 20.00mm
1x 565-1550-ND (470uF / 25V) 3.50mm 20.00mm

* Note, if the screen’s backlight cuts out (often after a couple seconds) but the monitor appears to remain powered, the fault is most likely in the backlights or backlight inverter section of the power supply board, not the low-voltage section. You can confirm whether the entire system or only the backlight has shut off by holding a strong flashlight directly against the screen while a valid video signal is present – if you can see the image around the edges of the flashlight, the low-voltage supply and controller board are probably OK. Replacing C204 MAY solve it, but otherwise, fixing backlight issues is a whole different animal, which I don’t cover here. You MAY be able to identify a single dud tube by unplugging one at a time (WITH THE MONITOR UNPLUGGED!!!) and testing the monitor, but this is not 100% reliable (some inverter circuits will detect a single “open” (e.g. unplugged) tube and shut down anyway).

Slam Stick: dissected!

Woot! It sounds like a gadget I designed will be featured in next month’s EDN magazine (Prying Eyes column). This must be some kind of ironic career turning point: I landed a job by reverse-engineering other peoples’ stuff; now people reverse-engineer my stuff.

UVLO, Comparators with hysteresis (now with 20% more equations!)

The Mosquino board is intended to operate from very low-power sources, such as RF, vibration energy harvesting and small thermal gradients (e.g. body heat). Although the ATMega and the rest of the circuit can be put to sleep at < <1uA once they have reached legal operating voltage, many semiconductor circuits fail this test with too-low or slowly rising power supplies. For example, the datasheet for the MCP1703 voltage regulator shown claims a quiescent current of a couple uA (in regulation), but it actually peaks out at over 100uA just below its regulation voltage, and that's not considering any other circuitry living downstream. So, as a key part of this balanced breakfast, this is a simple UVLO (undervoltage lockout) circuit that will hopefully become standard in the next Mosquino rev. It should be guaranteed to draw <10uA over the full (0.0 ~ 11V) range, and in practice probably much lower.

The active ingredient is simply a micropower comparator with a fixed reference and some positive feedback added to generate hysteresis. While deceptively simple, the math to cleanly resolve the desired on/off thresholds into a set of resistor values gets a little icky, so this post is mostly a note to myself so I never have to derive it again :-) (Yeah, I hate math and chose a career as an electronic engineer. Go figure.)

Operation

Two voltage thresholds, a “turn-on” threshold (Vh) and a lower “turn-off” threshold (Vl), determined by 3 resistor values, are defined by the user. (A reference voltage lower than either of these, Vref, is either provided by the user or comes for free with your comparator.) When a trickle of power is available, the input voltage charges up from zero until the higher, turn-on, thresold is reached, and this is then connected to the rest of the circuit (CPU, etc.). The circuit will be Doing Stuff, in some cases drawing more power than what’s coming in. In this case, the voltage at the input cap will begin to fall as power is consumed. The circuit gets cut off when the input voltage reaches the lower, turn-off threshold.

The feedback resistor, R3, is effectively placed in parallel with either R1 or R2 depending on the comparator’s state, which has the effect of pulling the compared voltage (+ terminal of the comparator) up or down slightly. This makes the divided Vcc appear lower than it really is until the comparator turns on, and higher than it really is until the comparator turns off again (see the equivalent circuits above).

Choosing these thresholds

The thresholds should be chosen such that the chosen power supply can actually (and reliably) charge up to the turn-on threshold, ideally in a reasonable amount of time. The turn-off threshold should be low enough (far enough from the turn-on threshold) that the turn-on current surge and any startup tasks don’t drag the supply all the way down to it and immediately turn your circuit off again. Needless to say, both should be within the circuit’s legal operating voltage range.

Setting the resistor values

R1 and R2 are a voltage divider; their ratio sets the comparison voltage between 0 and Vcc. For our purposes let’s also consider R3 this way, so we are really computing a relative relationship between R1, R2 and R3 that makes your Vh and Vl work. An approximately infinite number of actual resistances would work as long as the ratios between them are correct; we can worry about actual resistance values later. To make things simple we’ll define R3 = 1 and compute R1 and R2 relative to it. Here’s the math you need to do so (you can read the derivation below if interested).

  • Define R3 = 1.
  • Choose R1: R1 = (Vh/Vl) – 1
  • Choose R2: R2 = (Vref * R1) / (R1*Vl + Vl – Vref*R1 – Vref)

You should now have values (probably small decimal numbers < 1) for R1 and R2. Now let's choose real values for them. For a low-power application, you want to use large resistor values to minimize wasted current through them. But, the comparator's + input pin will have some amount of leakage / bias current, so this limits how large of resistors you can use (bias current sunk or sourced by the pin will affect its voltage and thus the overall setpoint accuracy). For decent accuracy, you want the current into the node containing the input pin to be at least 10x (ideally 100x) of the leakage current. For the LTC1540, the bias current is around 1nA, which is about as close to sweet f-all as you can get. In practice, the contribution of R3 in this application will be the weakest (highest resistance value) of the three by far, and so R1/R2 will be much lower. You can probably choose a value for R3 on the order of 15-30M ohms. In fact, a quick survey at Digikey says these are your only readily available standard values in that range; you might have to put two 15Ms in series. Beyond that point, you have to start worrying about truly silly stuff like the resistance of the PCB itself (especially on a humid day) goofing up your setpoints, so again, don't go too crazy. Now, multiply your ratio values for R1 and R2 by that value, and choose the closest standard value that is available for each. Optional, but recommended: Check the actual Vh and Vl you will get from choosing the standard values:

Notes for the LTC1540-based circuit above:

The part is guaranteed to operate correctly down to 2V, and in most cases will behave well below that. In my tests, it operated great down to about 1.4V. Below that, a spurious HIGH pulse on the output occurs from about 0.8 ~ 1.4V. For best results in the UVLO circuit shown above, be sure the FET it drives has a threshold voltage of at least 2V to guarantee the false signal will not be seen downstream.

If that part is not available, a couple parts with similar specs exist (e.g. MAX9117-9210 series), but they are not pin-compatible.

The Maths:


Optical Mouse Hacks: 2D Micropositioning using cheap mouse cameras

Optical mice work by pointing a tiny cheap camera at the surface of your desktop, tracking the motion of ‘interesting’ points in the surface texture (woodgrain, imperfections, highlight/shadow) as the mouse slides around over it, and converting this to an X and Y motion. An LED is used to light the surface beneath the sensor, typically at a very low angle to help highlight any surface roughness (so the sensor still works on rough, but solid-colored, surfaces such as paper). Many of these sensors allow you to read out the raw image, too. Historically, the sensors in optical mice have been a standalone chip with SPI interface, leaving a separate microcontroller to handle button clicks and PS/2 or USB interface – so you could hack a cheap optical mouse to output position or image data for unique scanner or robotics projects. Unfortunately, more and more of these high-volume, low-cost devices are moving to all-in one camera+micro+USB chips under an epoxy blob, so you can’t just buy any old optical mouse and expect any access to this internal data.

Videos:
Absolute microposition sensing using image recognition
Relative position sensing (i.e. just like a mouse) using the DELTA_X/DELTA_Y registers
Downloads:
Arduino Library


Naked mouse cam and lens wired to a microcontroller

Fortunately, standalone SPI sensors are still alive and well. Mouser.com (no pun intended) sells some of these (Avago ADNS-2610 and ADNS-2620) for the exhorbitant price of $1.56 each. It’s a CAMERA for a buck fifty. Not exactly a *good* camera (grayscale, 18×18 resolution), but you can still do some neat tricks with it. Of course, you will still need a cheap optical mouse to steal the lens off of (or maybe an old CD player, etc.).

If you want to be all lame and boring, you could use this mouse camera as, well, a mouse. An onboard DSP is constantly watching the surface below as it slides by, giving you an up-to-date relative position (DELTA_X and DELTA_Y) just by reading a pair of registers. Each ‘delta’ reading contains the number of +/- pixels the mouse has moved in each direction since the last time you read it. Since you are only reading 2 registers, you can read this information at very high speed. There are some additional registers that will give you the max and min brightness, sum of all pixel values, and a ‘surface quality’ value that represents the number of trackable points (divided by 2) under the imager.

But if you want to dig deeper, a builtin diagnostic feature lets you bang some other registers and return the entire image under the camera. A few things worth mentioning before you go further, though: this IS meant as a diagnostic feature only; they sell these things as mice and not cameras after all, and this feature is not the best implemented. There are 324 pixels (18×18 array), but you can only grab one pixel per frame. So when you get the image, you are actually seeing pixels composited together from 324 separate frames across maybe 1/2 second. If the camera is moving during this time, you’ll get a garbled image, so if you have this puppy strapped to a robot to take pictures (or position the robot), your robot has to stop for pictures. Also, your maximum full-image rate is only a couple images per second.

Following are some demos of monochrome and color image acquisition, surface identification and micro-position sensing down to the um range.

Circuit:
The ADNS-26xx parts only require a couple external components: an oscillator and a couple capacitors to stabilize its power supply and internal reference voltage. The oscillator frequency (about 20MHz-25MHz) is not critical; any cheap ceramic resonator will work fine here. So your complete parts list is:

1x ADNS-2620 mouse cam
1x 24MHz resonator (speed not critical)
1x 2.2uF capacitor
1x 0.1uF capacitor (optional but recommended power-supply bypass; value not critical)

Grabbing images:


The sensor’s great for reading that pesky fine print.

Above is a sample image taken from the sensor, looking at the little “Equal Housing Lender” glyph on some credit card junkmail. See below for some more. The process is straightforward; write once to the PIXEL_GRAB register to arm it, then read it 324 times (18*18) to read out the image bytes starting from the top left pixel. (Or use my Arduino library ;-)

And no, I’m certainly not the first to think of this. See here for a demonstration where someone combined the image and position readouts to use the mouse as a crude handheld scanner. I haven’t tried it, but I wonder how well this can see your fingerprints if the angle is right. (I assume not very well, otherwise mouse companies would have already enabled frame-grabbing on USB mice and tried to sell it as combination mouse and biometric ID thingy.)

Color imaging:
The grayscale sensor can be used as a crude color imager by replacing the standard red lighting with an RGB LED, and taking one frame with each color lit in turn. Depending on the LED, you may have to scale the R/G/B frame data differently for more accurate color representation. I assume like most photodiode technology the mouse cam pixels are most sensitive to the red-IR range, but the LED I used had a pretty weak red, so it was kind of a wash. (The image here is scaled red=0.75, green=1, blue=0.75).

2D position finding using the “Christopher Carter Algorithm”:
Very simple position-finding routine I wrote for testing purposes; named after a magician’s trick where the blindfolded practicioner (renowned hypnotist Christopher Carter, in the first case I saw it) “reads” a name written on a dry-erase board by swiping a finger across it at a few different heights. This is a similar idea, using a basic edge-detection to identify regions (“where to read”), then read them by the brightness at the center of each region.

In this method, you create a known optical pattern (in this example I used Gray Code) and apply it to the surface whose position you want to measure. Then aim the camera at it so that it looks at a small subset of the optical pattern at any given time. Ideally, each ‘pixel’ of the optical pattern should cover a 2×2 or more (3×3 or 4×4) pixel area on the sensor, since the optical pattern and the sensor’s pixels will never be *perfectly* aligned, and thus will blur across a couple neighboring pixels. Now you can identify the unique pixel pattern under the sensor and match it its position in the full optical pattern.


In a project at work, we needed to know how far a visual indicator pin on a piece of machinery was extended at any given time, and whether its position was in tolerance (reducing human observation error in dark and foul weather conditions). Since the sensor could not be permanently attached, we also wanted to be able to measure slop or shifting of the sensor itself relative to the pin, which would produce an incorrect reading. The small space, large pin travel and need for sensor cross-checking made common 1-D proximity sensors less attactive.

Definitions: The “pixel grid” is the actual sensor array. For ADNS-26xx, this is always 18×18. A “region” is one individual mark in the optical pattern, corresponding to a 3×3 (etc.) region of the pixel grid as mentioned above. The “region grid” is the array of these regions overlaid somewhere on the pixel grid. For example, with an 18×18 pixel grid and each region 3×3 pixels, the region grid overlaid onto the sensor can be as large as 6×6.

By performing this 2-stage lookup (find region grid offset on pixel grid, match region grid to known optical patterns), the total computation time is reduced by mainly working with only a small subset of the pixel data (the region grid), and the positioning resolution is at least (region size) and at most (pixel size). Working with only the center pixel of each region, to the extent possible (rather than e.g. averaging the entire region’s pixel values), is also beneficial since the regions may not be perfectly aligned to pixels and the focal plane at close range is very narrow (<1mm), thus the image may not be completely in focus – especially if looking at a curved or otherwise 3D surface. So all the pixels toward the edges of the region will tend to dilute the reading.


Absolute 2D position encoding/decoding using a Gray Code pattern. Position is resolvable generally to 1 pixel, in this case measured at about 2.4 mils (about 70um). The top-right shows the raw image with region grid (black squares) overlaid aligned to the strongest edges (pink crosshairs). The bottom-left shows the edge-detection itself, and finally, the top-left shows the recovered optical pattern. The actual position is the index of this pattern in the known fullsize pattern + the region grid’s offset.

Assuming an 18×18 image sensor:

Perform edge detection by taking the derivative of the image. Embedded systems such as Arduino are barely suited for non-integer math, let alone calculus, but we can take a poor-man’s “discrete derivative” easily by just subtracting neighboring pixels. Neighboring pixels on a uniform surface will not differ by much, so subtracting two neighbors will yield a low number, while along an edge, one will be very different from the other. We want to figure the vertical and horizontal edges separately. And we don’t care about the exact location of ALL the edges per se, just want to know on which rows and columns they occur. Once at least one good, strong edge is detected in each direction (horizontal and vertical), we know where to align the region grid so it is centered on valid regions.

For each horizontal row: For each pixel, its edginess (likeliness of being along a *vertical* edge) is given by the absolute value of (pixel – left neighbor) + the absolute value of (pixel – right neighbor).

v_edginess[row][col] = int(abs(image[row][col] – image[row][col-1]) + abs(image[row][col] – image[row][col+1]));

And of course that entire row’s vertical edginess is the sum of the edginess of all pixels in the row.

For each vertical column: Same thing, only going by columns, taking the pixel directly above and below. Again, the column’s edginess is the sum of the edginess of all the pixels in the column.

Obviously, the leftmost pixels has no left neighbors, and the rightmost pixels has no right neighbors (same goes for the top and bottom rows, they are missing neighbors on one side), so the easiest approach is to exclude them from the loops, e.g. for the 18×18 array, valid results start at (1,1) and end at (17,17). The result is an ‘edginess’ array of 16×16 pixels.

Once the region grid is positioned, threshold the region centers to black/white, then take the resulting region grid (4×4 in this example) and slide it around on an array containing the ‘known’ pattern until the best match is found. Obviously, in a real-world system subject to bad lighting, specks of dust, misalignment or misfocus, the match will not always be perfect. You might also want to know how well you can trust the measurement, so I compute a confidence value too. The confidence value is a function of the absolute % of regions matched, and the difference between the best match and the next best match. For example, if two different positions matched equally well (even if they are both “pretty good” percentage wise), you can’t uniquely identify a position and so your confidence must be zero.

Another thing briefly tested was to place an LED behind the pin and observe its side profile (Alfred Hitchcock Algorithm?), which worked surprisingly well.


Side profile of the pin showing the lower part of the indicator groove.

Weatherball

Last night I finished throwing together a workable version of the Weatherball, currently displaying a color code at the end of my flagpole to indicate whether tomorrow holds any interesting weather. Apparently cities and radio stations have been doing it since the 1950s, but now I have my own! The data is grabbed from the NOAA’s National Digital Forecast Database server (XML) using a quick C++ program, and currently acts on five variables: chance of precipitation, chance of hail, chance of tornado, chance of extreme wind, and cloud cover percentage. Any ‘interesting’ values in these fields are evaluated in order of decreasing importance (beginning with hail/tornadoes), and the most significant weather condition is sent to the das Blinkenlichten node in the ball at the end of the flagpole.

In the spirit of virtually all known Weatherballs to date, here is a not-very-catchy jingle expressing the color code:

If the weather ball is yellow/green, the sun’s expected to be seen
If the weather ball is gray, anticipate a cloudy day
If the weather ball is blue, it probably will sprinkle too
If the weather ball’s maroon, be prepared for a typhoon
And if the weather ball is red, forget the beach – head for the basement instead!

(And if the weather ball draws half an amp, the electronics have gotten damp – the Blinkenlicht inside the ball has been outside for nearly a year (just waiting for me to get around to writing the software) and seems to still work fine, but I really should weatherproof that sucker.)



Weatherball showing no interesting weather for tomorrow (yellow-green). Know what it needs now? More Power!


Here are the main parts – the ball is supposed to be a curtain rod capper.


The program to fetch weather reports from the interwebs and drive the ball

The DON’T PANIC flag* (Hitchhikers Guide reference; the house number is 42) is showing a bit of weathering, but is still intact. The flag pole is a piece of lightweight enameled metal rod from the big-box hardware store, intended for hanging stuff in closets. The bubbly clear ball on the end is a decorative curtain-rod endcap from Ikea. A set screw on the side allows it to be attached to rods of various diameters. The exposed clear plastic extends through the inner diameter of the endcap some on the inside, allowing the LED node placed in the base to light up the ball (though not brightly enough for my tastes; may beef it up a bit later). The material can also be drilled out to embed the LED further into the ball, if desired.

* If McCain gets elected, it will be replaced by a bright red PANIC! flag, and the weatherball recoded to display the current terrist alert level. It will operate briefly in this manner while I search for a homebuyer and a cheap one-way ticket to Canada…

And these points of data make a beautiful line…

(and we’re out of beta, we’re releasing on time… Err… deliverable code freeze will happen monday morning, or wednesday afternoon (due date), or before 50% of the devices are sealed up for delivery with the code already on them, whichever comes before the last bug is found. [Especially if the bugs are discovered in hardware, third-party hardware or attached wetware.]) As of tonight, all outstanding issues that I know of have been resolved and the hardware is performing beautifully… now we just have to build 30 more of them :-p

So, guess who has been and will continue to be semi-insanely busy for the next couple weeks or so?

My schedule for the forseeable future (i.e. as far as I’ve been forced to p-l-a-n):

Monday: Meatz, 7:30pm @ Midwest Grill, for mah birfday.

Tue-Fri.: Playing Metroid Set up a cot in the lab(?), get deliverable shizzle together, start(!) coding the (sender,receiver) sides of a completely secondary gadget our TPOC (not an embedded engineer) added to a very short contract extension at the very end, because “it’s the exact same thing, just operating 1,000x faster, right?” :-p Officially due Wed. as well, but that’s not going to happen, so I’m not going to spend the next two days sweating about it. (The actual delivery date is still up in the air, since we AFAIK haven’t been provided one, nor a destination address. Wed. is just the contract end date, i.e. last day we can book hours to it vs. stuffing engineering hours under “office supplies” or some such nonsense.)

Friday night ~ Wed. the 24th: Demoing my sssexy, self-powering gadget at the RSI conference in Chicago (train stuff, not excessive 2- or 1-handed typing injuries*) (environmental energy harvesting, not over-unity quantum-foam perpetual motion BS :-))

Wed ~ ???: Catching up; putting out whatever fires were started in my absence.

Real entries to come soon(ish)!

smallfish@tech

So yeah, that particular work project just keeps getting better. Today I got this in my email from the manufacturer of a critical component, reaffirming my personal “If it’s not in-stock on Digikey, I do not specify it in my design” policy.

[…] The <display> is on
hold. There are no technical reasons but it has been decided that it will be turned
on again if we receive a commitment from a customer. Makes it a bit harder to sell
without a product but that is the path that <vendor> has chosen to take. At 10K the
display would be $### each. Once turned back on, samples would take 10 to 12 weeks.

So, this display turns out to be a rather special type of display, which we’ve gone to considerable expense in researching, testing, and designing a product around. We’d been working with this vendor for the better part of a year and they’re already aware of and (until around today, apparently) cool with our expected volumes (5kU-10kU, contingent on, among other things, their product actually existing), so this is kind of a giant kick in the nuts. Basically, we’re too small-fish and they’ll maybe consider manufacturing the (already-designed) display product if a larger customer wants some. The specific reason we were working with <vendor> to begin with was that they were the only vendor of this type of display that didn’t give us the old “fuck off, come back and speak to us when you have that PO for 50kU in hand *click*” that seems to be the industry standard. Soooo… project is back to square one, $$$ of development money thrown into the trashcan. Not even from e.g. a big government contract, where it’s pretty much unnoticed and understood if some of the development time we’ve spent vaporizes for reasons beyond our control, but the hard-earned cash of a couple entrepeneurs, who are not going to be the least bit happy that their almost-product just went up in vaporware.

Blarg.

It’s a mean old bitch and it has stupid name, bitch bitch bitch bitch bitch bitch bitch

So, I got an email back today from a contractee, whereupon I learned:
1) A technology I created, which I envisioned as having significant pro-consumer subversive uses, will instead be used as a carrier for evil (“hey, can it collect usage data to sell to credit-card companies every time they use it? That would be gr-rrreat!”)
2) It’s going to have a really stupid name. The kind of short, vowel-laden nonsense syllable combination used by start-up Web marketing firms and overly cute Web 2.0 niche services for the Myspace generation. But stupider.

Bleh.

Blinkenlichten RGB LED controller: protocol / firmware (1.2)


This is the protocol spec and PIC10 firmware download for Das Blinkenlichten (1.2). This version improves handling of the ‘Identify’ command by end devices. Backward compatibility to 1.1 is not affected.

I don’t have pretty datasheets, application notes, timing diagrams, or much example code / pseudocode, but I’m sick of sitting on this thing until I get around to those :-P So I figured I’d just stick it on the internet and see what happens. The rest might be filled in in my future spare time (or by some nice person in the comments)…

Description:
Das Blinkenlichten is an open-source RGB LED lighting system and protocol written for the PIC10F200 microcontroller. A complete node consists of this chip, an RGB LED, three current-limiting resistors and a small capacitor for power-supply smoothing. A single chain can have up to 255 unique nodes (or as many non-unique ones as the wires will carry power/data for, without burning up!). Everything is coordinated by a single master device, which can be any low-cost microcontroller or equivalent with a free I/O pin. The beginnings and goals, etc. of the design are described on this page.

Pretty Pictures
Pic: Blinkenlichten in melty, icicle-like resin
Pic: Swirled around by a girl dancing
Video: Very simple random-color-generator demo
Video: Cool video of blinkenlichten who react to music

Features / Commands in brief:

  • Cheap! At 34 cents each (qty:100), the PIC10 is probably one of the world’s cheapest and simplest microcontrollers. Complete parts cost can be less than $1US per node.
  • Fast 1-wire data bus – complete operation with only 3 wires (power, data, ground)
  • 3 colors (R,G,B) can each be set to one of 9 intensity levels – total 729 possible colors
  • Set Group Address command: control groups of LEDs at a time with a single command
  • Deferred Update command: Allows simultaneous color changes even with a large number of devices.
  • Identify command: Discover the addresses present on the bus.
  • Power Save command: Stop all clocks and enter low-power mode until the next command

Arduino/Wiring library and example
Library and example sketch showing common usages (move to /hardware/libraries in your Wiring folder, close and re-open Wiring. The example will then appear under Sketchbook -> Examples -> Library-Blinken). This library is released under the GPL.

Firmware and source code (PIC10 assembler)
Version 1.3 (“It’s Log!” edition) can be donwloaded in this zip file. A few lines at the beginning will have to be set according to your hardware configuration (see below). The “#define MYADDR …” line contains the address the chip should respond to – change this and rebuild for each chip you program. This version adds a logorithmic color table so that the color intensities you specify will appear linear (evenly-spaced steps) to the human eye. Adding this meant some idiotproofing had to be removed – sending an invalid (>8) intensity value will cause undesired operation. Starting with 1.3, this code is released under the GNU General Public License v3.

Version 1.2 (‘dumb’ linear color table) can be donwloaded in this zip file. A few lines at the beginning will have to be set according to your hardware configuration (see below). The “#define MYADDR …” line contains the address the chip should respond to – change this and rebuild for each chip you program.

Hardware/Schematics:

Basic schematic for an individual node. The schematic shown uses a common-anode LED (common is connected to VCC); for a common-cathode, tie the LED common to Ground instead and change the appropriate #define at the beginning of the code. Different LED packages have different pinouts; test and make sure of them before wiring it up – or especially making boards. (The R/G/B connections to the LED can be easily remapped in software, but you have to get the LED’s common right the first time!)

Basic wiring diagram for a complete string with several nodes and a controller. There is a pulldown resistor between the data wire and ground (recommended value 100k ~ 1Meg). This is necessary for the ‘IDentify’ command to work, and it also helps prevent your string of lights from going haywire if the controller takes some time to start up and the voltage on the line is floating.

The maximum cable length, and maximum nodes reliably driven on it (or maximum speed), depends on how strong your controller drives the data line. As you add length and extra loads (inductance and capacitance) to this wire, the voltages on it will take longer to rise and fall, and be more difficult for the nodes to reliably consider a ‘1’ or ‘0’. I’ve run them with 6+m of cable without incident, but if you run into problems, reducing the data rate should help. If you don’t care about the IDentify feature, you can add a beefy buffer here to drive the data line harder. If driving long strings, you might also want to add decent-sized electrolytic capacitors between the power and ground wires at intervals along the string.

PCB and Parts List (Bill Of Materials)
This file contains a parts list for both DIP/breadboard and tiny surface-mount versions. Also included is an EAGLE schematic and Gerber files for a miniaturized, wearable board using surface-mount components. These data (schematics, BOM and Gerbers) are released into the public domain.

A picture of the finished SMT boards (panel) is shown below. With a jumbo 10mm RGB LED, the board is almost completely concealed behind the LED and only the sewable connections stick out.

Programming the chips
To write the firmware to these chips requires access to a PIC programmer. The official ones made by Microchip Inc. are quite expensive; fortunately there are many clones out there that work just as well, and some open-source designs you can build yourself. Just make sure that the programmer supports the PIC10 devices; some very simple/cheap designs (e.g. direct to PC serial port) may be designed only for “low voltage program” devices and won’t generate the +13V or so necessary to program this chip. The DIP variants can be programmed in or out-of-circuit; for the SMT variants, you will probably need to solder them to your board (with an appropriate pin header / etc for the programming lines), program the chip, and THEN add the LED (since it shares some of the programming pins and will interfere). For the ready-made SMT circuit board above, the following drawing indicates the pinout of the programming header on the edge of the board. For this, I soldered the wires from the programmer to the “wrong” side of a 5-pin 1.25mm connector (such as Molex 53047-05), then just press the other end into the PCB during program.

Command packet format: (forgive the horrible ASCII art)


     <start> <addr[7..0]><cmd[7..0]><stop>
_____- - - -. . . 16 data bits . . .______

The bus idles low.

Start condition: Bus goes HIGH and stays high for longer than the longest possible loop run (min. ~ 17uS), so that all devices are guaranteed to catch it.

Data bits consist of a low period (low half) followed by a high period (high half). A 1 is denoted by making the LOW half longer than the HIGH half, and a 0 by making the HIGH half longer. Ideally, all bits should total the same length, but since the low half sets the baud rate on a bit-per-bit basis, this is not required. However, any half should be a minimum 18 device clocks (18/1MHz=18uS) for most accurate timing, and should not exceed 255 device clocks (255uS).

Stop condition: Give some time for the cmd to be processed before sending a new one (bus idles low). If you’re in a hurry, this time depends on the specific cmd. Otherwise, you can just wait about 90uS (time for the longest 1-way cmd, activate_deferred, to complete) and not worry about it. (*See special timing notes for Identify cmd.) This is the preferred approach, but you could also just make the START condition longer.

Address BYTE format:

bit <76543210>
AAAAAAAA

where AAAAAAAA is an 8-bit device address (or group address). Address 0 is the broadcast address. Since the ‘Group Address’ cmd only supports addresses up to 64 (0x40), I recommend a handful of low addresses (0x01 ~ 0x0F) be set asdie for group addresses if you plan to use this feature.

Cmd BYTE format:

bit <76543210>
ERGBIIII

E: Extended Command flag. If ‘1’, decode remaining bits as Extended Cmd as described under Extended Commands. Otherwise,
RGB: Which color(s) cmd applies to (set ‘1’ for each color this intensity applies to)
IIII: Set intensity (0 ~ 8)

Extended Commands

11xxxxxx : Set Group Addr to value xxxxxx
10XXyyyy : Poke "Virtual reg" XX with contents yyyy (see below), where XX is the address of a virtual 4-bit reg and yyyy is the value to poke.

Vreg 00: Flags [x identify activate_deferred power_save]
Vreg 01: Defer buf R
Vreg 02: Defer buf G
Vreg 03: Defer buf B

Detailed description of the virtual registers:

Vreg 01 ~ 03 allow a deferred update to be sent for the R, G and B channel respectively. The new intensity value(s) are stored in memory, but the old intensity values continue to be displayed until an activate_deferred command is executed, at which point the new intensities are displayed. This will be particularly useful for trickling new values over the bus, then sending a single activate_deferred to all devices (addr 0) to give the appearance of a simultaneous update.

Vreg 00 is a virtual register among virtual registers: Rather than writing a value to it, you write to it setting an individual bit to perform the requested action. Once the action is performed, the bit can be considered automatically cleared.

  • Unused (bit 3): “No-Op” – Dummy command, doesn’t do anything.
  • Identify (bit 2): On receipt of this cmd by a given device address, this device shall pull the data line HIGH (internal weak pull-up) for a period of about 512 device clocks (or whatever, plenty long enough for master device to see it). Normal operation is then resumed. (Note that this may disrupt other devices on the bus, who interpret the pullup signal as a new START command. If this is bothersome an Identify command may be followed immediately by a dummy command if a device responds. The device’s response will be seamlessly eaten by the dummy cmd’s START, so it just looks like an extra-long start bit to all devices.)
  • Activate_deferred (bit 1): Replaces the currently displayed intensities with the contents of the Defer (R,G,B) regs if they contain a valid update.
  • Power_save (bit 0): This command will effectively stop the CPU and any pulse modulation activities and enter a low-power SLEEP mode. The device will remain in SLEEP mode until the next bus activity occurs, at which point it will re-awaken. Technically it will be waking up occasionally due to WDT, but these activity periods will be brief.

Quick Examples

Set device id 02 Red to max (8):
<start><02><01001000><stop>

Set device id 02 to bright white (Red, Green, and Blue to max):
<start><02><01111000><stop>

Set device id 02 to arbitrary color (Red 8, Green 2, Blue 3):
<start><02><01001000><stop>
<start><02><00100010><stop>
<start><02><00010011><stop>

Set device id 07 off (Red, Green, and Blue to 0):
<start><07><01110000><stop>

Clear all group addresses to 0 (default):
<start><00><11000000><stop>

Assign device id 0x9F to group (address) 05:
<start><9F><11000101><stop>

Set all devices to power save:
<start><00><10000001><stop>

Advanced Examples

Identify all the devices on the bus (pseudocode):

for (id = 1 to 255)
{
    Send1Wire(id, b'10000100'); // Extended cmd: Identify
    Delay(100); //delay 100 uS, to give device time to respond
    DATA_WIRE = 'INPUT'; // However you switch this pin to an input on your preferred platform
    gotResponse = DATA_WIRE; // read the data line to check if anyone is responding (pulling the data line high)
    DATA_WIRE = 'OUTPUT'; // Switch it back to an output (retaining same value as was read)
    if (gotResponse == 1) // Was there a response?
    {
       print("Found device " , id); // do something with this information, e.g. store active IDs to a table
       Send1Wire(0, b'10001000'); // send dummy command if there was a response.
                                        // Or you can just wait a few hundred msec for the other devices to reset
    }
}

Specific firmware points of interest

The intensity of the LED colors is controlled using pulse width modulation (PWM). The basic operation is that the intensity value for each color (0 ~ 8) is converted to that many ‘1’s and stored in a register, and this register’s contents are continually rotated in circles. Each time, the last bit is used to determine the on/off state of the LED. So with 8 bits in a register, it can be on 0/8 of the time (off) or 1/8 of the time or … 8/8 of the time (full brightness).

To provide the fastest possible update rate, it’s necessary to squeeze as much performance out of these cheap tiny PICs as possible. The PIC10 supports only a handful of instructions, no interrupts, and only a rudimentary 8-bit timer. For the PIC10F200, the entire program is limited by memory to 255 instructions. Therefore we can’t afford to be too sloppy.

The code uses look-up tables in place of any loops/math wherever possible. The chip does not support table-indexing operations in ROM (Flash), so this is done using computed GOTO: In many microprocessors including this one, the Program Counter register (which acts as the processor’s bookmark in the code’s execution) can be modified by the program directly. Thus, by writing a new value to the Program Counter you can force the processor to lose its place, resuming program execution from the address you just wrote. By performing math operations directly on the program counter, this method can be used to index a lookup table nearby. In the example below, the intensity value is added to the program counter to make it an index into a table stored just after it. The ‘retlw’ instruction returns from the function with a specific value saved in a register. This code snippet converts the (0 ~ 8) value to a value containing that many ‘1’s, using only a few clock cycles.


; Want to return a value containing the number of '1's specified in the intensity
; value. But want to spread them out for faster switching and less perceivable flicker.
setpwm:
    movf INDF, w ; cmd value
    andlw B'00001111' ; mask off bogus bits
    addwf PCL, f ; skip that many instructions
    retlw B'00000000' ; 0x00
    retlw B'00000001' ; 0x01
    retlw B'00010001' ; 0x02
    retlw B'01001001' ; 0x03
    retlw B'01010101' ; 0x04
    retlw B'01010111' ; 0x05
    retlw B'01110111' ; 0x06
    retlw B'01111111' ; 0x07
    retlw B'11111111' ; 0x08 ; last valid value

This same method is used to allow the PWM loops to keep running while receiving data. Each time a bit is received, the PWM loop “jump table” is called. The count of the number of bits received is used as the index into the jump table; instead of a list of data values, each table entry contains a jump (GOTO) to the address of either the red, green or blue updater.

Determining between ‘1’ and ‘0’ bits on the data wire also takes just a few instructions. For each bit, the line is held low for some amount of time by the controller, then held high. Whether the low or high half was longer determines whether it was a 1 or 0. The way to measure this can be thought of as a stopwatch that counts up during the first half, then down during the second half. If the count goes negative, the second half was longer and we record a ‘0’, else we record a ‘1’. The ‘stopwatch’ here is the chip’s 8-bit counter/timer register. But it can’t count down, it can only count up! So a little cheating: when finished timing the first half, we complement (invert) the contents of the timer register. Now it’s still counting up, but if the original count was 7, now it’s (256-7) or 249. If the 2nd half is longer, the timer will reach its maximum value (255) and roll over to zero again like an old car odometer (and ending at a low number again, the Most Significant Bit will be a 0). Otherwise it will be a high number, and the Most Significant Bit will be a 1. So, at the end of one up/down cycle on the data line, the timer’s MSB will automatically contain the correct bit as it was sent on the data wire.

You might also have noticed that the PIC10 only has 3 pins that can function as outputs; according to the datasheet the 4th (which I’ve used for the data wire) is input only. The 3 output pins are already being used to drive the 3 LED colors. So how does a node send data back to the controller in response to an IDentify command? There is a register setting that enables weak pullup resistors (~10k-20k) on all the pins. On the output pins this does nothing, but on the input (data) pin this applies voltage to the wire, overpowering the even weaker pulldown resistor (~100k) added to the controller side. (The controller stops driving the I/O pin briefly to await this response.) So by toggling the pullup resistor on and off, we can send data the ‘wrong’ direction :-)

Version History and Compatibility:

  • v0.x (2005) Nora Nightlight edition. Quick n dirty hack with hardcoded timer to distinguish 1/0 data bits. Set Group Address is the only valid extended command. Didn’t get around to touching it again for a long time.
  • v1.0 (2007) Beloved edition, demoed at VNV Nation concert April 07. Changed from fixed-frequency to variable baudrate data encoding/decoding; re-ordered some bits in the command packet format to make more sense.
  • v1.1 (2008) Proper edition; first public release. Implemented remaining Extended commands: power save mode, deferred update stuff, and device identification.
  • v1.2 (2008) More-Proper edition. Improved handling of IDentify cmd; now can avoid flashes during identify as non-responding devices on the bus reset. Compatibility with v1.1 devices is not affected.
  • v1.3 (2009) It’s Log! edition. This version implements a logorithmic color scale in order to better match the human visual response (intensity steps now appear evenly-spaced). Compatibility with v1.1 and v1.2 devices is not affected, unless you are sending invalid (>8) intensity values, which you shouldn’t be!

v1.1, v1.2, v1.3 are backward / forward compatible and can be used on the same bus. V1.0 supports only the basic command set (Set Colors and Set Group Address). Versions prior to 1.0 are not compatible at all…luckily, they basically don’t exist in the wild.