Software PWM using daisy chained 74HC595s / SPI

That is great to know. I am interested in seeing your final project if it is something you can show.

Always nice to see another way to make these LEDs go :slight_smile:

Definitely, a partner and I are working on using an Arduino to control a series of these ICs which are driving 12 high power 3W RGB LEDs mounted in polycarbonate tubes, and a series of RGB strobes in addition. We should have MIDI sync with Ableton Live and full manual control as well. We're trying to get it finished for a music festival in Raleigh next month, I'll be sure to post some videos when it's completed.

So we completed our project in time for its debut at Hopscotch Music Festival, which was Raleigh's first major music festival. We provided the stage lighting for Motor Skills, whose performance was well-received.

I don't have any HD video yet, but here's some taken from an iPhone: - YouTube
Edit - better video in HD: http://vimeo.com/15293908

The system is as described above; a Processing sketch handles MIDI input and generates the pattern data, which is communicated over serial to the Arduino. Using the SoftPWM code we control a custom PCB with 12 of the STP04CM05 ICs and all the other requisite circuit components. These are connected to the light bars via CAT5 cables through a 12-port patch panel. Finally the light bars consist of a high-power 3W RGB LED, some optics, and other various parts for optimum beam spreading and heat management.

This software PWM implementation worked excellently for the job, so thanks again. I probably wouldn't have attempted soft PWM if you hadn't posted this. Using your code on an Arduino with an Atmega328, we were able to get 128 brightness levels per channel before seeing noticeable flicker, which works well except for the lowest brightness levels. I think a resolution of at least 8x higher is necessary for better dimming, logarithmic brightness, and good color mixing at low brightness. I doubt that could ever be squeezed out of the Atmega328, however.

Perhaps you could formalize your code into a library for better accessibility to people getting started? It seems fairly optimized already what with all the bitwise operations.

Thank you very much for letting me know the code helped and for posting your video. Nice work!

I was thinking of using a library when I created the code but was not sure what to put into "library form". Most of my libraries are class based and it seemed to over complicate the implementation / usage to create a class for this operation. Maybe I'll just post the code in the playground so it won't get lost in forum land.

I currently do not use this type of process anymore so I figured I put up the cleaner code before it went into the big box with all my shift registers and raw LEDs. Now that I see it is useful, posting it on the playground is a good idea.

I'll have to re-look at that chip you are using after seeing your results. I may need similar caps to run the SMD strips since the TLCs are giving me a headache.

Thanks again for responding with your results and for posting the video of your nice light show.

Hello,
I am woking on a similar thing and found your code very helpful. The problem i encountered was that Arduino could not do more than a few 595s with 256 levels an decent 90hz refresh rate.

i implemented bit angle modulation and precalculation of the 595 data to save even more time. It uses SPI and Timer3.

All feedback and improvements are wellcome. I think we could make this thing into a library and call it "LED595" or something.

-------------------------PART1------------------------------------

/*
 This code drives leds using daisy chained 595 shiftregisters.
 
 Two different drive methods:
 PWM - just workks with 32 PWM levels, 6 registers and 90 HZ
 BAM - works for lot more with 256 PWM levels
 
 Todo:
 1) Precalculate the data for 595 always when PWM levels are changed. This should speed
 up the interrupt.
 2) Change the interrupt so that it is called only when needed by changing the interrupt time
    on every call. Dunno if this is necessary, the interrupt exists just after a few ifs if nothing
    need to be updated.
    
    Tomas Martinsen 29 Sep 2010
    
  
 Lot of code from:
 Created 22 May 2009
 Created 23 Mar 2010
 by Tom Igoe

*/
#include <SPI.h>
#include <TimerThree.h>


//
// Pins on arduino mega
//
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 53;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 52;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 51;

//
// constants
//
#define PWM_FREQ 100 // hz
#define PWM_STEPS 256 // PWM resolution - set to 256 when using bam
#define BAM_STEPS 8 // how many times BAM updates are done each cycle
#define TICKER_STEP 256/PWM_STEPS
#define NUM_SHIFT_REGS 6  
#define NUM_CHANNELS NUM_SHIFT_REGS*8


//
// Global variables
//
// holds the current pwm values of pins to be sent by interrupt
volatile unsigned char pwmValues[NUM_CHANNELS];
volatile byte bamLookup[BAM_STEPS*NUM_SHIFT_REGS]; // precalculate the bytes to send every time the PWM values change
volatile byte pwmLookup[PWM_STEPS*NUM_SHIFT_REGS];// precalculate the bytes to send to 595 for pwm

/*
  Precalculate the bytes to send for every PWM cycle. Note that this is not fast either!

*/
void precalcPwmBytes() {
  byte bytesToSend[NUM_SHIFT_REGS];
  
  
  for(int ticker = 0;ticker<PWM_STEPS;ticker++){
    //--- get ticker as a 0 to 255 value, so we can always use the same data regardless of actual PWM levels
    byte myPos = ticker * TICKER_STEP;
    // generate one byte per register
    for(byte regNo = 0 ;regNo<NUM_SHIFT_REGS;regNo++) {
      bytesToSend[regNo]  = 0;
      // loop bits of each register
      for(byte ch = 0;ch<8;ch++){
        if(myPos <= pwmValues[regNo*8+ch]) {
          // turn on channel 0-7
          bytesToSend[regNo] |= (1 << ch);
        }
        
      }
      pwmLookup[ticker*NUM_SHIFT_REGS + regNo] = bytesToSend[regNo];
    }
  }
  

}


/*
  Precalculate the bytes to send for each time slice. Call everytime you update or change
  pwmvalues.

*/
void precalcBamBytes() {
  byte bytesToSend[NUM_SHIFT_REGS];
  
  for(int slice=0;slice<BAM_STEPS;slice++) {
    unsigned char sliceMask = (1 << slice);   
    // generate one byte per register
    for(unsigned char regNo = 0 ;regNo<NUM_SHIFT_REGS;regNo++) {
      bytesToSend[regNo]  = 0; 
      // loop bits of each register
      for(unsigned char ch = 0;ch<8;ch++){
        // test if the pwm value has the current slicebit 1
        if( (pwmValues[regNo*8+ch] & sliceMask) == sliceMask) {
          // turn on channel 0-7
          bytesToSend[regNo] |= (1 << ch);
        }
        
      }
      bamLookup[slice*NUM_SHIFT_REGS + regNo] = bytesToSend[regNo];
    }
    
  }

}


// the current data that has last been sent to shift registers
//byte *shiftRegValues;

// interrupt counter
volatile byte ticker = 0;


void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  
  // serial communication to 595s
  SPI.begin(); 
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  
  // Activate the interrupt
  // calculate how many times per sec the ISR ISR is called
  // to get the requested pwm frequency
  Timer3.initialize(1000000/PWM_FREQ/PWM_STEPS); // Timer for updating pwm pins
  Timer3.attachInterrupt(iUpdateBAM3);
  
  // for debugging
  Serial.begin(9600);
  
  //
  // signal the setup is done
  //
  for(int i=0;i<NUM_CHANNELS;i++){
    setChannel(i,255);
    delay(50);
  }
  for(int i=NUM_CHANNELS-1;i>0;i--){
    setChannel(i,0);
    delay(50);
  }
  setAllChannelsTo(0);
  
}


void loop() {
  
  // test dimming
  int from = 0;
  int to = 255;
  int d = 10;
  for(int i = from;i<to;i++) {
    setAllChannelsTo(i);  
    delay(d);
  }
  
}



/*
  Sends a byte array using SPI to 595 shift registers
*/
void sendSPI(volatile byte *valuesToSend, int from, int to) {
  // latch off
  digitalWrite(latchPin, LOW);   
  // send bytes the last register first
  for(int i = to-1; i>=from;i--) {
    SPI.transfer(valuesToSend[i]);
  }
   // latch on
  digitalWrite(latchPin, HIGH);
}


void setAllChannelsTo(byte duty) {
  for(int i = 0;i<NUM_CHANNELS;i++) {
    pwmValues[i] = duty;
  }
  precalcBamBytes();
  //precalcPwmBytes();
}

void setChannel(int ch,byte duty) {
  pwmValues[ch] = duty;
  precalcBamBytes();
  //precalcPwmBytes();
}

/*
 Pulse Width modulation. Pretty slow. The limit is about 6 shift registers, 32 steps and 90hz. Not Good!


*/
void iUpdatePWM() {
  byte valuesTmp[NUM_SHIFT_REGS];
  
  // update ticker and reset if rolls over
  ticker++;
  if(ticker > PWM_STEPS) {
    ticker = 0;
  }
  //--- get ticker as a 0 to 255 value, so we can always use the same data regardless of actual PWM levels
  byte myPos = ticker * TICKER_STEP;
  
  // generate one byte per register
  for(byte regNo = 0 ;regNo<NUM_SHIFT_REGS;regNo++) {
    valuesTmp[regNo]  = 0;
    // loop bits of each register
    for(byte ch = 0;ch<8;ch++){
      if(myPos <= pwmValues[regNo*8+ch]) {
        // turn on channel 0-7
        valuesTmp[regNo] = valuesTmp[regNo] | (1 << ch);
      }
      
    }
  }
  // update registers
  sendSPI(valuesTmp,0,NUM_SHIFT_REGS);

}

/*
 Pulse Width modulation. This one uses precalculated values.
 This one can do 6 registers, 256 levels and 100 hz.

*/
void iUpdatePWM2() {
  byte valuesTmp[NUM_SHIFT_REGS];
  
  // update ticker and reset if rolls over
  ticker++;
  if(ticker > PWM_STEPS) {
    ticker = 0;
  }

  // update registers. The lookup table is recalculated always when setting pwm values.
  sendSPI(pwmLookup,ticker*NUM_SHIFT_REGS,ticker*NUM_SHIFT_REGS + NUM_SHIFT_REGS);

}



/*
  
  Bit Angle modulation. This version has a problem:
  When the slice hits and we do send data, the function takes too long to execute.
  The result is that all ticks are not of equal length and the brightness depends also on
  how many bits are 1. The result is that 7 is brighter than 9 and 15 brighter than 16.
  Not good for dimming!

*/
void iUpdateBAM() {
  byte bytesToSend[NUM_SHIFT_REGS];
  
  // update ticker and reset if rolls over
  ticker++;
  if(ticker > PWM_STEPS) {
    ticker = 0;
  }
  
  // find out timeslice startpoint we are at
  unsigned char slice;
  if(ticker == 0) {
    slice = 0;
  } 
  
  else if(ticker == 1) {
    slice = 1;
  } 
  else if(ticker == 3) {
    slice = 2;
  } 
  else if(ticker == 7) {
    // B3 - 8 long
    slice = 3;
  }
  else if(ticker == 15) {
    //
    slice = 4;
  }
  else if(ticker == 31) {
    // B4 - 16 long
    slice = 5;
  }
  else if(ticker == 63) {
    // B6A - 32 long
    slice = 6;
  }
  else if(ticker == 127) {
    // B7a - 32 long
    slice = 7;
  }
  else {
    // no actions required
    return;
  }
  
  unsigned char sliceMask = (1 << slice);
  
  
  // generate one byte per register
  for(unsigned char regNo = 0 ;regNo<NUM_SHIFT_REGS;regNo++) {
    bytesToSend[regNo]  = 0; 
    // loop bits of each register
    for(unsigned char ch = 0;ch<8;ch++){
      // test if the pwm value has the current slicebit 1
      if( (pwmValues[regNo*8+ch] & sliceMask) == sliceMask) {
        // turn on channel 0-7
        bytesToSend[regNo] |= (1 << ch);
      }
      
    }
  }
  // update registers
  sendSPI(bytesToSend,0,NUM_SHIFT_REGS);
  

}


/*
  
  Bit Angle modulation. Faster version that uses precalculated data for each slice.
  Mighty fast compared to the other version.
  TODO:
  Split slice 6 to 2 parts slice 7 to 4 parts and interleave to avoid flicker.

*/
void iUpdateBAM2() {
  // update ticker and reset if rolls over
  ticker++;
  if(ticker > PWM_STEPS) {
    ticker = 0;
  }
  
  // find out timeslice startpoint we are at
  unsigned char slice;
  if(ticker == 0) {
    slice = 0;
  } 
  else if(ticker == 1) {
    slice = 1;
  } 
  else if(ticker == 3) {
    slice = 2;
  } 
  else if(ticker == 7) {
    // B3 - 8 long
    slice = 3;
  }
  else if(ticker == 15) {
    slice = 4;
  }
  else if(ticker == 31) {
    // B4 - 16 long
    slice = 5;
  }
  else if(ticker == 63) {
    // B6A - 32 long
    slice = 6;
  }
  else if(ticker == 127) {
    // B7B - 32 long
    slice = 7;
  }
  else {
    // no actions required
    return;
  }
  
  // update registers. The lookup table is recalculated always when setting pwm values.
  sendSPI(bamLookup,slice*NUM_SHIFT_REGS,slice*NUM_SHIFT_REGS + NUM_SHIFT_REGS);
  

}

--------------------------- TO BE CONTINUED -------------------------

And the rest of the code:

/*
  
  Bit Angle modulation. Faster version that uses precalculated data for each slice.
  Mighty fast compared to the other version. 
  
  This fersion also divideds
  the bits 6 and 7 to 32 tick slices to smoothen the transitions over 126->127
  

*/
void iUpdateBAM3() {
  // update ticker and reset if rolls over
  ticker++;
  if(ticker > PWM_STEPS) {
    ticker = 0;
  }
  
  // find out timeslice startpoint we are at
  unsigned char slice;
  if(ticker == 0) {
    slice = 0;
  } 
  else if(ticker == 1) {
    slice = 1;
  } 
  else if(ticker == 3) {
    slice = 2;
  } 
  else if(ticker == 7) {
    // B3 - 8 long
    slice = 3;
  }
  else if(ticker == 15) {
    // B5 - 32 long
    slice = 5;
  }
  else if(ticker == 47) {
    // B4 - 16
    slice = 4;
  }
  else if(ticker == 63) {
    // B7A - 32 long
    slice = 7;
  }
  else if(ticker == 95) {
    // B6A - 32 long
    slice = 6;
  }
  else if(ticker == 127) {
    // B7B - 32 long
    slice = 7;
  } else if(ticker == 159) {
    // B6B - 32 long
    slice = 6;
  }else if(ticker == 191) {
    // B7C - 32 long
    slice = 7;
  } else if(ticker == 223) {
    // B7D - 32 long
    slice = 7;
  }
  
  else {
    // no actions required
    return;
  }
  
  // update registers. The lookup table is recalculated always when setting pwm values.
  sendSPI(bamLookup,slice*NUM_SHIFT_REGS,slice*NUM_SHIFT_REGS + NUM_SHIFT_REGS);
  

}

Tomppu, this is great. The speed limitations were the biggest difficulty with the previous version of the code.

I was controlling 30 channels, with their values being updated over serial at about 50hz. So I would still be calling precalcBamBytes() around 1500 times per second. Is it possible to only call precalcBamBytes() once after updating all 30 channels with setChannel()? That would reduce it to about 50 calls per second.

Also, what is the difference between the iUpdateBam 1, 2, and 3 functions? It seems that version 3 is the superior version. Is there any reason to leave the other two in the code, possibly just to provide an example?

Finally, is it possible to increase the PWM resolution above 256 levels? Possibly 1024 levels, or higher? This would make something like brightness calibration with a logarithmic curve (gamma correction) possible.

I will give your code a try, if I don't see any bugs then it will go into production. If you know of or notice any bugs please let us know in this thread, I would also be willing to help finalize the code and make this into a library like ShiftOut so that more people can take advantage of it. That is, after I wrap my head around bit angle manipulation...

Thanks for the compliments :). I did a lot of digging on the internet about Bit Angle Modulation and i found something but nothing ready for Arduino. You had nice working code base where to start experimenting.

The code there is work in progress and i suggest we play with it a bit and then pack it as a library for others to use and improve. A lot of people seem to like driving leds with Arduino.

I even tried the propeller chip that packs a nice punch with 8 cores but found learning the spin language too akward and "specialised" compared to standard c++.

I also tried TLC5940 but they cost money, and cannot drive hight currents so real room lighting is out of question. I got them working and burned quite few of them :D.

The best was to use cheap 595 and try to run them with software. This is also simple and easily understandable. But PWM is too processor intensive. Even BAM took too much processor without the precalculation of the bits.

I also think that there should be at least 256 levels. Otherwise the steps are noticable with low intensities. 10 bits would be nice.

Feel free to try addning more levels, just speed up the interrupt 4 times and count to 1024 and do the same stuff. Should still work.

I also found a working solution for driving the high power leds with 2 resistors, a transistor and a fet. A simple circuit that limits the current for the led. It can handle huge currents, several A, no problem. Only downside is that the fet costs about 0.5-1eur / piece. If somebody could come up with something that does not need the FET.

Then the functions:

1st try: BAM1 without precalculation. My version is too slow, it does not get out of the interrupt fast enough.

2nd try: BAM2 preconstruct the bytes to be sent. Recalculate only when dutys change. Nice but still some flicker when fading. You can find the reason from google.

3rd Try. BAM3 precalculate AND reorder and split the bits 7 and 8 to smaller 32 tick pieces to make transition form say 127 to 128 smoother. Still needs some improvement. Have to think a bit :slight_smile:

4th: PWM2 interrupt works fine but the precalculation is too slow for my taste. About 8000 iterations with 48 channels and 256 levels. Optimise?

TODO:
-get rid of the flicker in BAM3 when fading.

-Maybe optimise the precaculation loops. Ideas?

-include a gammacorrection lookup table the make fades smooth.

-improve the interrupt in BAM so that the interrupt is not entered regularly but only when needeed. I think though that it gets out of there fast enought when nothing needs to be done.

-some animation and pattern stuff
--frame playing
--timed transitions

Just keep your ideas coming and i'll keep mine :smiley:

Happy hacking!

And sure the precalculation can be optimised. So that it is only done when you have set all the new channel values you are going to set at one time.

Idea:
make so that you call many setChannels functions and whatever and AFTER you are ready. Call a function that does the precalculation only once.

Post back if get working code!

Sorry for multiple posts. Here are some usefull links:

How to make a current limiting circuit I mentionded earlier. Tested and works!

Cheapest 3w RGB leds you can find:
http://www.dealextreme.com/details.dx/sku.4530

Nice stuff about BAM:

Other problems:
How an earth to get a tight beam from a rgb led with good color mixing. Lenses show the colors separate. Maybe a reflector with a bit wider base? Dunno....

@Tomppu - nice updates - thanks for contributing improvements.

Honestly, I think it's easier and nearly as cheap to drive power LEDs with dedicated ICs. There are many out there on the market, like the STP04CM05 I mentioned earlier. I got those for $2.20 a pop from Mouser. There are also single-channel drivers with PWM input that you can run from the TI PWM chips like the TLC5940, which you can combine for hardware PWM control (3000+ levels). I like the STP04CM05 with software PWM because it minimizes the PCB size and BOM.

If you are using the TLC5940, you don't want to drive LEDs directly with it, but instead control a constant-current IC or a transistor (you may find a hex inverter IC useful in that case since 'on' is LOW on the TLC).

I'm actually using the DealExtreme LEDs in our projects. They have good consistency and you can't beat the price. The are very sensitive to overcurrent situations though.

As far as beam concentration, I recommend a reflector over a lens for most uses. As you have found, the collimating lenses essentially project a huge image of the LED pads onto your target surface. Personally, I like the SO27XA reflector but I'm not sure about it's availability outside of the States. A diffusing material can help as well; frosted window film is cheap and works quite nicely.

Tomppu, the thread you linked to actually contains the explanation and the solution to the flickering problem you encountered. Start at this post to see what I mean. The solution is to output the BAM waveform followed by a mirror image of it.

I don't have time to modify the code right now, but I might later this week. If you can get a working version using MIBAM (mirror image bit-angle modulation) I would be glad to test it!

Edit: There is a dedicated MIBAM thread here. After reading through, on the Atmega328 at 16MHz, I think it is possible to drive 64 channels at 120Hz with 11-bit resolution (2048 levels). At 10-bits you could drive 128 channels, etc. Then again that is based on assembly performance so I'm not sure what the difference would be using the Arduino IDE. But it's encouraging!

I saw the mirror thing and I tried it but it did not seem to solve the problem. And is a bit the same thing done differently. The problem are the "long" bits 6, 7 and anything that splits them to pieces (mirror = each of the bits in two time slices.

Assembly would help but at least for me it makes the code slow to write and difficult to understand so I try to avoid it.

I am building a mood/disco light with 16 RGB=48 channels and the BAM seems to solve that.

Lets keep the thread open and post when ever new links or info comes or somebody gets new code working!

@PostOfficeBuddy - thanks for your input.

STP04CM05 seems like a smart choice if you combine with sofware PWM/BAM. The current range of <400ma seems to fit many high power rgb leds. Digikey was $2.5 apiece and you need one per led.

The TLC5940 is not really that useful - $4,5 for hardware PWM and 16 channels, but it does not help driving the leds due to power constraints. 120ma per channel but not at all once.

I kind of liked the software + shift registers due to the cheap price and part availability for hobbyists. But this does not yet drive the leds and still needs a transistor / FET circuit.

Can somebody figure out how to make a working current limiting circuit with cheap PNPs that can handle <400ma. That would make a simple cheap driving system.

A lot of different choices as we can see and not one single best way to do things.

Part count and pcb area is also one constraint / design driver.

What we would like is probably the cheapest, easiest to build, easiest to control led driver solution for 10-100 leds.

Right, with the TCL5940 you still need power handling. It's only good for hardware PWM. The simplest true constant-current circuits (without an IC) that I've found are these:

But like I said there are many suitable ICs for the task that are not that expensive. Linear drivers are less efficient but reduce the board space and necessary components. You just have to pay more attention to heat and voltage requirements. Switching drivers have a larger BOM but are much more efficient and flexible.

The STP04CM05 is a linear regulator and you actually don't need one per LED. You need 3 per 4 LEDs. :slight_smile: Since they have 4 channels a piece. The only hardware I've had to use in addition was a simple PI (L/C) filter and a heavy-duty 25A protection diode which also lowers my 5V supply down to 3.55V. That has a large heatsink.

Also try Mouser for the driver ICs like STP04CM05, I've found they are significantly cheaper there.

Mr PostOfficeBuddy. Thank you for your input. After sleeping over it would like to make a summary of what I have learned about driving leds with Arduino:

I think your idea of using the 400+mA 4 ch http://fi.mouser.com/Search/Refine.aspx?Keyword=STP04CM05 is the the best compromise in all respects if you want to make led room lighting with many channels. Want more light? put the leds in series (no common anode/cathode RGB leds then). Needs soft PWM/BAM, interrupts etc.

For something really huge (10-50A!) the 595 shift register mosfet solution might be the way to go. The mosfet FQP50N06L is $1 per channel so the price is really there. Not too bad, but that results in quite a big board if you go through hole. With surface mount components/board it would work ok. Needs soft PWM/BAM, interrupts etc. The current is defined by a 0.5-X Ohm resistor and you need one per channel so you cannot easily alter the current.

Dont like software PWM/BAM? Use TLC5940/TLC5947/MAX stuff, really easy to use with Arduino. Use the FET circuit we talked about for driving or if you do not have that many channels constant current sources might work for you and still keep your budget.

You like led cubes and matrices (low power stuff)? The Lightuino 3.0 Arduino Led driver with 70 sinks and 16 sources will drive your 1000+ leds and if you need more you can stack them. http://makersmarket.com/products/lightuino-led-driver-30-superstackable. Out of stock but they just sent me one for $60 or so. Just connect the leds and you are ready to go.

How to power everything? For low power and/or high voltage (=some leds in series) normal 9-24V power sources are cheap enough and give you enough current.

For low voltage (=5V) and high power you can use FlexATX computer power supplies like HEC-120SA-7FX that are small and cheap and will give you a lot of regulated current with 5V and 12V.

Please correct me if I am wrong or you get new ideas!

Best Regards,

Tomas

ps PostOfficeBuddy - it would be nice to learn more about your (and other's) projects as I can see you have spent a lot of time working with these things.

ps2 One more thought about power losses. People seem to pay a lot of attention to power losses when driving these led things. I think this is illogical as long as we are not doing office lighting or 1000 street lights. I have maybe 500W of light bulbs lighting the house so 10+W of heat from my led mood lights is not really a problem or is it :slight_smile: And I do not even want to think about the new graphic cards for gamers.

One more nice link. 38 a page document from ST micro.

"Generating multicolor light using RGB LEDs" (using a microcontroller, soft PWM and STP04CM05 4 channel driver)

http://www.st.com/stonline/books/pdf/docs/13431.pdf

Hello. Marklar, Tomppu thanks for a good sources.
I try to adapt your code for LED cube 3x3x3. In the code there are comments about the multiplex, I need this, but I do not understand how to do it correctly. Layers of the cube (cathodes) must be LOW for small intervals of time, but so that the PWM continued to work.As I understand it, it is necessary for the time TIMER_DELAY run through all layers and turn they to LOW then HIGH.
Please, tell me how to include it in your code right. Maybe the second timer?

And yet, once I started to ask))) I want to do frame animation with array with the LEDs status for each layer or column, like this:
array [x] [x] {
{B01110000, b00001111},
{}
}:
Can you advise how best to use your code for this?