PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bytes parallel ausgeben - Bitmatrix drehen.



Gnom67
30.09.2020, 20:19
Hallo!
Weiß jemand eine effiziente Methode, wie man die jeweils parallelen Bits der jeweils gleichen Stelle von 8 Bytes in ein Byte schreiben kann, um sie dann parallel in einen GPIO-Port zu schreiben? Es geht um die parallele Übertragung von 8 Bytes über 8 serielle GPIO outputs (nicht UART, sondern einfach GPIO Outputs - es geht mir hier auch nicht um Timings oder sowas... es geht sozusagen um das Drehen der Bitmatrix.)

Also 8 Bytes, z,B.
11111000
11111000
00000111
00000111
00000000
00000001
00000010
00000011

Ergibt für das erste Byte 00110101 -> damit werden sozusagen die 8 jeweils ersten Bits der 8 Ausgangsbytes zu einem Byte zusammengefasst und können parallel gesendet werden.
Ergibt für das erste Byte 00110011
Ergibt für das erste Byte 11000000
Ergibt für das erste Byte 11000000
usw. Die Matrix ist dann quasi gedreht oder transformiert.

Spontan würden mir nur Bitoperatoren einfallen.
- Erst alle Bytes mit der Position XORen
- Dann jeweils an die richtige Stelle schieben und mit OR ins Zielbyte kopieren.

OutByte = 0
OutByte = OutByte | (byte1 & 1 << i) << 0
OutByte = OutByte | (byte2 & 1 << i) << 1
OutByte = OutByte | (byte3 & 1 << i) << 2

Für i = 0 bis 7... erscheinen mir da etwas aufwändig. Gibts eine effizientere Lösung.
Wenns Hilfreich ist, könnte man auch 8 Output Bytes erstellen und dann erst ausgeben.

Erstmal würde mich eine generelle Lösung interessieren (für Tests auf einem Arduino/328P).
Am Ende will ich das mit 32-Bit-Werten in einem ESP32 machen. Wie sieht es da aus? Bietet der was handliches dafür.

Moppi
30.09.2020, 20:51
Hallo,

wenn Du Bytes aus Bits, anderer Bytes, zusammensetzen willst, bleiben nur Bitoperatoren.

Vorschlag:



Byte = (B1&1) | ((B2&1)<<1) | ((B3&1)<<2) | ((B4&1)<<3) | ((B5&1)<<4) | ((B6&1)<<5) | ((B7&1)<<6) | ((B8&1)<<7);


Bei solchen Sachen tendiere ich dazu, keine Schleife zu bauen, da dies zusätzliche Zeit kostet (Auswertung der Schleifenbedingung und Rücksprung an den Anfang).
Da nehme ich lieber etwas mehr Bytes an Code in Kauf, aber der wird schnell abgearbeitet.


MfG

Gnom67
01.10.2020, 02:23
Hab nach einigem Googeln was Gutes dazu gefunden...
Beispielcode wesentlich aus dem Kapitel "Transposing a Bit Matrix"
Warren Jr., Henry S. (2013). Hacker's Delight (2 ed.).
Addison Wesley - Pearson Education, Inc. ISBN 978-0-321-84268-8



#include <stdio.h>

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
(byte & 0x80 ? '1' : '0'), \
(byte & 0x40 ? '1' : '0'), \
(byte & 0x20 ? '1' : '0'), \
(byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \
(byte & 0x04 ? '1' : '0'), \
(byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')

int main(void)
{
unsigned char A[8] = {0xf8, 0xf8, 0x07, 0x07, 0x00, 0x01, 0x02, 0x03}; //Array mit Ausgangsbytes
int m = 1;
int n = 1;
unsigned char B[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //Array für Ergebnisbytes
unsigned x, y, t;

for (int i = 0; i < 8; i++) {
printf("Ausgangsbytes "BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(A[i]));
}
printf("\n");

// ********* Hier der eigenliche Code **********

x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m];
y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m];

t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);

t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);

t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
x = t;

B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x;
B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y;

// ********* Ende **********

for (int i = 0; i < 8; i++) {
printf("Ergebnisbytes "BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(B[i]));
}

return 0;
}


Wird auf einem RISC-Prozessor laut der Quelle in 101 Prozessorinstruktionen ausgeführt.

Trotzdem stell ich mir vor, dass sowas nicht selten gebraucht wird. Mit ein paar zusammengeschalteten Latches könnte man das doch wahrscheinlich in wenigen, vielleicht sogar in einem Taktzyklus erledigen. Kennt jemand Prozessoren, die sowas machen?