Move first bit from one byte to last bit in a second byte and vs

Hello,

I am working on an 8x24 multiplexed LED grid that I am running with shift registers. I am running it with an Arduino nano that uses SPI to send 32 bytes out to 4x 74HC595 shift registers.

The shift registers are linked such that the output of the first one feeds the second one, and so on. The first shift register in sequence controls the anodes on the horizontal rows and the other three handle the cathodes for the columns. So the Arduino outputs 4 bytes with the first three being the columns and the last one being the row.

I would like to be able to scroll the contents of the display left or right. I believe in order to do this, I need to be able to shift each of the three column bytes left or right. I believe I can do this with bitwise shifts, however, this will shift each byte individually. I actually would need to gradually shift the contents of one byte into another.

To clarify, here is an example. Let us suppose I am merely working with one row. So I will ignore the first shift register (row anode). I want a group of three bits to scroll from right to left. I'd like the sequence of events to appear as follows.

First iteration: 00000000 00000000 01110000
Second iteration: 00000000 00000000 11100000
Third iteration: 00000000 00000001 11000000
Fourth iteration: 00000000 00000011 10000000
Fifth iteration: 00000000 00000111 00000000
Sixth iteration: 00000000 00001110 00000000


If I merely do bitwise shifts, the bits will "fall off" their respective bytes that they originated on when they reach the "edges" of the bytes. They won't be handed off to the next byte as I am hoping to do.

How could I go about accomplishing this?

Let me know if more information is needed to clarify what I'm asking.

[u]bitRead()[/u] into a temporary variable before shifting the bit off the end. Then bitWrite() to the destination after shifting.

That looks exactly like what I need. Thank you!

You could also just use a long data type (32bits) to hold the entire thing.

Indeed. Use a 32-bit (or even 64-bit) int, then you can use the << bit shift operator to move bits left (or right).

uint32_t data = 0b000000000000000001110000;
data = data << 1; 0b000000000000000011100000;

Hi,
Welcome to the forum.

Have you googled

arduino scrolling text led matrix

Tom... :slight_smile:

wvmarle:
Indeed. Use a 32-bit (or even 64-bit) int, then you can use the << bit shift operator to move bits left (or right).

uint32_t data = 0b000000000000000001110000;

data = data << 1; 0b000000000000000011100000;

I ended up doing this. Much easier! It did cross my mind that this might be an option, but since I only need three bytes to handle the columns, I was concerned about how to handle the extra byte. Since I’d be shifting bits, I didn’t think I could use the first byte for the column select since the shifting would affect that (the first byte/shift register is the row selection). However, it then occurred to me to just make the fourth byte (first to enter), all zeros or ones or whatever, because I could simply output the long into the shift registers and then output a byte for the row selection, and the “extra byte” would be shoved out of the last shift register and become irrelevant anyway.

Short answer; this was the easiest and likely the most efficient way to do this is seems. I’m now moving onto the other challenges as I continue the project.

Is “uint32_t” the same as an “unsigned long”? I just specified “unsigned long” in my code.

Thanks for the help!

JDDellGuy:
Is "uint32_t" the same as an "unsigned long"? I just specified "unsigned long" in my code.

On ATmega processors, yes. On other processors, maybe. uint32_t is explicitly defined as 32 bit unsigned integer; a long is usually but not necessarily 32 bits.

I've been bitten hard by this before moving code from ESP8266 to an Arduino Nano. Turned out that an int on ESP8266 is 32-bit, while on the ATmega328p it's 16-bit... Since then I use the uint8_t/uint16_t/uint32_t/uint64_t notation, just to be safe when moving between platforms.

JDDellGuy:
this was the easiest and likely the most efficient way to do this is seems.

But then how did you shift the bytes to the registers? If you made that code more complex to make the scrolling easier, you're no better off.

I would use a union to allow me to treat the same variable as a uint32_t or as an array of 4 uint8_t.

PaulRB:
But then how did you shift the bytes to the registers? If you made that code more complex to make the scrolling easier, you’re no better off.

I would use a union to allow me to treat the same variable as a uint32_t or as an array of 4 uint8_t.

At this current time, I’m actually doing another bitshift in a separate function that does the actual “writing” to the 24x8 grid. That bitshift splits up the long into 3 bytes (it ignores the fourth byte in the long since it’s not needed) and then uses SPI to send those three bytes to identify the columns, followed by a fourth byte which identifies the row.

Would using a union allow me to easily bitshift the bytes all together such that one byte’s first bit can end up in the next bytes last bit position as it shifts?

Here’s a sample. I’m completely aware that this code could use some optimizing. This is one of my first major Arduino projects, so I’m completely new to C coding. My background is in Powershell and Batch scripting, so actual coding, especially this close to the hardware, is very new to me. I’m getting better. A few weeks from now, I’m sure I won’t be using the same functions. :slight_smile:

unsigned long River[8] = {  //The word "River."  Due to PNP transistors, 0's represent lit LEDs.
/*
* Ignore the fourth (rightmost) byte in the below array entries.
* Despite mixing the 1's and 0's, it's completely ignored by the code.
* Originally, I was specifying the multiplex row in that byte, but due to the bitshifting,
* I'm now sending that byte separately afterward.
*/

  0b11111111111111111110001100000001, //Row1
  0b11111111111111110101101100000010, //Row2
  0b11111111111111111101101100000100, //Row3
  0b11101100110111010110001100001000, //Row4
  0b10001011010111010110101100010000, //Row5
  0b11101000010111010101101100100000, //Row6
  0b11101111011010110101101101000000, //Row7
  0b11101000111101110101101110000000  //Row8
};

void scrollLeft(unsigned long pattern[8],byte iterations,int speed){
    for(byte i=0;i<iterations;i++){
      unsigned long patternData[8];
        for (byte j=0;j<8;j++){
          patternData[j] = (long) pattern[j] >> i;
        };
      for(int h=0;h<speed;h++){
        pixelWrite(patternData,0);
      };
    };  
}

void pixelWrite(unsigned long phrase[8],byte lineDelay){
  
    int i=1;
    for(byte j=0;j<8;j++){

      i*=2;
      byte data[4];
        data[0] = phrase[j] >> 8;
        data[1] = phrase[j] >> 16;
        data[2] = phrase[j] >> 24;

      digitalWrite(srSS,LOW);
      for(byte k=0;k<3;k++){
        SPI.transfer(data[k]);
      };
      SPI.transfer(i/2);

      digitalWrite(srSS,HIGH);
      delay(lineDelay);
    };
}

void setup() {
  // put your setup code here, to run once:

  SPI.begin();
  SPI.beginTransaction(SPISettings(14000000, LSBFIRST, SPI_MODE0));
  pinMode(srSS, OUTPUT); 

}

void loop() {
  // put your main code here, to run repeatedly:

scrollLeft(River,25,750);

}

You can cast a pointer to uint32_t to a pointer to uint8_t.

It will point to the low byte of the UL. Next bytes are the uint8_t pointer + 1 then + 2 (or +1 twice).

How a union actually works depends on the compiler though -usually- a union can be used for this purpose the standard since the start says don't count on it (K&R used more words).

Learn to use pointers and you won't need black boxes to get into your data.

JDDellGuy:
Hello,

I am working on an 8x24 multiplexed LED grid that I am running with shift registers. I am running it with an Arduino nano that uses SPI to send 32 bytes out to 4x 74HC595 shift registers.

The shift registers are linked such that the output of the first one feeds the second one, and so on. The first shift register in sequence controls the anodes on the horizontal rows and the other three handle the cathodes for the columns. So the Arduino outputs 4 bytes with the first three being the columns and the last one being the row.

I would like to be able to scroll the contents of the display left or right. I believe in order to do this, I need to be able to shift each of the three column bytes left or right. I believe I can do this with bitwise shifts, however, this will shift each byte individually. I actually would need to gradually shift the contents of one byte into another.

To clarify, here is an example. Let us suppose I am merely working with one row. So I will ignore the first shift register (row anode). I want a group of three bits to scroll from right to left. I’d like the sequence of events to appear as follows.

First iteration: 00000000 00000000 01110000
Second iteration: 00000000 00000000 11100000
Third iteration: 00000000 00000001 11000000
Fourth iteration: 00000000 00000011 10000000
Fifth iteration: 00000000 00000111 00000000
Sixth iteration: 00000000 00001110 00000000


If I merely do bitwise shifts, the bits will “fall off” their respective bytes that they originated on when they reach the “edges” of the bytes. They won’t be handed off to the next byte as I am hoping to do.

How could I go about accomplishing this?

Let me know if more information is needed to clarify what I’m asking.

Why not use a 32 bit uint32_t variable as “virtual” shift register, modify the bits any way you like, then shift it into the real shift register gang all at once? I’m sure the update will be so fast that you won’t see any glitch on the display.

By the way, you cannot use _bv() to change the bits because the bv macro in avr-gcc is wrong (it fails at the 15 bit mark).

Instead, use (1UL << B). The bv macro uses (1 << b) and since “1” is an int (16 bits in avr), the shifting “falls off the end” after 15. Using 1UL allows it to work for all 32 bits (and if you needed even more, 1ULL would give you 64 bits!

Hope this helps.

Heads up: when you use SPI.transfer(b), the return value is a byte read from MISO. Often in code examples that byte is discarded (because MISO is not connected). The value of b is unaffected. But when you use SPI.transfer(arrayb, sizeof(arrayb)) where arrayb is an array of bytes, the array will be overwritten with bytes of data read from MISO. So if you don't want your data overwritten, take a copy and give the copy to SPI.transfer().

      byte data[4];
        data[0] = phrase[j] >> 8;
        data[1] = phrase[j] >> 16;
        data[2] = phrase[j] >> 24;

This is the point I was making in post #8. You may have made your scrolling faster and simpler by using bitshift on a uint32_t, but now you are having to do more bitshifting to extract the bytes to send to the register.

I don't know if the compiler is clever enough to realise that it can perform ">>24" by extracting a byte from the uint32_t. If it isn't, it may have to do 24 repeats of a single 32-bit bitshift, end each single bitshift may be 4 bitshifts on single bytes, so almost 100 machine instructions!

So in terms of code simplicity, you are not much better off than where you started, in terms of performance (which may matter less to you) you may be worse off.

Hence the suggestions above to use a union or pointer casting to turn the uint32_t into an array of bytes and shift them out together using SPI.transfer(arrayb, sizeof(arrayb)).

PaulRB:

      byte data[4];

data[0] = phrase[j] >> 8;
        data[1] = phrase[j] >> 16;
        data[2] = phrase[j] >> 24;



This is the point I was making in post #8. You may have made your scrolling faster and simpler by using bitshift on a uint32_t, but now you are having to do more bitshifting to extract the bytes to send to the register.

And that is where using pointers saves cycles.

unsigned long bigVar; // 4 bytes in RAM interpreted as an unsigned long
byte *bp; // can point to any byte in RAM as a byte regardless of how it was declared

.....

bp = (byte *)( &bigVar ); // takes the address of bigVar and casts it to a byte pointer

*bp is now the low order byte of bigVar
*bp+1 is the next byte
*bp+2 is the next

You don't have to make a set of bytes to put the results in, they are in bigVar and can be used right there.

If you would have a bit shifted off the right end, before you do that save (bigVar % 2) and you have that bit, 0 or 1.
What shifts left off *bp+2 can be found in *bp+3.

As far as shifts and rotates, AVR only has instructions to shift or rotate 1 bit (at a time) so >> 16 takes 16 cycles.

GoForSmoke:
And that is where using pointers saves cycles.

unsigned long bigVar; // 4 bytes in RAM interpreted as an unsigned long
byte *bp; // can point to any byte in RAM as a byte regardless of how it was declared

.....

bp = (byte *)( &bigVar ); // takes the address of bigVar and casts it to a byte pointer

*bp is now the low order byte of bigVar
*bp+1 is the next byte
*bp+2 is the next

You don't have to make a set of bytes to put the results in, they are in bigVar and can be used right there.

If you would have a bit shifted off the right end, before you do that save (bigVar % 2) and you have that bit, 0 or 1.
What shifts left off *bp+2 can be found in *bp+3.

As far as shifts and rotates, AVR only has instructions to shift or rotate 1 bit (at a time) so >> 16 takes 16 cycles.

This is great info, thank you! I'm now using pointers for those bytes. I can see where pointers are useful; I'll just have to get used to the syntax a bit.

JDDellGuy:
This is great info, thank you! I'm now using pointers for those bytes. I can see where pointers are useful; I'll just have to get used to the syntax a bit.

Do a bit of study, look up pointer math. In a loop you can do pointer++ to walk through arrays like char strings.

You can pass pointers as function args, the same function can work on different data sets and yeah there are many standard functions that take and return pointers. They are down to the roots addresses in memory, very powerful tools for writing shorter code.

When to use the * and the & take a bit of memorizing, best way is to play around making very-small examples -- with Arduino just do little trivial examples in void setup(). The act of putting it in code will help with memorizing, when the code runs right you get that reward boost. As little things get easier, less reward feeling, you come back to it in bigger sketches and keep it.

Learning is part biology, your brain has to grow connections for anything to get into long-term memory and then it's part of you. Learn enough and you change, it's mental weight-lifting.

As far as #define goes, see Reply #3 in this thread on the subject of RAM,

GoForSmoke:
When to use the * and the & take a bit of memorizing, best way is to play around making very-small examples – with Arduino just do little trivial examples in void setup().

That’s what I attempted with the pseudo code given. I thought I should see the constituent bytes of bigVar printed but, I can’t make it happen.

// extract bytes from 32-bit variable with a pointer

// https://forum.arduino.cc/index.php?topic=630682.msg4279573#msg4279573


unsigned long bigVar = 0x5533aacc; // 4 bytes in RAM interpreted as an unsigned long
// byte *bp; // can point to any byte in RAM as a byte regardless of how it was declared

byte *bp = (byte)(&bigVar); // takes the address of bigVar and casts it to a byte pointer
//bp = (byte)(&bigVar); // takes the address of bigVar and casts it to a byte pointer

//*bp is now the low order byte of bigVar
//*bp+1 is the next byte
//*bp+2 is the next
//*bp+3 is high order byte of bigVar

byte printVar; // a place to store extracted bytes

void setup() {
  Serial.begin(115200);
  Serial.print("bigVar - \t");
  Serial.println(bigVar, HEX);

  printVar = *bp; // when asterisk removed printVar prints as zero.
  Serial.println("\n*bp+i\tbp[i]");
  for (byte i = 0; i < sizeof(bigVar); i++) {
    Serial.print(*bp + i, HEX);
    Serial.print("\t");
    Serial.println(bp[i], HEX);
    //     Serial.println(bp + i, HEX); // no matching function for call to 'println(byte*, int)'
  }
  *bp = 0x66;
  Serial.print("\nmodified bigVar ");
  Serial.println(bigVar, HEX); // bigVar doesn't change
}

void loop() {
}

yields:

bigVar - 	5533AACC

*bp+i	bp[i]
F6	F6
F7	0
F8	4
F9	2

modified bigVar 5533AACC

Which I presume, due to the sequential numbering, is a series of addresses of something.

This construction:

byte *bp; // can point to any byte in RAM as a byte regardless of how it was declared

bp = (byte)(&bigVar); // takes the address of bigVar and casts it to a byte pointer

produces the error - ‘bp’ does not name a type

I think I understand the principle - it’s the mechanics that elude me.

    Serial.print(*bp + i, HEX);  //  gets the 1st byte and adds 1

should be

    Serial.print( *( bp + i ), HEX); // now gets the next byte