A fashionable lamp for our times

Written by lcamtuf@coredump.cx

1. But why?

In this age of peace and prosperity, our generation truly is blessed! Our parents and grandparents trembled in fear of global thermonuclear war. With the era of paranoia and fear now firmly in the rearview mirror, what better way to celebrate world peace than by building a spiffy floor lamp?

2. The lamp

Remember that floor lamp that looked really good in the mail order catalog, but turned out kinda weird and way too bright for the room? Yep, that's right! That's the one:

Let's gut it and run some new wiring! Four strands of 18 gauge wire to every pendant seems like a wise choice. We're just getting started, but it's already lookin' good:

That's quite a bit of wiring - too much to fit through the original opening at the base of the lamp... Luckily, it's nothing that some vigorous cut-off wheel action could not fix. Go nuts with that power tool, my Internet friend! When done, be sure to remove any burr and file the edges; otherwise, should the wires catch on on the jagged edges, the resulting electrical fire could mess up the ambiance of the room.

Let there be light! Oh... right, hold on. Let's grab some high-power RGB LED modules. Bivar L24-ZRGBW is just the right size, and most people probably have some just lying around.

The modules go into each pendant. You may have to mill the heatsinks a bit to make it fit. A gob of silicone sealant is a nasty but effective way to pot the whole thing:

Hooray! We turned a lamp into a lamp.

3. The power of the atom

When done with the LEDs, why not check out this Soviet SBM-20 Geiger-Müller tube? It's been collecting dust for way too long:

A Geiger-Müller tube consists of two electrodes separated by some noble gas. Under normal circumstances, the tube does not conduct direct current and acts like a really expensive, tiny capacitor. But when you charge it to a sufficiently high voltage and the gas inside is then struck by a high-energy particle, this creates a conductive plasma pathway inside the tube, causing it to discharge:

Sweet! But to operate it, we first need to charge the GM tube to about 400 volts. Alas, all we have is this cheap 12V 5A supply; I crunched the numbers, and it turns out that we are 388 volts short.

Luckily, a miniature 1:50 CCFL transformer, such as Coilcraft FL2015-4L or Eaton CTX210403-R, is all we really need to build a Royer topology inverter. It's a pretty simple and efficient oscillator that can boost the input voltage just the right amount:

Most of the components are not critical and can be substituted with whatever the cat drags in. The 100 nF capacitor should be MLCC (not electrolytic), and the input capacitor must be rated for at least 16 V. The output voltage can be adjusted by varying the 220 Ω resistor; in a higher-powered inverter, we'd be using an inductor here instead - but in this case, a resistor is actually a safety feature that limits the current that will flow through your squishy human body should something go wrong. Be sure to observe the polarity of the windings, too - otherwise, the oscillator won't... well, oscillate.

Note: even with such an intentionally underpowered inverter, getting too chummy with high voltages can cause serious harm. Observe basic safety precautions and do not touch the HV side. Keep in mind that any capacitors in any HV circuit can hold their charge for a very long time after the power is switched off.

To test that our contraption is working correctly, don't hook up a multimeter or an oscilloscope directly to the HV side. Such instruments can be damaged by high voltages - and even if not, they will load the circuit and give you an inaccurate reading. Instead, outwit the enemy by building a simple measuring circuit like this:

If your meter has an internal resistance of 10 MΩ, you will need to multiply the reading by 105 to get the actual voltage, and the signal will be a bit more noisy - but that's about it. Another hurdle cleared - but hey, making lamps is supposed to be hard work!

Alas, our problems don't end there. You see, the output of the transformer is a menacing alternating current, ill-suited for our delicate GM tube. To get a steady supply of 400 volts, we need to employ a nifty circuit called a clamper, in which an capacitor in series with a diode is used to add a DC bias. That biased AC signal is then used to charge a second capacitor through another diode, ultimately producing a DC voltage that suits our needs. Goodbye, evil AC!

The capacitors are not critical, although they should be rated for around 1 kV; the same goes for the diodes. The tube itself needs to be connected through a 4.7 MΩ resistor to limit discharge current. Another small resistor on the "low" side is used to convert the discharge current to a low-voltage pulse that can be safely read by a microcontroller. An optional 33 pF capacitor may be useful for stretching the pulse in case the MCU has any difficulty picking it up. Here's what the MCU should see:

And here's the whole thing put together. Be sure to keep the HV side and the low-voltage side separate on the board - otherwise, delicate semiconductors may go poof:

To make sure that the circuit is working properly, confirm that you're getting several pulses per minute between the "event" terminal and the ground. If you're seeing nearly-constant pulses, you're either unusually radioactive, or the voltage supplied to the tube is too high - try increasing the 220 Ω resistor or the 100 nF capacitor in the inverter circuit and see if that helps. If the circuit is oscillating but you're not seeing any output, the voltage may be too low - try going the other way round.

4. The braaaains

To interpret the microsecond-scale pulses produced by the GM tube and use them in a practical way, we are going to employ a microcontroller, ATmega328P. For opsec reasons, the microcontroller is best purchased with Bitcoin or cash. The circuit is as simple as they get:

Since we're running off 12 volts, I used LM2576T-5.0 to step down the voltage to 5V - although a simple linear regulator would also do the trick. The MCU is taking input from the GM tube and controlling one indicator LED and five banks of RGB LEDs; the LED driver circuit will be discussed later on.

The diode, the inductor, and the output capacitor should be placed close to LM2576. The 1 µF MLCC capacitor should be close to the MCU. As in the previous circuit, the values are not critical, although the inductor must be rated for at least 500 mA, and the diode should have a reverse breakdown voltage of around 20V. Here's how the whole thing looks like by the end of the day:

The program for the MCU is pretty trivial, too: whenever it sees a GM event on the input pin, it randomly toggles the colors for one of the pendants, taking care to avoid repetition and to always keep at least one LED per pendant on. The source of randomness is the timing of the events themselves, causing the program to latch onto the state of a rapidly-advancing counter:

#define F_CPU 8000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> /************************** * User-friendly typedefs * **************************/ typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; /************** * MCU pinout * **************/ #define B_TUBE 0 /* GM tube event input: PB0 */ #define B_PEND0 1 /* Pendant 0 RGB: PB1, PB2, PB3 */ #define C_PEND1 0 /* Pendant 1 RGB: PC0, PC1, PC2 */ #define C_PEND2 3 /* Pendant 2 RGB: PC3, PC4, PC5 */ #define D_PEND3 0 /* Pendant 3 RGB: PD0, PD1, PD2 */ #define D_PEND4 3 /* Pendant 4 RGB: PD3, PD4, PD5 */ #define D_LED 7 /* White LED: PD7 */ /*********** * Globals * ***********/ u8 cycle_count, /* Busy loop cycle counter */ cur_rgb[5], /* Current pendant colors */ turn_off_cnt; /* Counter to turn off white LED */ volatile u8 event_detected; /* GM event, set via interrupt */ /*************** * Entry point * ***************/ int main() { CLKPR = _BV(CLKPCE); /* Enable clock prescaler change */ CLKPR = 0b00000000; /* Clock prescaler: 1 (8 MHz) */ PCMSK0 = _BV(PCINT0); /* Interrupt on pin 14 (PB0) */ PCICR = _BV(PCIE0); /* Enable interrupt 0 */ /* Configure inputs and outputs: */ DDRB = 0b11111110; DDRC = 0b11111111; DDRD = 0b11111111; /* Say "hi" */ PORTD = _BV(D_LED); _delay_ms(100); PORTD = 0; _delay_ms(100); PORTD = _BV(D_LED); _delay_ms(100); PORTD = 0; _delay_ms(300); sei(); /* The basic idea is to just keep counting in a busy loop. The GM tube will trigger an event at random intervals, which will cause us to latch the current counter state and output it to LM2576 enable pins to drive RGB LEDs. */ while (1) { cycle_count++; if (!cycle_count) { /* Every 256 cycles, we look at a counter used to turn off the white LED, lit up for a short time after registering an event. */ switch (turn_off_cnt) { case 0: break; case 1: PORTD ^= _BV(D_LED); /* fall through */ default: turn_off_cnt--; } } /* If we registered an event, let's mess with the pendants. */ if (event_detected) { u8 target_pendant = (cycle_count >> 3) % 5, new_rgb = cycle_count & 0b111; /* Make sure that we don't turn the pendant off completely, and that the new color differs from the current state. Note that the output uses inverted logic (0 = LED on, 1 = LED off). */ if (new_rgb == 0b111) new_rgb = cur_rgb[target_pendant]; if (new_rgb == cur_rgb[target_pendant]) { if (new_rgb) new_rgb ^= 0b111; else new_rgb = 0b001; } cur_rgb[target_pendant] = new_rgb; PORTB = cur_rgb[0] << B_PEND0; PORTC = (cur_rgb[1] << C_PEND1) | (cur_rgb[2] << C_PEND2); PORTD = (cur_rgb[3] << D_PEND3) | (cur_rgb[4] << D_PEND4) | _BV(D_LED); turn_off_cnt = 100; event_detected = 0; } } } /***************************** * GM tube interrupt handler * *****************************/ ISR(PCINT0_vect, ISR_BLOCK) { /* We only care about falling edge events (PCINT toggles on both edges). */ if (PINB & _BV(B_TUBE)) return; event_detected = 1; }

As easy as a really easy pie!

5. The muscle

The last part of the project is a driver to control the high-powered LEDs in the pendants without frying the MCU or the LEDs themselves. Each LED must be electronically limited to about 300-500 mA. Using linear regulators or resistors would be extremely wasteful and probably set the whole thing on fire, which would be detrimental to the aesthetics of the lamp. I decided to use a bunch of LM2576-3.3 switching regulators to step down 12 V to something very close to what the LEDs require (3.3 V):

There is a small 2-3 Ω 1W resistor as the final current limiting step for each LED. The whole circuit is repeated fifteen times, once for every LED; in retrospect, I should have used one higher-power regulator for every pendant or color bank, and then just a bunch of MOSFETs to switch individual LEDs. But I had this realization halfway through, so I decided to push on.

As with the previous switching converter, the components are not critical, but the inductor must be rated for at least 500 mA, the diode must have a reverse breakdown voltage of around 20 volts, and all the components should be physically close to each other. You also need at least one 220+ µF input capacitor on the 12V side close to every color bank.

Here the driver board after assembly and on its way into the project box:

6. The whole shebang

The lamp looks pretty nice, but is hellishly difficult to photograph, let alone film; the high contrast between the pendants and the ambient illumination is too much for my dSLR. But imagine a soothing sequence of colors:

God bless and remember to stay indoors!

7. Contact and such

Questions or feedback? You can reach me at lcamtuf@coredump.cx.
Interested in the earlier version of this project? Click here.
Curious about more useful radiation data? Try this.
Want to prepare for the inevitable nuclear apocalypse? Now you can!

Your lucky number is: 20813354