I recently acquired two 5m lengths of RGB LED strip, both of which came with control boxes, remote controls, and power supplies. Right now they're basic mood lighting for a room in my apartment. The problem is that the control boxes each drive their own strips, but work off of the same remote control. As such, I'm controlling them "together" by virtue of having taped their IR sensors next to each other. This...doesn't always work properly.
So instead, I would like to make a custom control box, one that can control the strips separately or in tandem, but will still function using the included remote control. I will be adding an increased brightness range and individual control over the red, green, and blue channels in the process. The MCU driving all this will be an MSP430G2553. If possible, I will also add an audio input that the MSP430 can use to sync the lights to music / sound.
The first step is reverse engineering the remote control and writing control codes for it. Thankfully this part has been taken care of for me, thanks to
this post by Mohonri. Using a TSOP34838 38 kHz IR receiver and a Saleae Logic Probe, I was able to confirm that the IR protocol is the same from Mohonri's post.
The protocol works by sending IR pulses at a 38 kHz rate when active. The start of a sequence is indicated by an active period of around 9 ms, followed by an inactive period of around 4.5 ms. After this, data is transmitted by sending a short pulse of around 650 us, then pausing either 650 us or 1.65 ms before sending another short pulse. A short pause indicates a 1, and a long pause indicates a 0. Decoding the data this way, I verified Mohonri's statement that 4 bytes are sent: the inverse of the address byte, the address byte, the inverse of the data byte, and the data byte. If a short pause were taken to be a 0 and a long pause to be a 1, then the bytes and their inverses would be swapped. So really, it can be taken either way.
Anyway, after decoding the data this way, I noted that the address byte is 0x00, that the data byte varies depending on the button pressed. After a bit of mucking around, I realized that the most logical arrangement is if the data is read as being sent least significant bit first. Decoding the button presses this way yielded the following layout:
RGB Remote Codes
Up
5C |
Down
5D |
Forward
41 |
Power
40 |
Red
58 |
Green
59 |
Blue
45 |
White
44 |
54 |
55 |
49 |
48 |
50 |
51 |
4D |
4C |
1C |
1D |
1E |
1F |
18 |
19 |
1A |
1B |
Up Red
14 |
Up Grn
15 |
Up Blu
16 |
Quick
17 |
Dwn Red
10 |
Dwn Grn
11 |
Dwn Blu
12 |
Slow
13 |
DIY1
0C |
DIY2
0D |
DIY3
0E |
Auto
0F |
DIY4
08 |
DIY5
09 |
DIY6
0A |
Flash
0B |
Jump3
04 |
Jump7
05 |
Fade3
06 |
Fade7
07 |
Notice how the codes mostly make sense once you get past the third row of colors. It kind of annoys me that the sensible layout gets ditched for the top part of the remote, but oh well; it wouldn't have made a difference in the code anyway.
Rather than manually decode these button presses, I used some MSP430 coding to get the data for the above table. Using the MSP430 Launchpad, I connected the IR receiver output directly to the TimerA1 CCR0 module and had it trigger an interrupt every time the line changed. I used some simple state machine coding to have it detect the initial pulse, then to start reading out data based on the length of each pause. The TimerA1 was configured to count to 0xFFFF continuously, so I could detect length of pauses by subtracting a second capture value from a previous capture value. CCR1 was used to reset it to initial conditions if no state change occurred after a certain period of time. The interrupt routine stored the data to a circular buffer, which I then read out using the USCI peripheral, which was set up as a UART transceiver.
(Side note: The Launchpad, for whatever reason, has the TX and RX lines hooked up wrong for the MSP430G2553. I had to swap them with some jumper cables. That little detail held me up a bit...)
I have uploaded all of my code, written in the Code Composer Studio 5.2 IDE, to Google Drive. Also included are my personal VT100 library and my BCD converter assembly function, which I find useful any time I'm dumping data out over a terminal.
Link to CCS Project:
https://docs.google.com/open?id=0B5dybbS2PoDtV1dIaWNVLWhZWTA
With this code implemented, it should be easy to deal with IR remote data in the main program loop, especially if I just have it read in the data to a 4-byte buffer instead of a circular buffer, like I am now.
In my next post, I'll be working out how I'm going to actually drive all the channels on the LED strips.