Pages: [1] 2 3 ... 20   Go Down
Author Topic: ShiftPWM support topic. Latest update: Schematics, high power LED's, LED strips  (Read 65705 times)
0 Members and 1 Guest are viewing this topic.
Eindhoven
Offline Offline
Jr. Member
**
Karma: 1
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Update August 9 2012:
I finally had the time to completely rewrite the documentation. You can now find schematics for normal RGB LED's, LED strips and high power LED's on www.elcojacobs.com/shiftpwm.

I also updated the library to include load balancing and made the initialization much cleaner. Switching between SPI and no-SPI has become a lot easier. And I added Arduino Leonardo compatibility.

Old stuff:

Update May 9 2012:
Support for NOT using the SPI pin. 2.5x slower, but the freedom to use your SPI port for something else.
Download here: https://github.com/elcojacobs/ShiftPWM/downloads
Extract files to libraries/ShiftPWM/ and open one of the examples.

Update May 8 2012:
Led setup flexibility: http://arduino.cc/forum/index.php/topic,66988.msg786810.html#msg786810

Based on some great suggestions that I got in this thread I have updated ShiftPWM to use the SPI bus.
That took down the number of clock cycles per shift register from 108 to 43.

I have created a page for ShiftPWM on my website www.elcojacobs.com/shiftpwm where you can find more info and download the newest version.

Even Older stuff:

First some pictures to get your attention:



I study Electrical Engineering, but have a job for 8 hours a week at the Electronics Atelier of the Industrial Design department of the Technical University of Eindhoven. My job is to help the ID students with the electronics in their projects. A request I often get is to control many, many LED's. TLC5940 were often used, but they are very expensive compared to shift registers (74HC595).

For shift registers you have to write the PWM code in software and drive the control lines of the registers fast enough.
Especially doing it fast enough is difficult, but I think I have reached the optimum at 13 clock cycles (worst case) to update each pin. This drives the clock line of the registers at 1.33 MHz.
The interrupt function is optimized to be as fast as possible, but the other functions to set duty cycles and configure the library are as easy to use as possible.

I put the library in a class as much as possible without slowing down the code too much. There are many tricks needed to make the library easy to use and configurable, but still as fast as possible. I have written a lot of commentary in the source files to explain these tricks, but I might write a blog post on writing fast Arduino code if there is much demand.

Features of the library:
- Control the duty cycle of many PWM outputs in a single shift register chain.
- Easily configure frequency, number of registers and number of brightness levels.
- Outputs can be inverted for common anode RGB LED's
- Function to print information on timer settings and interrupt load
- Switches to timer2 if timer1 is in use by the servo library
- Checks for input to functions that is out of range and prints error messages to the serial port
- Can be placed in the libraries directory of Arduino
- Includes an example (see video) which can be accessed by file->examples
- Example includes HSV to RGB function for easy color shifting with RGB LED's.

- The load of the interrupt function on your program can be calculated as follows:
 * L = Interrupt frequency * interrupt duration / clock frequency
 * L = F*(Bmax+1)*(96+108*N)/F_CPU
 * Quick reference for load:
 * 3 registers  255 maxBrightness 75Hz  load = 0.50
 * 6 registers  100 maxBrightness 75Hz  load = 0.35
 * 24 registers  50 maxBrightness 75Hz  load = 0.64
 * 48 registers  32 maxBrightness 75Hz  load = 0.81
 * 96 registers  16 maxBrightness 75Hz  load = 0.83


Functions:
 * ShiftPWM.Start(int ledFrequency, int max_Brightness)      Enable ShiftPWM with desired frequency and brightness levels
 * ShiftPWM.SetAmountOfRegisters(int newAmount)         Set or change the amount of output registers. Can be changed at runtime.
 * ShiftPWM.PrintInterruptLoad()            Print information on timer usage, frequencies and interrupt load
 * ShiftPWM.OneByOne()                      Fade in and fade out all outputs slowly
 * ShiftPWM.OneByOneFast()               Fade in and fade out all outputs fast
 * ShiftPWM.SetOne(int pin, unsigned char value)      Set the duty cycle of one output
 * ShiftPWM.SetAll(unsigned char value)            Set all outputs to the same duty cycle
 
 * ShiftPWM.SetGroupOf2(int group, unsigned char v0, unsigned char v1);
   ShiftPWM.SetGroupOf3(int group, unsigned char v0, unsigned char v1, unsigned char v2);
   ShiftPWM.SetGroupOf4(int group, unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3);
   ShiftPWM.SetGroupOf5(int group, unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3, unsigned char v4);
        --> Set a group of outputs to the given values. SetGroupOf3 is useful for RGB LED's. Each LED will be a group.

** Very technical stuff alert **
I have optimized the C code to compile to the most efficient instructions available. The interrupt function loops over all shift registers and for each output executes the following instructions:
- Write clock output low (cbi, 2 clock cycles)
- Load the duty cycle for this pin from memory (ldd, 2 clock cycles)
- Compare the duty cycle with a counter (cp, 2 clock cycles)
- Branch on compare result (brcs, 2 clock cycles)
- Write the datapin high or low (cbi or sbi, 2 clock cycles)
- Jump instruction (1 clock cycle, not always executed)
- Write clock output high (sbi, 2 clock cycles)
This takes 12 or 13 clockcyles per output and I don't think it can be done any faster.
** End technical stuff **

So unzip the attachment in your Arduino library directory and try it. The circuit is exactly the same as the ShiftOut example, but leave out the latch pin capacitor.

This library is not tested with the atmega1280, if you use it please report back to me.

I would really appreciate some feedback on usability and possible bugs. If someone could test this with ShiftBrites would be great.

If you would like to include this library as a standard library for Arduino, I would be honored.

Video of ShiftPWM_example1:



* ShiftPWM.zip (14.19 KB - downloaded 204 times.)
« Last Edit: August 09, 2012, 11:17:25 am by elcojacobs » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Well done,

No comments right now, but this is good stuff for an article on the playground, where you can explain the working (design decissions) in more detail.

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This could be perfect for a project I am trying to complete, where I am hoping to fade multiple LEDs slowly (have enough LEDs that I am at 6 registers) on and off.  I am very new to writing code.  Do you have any example code that would work in this regard using your library?  Not using RGB LEDs, and I am unfamiliar with commands dealing with frequency/loads and LEDs...  Appreciate any guidance!
Logged

Eindhoven
Offline Offline
Jr. Member
**
Karma: 1
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There is an example in the library. Extract the zip file in the library directory of arduino, restart arduino and go to file->examples->ShiftPWM to open it.

Only the rainbow example is specifically for RGB LED's, the rest of the examples should work directly with your current circuit.
Only a few things to keep in mind: select the correct pins, keep wires from arduino to first shift register short, and keep load under 0.9 (see the formula).

The load is also printed by the printInterruptLoad() function, so it is automatically calculated for you.

If you open the example, things will be pretty straight forward.
Logged

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 36
Posts: 5519
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm - what's the possibility of doing this for PPM and servos? smiley
Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Eindhoven
Offline Offline
Jr. Member
**
Karma: 1
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm - what's the possibility of doing this for PPM and servos? smiley
I thought about it, let me do a few calculations.
The design would be a bit different: the interrupt frequency will be much lower at and the pulse for the servo would be generated in one interrupt. The problem is squeezing enough resolution in the 1 ms time difference that defines the position.

Typical servo:    pulses of 1.0-2.0 ms, repeat every 20 ms.
13 clock cycles for updating one pin.
Number of clock cycles in one millisecond = 16000
Resolution = 16000/(13 * number of servos) =
24.6 steps for 50 servos
12.3 steps for 100 servos

So you would quickly lose a lot of resolution, but it is possible with a few alterations.




« Last Edit: July 20, 2011, 02:00:05 am by elcojacobs » Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 10
Posts: 1235
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I would really appreciate some feedback on usability and possible bugs. If someone could test this with ShiftBrites would be great.

What would you want to see done with ShiftBrites and this library? As far as I can tell there would be no compatibility, the ShiftBrite PWM management is internal to each module and does 10bit PWM per color already.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

Eindhoven
Offline Offline
Jr. Member
**
Karma: 1
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What would you want to see done with ShiftBrites and this library? As far as I can tell there would be no compatibility, the ShiftBrite PWM management is internal to each module and does 10bit PWM per color already.

Ah, sorry, I didn't really look into shiftbrites and just assumed they were LEDs with shift registers, without internal pwm control.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice, will try this out sometime; will be curious to see how it compares to using TLC5940's.
Logged

Seattle WA
Offline Offline
Full Member
***
Karma: 1
Posts: 208
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Very slick. I'm selling a couple of high current driver boards based around the 595 (http://www.logos-electro.com/ard-srg-ips4x4-1/ , http://www.logos-electro.com/1x3-srg-ips6-1/) and I'd like to include a link to your code once you have it up in a public place like GitHub.

PS -- have you tried daisy chaining 96 shift registers at once? AIUI, the fanout limit on the Arduino pins without buffers is about 50.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am also curious about the extremely long chain, I currently have a 34 shift register chain with decent wire lengths between each register that picks up other signals. Is there a simple way to buffer/reduce noise?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi. I was looking and felt that is a great job.
I also do this kind of serialization for my steper motor control, because the microsteper CHIP used for serial input at 11 bits(no 8, no 16, 11 bits).
But if i was you, surelly I would use the SPI interface.
Your Arduino dont has one? this way you just set the byte and trigger the start flag! just 2 instructions and 4 cicles!
Surelly Arduino al so have. With DATA and CLOCK you can simplify this a lot!
and get much more speed.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As mentioned by the previous poster, why not use the SPI? The HC595 is perfectly happy being driven by SPI, and on an Arduino you can clock the bits out at 8MHz.
Logged

Lancaster, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 4
My own, copyrighted, IP protected, personal text.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was about to make something like this. THANK YOU so much for the effort of doing it and posting for all of us.
I'm thinking about a present to express my appreciation to someone and wanted to have some fancy LED routines on a cast of their name.
I was already thinking about shift registers and getting them to work fast enough to have PWM on all the LEDs.
This just embodies what I was about to do in a nice package!

Once again, many thanks!!
Logged

Eindhoven
Offline Offline
Jr. Member
**
Karma: 1
Posts: 87
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To answer the question that is asked the most: why no SPI?

I don’t think it will be faster. The 1.3 MHz clock speed now includes retrieving the dutycycles from memory and comparing each of them with a counter.

The SPI sends out whole bytes, so you would have to put your bits into bytes before sending them out. Now I write the compare result to the data pin directly.

The SPI would only increase speed by combining these instructions:
clear clock pin, write data pin, set clock pin. Which take 6 clockcycles.
The SPI at 8 MHz would be able to do this in 2 clockcycles, but would require a bit write to the byte you want to send out, which takes 2 clock cycles.

The maximum gain wil be 2 clockcycles per pin, but I doubt you can squeeze it out. It also removes the freedom to choose pins.
Logged

Pages: [1] 2 3 ... 20   Go Up
Jump to: