ShiftPWM support topic. Latest update: Schematics, high power LED's, LED strips

This library is great, tested and will be used for my girlfriend's project.

But, has anyone brought out the point that using regular 74HC595 shift register is actually a bad design as you are forcing it to drive harder then it's rated for?

Yes, each IO is rated for 20mA, but supply/GND current is only rated to 70 mA. All outputs 'on' would be 160 mA with 20mA LEDs. 160 > 70

I suggest a TLC5916 instead as it's rated to drive LEDS like this and it has built in Constant Current driver, so you don't need to add resistors in series with each LED.

I apologize as I had originally asked this question on the contact page on the authors website before discovering this forum thread.

I often use the timer2 library to run tight polling loops to scan for input changes (buttons). As a simple test I added a button that would cycle through the different modes in the default shiftpwm example code. The problem I ran in to is while my buttons are nice and responsive I am getting "artifacts" in the display of leds. I suspect this is because the timer2 (and code) is interrupting the shiftpwm shifts to the shift register causing a state to hang for a ms longer. Is there an easy way around this? Simply placing my polling code in the main-loop won't work due to the lag of having to wait for the current subroutine to finish before the input can be 'scanned'. Is there a way to "piggyback" on to the shiftpwm interrupt to add my polling code to the end of the shift code? I don't have enough experience with C or library development to dissect the code to figure this out. Eventually I want to make a Mastermind game using RGB leds via this library and a few tactile push-buttons.

milamber:
This ShiftPWM library looks fantastic and is a very nice implementation of Shift Registers. I have been working on a Matrix display (Seems there are alot of us doing this) and I am wondering how ShiftPWM would hold up being used in a matrix? I understand that it is not setup to run a matrix but could it? Or would there be too many issues? I found another thread by Zuluriney (http://arduino.cc/forum/index.php/topic,69235.0.html), he is trying to do the same thing. Seems he has it working but I doubt it would be optimal.

I am not a great programmer but could the Library be written to do this very fast software PWM for a matrix?

If not then still a very cool thing to have in the tool collection. Thanks Elco!

It would be possible to use ShiftPWM to drive each row. The difference with a matrix and a chain is that in a matrix, you basically alternate in driving multiple chains. The maximum duty cycle for the LED's is 1/rows.
If each time you reset the counter, you also switch rows you can make some modifications to use it for matrices.

madsci1016:
This library is great, tested and will be used for my girlfriend's project.

But, has anyone brought out the point that using regular 74HC595 shift register is actually a bad design as you are forcing it to drive harder then it's rated for?

Yes, each IO is rated for 20mA, but supply/GND current is only rated to 70 mA. All outputs 'on' would be 160 mA with 20mA LEDs. 160 > 70

I suggest a TLC5916 instead as it's rated to drive LEDS like this and it has built in Constant Current driver, so you don't need to add resistors in series with each LED.

You are right about the supply current rating. I had not even noticed it. The 595 do not get hot and seem to have no problem driving the LED's, but I am indeed exceeding the datasheet specs.

Damage65:
I apologize as I had originally asked this question on the contact page on the authors website before discovering this forum thread.

I often use the timer2 library to run tight polling loops to scan for input changes (buttons). As a simple test I added a button that would cycle through the different modes in the default shiftpwm example code. The problem I ran in to is while my buttons are nice and responsive I am getting "artifacts" in the display of leds. I suspect this is because the timer2 (and code) is interrupting the shiftpwm shifts to the shift register causing a state to hang for a ms longer. Is there an easy way around this? Simply placing my polling code in the main-loop won't work due to the lag of having to wait for the current subroutine to finish before the input can be 'scanned'. Is there a way to "piggyback" on to the shiftpwm interrupt to add my polling code to the end of the shift code? I don't have enough experience with C or library development to dissect the code to figure this out. Eventually I want to make a Mastermind game using RGB leds via this library and a few tactile push-buttons.

I'll copy my answer here as well then for future reference:

The first line of the interrupt service routine in shiftpwm.h is this:

sei(); //enable interrupt nesting to prevent disturbing other interrupt functions (servo's for example).

Nested interrupts are normally disabled on arduino. This re-enables interrupt nesting and thus allows the shiftpwm interrupt to be interrupted by other interrupts. Maybe it helps to remove it here and add it as the first line of your interrupt function. If your interrupt takes many clockcycles it will disturb the pwm signal. You will want it just the other way around: shifpwm is allowed to interrupt your interrupt.

You could also add the input polling to the interrupt service routine, for example when the counter is reset.

elcojacobs:
It would be possible to use ShiftPWM to drive each row. The difference with a matrix and a chain is that in a matrix, you basically alternate in driving multiple chains. The maximum duty cycle for the LED's is 1/rows.
If each time you reset the counter, you also switch rows you can make some modifications to use it for matrices.

How would this be achieved? I don't see a reference to a counter inside the example code? Would it require another interrupt to fire when the counter reached 0? Sorry for the questions just trying to understand. I have a hand made matrix that I would like to try this out on. Thanks.

milamber:

elcojacobs:
It would be possible to use ShiftPWM to drive each row. The difference with a matrix and a chain is that in a matrix, you basically alternate in driving multiple chains. The maximum duty cycle for the LED's is 1/rows.
If each time you reset the counter, you also switch rows you can make some modifications to use it for matrices.

How would this be achieved? I don't see a reference to a counter inside the example code? Would it require another interrupt to fire when the counter reached 0? Sorry for the questions just trying to understand. I have a hand made matrix that I would like to try this out on. Thanks.

The counter is in the library code. If you can send me a schematic, I'll have a look how much work it is to change the code for the matrix. It's quite popular so I might add a different version of shiftpwm to work with matrices. I cannot test it, because I don't have a led matrix.

Hey, working with your code and am slightly confused as how you got this to work without a function really being created as to how this works or i simply can not find it...

// The macro below uses 3 instructions per pin to generate the byte to transfer with SPI
// Retreive duty cycle setting from memory (ldd, 2 clockcycles)
// Compare with the counter (cp, 1 clockcycle) --> result is stored in carry
// Use the rotate over carry right to shift the compare result into the byte. (1 clockcycle).
#define add_one_pin_to_byte(sendbyte, counter, ledPtr) .

which is than used in the intterupt routine by :
add_one_pin_to_byte(sendbyte, counter, --ledPtr);

i understand that
if ledPtr >= counter, sendbyte(actually bit) = 1
else sendbyte(actually bit) = 0
but i don't see how its actually done.

The reason why i am asking is because i want to add this look-up table for gamma correction to create a more realistic appearance of how the lights should look and possibly create more performance.

Gamma array size: 64
Total PWM steps: 255
Gamma correction: .74

static int Gamma_Cor[64] = {
0, 1, 2, 2, 2, 2, 3, 3, 3, 4,
4, 5, 5, 6, 6, 7, 8, 9, 9, 10,
11, 12, 13, 14, 16, 17, 18, 20, 22,
23, 25, 27, 30, 32, 34, 37, 40, 43,
46, 50, 54, 58, 62, 66, 71, 76, 82,
88, 94,101,108,116,124,132,141,
151,162,173,184,197, 210,224,239,255
};

using look-up table during interrupt would yield:
add_one_pin_to_byte(sendbyte, Gamma_Cor[counter], --ledPtr);
if i am not mistaken.

If the counter has to only go through 64 steps instead of 255 to complete a full pwm cycle, would that not cut down the need of the interrupt to send bytes out by 75% or so lessening the load of the program?

You are confused by the fact that sendbyte contains 8 bits, for 8 pins when it is sent to the SPI. These bytes are put in by making clever use of the rotate over carry right (ror) instruction.
If we assume it starts at 0000 0000.

The the first bit, a 1, is put in by the ror instruction.
1000 0000

The the second bit, a 0, is put in by the ror instruction.
0100 0000

The the third bit, a 1, is put in by the ror instruction.
1010 0000

See that each time these 3 assembly instructions are executed, all bits already in the byte are shifted right (rotate right) and the new compare result (which is stored in the carry) is shifted in (over carry). After doing this 8 times, the sendbyte contains the new bits for 8 pins and is sent to the SPI.

If you want to use 64 levels, you can set maxbrightness to 63. What you are proposing is that the time between interrupts is not constant. You have 2 options to achieve that:

  • change the timer compare register each interrupt
  • leave the compare register and use 256 interrupts, but on values of the counter that are not in your lookup table, leave the interrupt immediately.

If you don't necessarily want the performance increase, but you do want the gamma correction, do it before the interrupt. Leave maxbrightness at 255 and create a function that does the gammacorrection before using the library functions.

unsigned char get_gamma_corrected_value(unsigned char original_value){
   unsigned char corrected_value;

// set correct value here;

  return corrected_value;
}

Then use the function like this:

ShiftPWM.SetOne(3, get_gamma_corrected_value(original_value));

elcojacobs:
It would be possible to use ShiftPWM to drive each row. The difference with a matrix and a chain is that in a matrix, you basically alternate in driving multiple chains. The maximum duty cycle for the LED's is 1/rows.
If each time you reset the counter, you also switch rows you can make some modifications to use it for matrices.

Investigating this some more, I think I understand. If I switch the column(using your above example) when the counter reaches 0 then each pwm cycle will happen on a new set of LED's. This would effectively drop the overall refresh rate by the number of columns being used.
Say you were using an 8x10 matrix at pwm speed 50hz. The 8 Rows being driven by the 595's and some other way of selecting the columns(there seem to be mulitple ways of doing this). It would take 10 PWM cycles to complete 1 refresh of the whole matrix. Meaning 5hz for the whole screen. Can your PWM cycle speed be increased high enough to bring the whole matrix up to 50hz? Does this mean straight multiplying the PWM hz by the number of columns, in this case equalling 500hz?

I am sorry if any of the above is incorrect. I am just trying to understand as I would like to use your library. I am trying to see if I could drive a 16x16 RGB matrix this way. ( if above is correct that would need 800hz for the pwm cycle but there would only be 6 SR's being driven)

I have replicated this on a breadboard using common Cathode RGB LED’s. You have stated above to look for “#define statement to invert the outputs, just toggle it to suit your LED’s.” I am unable to find the correct value to change in the code to suite my LED’s. Sorry if this is clear as day, would you be able to assist me to find this to change.

The only #define I could find was “#define RGB2HSV_h” in the “hsv2rgb.h”

I am new to Arduino and this is my first play around.

Cheers in advance.

I think he was refering to this line in the example.pde:

const bool ShiftPWM_invertOutputs = 1; // if invertOutputs is 1, outputs will be active low. Usefull for common anode RGB led's.

I am sure this is just a binary switch. 1 is true, so it would invert(as he said active low). 0 is False, not inverted(active high). :slight_smile:

milamber:
I think he was refering to this line in the example.pde:

const bool ShiftPWM_invertOutputs = 1; // if invertOutputs is 1, outputs will be active low. Usefull for common anode RGB led's.

I am sure this is just a binary switch. 1 is true, so it would invert(as he said active low). 0 is False, not inverted(active high). :slight_smile:

Thank you, this worked a treat. Now I can continue my exploration into Arduinoness.
8)

I have a problem regarding the timeout duration for the example code. I'm currently using the ShiftPWM library in my first project with an Arduino to line the underside of my longboard with an array of 24 RGB LEDs passing through 9 shift registers. The electronics of the project are sound - I have 17 of the 24 LEDs wired up and working (the rest are being wired in tonight), and when plugged in via USB the examples run perfectly and for the full number of cycles. The problem comes when I disconnect the Arduino from the USB cord and attempt to power it via 9V. The board seems to reset itself quite frequently, interrupting itself less than 5 seconds after its initial execution and continually restarting in that fashion. At first I thought this had to do with the timeout comments in the ShiftPWM example code regarding the number of shift registers versus the interrupt duration. However, it's only 9 shift registers, meaning I should get close to the full 255 value for that duration. Does anyone have any ideas or comments on how to properly get this project functioning off a battery? Why is there this discrepancy between power sources?

Thanks in advance!

The problem comes when I disconnect the Arduino from the USB cord and attempt to power it via 9V.

If you are using those standard small 9vdc batteries then that is the reason for the failures, it just doesn't have the current capacity to handle your load. You need to use batteries that support the current requirements.

Lefty

retrolefty:

The problem comes when I disconnect the Arduino from the USB cord and attempt to power it via 9V.

If you are using those standard small 9vdc batteries then that is the reason for the failures, it just doesn't have the current capacity to handle your load. You need to use batteries that support the current requirements.

Lefty

Ah, thank you! What kind of battery/batteries should I use? Thanks so much.

What kind of battery/batteries should I use

A bigger one.

Voltage, anywhere from 8 to 12vdc
Current (MAH or AH) rating depends on how much current your project draws and for how long you want the battery to power the project. Rechargeable would save you lots of money in the long run. Learning about batteries and there specifications is part of learning of electronics. Do some research so you can answer your own questions in time, but ask questions when you get stuck or don't understand something.

First order of business is to know how much current your project draws, that takes a digital multimeter, which if you don't own one should get one as soon as possible. They can be very affordable and it's an important tool to have and learn to use if you want to be successful with electronic projects.

Lefty

retrolefty:

What kind of battery/batteries should I use

A bigger one.

This made me laugh way more than it should have :slight_smile:

How about this one? >> http://goo.gl/C82OT (58 Ah - hooah!)

Seriously though, LEDs are quite power hungry little beasts and will deplete small batteries in short order. Like Lefty says, you need to determine your device's current draw combined with the intended use for your device. If you want your design to run for several days off of a single battery/charge, your selection will be quite different than if you want to run it for a few minutes at a time. There is no shortage of information on the subject of power management available. It's an important aspect to learn and understand.

buzzdavidson:
This made me laugh way more than it should have :slight_smile:

How about this one? >> http://goo.gl/C82OT (58 Ah - hooah!)

Seriously though, LEDs are quite power hungry little beasts and will deplete small batteries in short order. Like Lefty says, you need to determine your device's current draw combined with the intended use for your device. If you want your design to run for several days off of a single battery/charge, your selection will be quite different than if you want to run it for a few minutes at a time. There is no shortage of information on the subject of power management available. It's an important aspect to learn and understand.

I really appreciate the suggestion, however I feel I should note that this project is simply lining the underside of my longboard with the array of LEDs; a 20-pound battery would be a little much! Regardless, I appreciate all the advice you and Lefty have given me; I've been e-mailing back and forth with Elco about the best solution for this particular application, which is to say, only being powered a few minutes at a time (just while I'm riding around). I wasn't aware that LEDs were so power-hungry; on the contrary, I always had them in my mind as being more efficient light sources, although I guess by typical lighting standards they probably are. At any rate, I think I'm nearing a solution, so thanks again for all the help.

Well the fact that your project can run on USB power (did I understand that correctly?) then your total current consumption must be under 500ma otherwise the thermofuse on the board would open up and power down the board.

So rechargeable Nimh AA batteries are stated good for 2500+ mah or so, so six or seven AA cells wired in series could power the board via the external power connector, or four AA cells wired in series could power the board via the ground and +5vdc pins. This should give you at least four hours of run time and probably the most cost effective batteries avalible.

Lefty