Atmoduino - Ambilight for the masses

by RickDB on Wed Apr 18, 2012 6:57 am

Recently published my projects online and wanted to share them, basically what it will allow you to do is create a complete amblight setup with an Arduino and Atmowin (modded to support 256 led channels).
The projects are posted on bitbucket:

https://bitbucket.org/RickDB/atmoduino/wiki/Home - Led Control via Arduino using FastSPI
https://bitbucket.org/RickDB/atmowin-at ... /wiki/Home - Modified version of Atmowin to support up to 256 channels (custom protocol)

Documentation is posted on the Wiki pages, it will describe the basic steps needed to build it yourself.

What I like about this setup is that it has proper gaming support (DX9/10/11) and has a Mediaportal plugin, for Linux you can modify the Atmoduino code to support Boblight.
There are currently lots of alternatives (Adalight/iBelight/etc..) so this will add some more choice to the whole DIY ambilght setups :)
The Atmowin software allows you to set everything nicely via a GUI, the timings in the demo video's were set to be dynamic (slow and smooth) but it can be set to anything you want.

Some old demo videos (the current version runs better and uses FastSPI):

Smart Lights - Demo (Kanye West - All Of The Lights)
http://www.youtube.com/embed/zC1Of8T3sKI

Smart Lights - Demo (Ribbons)
http://www.youtube.com/embed/0QmGFFKVXzg

Smart Lights - Demo (GL)
http://www.youtube.com/embed/odYVcl9fTt0

/EDIT: Updated Atmoduino project Wiki to list FastSPI requirements, for newer versions of Arduino you need my modified version of FastSPI (listed there).
Last edited by RickDB on Wed May 02, 2012 8:42 am, edited 3 times in total.
User avatar
RickDB
 
Posts: 7
Joined: Mon Mar 05, 2012 5:06 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Fri Apr 20, 2012 3:41 pm

Hi,

since days I'm trying to find a code (pde) for the arduino thats works with atmowin. Now I found your little wiki. But still I have problems, caused by my bad english. A step by step howto would be nice


regards
scorpie
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by RickDB on Sat Apr 21, 2012 5:16 am

scorpie wrote:Hi,

since days I'm trying to find a code (pde) for the arduino thats works with atmowin. Now I found your little wiki. But still I have problems, caused by my bad english. A step by step howto would be nice


regards
scorpie



Sure :) :

1. Connect the LPD8806 ( http://www.adafruit.com/products/306 ) led strip to your arduino according to this scheme:

http://goo.gl/PBo7s

2. Modify the Atmoduino code to suite your setup, setting the number of leds would be enough if you are using the LPD8806 chips.
3. Upload the Atmoduino code to your Arduino.
4. Follow the setup instructions that are listed here:

https://bitbucket.org/RickDB/atmowin-at ... /wiki/Home
User avatar
RickDB
 
Posts: 7
Joined: Mon Mar 05, 2012 5:06 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Sat Apr 21, 2012 2:10 pm

Thanks for your answer

I bought these leds http://www.adafruit.com/products/322

I don't have a clue about programming, really not.

I changed your AtmoDuino.ino into this

#include <FastSPI_LED.h>

//Set the number of leds in the strip.
#define NUM_LEDS 50

// Sometimes chipsets wire in a backwards sort of way
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
// struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

#define PIN 4
void setup(){
Serial.begin(115200);
FastSPI_LED.setLeds(NUM_LEDS);

//Change this to match your led strip
FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
FastSPI_LED.setDataRate(1);

//If non-default SPI pins have been used change this.
FastSPI_LED.setPin(PIN,11,13);

FastSPI_LED.init();
FastSPI_LED.start();
leds = (struct CRGB*)FastSPI_LED.getRGBData();
clearLeds();
}

int readByte(){
while(Serial.available()==0){
FastSPI_LED.stop();
}
FastSPI_LED.start();
return Serial.read();
}

void clearLeds(){
for(int tmpChannel=0; tmpChannel<NUM_LEDS; tmpChannel++){
leds[tmpChannel].r = 0;
leds[tmpChannel].b = 0;
leds[tmpChannel].g = 0;
};
FastSPI_LED.show();
}

void loop(){
if(readByte() == 0xFF){
if(readByte() == 0x00){
if(readByte() == 0x00){
int channels = readByte();
for(int channel=0; channel<channels; channel++){
leds[channel].r = readByte();
leds[channel].b = readByte();
leds[channel].g = readByte();
}
FastSPI_LED.show();
}
}
}
}

here FastSPI_LED.setDataRate(1); the 0 into 1 as discribed here

Note for people using sparkfun's ws2801 led strips - you need to call FastSPI_LED.setDataRate(1) before calling init/start.
The library defaults to a data rate of 0 for ws2801 strips, which is valid for the chips on the 12v strips, but not on the 5v strips (or, at least, the 12v strips that I have here) - it's too fast and you get weird random flashing occuring.

When I try to compile it I get this

AtmoDuino.cpp:1:25: error: FastSPI_LED.h: No such file or directory
AtmoDuino.cpp: In function 'void setup()':
AtmoDuino:13: error: 'FastSPI_LED' was not declared in this scope
AtmoDuino:16: error: 'CFastSPI_LED' has not been declared
AtmoDuino.cpp: In function 'int readByte()':
AtmoDuino:30: error: 'FastSPI_LED' was not declared in this scope
AtmoDuino:32: error: 'FastSPI_LED' was not declared in this scope
AtmoDuino.cpp: In function 'void clearLeds()':
AtmoDuino:42: error: 'FastSPI_LED' was not declared in this scope
AtmoDuino.cpp: In function 'void loop()':
AtmoDuino:55: error: 'FastSPI_LED' was not declared in this scope

uhaaaa I really need help - where do I put the "FastSPI_LED.h" in and what is wrong with the rest. Can you do it for me.

I would really appreciate this.
scorpie
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by franklin97355 on Sat Apr 21, 2012 4:00 pm

FastSPI_LED.h
Where did you put this file, r where is it on your disk when you search for it?
User avatar
franklin97355
 
Posts: 2662
Joined: Mon Apr 21, 2008 1:33 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Sat Apr 21, 2012 7:54 pm

I played around with the folder and put the FastSPI_LED folder in the libraries folder. now I get this error

In file included from AtmoDuino.cpp:1:
E:\XXX\programme\adalight\arduino-1.0\libraries\FastSPI_LED/FastSPI_LED.h:3:22: error: WProgram.h: No such file or directory

I don't have a file called WProgram.h

gosh, is that complicated
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Sun Apr 22, 2012 3:21 am

could compile it using an older arduino software and renaming .ino to .pde. but still not working. I can change whatever I want in the atmowin software. All I get is one blue led, thats it.

in the pic, the pins 3/4 are connected in the .pde it is FastSPI_LED.setPin(PIN,11,13);

I tried the pins 3/4 but still no luck

edit

Using arduino-1.0 I got this:

E:\XXX\programme\adalight\arduino-1.0\libraries\fastspi_led/FastSPI_LED.h:3:22: error: WProgram.h: No such file or directory

so I changed in the "FastSPI_LED.h"

#include <WProgram.h>
with
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

after that I got:

E:\XXX\programme\adalight\arduino-1.0\libraries\fastspi_led\FastSPI_LED.cpp:1:22: error: WProgram.h: No such file or directory
E:\XXX\programme\adalight\arduino-1.0\libraries\fastspi_led\FastSPI_LED.cpp:5:20: error: wiring.h: No such file or directory

so I changed in the "FastSPI_LED.cpp"

#include <WProgram.h>
with
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

and for:

E:\XXX\programme\adalight\arduino-1.0\libraries\fastspi_led\FastSPI_LED.cpp:9:20: error: wiring.h: No such file or directory

I copied the wiring.h from arduino-0023 to arduino-1.0

It can be found here: arduino-0023\hardware\arduino\cores\arduino

others are replacing the wiring.h entry with Arduino.h or wiring_private.h, but i don't know what's right here, cuz it is still not working, but I can compile and upload now.

Please don't let me alone with that - help me I'm willing to do my part to get it running
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by RickDB on Sun Apr 22, 2012 2:31 pm

scorpie wrote:could compile it using an older arduino software and renaming .ino to .pde. but still not working. I can change whatever I want in the atmowin software. All I get is one blue led, thats it.
<...>
It can be found here: arduino-0023\hardware\arduino\cores\arduino

others are replacing the wiring.h entry with Arduino.h or wiring_private.h, but i don't know what's right here, cuz it is still not working, but I can compile and upload now.

Please don't let me alone with that - help me I'm willing to do my part to get it running


The problem is that the latest version of Arduino changed alot in the core, the clean way is to adjust FastSPI to do a version check.
Have uploaded the modified FastSPI library and shared it here:

http://dl.dropbox.com/u/2953810/FastSPI_LED.zip

Place the files in your Arduino library folder (E:\XXX\programme\adalight\arduino-1.0\libraries\fastspi_led\ ) , you should now be able to compile everything normally.

Make sure you don't change anything else in the Arduino installation and remove the other version of FastSPI as well , this can stay the default as it is after installation.
Will add this to the Atmoduino repository in the future.
User avatar
RickDB
 
Posts: 7
Joined: Mon Mar 05, 2012 5:06 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Mon Apr 23, 2012 12:04 pm

HI,

can compile it know using the latest version for the arduino and your library, but still no funktion


I know my leds and the arduino are working together very well using a sketch called ledstream and a prog called lightpack (it makes a kind of screenshot and sends it to the arduino). but this needs a lot of my cpu and the movies are stuttering then.

I don't get it, whats wrong why is it not working.
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by RickDB on Mon Apr 23, 2012 12:09 pm

scorpie wrote:HI,

can compile it know using the latest version for the arduino and your library, but still no funktion


I know my leds and the arduino are working together very well using a sketch called ledstream and a prog called lightpack (it makes a kind of screenshot and sends it to the arduino). but this needs a lot of my cpu and the movies are stuttering then.

I don't get it, whats wrong why is it not working.


Could you post your ledstream and atmoduino sketch with the forum code tags (makes it easier to read) ?
Most likely something is wrong in the arduino code, did you also change your settings in Atmowin to match your config as stated in the Wiki Setup chapter ( https://bitbucket.org/RickDB/atmowin-at ... /wiki/Home )?
User avatar
RickDB
 
Posts: 7
Joined: Mon Mar 05, 2012 5:06 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Mon Apr 23, 2012 2:25 pm

I think I made all necessary changes, the arduino is connected at com 1. Maybe I missed something. Just using the AtmoWinA.exe not the mediaportal plugin should work, too! Am I wrong? I tried mediaportal with the plugin enabled (live view) - still nothing

ledstream.pde

// Arduino "bridge" code between host computer and WS2801-based digital
// RGB LED pixels (e.g. Adafruit product ID #322). Intended for use
// with USB-native boards such as Teensy or Adafruit 32u4 Breakout;
// works on normal serial Arduinos, but throughput is severely limited.
// LED data is streamed, not buffered, making this suitable for larger
// installations (e.g. video wall, etc.) than could otherwise be held
// in the Arduino's limited RAM.

// Some effort is put into avoiding buffer underruns (where the output
// side becomes starved of data). The WS2801 latch protocol, being
// delay-based, could be inadvertently triggered if the USB bus or CPU
// is swamped with other tasks. This code buffers incoming serial data
// and introduces intentional pauses if there's a threat of the buffer
// draining prematurely. The cost of this complexity is somewhat
// reduced throughput, the gain is that most visual glitches are
// avoided (though ultimately a function of the load on the USB bus and
// host CPU, and out of our control).

// LED data and clock lines are connected to the Arduino's SPI output.
// On traditional Arduino boards, SPI data out is digital pin 11 and
// clock is digital pin 13. On both Teensy and the 32u4 Breakout,
// data out is pin B2, clock is B1. LEDs should be externally
// powered -- trying to run any more than just a few off the Arduino's
// 5V line is generally a Bad Idea. LED ground should also be
// connected to Arduino ground.

#include <SPI.h>

// LED pin for Adafruit 32u4 Breakout Board:
//#define LED_DDR DDRE
//#define LED_PORT PORTE
//#define LED_PIN _BV(PORTE6)
// LED pin for Teensy:
//#define LED_DDR DDRD
//#define LED_PORT PORTD
//#define LED_PIN _BV(PORTD6)
// LED pin for Arduino:
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN _BV(PORTB5)

// A 'magic word' (along with LED count & checksum) precedes each block
// of LED data; this assists the microcontroller in syncing up with the
// host-side software and properly issuing the latch (host I/O is
// likely buffered, making usleep() unreliable for latch). You may see
// an initial glitchy frame or two until the two come into alignment.
// The magic word can be whatever sequence you like, but each character
// should be unique, and frequent pixel values like 0 and 255 are
// avoided -- fewer false positives. The host software will need to
// generate a compatible header: immediately following the magic word
// are three bytes: a 16-bit count of the number of LEDs (high byte
// first) followed by a simple checksum value (high byte XOR low byte
// XOR 0x55). LED data follows, 3 bytes per LED, in order R, G, B,
// where 0 = off and 255 = max brightness.

static const uint8_t magic[] = {'A','d','a'};
#define MAGICSIZE sizeof(magic)
#define HEADERSIZE (MAGICSIZE + 3)

#define MODE_HEADER 0
#define MODE_HOLD 1
#define MODE_DATA 2

// If no serial data is received for a while, the LEDs are shut off
// automatically. This avoids the annoying "stuck pixel" look when
// quitting LED display programs on the host computer.
static const unsigned long serialTimeout = 15000; // 15 seconds

void setup()
{
// Dirty trick: the circular buffer for serial data is 256 bytes,
// and the "in" and "out" indices are unsigned 8-bit types -- this
// much simplifies the cases where in/out need to "wrap around" the
// beginning/end of the buffer. Otherwise there'd be a ton of bit-
// masking and/or conditional code every time one of these indices
// needs to change, slowing things down tremendously.
uint8_t
buffer[256],
indexIn = 0,
indexOut = 0,
mode = MODE_HEADER,
hi, lo, chk, i, spiFlag;
int16_t
bytesBuffered = 0,
hold = 0,
c;
int32_t
bytesRemaining;
unsigned long
startTime,
lastByteTime,
lastAckTime,
t;

LED_DDR |= LED_PIN; // Enable output for LED
LED_PORT &= ~LED_PIN; // LED off

Serial.begin(115200); // Teensy/32u4 disregards baud rate; is OK!

SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV16); // 1 MHz max, else flicker

// Issue test pattern to LEDs on startup. This helps verify that
// wiring between the Arduino and LEDs is correct. Not knowing the
// actual number of LEDs connected, this sets all of them (well, up
// to the first 25,000, so as not to be TOO time consuming) to red,
// green, blue, then off. Once you're confident everything is working
// end-to-end, it's OK to comment this out and reprogram the Arduino.
uint8_t testcolor[] = { 0, 0, 0, 255, 0, 0 };
for(char n=3; n>=0; n--) {
for(c=0; c<25000; c++) {
for(i=0; i<3; i++) {
for(SPDR = testcolor[n + i]; !(SPSR & _BV(SPIF)); );
}
}
delay(1); // One millisecond pause = latch
}

Serial.print("Ada\n"); // Send ACK string to host

startTime = micros();
lastByteTime = lastAckTime = millis();

// loop() is avoided as even that small bit of function overhead
// has a measurable impact on this code's overall throughput.

for(;;) {

// Implementation is a simple finite-state machine.
// Regardless of mode, check for serial input each time:
t = millis();
if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) {
buffer[indexIn++] = c;
bytesBuffered++;
lastByteTime = lastAckTime = t; // Reset timeout counters
} else {
// No data received. If this persists, send an ACK packet
// to host once every second to alert it to our presence.
if((t - lastAckTime) > 1000) {
Serial.print("Ada\n"); // Send ACK string to host
lastAckTime = t; // Reset counter
}
// If no data received for an extended time, turn off all LEDs.
if((t - lastByteTime) > serialTimeout) {
for(c=0; c<32767; c++) {
for(SPDR=0; !(SPSR & _BV(SPIF)); );
}
delay(1); // One millisecond pause = latch
lastByteTime = t; // Reset counter
}
}

switch(mode) {

case MODE_HEADER:

// In header-seeking mode. Is there enough data to check?
if(bytesBuffered >= HEADERSIZE) {
// Indeed. Check for a 'magic word' match.
for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
if(i == MAGICSIZE) {
// Magic word matches. Now how about the checksum?
hi = buffer[indexOut++];
lo = buffer[indexOut++];
chk = buffer[indexOut++];
if(chk == (hi ^ lo ^ 0x55)) {
// Checksum looks valid. Get 16-bit LED count, add 1
// (# LEDs is always > 0) and multiply by 3 for R,G,B.
bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
bytesBuffered -= 3;
spiFlag = 0; // No data out yet
mode = MODE_HOLD; // Proceed to latch wait mode
} else {
// Checksum didn't match; search resumes after magic word.
indexOut -= 3; // Rewind
}
} // else no header match. Resume at first mismatched byte.
bytesBuffered -= i;
}
break;

case MODE_HOLD:

// Ostensibly "waiting for the latch from the prior frame
// to complete" mode, but may also revert to this mode when
// underrun prevention necessitates a delay.

if((micros() - startTime) < hold) break; // Still holding; keep buffering

// Latch/delay complete. Advance to data-issuing mode...
LED_PORT &= ~LED_PIN; // LED off
mode = MODE_DATA; // ...and fall through (no break):

case MODE_DATA:

while(spiFlag && !(SPSR & _BV(SPIF))); // Wait for prior byte
if(bytesRemaining > 0) {
if(bytesBuffered > 0) {
SPDR = buffer[indexOut++]; // Issue next byte
bytesBuffered--;
bytesRemaining--;
spiFlag = 1;
}
// If serial buffer is threatening to underrun, start
// introducing progressively longer pauses to allow more
// data to arrive (up to a point).
if((bytesBuffered < 32) && (bytesRemaining > bytesBuffered)) {
startTime = micros();
hold = 100 + (32 - bytesBuffered) * 10;
mode = MODE_HOLD;
}
} else {
// End of data -- issue latch:
startTime = micros();
hold = 1000; // Latch duration = 1000 uS
LED_PORT |= LED_PIN; // LED on
mode = MODE_HEADER; // Begin next header search
}
} // end switch
} // end for(;;)
}

void loop()
{
// Not used. See note in setup() function.
}


yours - changes in bold red

#include <FastSPI_LED.h>

//Set the number of leds in the strip.
#define NUM_LEDS 50

// Sometimes chipsets wire in a backwards sort of way
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
// struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

#define PIN 4
void setup(){
Serial.begin(115200);
FastSPI_LED.setLeds(NUM_LEDS);

//Change this to match your led strip
FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
FastSPI_LED.setDataRate(1);

//If non-default SPI pins have been used change this.
FastSPI_LED.setPin(PIN,11,13);

FastSPI_LED.init();
FastSPI_LED.start();
leds = (struct CRGB*)FastSPI_LED.getRGBData();
clearLeds();
}

int readByte(){
while(Serial.available()==0){
FastSPI_LED.stop();
}
FastSPI_LED.start();
return Serial.read();
}

void clearLeds(){
for(int tmpChannel=0; tmpChannel<NUM_LEDS; tmpChannel++){
leds[tmpChannel].r = 0;
leds[tmpChannel].b = 0;
leds[tmpChannel].g = 0;
};
FastSPI_LED.show();
}

void loop(){
if(readByte() == 0xFF){
if(readByte() == 0x00){
if(readByte() == 0x00){
int channels = readByte();
for(int channel=0; channel<channels; channel++){
leds[channel].r = readByte();
leds[channel].b = readByte();
leds[channel].g = readByte();
}
FastSPI_LED.show();
}
}
}
}
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by tmaniac on Tue Apr 24, 2012 7:12 am

i also have an arduino uno with a ws2801 led string of 50 leds.

i have been playing around with this yesterday but my led's are not responding to the atmowina.exe software.

i have loaded the latest fastspi library from the google code source but nothing happens :(

i could really use some pointers. here are the steps i take;

1) Load AtmoDuino.ino with Arduino IDE
2) Edit it for my number of leds, pins (pin 11 and 13) and the correct Chipdriver (ws2801)
3) upload the sketch to the arduino

4) open up the Atmowina.exe application and configure the zones, com-port and number of leds (17 top, 10 left/right, 13 bottom = 50 total)
5) safe everything (hit OK) and restart the atmowin application.

And then.....nothing, nada, zilch :(
tmaniac
 
Posts: 16
Joined: Mon Apr 02, 2012 3:42 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Tue Apr 24, 2012 7:29 am

Code: Select all
And then.....nothing, nada, zilch
sounds similar to me :) so let me add... nichts kai・mu, mog ned.

I really don't know why it is not working, could it be the chip ws2801?
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm

Re: Atmoduino - Ambilight for the masses

by tmaniac on Tue Apr 24, 2012 2:11 pm

i've been playing a bit with the fastspi.

My string IS a ws2801 string.

However, when stating the correct pin and the correct chip i do NOT get any leds.
When changing the driver chip to another 1, it does work.

Now, i started to think my string was not WS2801.
I loaded the ws2801 adafruit library and the test-program works like a charm.

Ho can i change the sketch to use de adafruit spi/ws2801 library?

My guess is that something in the ws2801 fastspi chipset library is not correct.
Unfortunately i'm a total noob in library coding. So if you know how it works...please help! :)
tmaniac
 
Posts: 16
Joined: Mon Apr 02, 2012 3:42 pm

Re: Atmoduino - Ambilight for the masses

by scorpie on Fri Apr 27, 2012 1:04 am

none?
scorpie
 
Posts: 48
Joined: Fri Apr 20, 2012 3:35 pm