Go Down

Topic: Amblone running via TLC5940 (Read 838 times) previous topic - next topic

dtokez

Hi all, I'm looking to make a diy Ambilight system using the www.amblone.com method.

Looking at the code, it looks like it would be straightforward enough to write to TLC outputs instead of digital pins, that way I could just use a 328p and run the 4 RGB channels on the 16 channel TLC.

The code must be scaled for analog write 256 right? I would imagine it look like jumpy if I simply scaled it up to 4096 for the TLC?

Is there a way for the software to be modified to 4096 scaling?

Code: [Select]
// Amblone code for the Arduino Mega
// Author: Bart van der Drift

// License:
// Anyone is free to change, redistribute or copy parts of this code
// as long as it is not for commercial purposes
// Please be so kind to pay credit where due

//---------------------------------------------------------------------------
//---------------------------------- DEFINES --------------------------------
//---------------------------------------------------------------------------

// Flags for the USB communication protocol
#define C_SF1 0xF1 // Startflag for 1-channel mode (1 RGB channel)
#define C_SF2 0xF2 // Startflag for 2-channel mode (2 RGB channels)
#define C_SF3 0xF3 // Startflag for 3-channel mode (3 RGB channels)
#define C_SF4 0xF4 // Startflag for 4-channel mode (4 RGB channels)
#define C_END 0x33 // End flag
#define C_ESC 0x99 // Escape character

// States for receiving the information, see the flow chart for more info
#define S_WAIT_FOR_SF  0
#define S_RECV_RGB     1
#define S_RECV_RGB_ESC 2

//---------------------------------------------------------------------------
//--------------------------- FUNCTION DECLARATIONS -------------------------
//---------------------------------------------------------------------------

// Receives bytes and returns true if a valid packet was received
boolean PacketReceived();

// Uses the rgb values to set the PWMs
void SetPWMs();

//---------------------------------------------------------------------------
//--------------------------- VARIABLE DECLARATIONS -------------------------
//---------------------------------------------------------------------------

int pulse = 0;

// State we are in: one of the S_* defines
int State = 0;
// The payload of a received message
int Payload[32];
// The amount of RGB values we have received
int ByteCount = 0;
// The character we received
int Recv;

// The amount of RGB channels we are using
int ChannelMode;

// PWM pins for channel 1
int r1_pin = 2;
int g1_pin = 3;
int b1_pin = 4;

// PWM pins for channel 2
int r2_pin = 5;
int g2_pin = 6;
int b2_pin = 7;

// PWM pins for channel 3
int r3_pin = 8;
int g3_pin = 9;
int b3_pin = 10;

// PWM pins for channel 4
int r4_pin = 11;
int g4_pin = 12;
int b4_pin = 13;

//---------------------------------------------------------------------------
//----------------------------- IMPLEMENTATIONS -----------------------------
//---------------------------------------------------------------------------

void setup()   {                
 // initialize the serial communication
 Serial.begin(256000); // opens serial port, sets data rate to 256000 bps
 
 TCCR0B = TCCR0B & 0b11111000 | 0x2;
 TCCR1B = TCCR0B & 0b11111000 | 0x2;
 TCCR2B = TCCR0B & 0b11111000 | 0x2;
 TCCR3B = TCCR0B & 0b11111000 | 0x2;
 TCCR4B = TCCR0B & 0b11111000 | 0x2;
 
 State = S_WAIT_FOR_SF;
}
//---------------------------------------------------------------------------

void loop()                    
{
 if (Serial.available() > 0) {
   if (PacketReceived()) {
     SetPWMs();
   }
 }
}
//---------------------------------------------------------------------------

boolean PacketReceived() {
 Recv = Serial.read();
 
 switch (State) {
   case S_WAIT_FOR_SF:
     // =============================== Wait for start flag state
     switch (Recv) {
       case C_SF1:
         // Start flag for 1-channel mode
         ChannelMode = 1;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_SF2:
         // Start flag for 2-channel mode
         ChannelMode = 2;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case 243://C_SF3:
         // Start flag for 3-channel mode
         ChannelMode = 3;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_SF4:
         // Start flag for 4-channel mode
         ChannelMode = 4;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       default:
         // No action for all other characters
         return false;
     }
     break;
   case S_RECV_RGB:
     // =============================== RGB Data reception state
     switch (Recv) {
       case C_SF1:
         // Start flag for 1-channel mode
         ChannelMode = 1;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_SF2:
         // Start flag for 2-channel mode
         ChannelMode = 2;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_SF3:
         // Start flag for 3-channel mode
         ChannelMode = 3;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_SF4:
         // Start flag for 4-channel mode
         ChannelMode = 4;
         State = S_RECV_RGB;
         ByteCount = 0;
         return false;
       case C_END:
         // End Flag
         // For each channel, we should have received 3 values. If so, we have received a valid packet
         if (ByteCount == ChannelMode * 3) {
           State = S_WAIT_FOR_SF;
           ByteCount = 0;
           return true; // <------------------------ TRUE IS RETURNED
         }
         else {
           // Something's gone wrong: restart
           State = S_WAIT_FOR_SF;
           ByteCount = 0;
           return false;
         }
       case C_ESC:
         // Escape character
         State = S_RECV_RGB_ESC;
         return false;
       default:
         // The character received wasn't a flag, so store it as an RGB value        
         Payload[ByteCount] = Recv;
         ByteCount++;
         return false;
     }
     case S_RECV_RGB_ESC:
       // =============================== RGB Escaped data reception state
       // Store the value in the payload, no matter what it is
       Payload[ByteCount] = Recv;
       ByteCount++;
       State = S_RECV_RGB;
       return false;
 }
 
 return false;
}
//---------------------------------------------------------------------------

void SetPWMs() {
 // Channel 1
 analogWrite(r1_pin, Payload[0]);
 analogWrite(g1_pin, Payload[1]);
 analogWrite(b1_pin, Payload[2]);
 
 // Channel 2
 if (ChannelMode > 1) {
   analogWrite(r2_pin, Payload[3]);
   analogWrite(g2_pin, Payload[4]);
   analogWrite(b2_pin, Payload[5]);
 }
 else {
   // turn the rest to 0 (black)
   analogWrite(r2_pin, 0);
   analogWrite(g2_pin, 0);
   analogWrite(b2_pin, 0);
   
   analogWrite(r3_pin, 0);
   analogWrite(g3_pin, 0);
   analogWrite(b3_pin, 0);
   
   analogWrite(r4_pin, 0);
   analogWrite(g4_pin, 0);
   analogWrite(b4_pin, 0);
 }

 // Channel 3
 if (ChannelMode > 2) {
   analogWrite(r3_pin, Payload[6]);
   analogWrite(g3_pin, Payload[7]);
   analogWrite(b3_pin, Payload[8]);
 }
 else {
   // turn the rest to 0 (black)
   analogWrite(r3_pin, 0);
   analogWrite(g3_pin, 0);
   analogWrite(b3_pin, 0);
   
   analogWrite(r4_pin, 0);
   analogWrite(g4_pin, 0);
   analogWrite(b4_pin, 0);
 }
 
 // Channel 4
 if (ChannelMode > 3) {
   analogWrite(r4_pin, Payload[9]);
   analogWrite(g4_pin, Payload[10]);
   analogWrite(b4_pin, Payload[11]);
 }
 else {
   // turn the rest to 0 (black)
   analogWrite(r4_pin, 0);
   analogWrite(g4_pin, 0);
   analogWrite(b4_pin, 0);
 }
}
//---------------------------------------------------------------------------

James C4S

You wouldn't use analogWrite() with a TLC5940.  You communicate with the TLC5940 over SPI (or bit banging).  It is a serial-in chip / pwm-out.

I would suggest one of the TLC5940 libraries as it makes communicating and programming it significantly easier.
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

poeticoddity

http://playground.arduino.cc/learning/TLC5940

This library makes using a TLC5940 pretty easy.
When your adjustments are on a 12-bit scale for the TLC5940 instead of an 8-bit scale from the Arduino PWM, the transitions actually look less jumpy because there are 16 times as many discrete values to transition between.

dtokez

Thanks all. I have used the TLC's before but just not sure about the up-scaling issue. I what would be the best way to do it, TLC.Write(r1_pin, (Payload[0] *4)); or using a map function?


James C4S

Simple multiplication going to be fast than the Arduino map() which does (in this case) an unnecessary division.

Code: [Select]

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

dtokez

Thanks James.

Where is the 8 bit scale being generated from? I guess it is from the PC software that talks via serial to the arduino?

Just wondering if it would be possible to change to 12 bit for the TLC?

James C4S

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

poeticoddity

If you can avoid having to multiply your 8-bit values and use 12-bit values directly, you'll probably get nicer looking results.

If you have to translate 8-bit values into 12-bit values, you should be able to bit-shift them (by 4) instead of multiplying them, which is faster if I'm not mistaken.

dtokez

Thats what I'm wondering at the moment, where are the 8 bit values being generated? I cant see anything in the arduino code, so I guess the windows software must be generating them and simply passing them on to the arduino?

Not sure what you mean by bit shifting by 4?

Thanks!

James C4S


I cant see anything in the arduino code

The code receives a series of packets from serial that contains values which are set with analogWrite().

Code: [Select]

void SetPWMs() {
  // Channel 1
  analogWrite(r1_pin, Payload[0]);
  analogWrite(g1_pin, Payload[1]);
  analogWrite(b1_pin, Payload[2]);
 



Not sure what you mean by bit shifting by 4?

http://arduino.cc/en/Reference/Bitshift

Bit shifting once to the left is the same as multiplying a value by 2.
For example:
The decimal number 3 in binary is 0011.  If you bit shift once to the left the binary value becomes 0110 which is decimal 6.
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

Go Up