Go Down

Topic: Shift register update code malfunction (Read 577 times) previous topic - next topic

KnuttyD

Hey guys:
As some of you may or may not know, I am working on a shift register PWM project for some RGB leds to go in my case fans. It works great (I'm gonna speed up the crystal when I get ahold of one, but thats a different story), except when I try to modify the brightness of any LEDS that have a higher address of 16 bits (2 bytes), the states are lost. In other words, the buffer that I am holding the frame in is not large enough for all of the bits to be held in. I need at least 3 bytes for my project to work (4 bytes would be great :) give me a little legroom) . When I use a LONG, any bytes above 16 bits get set to 0. WTFBOOM!??!  :'(

I have no idea whats goin on with these data types. I've tried all the 4 byte data types (the long and doubles cannot be read on the bit-level), to no avail. For some reason I cannot use __int32? It shows up as not defined.

Anybody know of some fancy-new 4 byte data types that can be bit-manipulated higher than 2 bytes?

Here is my code:
Code: [Select]

#define __dataPin 9
#define __clockPin 10
#define __latchPin 11
#define __numLedsInArray 8
#define __numPinsPerLed 3
#define __maxBrightness 100
#define __delayMultiplier .5
int ledPin =  13;    // LED connected to digital pin 13
int i=0;
int tcnt2;
int isrCount = 0;

int ledStates[__numLedsInArray][__numPinsPerLed];


long currBuffer = 0; //I thought an INT was 4 bytes?

void setup()   {                
 // initialize the shift reg control pins as outputs:
 pinMode(__dataPin, OUTPUT);
 pinMode(__clockPin, OUTPUT);
 pinMode(__latchPin, OUTPUT);
 digitalWrite(__latchPin, LOW);
 for(int i=0; i<10; i++) //((int) (((__numLedsInArray*3))/s8)+1)
 {
   shiftOutDedicated(B00000000); //Set all of the regs to 0.
 }

 digitalWrite(__latchPin, HIGH);
 Serial.begin(9600);
 
 setupTimer();
 
}

ISR(TIMER2_OVF_vect) {
 /* Reload the timer */
 TCNT2 = 147; //This seems to not flicker very much. 205 for 4 LEDS, 147 for for 8 LEDS (Must shift out 3 bytes)
 //New update code:
 for(int isr_ledNumber=0; isr_ledNumber < __numLedsInArray; isr_ledNumber++)
 {
   for(int isr_loopCount=0; isr_loopCount < 3; isr_loopCount++)
   {
     if(ledStates[isr_ledNumber][isr_loopCount] <= isrCount)
     {
       currBuffer |= (1<<isr_loopCount+(isr_ledNumber*3));
     }
     else
     {
       currBuffer &= ~(1<<isr_loopCount+(isr_ledNumber*3));
     }
     
   }
 }
 
 //digitalWrite(__latchPin, LOW);
 PORTB &= ~(1<<3);
 shiftOutDedicated((byte)currBuffer); //First Byte
 shiftOutDedicated((byte)(currBuffer>>8)); //Second
 shiftOutDedicated((byte)(currBuffer>>16)); //Third to get a total of 24 bits (/3 pins = 8 RGB LEDS)
 //digitalWrite(__latchPin, HIGH);
 PORTB |= (1<<3);
 isrCount++;
 
 if(isrCount >= 100)
 {
   isrCount=0;
 }
 
}

void shiftOutDedicated(byte val)
{
     for (int i = 0; i < 8; i++)  {
         if(!!(val & (1<<i)))
         {
           PORTB |= (1<<1); //Set the dataPin bit
         }
         else
         {
           PORTB &= ~(1<<1); //Clear the dataPin bit
         }
        //digitalWrite(dataPin, !!(val & (1 << i)));
         PORTB |= (1<<2); //Clock pin high
         PORTB &= ~(1<<2); //Clear clock pin to low
           //digitalWrite(clockPin, HIGH);
           //digitalWrite(clockPin, LOW);            
 }
}

 void setupTimer() //Set up the ISR.
 {
   unsigned int tcnt2;
 
   TIMSK2 &= ~(1<<TOIE2);
 
 
   TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
   TCCR2B &= ~(1<<WGM22);
 
   ASSR &= ~(1<<AS2);
 
   TIMSK2 &= ~(1<<OCIE2A);
 
   TCCR2B |= (1<<CS22)  | (1<<CS21) | (1<<CS20); // Set bits
   //
   //TCCR2B &= ~(1<<CS21);      
   //TCCR2B &= ~(1<<CS20);
   TCCR2B &= ~(1<<CS22); //Clearing only this gives best timing.
   
   TIMSK2 |= (1<<TOIE2);
 }

void loop()
{
 pattern_ledDebug();
 //pattern_rainbow();
 /*
 easeAllRed(100, 0);
 easeAllGreen(0, 0);
 delay(0);
 easeAllRed(50, 0);
 easeAllGreen(50, 0);
 delay(0);
 easeAllGreen(100, 0);
 easeAllRed(0, 0);
 delay(0);
 easeAllRed(50, 0);
 easeAllGreen(50, 0);
 delay(0);
 */
 //easeAllBlue(100, 0);
 //easeAllBlue(0, 0);
}    
/*
void pattern_rainbow() //These values will give a roy-g-biv effect.
{
 
 easeAll(100, 0, 0, 100, 0); //Have not implemented easeAll yet.
 easeAll(100, 64, 0, 100, 0);
 easeAll(100, 100, 0, 100, 0);
 easeAll(00, 50, 0, 100, 0);
 easeAll(0, 0, 100, 100, 0);
 easeAll(93, 32, 93, 100, 0);
 
}
*/
void pattern_ledDebug() {

 //This fades in and out the individual colors on the LED's.
for(int ledNumberID=0; ledNumberID < __numLedsInArray; ledNumberID++)
{
 for(int ledLoopNum=0; ledLoopNum < 3; ledLoopNum++)
 {
     i=0;
     while(i <= 100)
     {
       ledStates[ledNumberID][ledLoopNum]=i;
       i++;
       delay(1);
     }
     i=100;
     while(i>=0)
     {
       ledStates[ledNumberID][ledLoopNum]=i;
       i--;
       delay(1);
     }
   }
 }
}

void easeAllRed(int red, int ledToUsePrevValue)
{  
   int redDiff = red - ledStates[ledToUsePrevValue][0];
   int loopsToRun = 100;
   float redStep = (float)redDiff/(float)loopsToRun;
   float redBuffer = ledStates[ledToUsePrevValue][0];
   /* //Uncomment this to debug
   Serial.print("Red is currently: ");
   Serial.println(ledStates[ledToUsePrevValue][0]);
   Serial.print("Red will ease to: ");
   Serial.println(red);
   Serial.print("The number of loops to run is: ");
   Serial.println(loopsToRun);
   Serial.print("redStep: ");
   Serial.println(redStep);
   Serial.print("redDiff: ");
   Serial.println(redDiff);
   */
   for(int i = 0; i<=loopsToRun; i++)
   {
     redBuffer += redStep;
     //Serial.println(redBuffer);
     for(int b = 0; b <= __numLedsInArray; b++)
     {
     ledStates[b][0] = redBuffer;
     //Serial.print("The red LED is at state: ");
     //Serial.println(ledStates[0][0]);
     delayMicroseconds(15);
     }
 }
 for(int b = 0; b <= __numLedsInArray; b++)
 {
 ledStates[b][0] == red;
 }
 //Serial.println("-------");
 return;
}

void easeAllGreen(int green, int ledToUsePrevValue)
{  
   int greenDiff = green - ledStates[ledToUsePrevValue][1];
   int loopsToRun = 100;
   float greenStep = (float)greenDiff/(float)loopsToRun;
   float greenBuffer = ledStates[ledToUsePrevValue][1];
   for(int i = 0; i<=loopsToRun; i++)
   {
     greenBuffer += greenStep;

     for(int b = 0; b <= __numLedsInArray; b++)
     {
     ledStates[b][1] = greenBuffer;
     delayMicroseconds(15);
     }
 }
 for(int b = 0; b <= __numLedsInArray; b++)
 {
 ledStates[b][1] == green;
 }
 //Serial.println("-------");
 return;
}

void easeAllBlue(int blue, int ledToUsePrevValue)
{  
   int blueDiff = blue - ledStates[ledToUsePrevValue][2];
   int loopsToRun = 100;
   float blueStep = (float)blueDiff/(float)loopsToRun;
   float blueBuffer = ledStates[ledToUsePrevValue][2];
   for(int i = 0; i<=loopsToRun; i++)
   {
     blueBuffer += blueStep;
     //Serial.println(blueBuffer);
     for(int b = 0; b <= __numLedsInArray; b++)
     {
     ledStates[b][2] = blueBuffer;
     delayMicroseconds(15);
     }
 }
 for(int b = 0; b <= __numLedsInArray; b++)
 {
 ledStates[b][2] == blue;
 }
 return;
}



Thanks guys! ;D

deSilva

Why on earth are you packing all your LED date into "currBuffer", to no avail but to unpack it again? Just leave that out...

drhex

Code: [Select]
currBuffer |= (1[glow]L[/glow]<<isr_loopCount+(isr_ledNumber*3));

The value you "or" with is probably clipped to int size = 16 bits before being applied to currBuffer. Try adding an L.

deSilva


KnuttyD

Code: [Select]
The value you "or" with is probably clipped to int size = 16 bits before being applied to currBuffer. Try adding an L.


It is being clipped to 16 bits, that is true. What is this adding an L though? I have never heard of this in C++ for all the years I've been coding  :D. Unfortunatly, it did not work  :'( but its OK, I'm going to try to modify my code in a new way.

[a little while later]

Code: [Select]

 PORTB &= ~(1<<3); //Latchpin low!
 for(int isr_ledNumber=0; isr_ledNumber < __numLedsInArray; isr_ledNumber++)
 {
   for(int isr_loopCount=0; isr_loopCount < 3; isr_loopCount++)
   {
     if(ledStates[isr_ledNumber][isr_loopCount] <= isrCount)
     {
       PORTB |= (1<<1); //Set dataPin to high.
       PORTB |= (1<<2); //Clock pin high
       PORTB &= ~(1<<2); //Clear clock pin to low
     }
     else
     {
       PORTB &= ~(1<<1); //Set dataPin to high.
       PORTB |= (1<<2); //Clock pin high
       PORTB &= ~(1<<2); //Clear clock pin to low
     }
     
   }
 }
 PORTB |= (1<<3); // Set latchpin HIGH! :D

That should bypass the need to read any bits higher than 16. Plus, shouldent it run much faster because its skipping creating the buffer, and then running another function at the end of the program to shiftOut all the data.

Also, it works! More RAM free for other important stuff.

Thanks guys, I honestly wouldent thought of this if deSilva had never said
Quote
Why on earth are you packing all your LED date into "currBuffer", to no avail but to unpack it again? Just leave that out...

It was one of those light-bulb moments
;D
Have a great one!
--Dylan

KnuttyD

Just as some comparisions, heres the speed differance:
TCNT2 is what sets the clock to a value (to modify the speed at which it fires by lowering the number of times it ticks before calling ISR(TIMER2_OVF_vect){})

Higher number is faster (therefore less flicker):

REV1 (the first version I made):
1 LED: maxed out @ 150;
2 LEDS: 130;
3 LEDS: 100;
4 LEDS: couldn't do it without a migrane!

REV2 (the version I first posted in this thread)
1LED: 240 (Huge improvement at the time.)
2LEDS: 235 (again, wow i thought)
3LEDS: 221
4LEDS: 204
---
8 LEDS: 147 (ARGH MIGRANE) the flicker was killer

NOW: Rev3: SUPA FAST VERSION

8 LEDS:
bababdabaaaa:
232.
Thats right. 232. I'm not even pushing it to its limits (around 235)

So theres my update code, I hope someone can put use to its speed as I have  :D

I'll try to make it faster, once the project is finished (it will be sporting a nice 20mhz crystal for the speed too) I'll post in exhibitions!

Go Up