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

This library is amazing and has saved me a TON of work, thank you VERY much for all of your hard work. Great stuff! I would absolutely love to see some articles from you regarding optimizing and performance tweaking for Arduino.

This library is amazing and should have been written as soon as shift registers were introduced on the Arduino website. It will save me plenty of time now that I wanted to do a high-power LED project. What I would like however is a "get" function for the array that stores the PWM values. I notice that in CShiftPWM.h there is a public variable named "unsigned char * m_PWMValues;". However I am not sure how to access this value.

You could add this to CShiftPWM.cpp:

unsigned char CShiftPWM::GetOne(int output){
return m_PWMValues[output];
}

And add to CShiftPWM.h the prototype for the public member function:

unsigned char GetOne(int output);

I have designed a 24 channel LED driver board for high power LED's. The constant current outputs can be adjusted from 60 to 350 mA and it is directly compatible with the library. Size is about the same as the Arduino. The first prototype will arrive in a week. Would you be interested in such a board? It is not in production at the moment, but will be soon.

Excellent. I will make use of that get function immediately. And I would love to take a look at the board when it is done.

Loving the library, but I'm finding that I can't get decent output on serial LCDs-- character LCD backpacks from both SparkFun and Modern Device (LCD117) are printing odd characters. I've tried using the ATmega328's built-in serial port and softwareSerial, and I get the same strange results.

Regular serial reporting seems OK though, so I'm confused. Any clues would be appreciated!

I'm going to try stripping all serial reporting out of the library and see if I get any different results...

Hi Salsaman,

If you are using softwareSerial, the two serial communications should be unrelated and you should have no problems.
I cannot find the LCD you are using on Sparkfun, so I will give you my best guess:

Your function to print to the LCD is interrupted by the ShiftPWM library and the LCD controller can not handle a long pause between the received characters. Could you try using this:

cli(); //disable interrupts
/* print to lcd */
sei(); //enable interrupts

It's just a guess, because I cannot test it.

Strange, that's not fixing things... I can get the LCD117 working on the regular serial port though, if I gang up what I send it so it happens at once; makes things much better.
Using softwareSerial with ShiftPWM and either serial display isn't working for me at all though, I wonder if anybody else has tried?
This is the SparkFun backpack I'm using: SparkFun Serial Enabled LCD Backpack - LCD-00258 - SparkFun Electronics though the one I have is ~2 years old and may not behave like the newer ones.
Anyway, I'm up and running with the LCD117, many thanks again for this awesome library!

Very strange.
In the code of softwareSerial (Google Code Archive - Long-term storage for Google Code Project Hosting.) I cannot see anything that would conflict with ShiftPWM.

But I understand that you got it working now with the normal serial port? Please show off your project when it's done!

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!

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.