Dejan Levec

Ambilight part 1 & Netduino

I always liked Ambilight feature, but our TV doesn’t have it. I have seen some home made look-alikes on the Internet, however, I never really thought about buying it until I’ve seen Ladyada’s strand of 25 RGB LEDs and instantly wanted to build it myself. Since I have 42″ TV I decided to buy 2 strands, totaling 50 RGB LEDs.

Each LED has dedicated IC, which allows for individual control of color and brightness. IC is WS2801 and supports SPI like protocol which can be found on most (if not all) microcontrollers. I also like that they are waterproof in case I want to use it as christmas lights.

Since 3 years ago, when I first used microcontroller I have only used AVRs, altough I bought Arduino last year, but it’s still an AVR. I have two PIC samples, but haven’t come around to build programmer. Also have MSP-430 based board, but haven’t got a project where I could use it, so that doesn’t count.

I have been looking at .NET Micro Framework for a while and finally decided to try it. What I like about Netduino:

– Threading
– Debugging (it’s like debugging Windows application)
– C# (I like C/C++ but find that I’m more productive with a higher level language)
Р Great networking support (for Netduino Plus)

I bought them specially for prototyping & one-time projects, but may decide to use it for some big project in the future.

Let’s get back to my ambilight like system. Yesterday, I have spend a few hours trying to interface with those LEDs, but haven’t had much luck. On the end I kinda blamed Netduino for this, which turned out to not be the problem. Most of the times they didn’t even light up, when other times they were in random colors.

Today I decided to test it with ATmega168, since I know it pretty well and original code from Ladyada is based on similar microcontroller. After I figured out the chip worked, I struggled with the same problem that was present with Netduino yesterday, I couldn’t control the lights.

After another reading of technical data about this strand I noticed that I’m connecting MISO to CLK and CLK to MISO. Well, that doesn’t look right, but I was completely sure, that yellow cable was clock and green cable was data. After a simple switch everything was working fine and I was playing with different animations using same controller.

Sample code for one of the animations (walking blue light):

#include <avr/io.h>
#include <util/delay.h>
#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_CS PB2

#define SPI_CLOCK_MASK 0x03
#define SPI_2XCLOCK_MASK 0x01

#define SPI_MODE_MASK 0x0C

void delay_ms(uint16_t x);

int main (void)
{
SPI_DDR = (1<<PB3)|(1<<PB5)|(1<<PB2);

SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);

SPCR &= ~(_BV(DORD));
SPCR = (SPCR & ~SPI_MODE_MASK) | 0x00;

SPCR = (SPCR & ~SPI_CLOCK_MASK) | (0x01 & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((0x01 >> 2) & SPI_2XCLOCK_MASK);

SPCR &= ~(_BV(DORD));

int selected=0;
while(1) {

for(int c=0; c<25; c++) {
if(!(c==selected)) {
for(SPDR = 255; !(SPSR & _BV(SPIF)); );
for(SPDR = 0; !(SPSR & _BV(SPIF)); );
for(SPDR = 0; !(SPSR & _BV(SPIF)); );
}else{
for(SPDR = 0; !(SPSR & _BV(SPIF)); );
for(SPDR = 0; !(SPSR & _BV(SPIF)); );
for(SPDR = 255; !(SPSR & _BV(SPIF)); );
}
}

_delay_ms(50);

selected++;
if(selected==25){
selected=0;
}

}

return(0);
}

Blue and brown wires are going to LED strand, flat cable is for ISP programmer, and yellow LED was used to test accuracy of uC fuses and crystal. I used first crystal I could found and it has frequency of 19,6608 MHz.

With my problem solved I tried using it with Netduino and it worked in first try.

Sample code for Netduino:

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace NetduinoApplication2
{
public class Program
{

public static void Main()
{

SPI.Configuration Device1 = new SPI.Configuration(
Pins.GPIO_NONE, // SS-pin
false, // SS-pin active state
0, // The setup time for the SS port
0, // The hold time for the SS port
false, // The idle state of the clock
true, // The sampling clock edge
2000, // The SPI clock rate in KHz
SPI_Devices.SPI1 // The used SPI bus (refers to a MOSI MISO and SCLK pinset)
);

SPI SPIBus = new SPI(Device1);

SPIBus.Config = Device1;

byte[] WriteBuffer = new byte[3];

int t = 0;
while (true)
{

for (int c = 0; c < 25; c++)
{
if (c < 13 && t>0 || t==0 && c >= 13)
{
//R

WriteBuffer[0] = 0xFF;
WriteBuffer[1] = 0x00;
WriteBuffer[2] = 0x00;
}
else
{
//B
WriteBuffer[0] = 0x00;
WriteBuffer[1] = 0x00;
WriteBuffer[2] = 0xFF;
}

SPIBus.Write(WriteBuffer);
}

Thread.Sleep(100);

t = (t>0) ? 0 : 1;
}
}

}
}

What have I learned from this experience? Always triple-check your wiring with datasheet or other documentation, if something is not working like expected. I also decided to use AVR instead of Netduino for Ambilight project, because it costs 3x less and offers what I need, SPI to interface with lights and USB support (V-USB for AVR which I have used in a few projects).

Leave a Reply

Your email address will not be published. Required fields are marked *