Really challenging and tempting ...
I came up with this structure of the data in the matrix:
where the yellow bits belong to frame[0], the green to frame[1] and the blue to frame[2].
If you look at the data there is a certain pattern:
- Use the first column to apply
- bit 7 of the first (vertical) byte to bit 31 of frame[0]
- bit 6 to bit 19 of frame[0]
- bit 5 to bit 7 of frame[0]
- bit 4 to bit 27 of frame[1]
- etc.
- Decrement the "frame bits" and - if you come below 0
- start with bit 31 for the frame and increment the frame no for this row
- Go on with the vertical byte no 2 etc. until all 12 bytes are done.
That's the principle.
The function requires more lines but seems to be about 5 times as quick ...
See on Wokwi: https://wokwi.com/projects/375508353239239681
I used the famous heart image as an example and added a function to print the matrix result via Serial ...
(This is the standard heart image but coded in 12 vertical bytes.
Sketch:
/*
Forum: https://forum.arduino.cc/t/can-this-array-rotation-be-better/1167029
Wokwi: https://wokwi.com/projects/375508353239239681
*/
// Initialized with "heart" image
uint32_t frame[3] = {
0x3184a444,
0x42081100,
0xa0040000
};
// Initialized with "heart" image
byte rot_frame[12] = {0, 96, 144, 136, 68, 34, 68, 136, 144, 96, 0, 0};
unsigned long startTime = 0;
constexpr byte NoOfTest = 10;
void setup(){
Serial.begin(115200);
Serial.println("Start");
//printMatrix();
Serial.println(F("---convert---"));
startTime = micros();
for (int k= 0;k<NoOfTest;k++) convertFrame();
Serial.print((micros()-startTime)/NoOfTest);
Serial.println(F(" microsec per conversion"));
//printMatrix();
Serial.println(F("---rotate----"));
startTime = micros();
for (int k= 0;k<NoOfTest;k++) rotateFrame();
Serial.print((micros()-startTime)/NoOfTest);
Serial.println(F(" microsec per rotation"));
//printMatrix();
}
void loop(){
}
// Function to convert 8 byte array to 32 bit matrix data
constexpr byte arrLen = 8;
constexpr uint8_t startBitNo[arrLen] = {31, 19, 7, 27, 15, 3, 23, 11};
constexpr uint8_t startFrameIndex[arrLen] = {0,0,0,1,1,1,2,2};
uint8_t frameIndex[arrLen] = {0,0,0,1,1,1,2,2};
uint8_t bitNo[arrLen];
void convertFrame(){
// Prepare arrays
memcpy(bitNo,startBitNo,sizeof bitNo);
memcpy(frameIndex,startFrameIndex,sizeof frameIndex);
for (int i=0; i<3; i++){
frame[i] = 0;
}
// Convert from 8 bit rot_frame to 32 bit frame array
for (int i=0;i<12;i++){
for (int j = 0;j<arrLen;j++){
if (rot_frame[i] & (1 << (7-j))) {
frame[frameIndex[j]] |= (1ul << bitNo[j]);
}
bitNo[j]--;
if (bitNo[j] > 31){
bitNo[j] = 31;
frameIndex[j]++;
}
}
}
}
// Original: Shorter but takes about five times longer
void rotateFrame(){
for (int i=0; i<3; i++){
frame[i] = 0;
}
for(int i=0; i<96; i++){
if(rot_frame[i%12] & (1<<(7-(i/12)))){
frame[i/32] |= (1ul << (31 - (i%32)));
}
}
}
// Functions to print the matrix via Serial
void printBinary(uint32_t val, byte from, byte to, bool CR){
byte bitN = to;
for (int i = from;i<=to;i++,bitN--){
if (val & (1uL << (bitN) )) Serial.print("1");
else Serial.print("0");
}
if (CR) Serial.println();
}
void printMatrix(){
printBinary(frame[0],20,31,true);
printBinary(frame[0],8,19,true);
printBinary(frame[0], 0, 7,false);
printBinary(frame[1], 28,31,true);
printBinary(frame[1],16,27,true);
printBinary(frame[1],4,15,true);
printBinary(frame[1],0,3,false);
printBinary(frame[2],24,31,true);
printBinary(frame[2],12,23,true);
printBinary(frame[2],0,11,true);
}
I hope I did not make too many or severe mistakes while trying to understand the way the coding of the matrix data is done ...