0
votes

I am trying to implement an animation shifting function, that will allow me to shift all (LAYERS*BYTES) LEDS by 32 bits with an overlap. I only could do it with byte shifting, but that is not what I need.

To better understnad the idea, the image is provided below:

enter image description here

I drew it out where C is a carry bit that is moved to the start of the following byte and the last element of 4 bytes is assigned to the first element of the first byte.

There might be a better way to implement this. I appreciate for any help in advance.

Additional information:

void Shift_Right_Byte(void){
    for (int row = 0; row < LAYERS; row++) {
            for (int col = 0; col < BYTES; col++) {
                LED_Buffer[row][col] = LED_Buffer[row][(col + 1) % BYTES];
            }
        }
        delay(1000);
}

New function:

void layer_rotate_right(void) 
{
    for (int row = 0; row < LAYERS; row++) {
        unsigned char carry = LED_Buffer[row][BYTES - 1] << 7 ;
        for( int i = 0; i < BYTES; i++ )
        {   
            unsigned char next_carry = LED_Buffer[row][i] << 7 ;
            LED_Buffer[row][i] = (LED_Buffer[row][i] >> 1) | carry ;
            carry = next_carry ;
        }
    }
}
2
This is commonly referred to as rotating a 4 byte array.user3386109
If it aligns on a proper boundary it might be possible to manipulate as a uint32_t* using a a shift | masked_shift (sometimes known as a "barrel roll" or "circular shift"). The bit patterns of the device are important (and may require a 'mix' instead of a shift on, eg, Big Endian).user2864740
"I only could do it with byte shifting, but that is not what I need" ...cool, show us the code.bigwillydos
I edited the post and added the code.RytisBe

2 Answers

2
votes

A specific solution for if the layer is always 4 bytes is to pack the bytes into a uint32_t and apply the rotation to that.

Given:

void layer_rotate_right( uint8_t layer[4] ) 
{
    // Pack...
    uint32_t word = layer[0]<<24 | layer[1]<<16 | layer[2]<<8 | layer[3] ;

    // Rotate...
    uint32_t rotated = word << 31 | word >> 1 ;

    // Unpack...
    layer[0] = rotated >> 24 ;
    layer[1] = (rotated >> 16) & 0xff ;
    layer[2] = (rotated >> 8) & 0xff ;
    layer[3] = rotated & 0xff ;
}

Then:

for (int row = 0; row < LAYERS; row++) 
{
    layer_rotate_right( LED_Buffer[row] )
}

The packing and unpacking is somewhat cumbersome. Given appropriate endianness and alignment you may get away with casting, but as a solution it does not scale.

A more general solution for any size byte array is:

void layer_rotate_right( uint8_t* layer, int len ) 
{
    uint8_t carry = layer[len - 1] << 7 ;
    for( int i = 0; i < len; i++ )
    {   
        uint8_t next_carry = layer[i] << 7 ;
        layer[i] = (layer[i] >> 1) | carry ;
        carry = next_carry ;
    }
}

Then:

for (int row = 0; row < LAYERS; row++) 
{
    layer_rotate_right( LED_Buffer[row], BYTES )
}
1
votes

A different approach would be to use a union. For example,

typedef union{
    uint8_t buff8[4];
    uint32_t buff32;
}led_buffer_t;

Then use this to declare LED_Buffer (e.g. led_buffer_t LED_Buffer[LAYERS] = {0};)

And then use the circular shift answer here: Circular shift in c

I tried it out here: https://onlinegdb.com/ByfcMY1sE