mtAtmo: Insanely Bright 60W LED Backlight for a 58" Plasma Screen

Ever since Philips released their Ambilight enabled televisions, hackers around the world have gone "ooooh, cool" and then immediately "how can I build that?"

If you're not familiar with the concept, it's basically a light source that surrounds a display screen. It's not a new idea...many very old televisions had a white "halo" around the screen both to make the screen seem bigger, and to reduce eyestrain. Flat panel televisions are usually mounted on or near a wall, so the idea of putting a glow on the surrounding wall was born. Philips improved on the idea by building a processor into their TVs that analyzes the signal and adjusts a ring of LEDs to match colors. Supposedly this increases immersion and reduces eyestrain...but we all know it just looks really cool.

DIY Ambilight-style setups have been around for years. One of the more popular video viewing programs, VLC, even ships with a plugin to control external LED hardware. Many purpose-built devices and DIY designs exist too. But you can use general-purpose controllers, like an Arduino, with general-purpose LED modules. Here are a few easy to build projects (some of which are pretty recent):

There are many designs that just rely on a microcontroller or chips like the TLC5940 to generate several channels of PWM. However, the more channels you can have, the better your system will look. So a chainable LED system like ShiftBrites or a digital pixel strand will look the best and allow expansion in the future. One thing to remember is that these systems all require the video source to be a computer, since high definition video signals are hard to analyze. Therefore only Philips' system will work with live TV. The exception would be a system that uses a webcam to analyze the picture, but that's another level of difficulty and I've only seen it done a couple times.

With all these Ambilight clone projects popping up in recent weeks, we decided to try building our own system. One problem...the only accessible TV with an ideal wall situation was a friend's 58" plasma screen. Plasma screens are bright! Therefore we would need LEDs that could compete. Naturally, the new OctoBar and Satellite S-001 came to mind...they are really bright and the phone cables would make it easy to wire up.

So, one Saturday afternoon, we gathered all the parts and tools needed and started building. The actual build and wiring process is shown in the video at the top of this post, if you haven't watched it already (I always watch the video first!). We started off with six modules on the top, three on each side, two on the bottom, and two in the back middle. However, there was a dark area in the top corners so we added two more modules on angle to fill in. The total is over 60 watts of LED power! This is the equivalent of 900 single LEDs, the ultrabright ones that are already blinding to look at directly! It's brighter than 270 ShiftBrite modules!

The LEDs are mounted on a stable frame of 3/4" square dowel that attaches to the TV's carry handles. Angle brackets mounted to the frame hold four more dowels that hold the Satellite S-001 modules. These dowels can pivot in the angle brackets when the screws and lock washers are loosened..this allowed us to find the perfect angles to project a smooth color field on the wall.

Once everything was assembled and glowing a test pattern, we configured the necessary software. The video source in this case was an Atom mini PC running Ubuntu. I downloaded and compiled the boblight software package. You'll need to remember to install the X11 development dependencies first, or boblight won't compile the boblight-X11 program.

Boblight is pretty simple to use. Define the type of device, number of channels, available colors, and screen zones to sample. This all goes in the /etc/boblight.conf file. In the config file below, I created [light] entries in the same order the light appeared on the OctoBar chain. Each zone corresponds to an individual Satellite S-001 module, matching the actual position of the module as closely as possible.

[global]
timeout         20
interface       127.0.0.1
port            19333
interpolation   on
proportional    100.0
saturation      1.5
value           1.2
valuerange      0.0 1.0
use             yes
method          average
threshold       10

[device]
name            ambilight
type            atmo
output          "/dev/ttyACM0"
rate            115200
channels        54
interval        20000
prefix          FF

[color]
name            red
rgb             FF0000
gamma           1.0
adjust          0.82
blacklevel      0.0

[color]
name            green
rgb             00FF00
gamma           1.0
adjust          1.12
blacklevel      0.0

[color]
name            blue
rgb             0000FF
gamma           1.0
adjust          0.9
blacklevel      0.0

[light]
name	BR
color	red	ambilight 1
color	green	ambilight 2
color	blue	ambilight 3
hscan	50 90
vscan	85 100

[light]
name	R3
color	red	ambilight 4
color	green	ambilight 5
color	blue	ambilight 6
hscan	90 100
vscan	70 100

[light]
name	R2
color	red	ambilight 7
color	green	ambilight 8
color	blue	ambilight 9
hscan	90 100
vscan	40 70

[light]
name	R1
color	red	ambilight 10
color	green	ambilight 11
color	blue	ambilight 12
hscan	90 100
vscan	10 40

[light]
name	T6
color	red	ambilight 13
color	green	ambilight 14
color	blue	ambilight 15
hscan	78 92
vscan	0 15

[light]
name	T5
color	red	ambilight 16
color	green	ambilight 17
color	blue	ambilight 18
hscan	64 78
vscan	0 15

[light]
name	T4
color	red	ambilight 19
color	green	ambilight 20
color	blue	ambilight 21
hscan	50 64
vscan	0 15

[light]
name	T3
color	red	ambilight 22
color	green	ambilight 23
color	blue	ambilight 24
hscan	36 50
vscan	0 15

[light]
name	T2
color	red	ambilight 25
color	green	ambilight 26
color	blue	ambilight 27
hscan	22 36
vscan	0 15

[light]
name	T1
color	red	ambilight 28
color	green	ambilight 29
color	blue	ambilight 30
hscan	8 22
vscan	0 15

[light]
name	L1
color	red	ambilight 31
color	green	ambilight 32
color	blue	ambilight 33
hscan	0 10
vscan	10 40

[light]
name	L2
color	red	ambilight 34
color	green	ambilight 35
color	blue	ambilight 36
hscan	0 10
vscan	40 70

[light]
name	L3
color	red	ambilight 37
color	green	ambilight 38
color	blue	ambilight 39
hscan	0 10
vscan	70 100

[light]
name	BL
color	red	ambilight 40
color	green	ambilight 41
color	blue	ambilight 42
hscan	10 50
vscan	85 100

[light]
name	C1
color	red	ambilight 43
color	green	ambilight 44
color	blue	ambilight 45
hscan	50 80 
vscan	25 75

[light]
name	C2
color	red	ambilight 46
color	green	ambilight 47
color	blue	ambilight 48
hscan	20 50 
vscan	25 75

[light]
name	TR
color	red	ambilight 49
color	green	ambilight 50
color	blue	ambilight 51
hscan	92 100 
vscan	0 15

[light]
name	TL
color	red	ambilight 52
color	green	ambilight 53
color	blue	ambilight 54
hscan	0 8 
vscan	0 15

The next step was to get the Arduino to understand the AtmoLight protocol and control the LEDs. This was pretty easy, since there's an existing product called ArduinoAtmo that already controls ShiftBrite, MegaBrites, ShiftBars, and OctoBars. I just used it pretty much as-is, modifying for the new number of channels, but believe the code could use some more straightforward handling of the color data and serial input.

#define clockpin 13 // CI
#define enablepin 10 // EI
#define latchpin 9 // LI
#define datapin 11 // DI

//number of modules in the chain
#define NumLEDs 24 
 
int LEDChannels[NumLEDs][3] = {0};
int SB_CommandMode;
int SB_RedCommand;
int SB_GreenCommand;
int SB_BlueCommand;
 
void setup()
{
  Serial.begin(115200);
   
   pinMode(datapin, OUTPUT);
   pinMode(latchpin, OUTPUT);
   pinMode(enablepin, OUTPUT);
   pinMode(clockpin, OUTPUT);
   SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);
   digitalWrite(latchpin, LOW);
   digitalWrite(enablepin, LOW);

}

//sample code from macetech
void SB_SendPacket() {
  
   if (SB_CommandMode == B01) {
     SB_RedCommand = 127;
     SB_GreenCommand = 127;
     SB_BlueCommand = 127;
    }
 
    SPDR = SB_CommandMode << 6 | SB_BlueCommand>>4;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_BlueCommand<<4 | SB_RedCommand>>6;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_RedCommand << 2 | SB_GreenCommand>>8;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_GreenCommand;
    while(!(SPSR & (1<<SPIF)));
}

//sample code from macetech
void WriteLEDArray() {
 
    SB_CommandMode = B00; // Write to PWM control registers
    for (int h = 0;h<NumLEDs;h++) {
	  SB_RedCommand = LEDChannels[h][0];
	  SB_GreenCommand = LEDChannels[h][1];
	  SB_BlueCommand = LEDChannels[h][2];
	  SB_SendPacket();
    }
 
    delayMicroseconds(15);
    digitalWrite(latchpin,HIGH); // latch data into registers
    delayMicroseconds(15);
    digitalWrite(latchpin,LOW);
 
    SB_CommandMode = B01; // Write to current control registers
    for (int z = 0; z < NumLEDs; z++) SB_SendPacket();
    delayMicroseconds(15);
    digitalWrite(latchpin,HIGH); // latch data into registers
    delayMicroseconds(15);
    digitalWrite(latchpin,LOW); 
}
 

int incomingatmo[255];
int buffer=0;
int channels;
int i=0;
int BluePin=11;
int GreenPin=9;
int RedPin=10;
int laststatus=0;
int lastbyte=0;
int average=0;
int j=0;
int channel=0;
int x=0;

//order is reversed, first byte is last module in the chain
//0=sum
//1=left
//2=right
//3=top
//4=bottom
byte channelorder[24]={15,15,15,14,14,14,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};

int gammatable[]={0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,3,/
3,3,4,4,4,5,5,6,6,6,7,7,8,8,9,10,10,11,12,12,13,14,14,15,16,17,18,19,/
19,20,21,22,23,24,26,27,28,29,30,31,33,34,35,36,38,39,41,42,44,45,47,48,/
50,52,53,55,57,58,60,62,64,66,68,70,72,74,76,78,80,82,85,87,89,92,94,96,99,/
101,104,106,109,112,114,117,120,123,125,128,131,134,137,140,143,146,149,153,/
156,159,162,166,169,172,176,179,183,187,190,194,198,201,205,209,213,217,221,/
225,229,233,237,241,246,250,254,258,263,267,272,276,281,286,290,295,300,305,/
310,314,319,324,329,335,340,345,350,355,361,366,372,377,383,388,394,400,405,/
411,417,423,429,435,441,447,453,459,465,472,478,484,491,497,504,510,517,524,/
530,537,544,551,558,565,572,579,586,593,601,608,615,623,630,638,645,653,661,/
668,676,684,692,700,708,716,724,732,740,749,757,765,774,782,791,800,808,817,/
826,835,844,853,862,871,880,889,898,908,917,926,936,945,955,965,974,984,994,/
1004,1014,1023};

const int numReadings = 1;

 int bluereadings[numReadings];      
 int blueindex = 0;                 
 int bluetotal = 0;                  
 int redreadings[numReadings];     
 int redindex = 0;                 
 int redtotal = 0;                 
 int greenreadings[numReadings];    
 int greenindex = 0;               
 int greentotal = 0;                


void outputpwm(int curchannel)
{
  int blue=gammatable[incomingatmo[(channelorder[curchannel]*3)+3]];
  int red=gammatable[incomingatmo[(channelorder[curchannel]*3)+1]];
  int green=gammatable[incomingatmo[(channelorder[curchannel]*3)+2]];
  
//  int blue=incomingatmo[(channelorder[curchannel]*3)+3]*4;
//  int red=incomingatmo[(channelorder[curchannel]*3)+1]*4;
//  int green=incomingatmo[(channelorder[curchannel]*3)+2]*4;  
  
  
   bluetotal= bluetotal - bluereadings[blueindex];
  redtotal= redtotal - redreadings[redindex]; 
  greentotal= greentotal - greenreadings[greenindex]; 
 
   bluereadings[blueindex] =  blue;
   redreadings[redindex] =  red;
   greenreadings[greenindex] =  green;
 
   bluetotal= bluetotal + bluereadings[blueindex];  
   redtotal= redtotal + redreadings[redindex]; 
   greentotal= greentotal + greenreadings[greenindex]; 
   // advance to the next position in the array:  
   blueindex = blueindex + 1;  
   redindex = redindex + 1;
   greenindex = greenindex + 1;

   if (blueindex >= numReadings)              
     blueindex = 0;   
    if (redindex >= numReadings)              
       redindex = 0;  
    if (greenindex >= numReadings)              
      greenindex = 0;       

   // calculate the average:   
    average = redtotal / numReadings; 
     LEDChannels[curchannel][0]=average;
   average = greentotal / numReadings; 
  LEDChannels[curchannel][1]=average;
  
   average = bluetotal / numReadings; 
   LEDChannels[curchannel][2]=average;  
  }

void loop()
{
  if(Serial.available()>0)
  {
    buffer = Serial.read();
   if(buffer==0xff)
   {
     while(Serial.available()==0)
     { }
     buffer=Serial.read();
     if(buffer==0x00)
     {
       while(Serial.available()==0)
     { }
       buffer=Serial.read();
       if(buffer==0x00)
         {
           for(i=0;i<55;i++)
            {
              while(Serial.available()==0)
             { }
              incomingatmo[i]=Serial.read();
   
             }
            for(channel=0;channel<NumLEDs;channel++)
             {           
                outputpwm(channel);
             }
             WriteLEDArray();
         }
       }    
     }
   }
   else
   {
   	 WriteLEDArray();
     delay(5);
   }
}

Overall results were great, as you can see in the video. I needed to spend about an hour tweaking the colors in boblight to get everything matching the TV, and it could probably be tuned further. During a scene with lots of action and bright colors, it lights up the entire room! For LED maniacs like us it can't possibly be bright enough, but most people would probably need to turn it down.

That's the project, hope you like it! Feel free to ask any questions or make suggestions in the comments.


Submitted by Garrett on Tue, 10/25/2011 - 22:21.

Insane! But how did you

Insane!

But how did you connect the lights to the computer??

Thanks

that is a great display of

that is a great display of LED and knowledge...good job guys!
now the questions:
how much did you spend on the project? did you use any computer to control the lights while the tv is running?
where did you purchase the equipment? can it be found at radio shack?
do you guys have the project writen down? do you guys mind it send it to me...i would love to do it on my tv...
thanks,
Claude

what do you connect to the

what do you connect to the tv? the computer...the board or what?

thanks

would it make it any faster

would it make it any faster using direct port access? just remembering one of your post before, you r about the only one else i know that has more than 4 channels using shiftbrites i'v had my going going for a few years now thanks to you and your awesome product, now you might want to consider making led strips up, but might be a bit costly or try a different chip?

How does the effect look on

How does the effect look on the wall without a diffuser? What do people use for a diffuser if any? I keep thinking some sort of frosted acrylic would be best but i keep looking at the florescent bulb lenses in the office and those are made for that very purpose.

That is by far the brightest

That is by far the brightest ambilight I have ever seen. I'm quite tempted to blog about it on my site, http://www.pcambilight.com

Very cool :)

Very cool :)

How many led's would you

How many led's would you recommend for a 50" tv ?

hi, results are very

hi,
results are very fabulous
do you have a list for mateials and a tutorial step by step please (noob about hack ambilight)
your help will be very appreciate ;)
Thanks