Go Down

Topic: ShiftPWM support topic. Latest update: Schematics, high power LED's, LED strips (Read 84 times) previous topic - next topic

dutchboy

Hi elcojacob,

Great work on the library, and i'm hoping you may be able to help with what i think might be a small problem but I dont know.

Now bare in mind I don't have a great deal of knowledge but I am using the code below which utilizes a code i have been using for "boblight"  for my diy ambilight and tried to integrated (mash up in my case lolol) shiftPWM.

To my surprise (i don't have a lot of faith in my abilities! lol) this actually works quite well with the one exception that the fade time between colours is a little slow when using 'ShiftPWM.SetOne' over 'analogWrite'.

Am i missing a setting in shiftPWM to make the fade faster???

I've actually got four channels from boblight working, Top, Bottom, Left and Right, so the only thing missing is speeding up the fade.

Thanks for your time.

My Code:
Code: [Select]
#include <SPI.h>
const int ShiftPWM_latchPin=8;
const bool ShiftPWM_invertOutputs = 0;
#include <ShiftPWM.h>

#define checkByte1 0x55
#define checkByte2 0xAA

#define channelCount 6
unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
int numRegisters = 1;
word channels[channelCount];
int channelPins[channelCount] = {0, 1, 2, 3, 4, 5}; // ShiftPWM pins to control LEDs (2x Common Cathode RGB's)

void setup() {
  pinMode(ShiftPWM_latchPin, OUTPUT); 
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV4);
  SPI.begin();
  Serial.begin(9600); // open serial
  ShiftPWM.SetAmountOfRegisters(numRegisters);
  ShiftPWM.Start(pwmFrequency,maxBrightness);

  for (int i =0; i<channelCount; i++)
  {
    channels[i] = 0;
    pinMode(channelPins[i], OUTPUT);
  }
  setLight();
}

void loop()
{
  pollSerialPort();             
}

void setLight() {
  word val;
  byte high, low;
  for (int i=0; i<channelCount; i++)
  {
    val  = channels[i];
    high = val >> 8;
    low  = val & 0xFF;
    ShiftPWM.SetOne(channelPins[i], high);
  } 
}

void pollSerialPort() {
  int data;
  if (Serial.available() >= 4) {
    data = Serial.read();
    echo(data);
    if (data == checkByte1) {
      data = Serial.read();
      echo(data);
      if (data == checkByte2) {
        data = Serial.read();
        if (data < 127)
          readChannels(data);
        else
          readCommand(data);
        return;
      }
    }
  }
}
void echo(int data) {
}

void readChannels(int startChannel) {
  int numChannels = Serial.read();
  while (Serial.available() < numChannels * 2)
    delay(10);
  byte high, low;
  word val;
  for (int i = 0; i < numChannels; i++)
  {
    high = Serial.read();
    low  = Serial.read();
    val  = word(high, low);

    if (startChannel+i < channelCount)
      channels[startChannel+i] = val;
  }
  setLight();                                   
}

void readCommand(int command) {
  int numBytes = Serial.read();
 
  if (command == 0x81)
  {
    requestValues();
  }
  else if (command == 0x83)
  {
    setLight();                                   
  }
  else if (command == 0x84)
  {
    for (int i =0; i<channelCount; i++) {
      channels[i] = 0;
    }
    setLight();                                   
  }
}

void requestValues()
{
    int startChannel = Serial.read();
    int numChannels =  Serial.read();   
    Serial.print(checkByte1, BYTE);
    Serial.print(checkByte2, BYTE);
   
    if (startChannel >= channelCount || numChannels <=0)
    {
      Serial.print(0, BYTE);
      Serial.print(0, BYTE);
    }
    else
    {
      numChannels = min(channelCount - startChannel, numChannels);
      Serial.print(startChannel, BYTE);
      Serial.print(numChannels, BYTE);
     
      byte high, low;
      word val;
      for (int i=startChannel; i< startChannel + numChannels; i++)
      {
         val = channels[i];
high = val >> 8;
         low  = val & 0xFF;
         Serial.print(high, BYTE);
         Serial.print(low, BYTE);
      }
   }
}





raymac

First, thanks for the great library.  I'm gearing up to do some RGB matrix stuff and have demo'd up your code on a RGB led matrix.  Here's some pics.  This one is a common cathode and a weird pinout (only $11 from http://www.futurlec.com/LEDMatrix.shtml).  I'll post more as I move forward.  I plan on testing the shift matrix code eventually too.


Hardware setup:
Duemilanove, 3x595's, RGB matrix, resistors


Too bright!


All rows hooked up, it just repeats what was on the first row.  Note the difference in colors across the rows, i'm guessing this is because i need to give this a dedicated 5v instead of just off the arduino rail.

ematson5897

Thanks for the library. I am testing on a 16x32 matrix (eight red 8x8s) with a Duemilanove and 6 595s

xforce30164


Do you have a 16x16 RGB matrix? I am very curious how that will look.


Hey Elco,
I'm actually trying to get this to work with my 16x16 rgb matrix (consisting of 4 8x8 submodules). however i've wired the shift registers in a different way. I made one long chain of 8 shift registers with just the three lines (data, latch and clock) going to the arduino.
The order of the shift registers is like this:
Code: [Select]

[arduino]---[v+ 1-8 (row)]---[+ 9-16]---[r 1-8 (cols)]---[r 9-16]---[g 1-8]---[g 9-16]---[b 1-8]---[b 9-16]


I already started on writing my own code to try and adress the matrix until i came across this post in your thread and i thought i want to try that one, seems so much more simple!

What would be the easiest way to get your library to work, what do i need to change to get the data to the correct registers.

Thanks in advance!

ps. In the meantime ill try to get it working by myself but your help is greatly appreciated :).

milamber

Quote
What would be the easiest way to get your library to work, what do i need to change to get the data to the correct registers.
The ShiftMatrixPWM code doesn't work on just one chain of shift registers and the normal ShiftPWM code would need to be rewritten to do the timings required for using only one chain to drive a full matrix. Also it would mean updating SR's that don't need to be updated every PWM cycle.

The following is how I understand it and please correct me if I am wrong.

For example an 8x8 matrix. 8 columns and 8 rows. As one chain it would be 2 SR's chained, 1 controlling the rows and 1 controlling the columns(or however you want). To do 16 level PWM the chain would have to be update 16 times per row which means that your updating 8 of the bits 15 times more that you need to and having to send an extra 8 bits every time. So an extra 8 bits x 15 times x 8 rows and that is only 1 full scan of the matrix, this would then be performed at 50+ HZ. This adds up to alot of extra data that really doesn't have to be shifted and scales up as the matrix gets bigger.

But with 2 seperate chains the way Elco made his code. Using the example above, the Row chain gets updated once to say which row is active. Then the Column chain does its 16 passes to accomplish PWM. The Row chain gets updated and selects the next row. The Column chain does the next lot of PWM passes. Even though the Row chain is being updated using a slower method (not SPI) it still saves time.

To help I have made a Fritzing Diagram of the setup I am using for my 16x16 RGB breadboard test. This is in my ShiftMatrixPWM thread.
http://arduino.cc/forum/index.php/topic,72474.msg599648.html#msg599648

I'm not the creator of this code only a happy user :). The ShiftPWM could probably be altered to accomadate what you want but I don't know what would need to be changed. I am just putting forward how to use the library as is.

Elco, would this be a big change?

xforce30164

Hey Milamber,
Thanks for the reply, even though as you already pointed out youre not the creator of the code.
However whem im reading this i think it will be way easier to split the row registers from the collum registers. (thats then a chain of 2 and a chain of 6). I was thinking originaly about having a multiplexer switch between the four groups of two shift registers each but i abandoned that idea a bit earlier. However after reading this that maybe could be a better idea, and maybe keeping the latch signal controlled seperately for each of the 4 registers. this would mean i need 8 pins instead of six if i made two chains, but it would also mean i only need 8 pins instead of twelve if i made 4 chains of two shift registers.

Elco, what do you think would be the easiest?

patrick88

Hi elco and others,

sorry about posting to the blog, I did'nt know about the support thread.

Ok so I have a problem using more than 7 registers and passing data on the fly trough serial. You can see a video of the thing working with 7 SR here: http://vimeo.com/33354111

When I take the serial option out I can go way over 7 SR but with the serial option I get very weird behavior from 8 and up. Including the servo.h didn't change anything.

Have anyone had this problem ? Where do I go wrong ? (see code below)

Also, there are concepts about the timer library that I still don't get, anyone knows a tutorial that "really takes you by the hand" on this ?

Thanks,

here is my arduino code:

//#include <Servo.h>
#include <SPI.h>
#include <Messenger.h>


//Data pin is MOSI (atmega168/328: pin 11. Mega: 51)
//Clock pin is SCK (atmega168/328: pin 13. Mega: 52)
const int ShiftPWM_latchPin=8;
const bool ShiftPWM_invertOutputs = 0;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!
unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
int numRegisters = 7;
Messenger message = Messenger();
int r = 0;


// Define messenger function
void messageCompleted() {
      int pin = message.readInt();
      int value = message.readInt();
      ShiftPWM.SetOne(pin, value);
  }


void setup()   {               
  pinMode(ShiftPWM_latchPin, OUTPUT); 
  SPI.setBitOrder(LSBFIRST);
  // SPI_CLOCK_DIV2 is only a tiny bit faster in sending out the last byte.
  // SPI transfer and calculations overlap for the other bytes.
  SPI.setClockDivider(SPI_CLOCK_DIV4);
  SPI.begin();

  Serial.begin(115200);


  ShiftPWM.SetAmountOfRegisters(numRegisters);
  ShiftPWM.Start(pwmFrequency,maxBrightness); 
  ShiftPWM.SetAll(r);
//  ShiftPWM.PrintInterruptLoad();
message.attach(messageCompleted);
}


void loop() {
  while ( Serial.available( ) ) message.process(Serial.read( ) );
}

Senso

Because the Serial receives data using interrupts, interrupts that are interrupting the function that is sending data to the shift-register.

patrick88

ok, so if I understand, serial uses interrupts which "pauses" the process that talks to the SR and somehow this is not a problem with only 7 SR. But with 8 SR and more it gets serious enough to make the thing work like crap.

Question: Is there a way to speak to the arduino without interrupting ? Or better, is there a solution for this, like "pausing" what I send to the SR without them going crazy?

thanks,
p

milamber

Hello patrick88,

Your project looks really cool. I hope you can get your issues cleared up. I haven't seen the Messenger Library before but I have a feeling that using this on an interrupt is slowing things down. As there are function calls and returns that introduce delays.

I am not sure what sort of data stream you are sending to the arduino but in a project I am doing with a big LED matrix, I am sending 768 byte values to the arduino 15 times a second. I am not using 0-255 levels however, I am only using 0-31 but they are still being sent as each value is one byte. I am simply using a start byte (a number above 31) then directly filling the PWM array used by ShiftPWM with the frame data. I have been able to get a high amount of through put using this method. I am not sure if this information can help in your project.

Integrating Serial and interrupts seems to be a bit tricky. I found that keeping the routine for using the serial data short helped alot.

patrick88

Hi milamber,

thanks for the tips. I actually found what the problem was. It was coming from the supercollider side of things where I was using the arduino quarks. Somehow, when using the arduino quarks, I get stuck to 7 SR but if I use the Serial Class then everything works smoothly. I have tested with 12 SR so far and I'm still counting.

thanks everyone and special thanks to Elco for this library this is amazing work.

p

bebo

Damn nice work on this library...just one question.   I'm running Arduino 1.0 on an Uno, using common anode LEDs.  The rainbow function looks beautiful, but when I try the oneByOneFast or Slow function, all the lights come on at once and then fade out and in one at a time.  In the video you have on the blog it looks like they are all supposed to start dark and fade in and out one at a time, not the other way around.  Is this the expected behavior??
bird denigration is a crime

ld3300

bebo, try changing the ShiftPWM_invertOutputs variable.

ematson5897

I'm running the library on a Duemilenove with an 8x8 rgb matrix. Everything works fine except the first rainbow function and the set all function. The set all function just sets the top row red leds, and the rainbow function seems to be having issues with blues.


Any help is appreciated,

ematson5897

elcojacobs

If you post a schematic of what you have built I can take a look. With only this info, I don't have much to go on

Go Up