Controlling a MegaBrite with shiftOut

Hello everyone!

I’m not sure if this should be here in the Arduino Section, or in with Projects and Product questions, but as I’m attempting this with an Uno, I might as well try here first.

Anyways, I’m trying to write my own code to control a single MegaBrite, as I only have one, and [I don’t understand the example code provided in the documentation at all. I get that the packets are 10 bits per colour, and then two control bits, and I believe I’ve constructed my code properly, but in testing, my code works properly up to around 1/4 to 1/2 power and then behaves very oddly, strobing if I’m trying to fade from 0-1023.

[Here’s a link to a youtube video of the current behaviour while running my code

[Here’s a link to the documentation, with the example code that I don’t understand at all, and the packet structure that I think I’m getting right

And here, finally, is my code:

/*
  Megabrite minus bewildering example code
  I can wrap my head around shiftout.
*/

// Pins
const int clockpin  = 2;  // CI
const int latchpin  = 3;  // LI
const int datapin   = 4;  // DI

void setup()
{
  pinMode(clockpin, OUTPUT);
  pinMode(latchpin, OUTPUT);
  pinMode(datapin, OUTPUT);
  
  sendToMegabrite(0,0,0); // All off.
  
}

void loop()
{
  for (int i = 0; i < 1024; i++)
  {
    sendToMegabrite(i,i,i);
    delay(10);
  }
}

void sendToMegabrite(int red, int green, int blue)
{
  unsigned long dataout = 0; // Packet storage

  // Assemble color packet
  dataout += blue;         // Blue level
  dataout = dataout << 10; // Make room for red
  dataout += red;          // Red level
  dataout = dataout << 10; // Make room for green
  dataout += green;        // Green level
  dataout = dataout << 2;  // Make room for control bits, leave zero!
    
  // Send color packet
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 24); // First byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 16); // Second byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 8);  // Third byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout);       // Fourth byte
  digitalWrite(latchpin, HIGH);
}

I have no idea what I’m doing wrong, and if someone could point me in the right direction, and/or explain what the heck is going on in that example code, it would be greatly appreciated.

Small edit: I’m controlling the enable pin with a physical switch, so I don’t blind myself quite so much when I take off the diffuser I made.](megabrite [macetech documentation])](http://www.youtube.com/watch?v=vh3KtGIuaPU)](megabrite [macetech documentation])

The code takes (3) 10 bit integers (colors b,r,g) and shifts them into a long integer with blue being msb.

It then adds two 0 bits at the end for the control bits (To adjust the pwm color registers)

dataout += blue;         // Blue level
  dataout = dataout << 10; // Make room for red
  dataout += red;          // Red level
  dataout = dataout << 10; // Make room for green
  dataout += green;        // Green level
  dataout = dataout << 2;  // Make room for control bits, leave zero!

It then shifts out the word, breaking the 32 bits into 8 bit packets for ShiftOut

shiftOut(datapin, clockpin, MSBFIRST, dataout >> 24); // First byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 16); // Second byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 8);  // Third byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout);       // Fourth byte

Is that the code you are using that is doing the flickering?

Are you going full power on the current control?

The shift/megabrights flicker at full or close to full current.

coyote20000:
The code takes (3) 10 bit integers (colors b,r,g) and shifts them into a long integer with blue being msb.

It then adds two 0 bits at the end for the control bits (To adjust the pwm color registers)

It then shifts out the word, breaking the 32 bits into 8 bit packets for ShiftOut

Is that the code you are using that is doing the flickering?

Are you going full power on the current control?

The shift/megabrights flicker at full or close to full current.

The code in that post and running in the video is the code that I wrote when I could not decipher the example code provided on the documentation page though the MegaBrite is so bright that the camera can’t pick it up properly. I’ll see about making another video with a much lower exposure setting to see if I can illustrate the fading more.

I’ve tacked the following code onto the end of my sendToMegabrite function, and while the additional code seems to work, it doesn’t fix the problem at all.

  dataout = 0; // Packet storage, again

  // Assemble control packet
  dataout += 50;           // Blue current
  dataout = dataout << 2;
  dataout += B00;           // PWM clock mode, 00 is internal
  dataout = dataout << 1;
  dataout += B0;            // Padding
  dataout = dataout << 7;
  dataout += 50;           // Red current
  dataout = dataout << 3;
  dataout += B000;          // More Padding
  dataout = dataout << 7;
  dataout += 50;           //Green current
  dataout = dataout << 1;
  dataout += B0;            // Yet more padding
  dataout = dataout << 2;
  dataout += B00;           // Internal testing bits
  dataout = dataout << 2;
  dataout += B10;           // Command mode
    
  // Send command packet
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 24); // First byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 16); // Second byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout >> 8);  // Third byte
  shiftOut(datapin, clockpin, MSBFIRST, dataout);       // Fourth byte
  digitalWrite(latchpin, HIGH);

The issue that I’m having, in case it isn’t clear, is that I can only seem to output pwm values up to 256 or so before the megabrite seemingly starts again at zero and ramps up quickly from there eight times before the code gets to 1023 and restarts.

If I set the current registers to almost anything, the megabrite instead changes colours slightly three or four times.

if I set the current registers to zero, the megabrite flashes the green LED seemingly at random, while the red and blue LEDs flicker very dimly.

Maybe this will help…

There are two modes.

PWM adj mode = Color brightness (B00)

Current adj mode = command mode = LED intensity (Current flow) (B10)

The packet looks like this in bits…

GGGGGGGGGGRRRRRRRRRRBBBBBBBBBBMM

(Sorry, I had it wrong in the previous post)

G=Green color (10 bits)

R=Red color (10 bits)

B=Blue color (10 bits)

M=Mode (2 bits)

First off, I see you are trying to adjust the current registers.

For now, don’t worry about the command mode (B10) just use (B00) (default)

(B00) is all you need to make the colors work. Once you understand the colors, the current adjustment will be cake.

Just a run down on how it works. I think you understand it, but just in case…

If you send.

11111111111111111111111111111100 (32 bits)

You will get max white.

Sending…

00000000001111111111000000000000 (32 bits)

You get max red

Being that ShiftOut only works on 8 bits at a time you have to call ShiftOut 4 times to send 32 bits.

The first time, it shifts those 32 bits 24 times to the right and sends whats left. Anything not underlined gets shoved out and dropped.

GGGGGGGGGGRRRRRRRRRRBBBBBBBBBBMM

shiftOut(datapin, clockpin, MSBFIRST, dataout >> 24); // First byte

The next ShiftOut occurrence shifts the same full 32 bits to the right 16 times.

Any bits to the right of the bold get dropped from bit shifting 16 times and the bits to the left of the bold get ignored cause ShiftOut sends only 8 bits.

GGGGGGGGGGRRRRRRRRRRBBBBBBBBBBMM

shiftOut(datapin, clockpin, MSBFIRST, dataout >> 16); // Second byte

You repeat this two more times, except the amount you shift decreases.

GGGGGGGGGGRRRRRRRRRRBBBBBBBBBBMM

shiftOut(datapin, clockpin, MSBFIRST, dataout >> 8 ); // Third byte

Of course the last ShiftOut requires no shifting. It sends only the first 8 bits of that 32 bit packet. The rest is ignored.

GGGGGGGGGGRRRRRRRRRRBBBBBBBBBBMM[/b]
shiftOut(datapin, clockpin, MSBFIRST, dataout); // Fourth byte
Let me know if this helps at all.

Yes, that is exactly what I intended my code to do, and it’s good to see that someone else has independently confirmed that my code is doing what I think that it’s doing, which is exactly what you described.

The example code, [located here in the documentation, which I will also post here, is apparently using some form of arcane magic that I do not understand to send data out to the MegaBrite module.

#define clockpin 13 // CI
#define enablepin 10 // EI
#define latchpin 9 // LI
#define datapin 11 // DI
 
#define NumLEDs 2
 
int LEDChannels[NumLEDs][3] = {0};
int SB_CommandMode;
int SB_RedCommand;
int SB_GreenCommand;
int SB_BlueCommand;
 
void setup() {
 
   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);
 
 
}
 
void SB_SendPacket() {
 
    if (SB_CommandMode == B01) {
     SB_RedCommand = 120;
     SB_GreenCommand = 100;
     SB_BlueCommand = 100;
    }
 
    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)));
 
}
 
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);
 
}
 
void loop() {
 
   LEDChannels[0][0] = 1023;
   LEDChannels[0][1] = 0;
   LEDChannels[0][2] = 0;
 
   LEDChannels[1][0] = 0;
   LEDChannels[1][1] = 0;
   LEDChannels[1][2] = 1023;
 
   WriteLEDArray();
   delay(200);
 
   LEDChannels[0][0] = 0;
   LEDChannels[0][1] = 0;
   LEDChannels[0][2] = 1023;
 
   LEDChannels[1][0] = 1023;
   LEDChannels[1][1] = 0;
   LEDChannels[1][2] = 0;
 
   WriteLEDArray();
   delay(200);
 
 
}

The aforementioned arcane magic is in the SB_SendPacket function of the example code, mainly, I have no idea what SPDR, SPSR or SPSF are, or what they do, aside from it being [apparently] the only way to make the MegaBrite respond properly.](megabrite [macetech documentation])

  1. The example code uses hardware SPI because that’s the fastest way to send the data. I suggest using it if you can. I recommend just copying the relevant sections of code and using the WriteLEDArray function to handle everything…it’s what I do to start every new project.

  2. If you don’t want to use hardware SPI, there is a non-hardware SPI example on the documentation page: http://docs.macetech.com/doku.php/non-h … pi_example

  3. In the video, I don’t see any extra power wires running to the MegaBrite. It will not work using only USB power. The MegaBrite wants more than 5V to operate, and at full power will draw 300mA. It’s a bad idea to draw that from the computer USB port, and it’s a bad idea to draw that from the Arduino power regulator. Both could be permanently damaged.

success (y/n)?

Does anyone know what the full output of this triplet is when driven full RGB? Or of the individual LEDs?

I’d love to see it expressed in lumens, actually, so I can compare with other high brightness LEDs.

It is alternately stated as “each LED” supplying ~35,000 mcd at 120 degrees (equal to 110 lumens for just that arc) and 40,000 mcd over 140 degrees (a whopping 165 lumens for each of the three LEDs!).

I am pretty sure that these figures are not correct.

Alternatively, I could look up the LED manufacturer’s specs on the individual lamps, if someone knows the LED manufacturer and model numbers.