I have this dream to someday light our basement with RGB LEDs. They often come with remotes and controllers, which are surprisingly inexpensive. The problem with the remotes you get for cheap on ebay is that you *have* to use the remote to change the lights, and that of course limits you to the buttons on the remote.
I’d like to make an in-wall dimmer/color changer for LED mood lighting, but with the added feature of being compatible with the existing cheap LED remotes on the market.
That means reverse-engineering one. And here it is:
Hardware
What’s the first thing I do when I get a new gadget? Take it apart, of course. Inside, it’s pretty simple:
There’s a 256-Byte two-wire serial EEPROM in the top left, a 5V linear regulator along the lower edge, and an unmarked 16-pin IC that is the main controller. Three transistors along the side drive the three colors of LEDs, and an external IR receiver connects to the board via the Red/Blue/Black triad.
I’m really not sure what the serial EEPROM is there for–perhaps the memory setting I couldn’t get to work?
IR Protocol
I soldered a couple leads to appropriate points and hooked it up to the oscilloscope to capture the incoming signals. Some day I hope to own a logic analyzer, but for now the oscope will suffice, especially when I only need one or two channels.
Run a Single trigger, press a button on the remote, and here’s what I got:
A bunch of zooming/shifting/saving/etc later, I had a bunch of data captured. Here’s the signal you get when pressing the “Red” button (click for big):
When the IR LED is on, the signal goes low, and when it’s off, the signal goes high.
There’s a 9ms low pulse, a 4.5ms high pulse, and then the data starts. Off I ran to find some IR protocols. I found myself in a familiar place–SBProjects, which contains a remarkably thorough knowledgebase on IR remotes and protocols. As it turns out, the protocol is the NEC protocol Each bit is encoded by a 560uS on pulse followed by an off pulse of varying length–560uS off is a logical 0, 1680uS off is a logical one. There are 32 bytes total. The first byte is an address, the second is the inverse of the address, the third is the command, and the fourth is the inverse of the command, with a final on pulse after the last bit. It’s little-endian, so least-significant bit comes first for each byte.
I mapped out all the remote’s buttons, and here’s the result. For all buttons, the address was 0xFF. Only in the command did it differ. The following table contains the buttons and commands. Note that these are little-endian, and written in hex.
Up Down Play Pwr
0x3A 0xBA 0x82 0x02
Red Grn Blu Wht
1A 9A A2 22
2A AA 92 12
0A 8A B2 32
38 B8 78 F8
18 98 58 D8
RUp GUp BUp Quick
28 A8 68 E8
RDn GDn BDn Slow
08 88 48 C8
DIY1 DIY2 DIY3 AUTO
30 B0 70 F0
DIY4 DIY5 DIY6 Flash
10 90 50 D0
JMP3 JMP7 Fade Fade7
20 A0 60 E0
It’s pretty much a binary key matrix–the remote is just sending a code for the key that was pressed, rather than RGB values or anything more complex. The first four rows have A as the second nybble (little-endian, though!), the next four have 8 (0xA minus 0x1), the last three have 0 (0x8 minus 0x8). The second column is the same as the first column except for the first bit being flipped. The third column is the same as the first, except the second bit is flipped, and the third column has both the first and second bits flipped compared to the first column.
All the decoding must be done in the controller.
Outputs
The controller outputs a PWM signal for each color. I noticed that the PWM frequency didn’t seem all that high–I could at times detect the flashing. (As an aside, it drives me nuts that car companies use stupidly low PWM frequencies for LED tail/brake lights, but that’s another subject) So I checked out the wave form for the outputs.
Each output is turned on for 840uS per cycle. To vary the brightness, the controller adjusts the off time. That varies from 5.36mS at the dimmest setting to 320uS at the brightest. That means the controller only gets up to about 72% duty cycle at its brightest setting, and down to 14% at the lowest setting. Since humans percieve brightness logarithmically, there’s a big low end that’s getting missed, although it might be too dim at that end to be useful.
Where am I going next with this? I’m not sure yet, but at least it’s now documented.