Hallo!
Ich habe ein Array von 54 Byte in meinem ATmega 644p, über SPI
eingelesene Werte. Nun interessiert mich jedes dritte Bit, also aus dem
ersten Byte die Positionen 2 und 5, aus dem 2. Byte die 0, 3 und 6,
dann aus dem dritten Byte 1,4 und 7, dann gehts wieder von vorne los.
Wie code ich sowas effizient? Der Rest des Programms ist C, inline asm
würde aber zur Not auch gehen. Im Prinzip würde ich gern Bit [2] testen,
drei mal rechtsschieben, Bit[2} testen, schieben, testen,... Aber ich
kann ja schlecht die kompletten 54 Byte am Stück schieben. Müsste also
im Prinzip 2Byte schieben, und wenn der Inhalt des oberen Byte komplett
raus geschoben ist, das nächste Byte nachladen.
Hat jemand spontan eine bessere Idee? Fehlen noch wesentliche Infos, die
ich bislang vergessen hab mitzuteilen?
Grüße,
Christoph
Was willst du denn mit den Bits dann machen? Das wär noch interessant.
Im prinzip könntest du schon die 56 Byte durschschieben. In Assambler
mit cpc, dauert halt etwas...
ich denke, ich würde mir eine Schleife bauen, die immer 3 Byte auf die
von dir genannten Bits testet (explizit die drei bit, ohne schieben) und
dann die nächsten 3 Byte durchmacht. Dürfte wohl am schnellsten gehn.
Aber genau sagen kann man das erst, wenn man weiß, was mit den Bits dann
passieren soll.
Sebastian
Christoph schrieb:
> würde aber zur Not auch gehen. Im Prinzip würde ich gern Bit [2] testen,> drei mal rechtsschieben, Bit[2} testen, schieben, testen,...
Das klingt soch schon fast wie wenn es ein vernünftiges Konzept wäre.
Die Frage ist nur, was du unter 'testen' verstehst.
> Aber ich> kann ja schlecht die kompletten 54 Byte am Stück schieben.
Ah, geh.
Deine Abfolge wiederholt sich doch alle 3 Bytes. Und zufällig ergeben
die auch noch in Summe 8 Bits. Passt doch perfekt.
Die Zählung versteh ich nicht ganz:
> also aus dem> ersten Byte die Positionen 2 und 5, aus dem 2. Byte die> 0, 3 und 6, dann aus dem dritten Byte 1,4 und 7,
+ + + + + + + +
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Byte n Byte n+1 Byte n+2
Jeweils die mit + markierten Bits möchtest du haben
1
j=0;
2
for(i=0;i<54;i=i+3)
3
Result[j++]=((Data[i]&0x20)<<2)|// Bit 7
4
((Data[i]&0x04)<<4)|// 6
5
((Data[i+1]&0x80)>>2)|// 5
6
((Data[i+1]&0x10))|// 4
7
((Data[i+1]&0x02)<<2)|// 3
8
((Data[i+2]&0x40)>>4)|// 2
9
((Data[i+2]&0x08)>>2)|// 1
10
((Data[i+2]&0x01)// 0
11
;
In Result hast du jetzt nur noch die dich interessierenden Bits in der
richtigen Reihenfolge.
In den 54 Byte stecken 144 Input Pins, die ich aus einer Boundary Scan
Kette eingelesen habe. Je Pin gibts drei Bit, Input, Output, Output
Enable. Für den Status interessiert mich in diesem Fall nur der Input.
Alle Inputs, die auf low-Pegel liegen, werden in einen Puffer
eingetragen. Ich teste also "wenn am dritten Bit des i-ten Triple low
Pegel ist, schreibe i in den Puffer".
Vermutlich ist Überprüfen von je drei Byte geschickter und schneller,
als die ganze Manipulation des Arrays, und auch besser als das
ausknobeln, an welcher Stelle ich nun prüfe.
Ich muss alle 144 Pins nacheinander durchscannen und Werte
zurückschreiben, daher ist das ganze schon ein wenig zeitkritisch.
Christoph schrieb:
> In den 54 Byte stecken 144 Input Pins, die ich aus einer Boundary Scan> Kette eingelesen habe. Je Pin gibts drei Bit, Input, Output, Output> Enable. Für den Status interessiert mich in diesem Fall nur der Input.> Alle Inputs, die auf low-Pegel liegen, werden in einen Puffer> eingetragen. Ich teste also "wenn am dritten Bit des i-ten Triple low> Pegel ist, schreibe i in den Puffer".
Ach sag das doch gleich.
Da muss man doch gar nicht die Bits extra extrahieren.
Du fasst dein ByteArray als fortlaufendes Bitarray auf.
Bit Nr x findet sich dann in Byte x / 8
Und dort ist es das Bit an der Position 7 - ( x % 8 )
Um das dich interessierende Statusbits des Sensors i zu finden, suchst
du also nach dem Bit Nr 3 * i + 2
Astelle des extensiven Schiebens bei der Ausmaskierung des Bits, würd
ich eine Tabelle mit Masken nehmen.
> Ach sag das doch gleich.
Sorry. :-) Ich bin noch ziemlich unerfahren im Programmieren, manchmal
fehlt mir noch der Blick für die wirklich relevanten Infos...
> + + + + + + + +> 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0> Byte n Byte n+1 Byte n+2
fast. Die Bytes n+1 und n+2 müssen getauscht werden:
+ + + + + + + +
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Byte n Byte n+1 Byte n+2
Um das ganze nicht per Funktionsaufruf zu machen, wäre das ganze dann so
zu lösen, oder (Maske umsortiert, spart wieder berechnungs-Aufwand):
Christoph schrieb:
>> + + + + + + + +>> 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0>> Byte n Byte n+1 Byte n+2>> fast. Die Bytes n+1 und n+2 müssen getauscht werden:>> + + + + + + + +> 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0> Byte n Byte n+1 Byte n+2
Dann stimmt an deiner Zählerei etwas nicht :-)
<Zitat>
Nun interessiert mich jedes dritte Bit
</Zitat>
Fang links zum zählen an und zähl jedes dritte Bit.
Ahhhh. Du fängst bei 0 an zu zählen. Ja geht auch.
Siehst du, das sind so die kleinen Informationen.
Ehe man sich ein Verfahren überlegt, muss man exakt wissen, was wo
steht, in welcher Richtung gezählt wird, etc.
Drum ist es immer gut, sich ein Schaubild zu malen. Die sind nämlich
meist ziemlich eindeutig, was man von textuellen Beschreibungen nicht
sagen kann.
> Um das ganze nicht per Funktionsaufruf zu machen,
kannst du machen.
Aber wahrscheinlich wird der Compiler sowieso da eine inline Version
daraus generieren :-):
Genauso, wie er lokale Variablen rausschmeissen wird.
> wäre das ganze dann so> zu lösen, oder (Maske umsortiert, spart wieder berechnungs-Aufwand):
Da deine Zählweise anders rum ist, hebt sich das dann auf :-)
Also Maske so wie bei mir, aber Berechnung der MaskenNr als i % 8
> [c]> uint8_t bitMask[] = {0x04, 0x20, 0x01, 0x08, 0x40, 0x02, 0x10, 0x80};
Die ist dir wohl etwas durcheinandergekommen :-)
uint8_t byteNr = (i * 3) / 8;
if (!(bsInBuffer[byteNr] & bitMask[i%8]))
Stimmt auch nicht. i ist nicht die Bitnummer.
Lass doch die Hilfs-Variablen drinnen, wenn du ansonsten durcheinander
kommst. Dein Compiler kann viel besser optimieren, als du denkst. Der
schmeisst sie dann wieder raus bzw. hält das Zwischenergbenis in einem
Register. Aber die Übersicht ist für dich als Programmierer mit den
Hilfsvariablen viel besser! Solche Low-Level Optimierungen wie
Funktionen inlinen oder Hilfsvariablen eliminieren oder konstante
Ausdrücke zusammenfassen, überlasst man am Besten dem Compiler.
Probiers mit Papier und Bleistift durch. Oder mach erst mal eine Version
am PC und lass dir die ByteNr und die Maske ausgeben. Dann siehst du
sehr schnell, ob die Zugriffe dort sind, wo du sie haben möchtest.
Nur so als Idee, wenn es auf zeit ankommt:
Der AVR kann in den unteren Registern auch Bit-Operationen direkt
durchführen. D.h. er kann set, clr, tst... in einem Zyklus auf ein Bit
eines der unteren Register anwenden. Das wird vermutlich einen längeren
Assembler Code erfordern, aber an Geschwindigkeit kaum zu übertreffen
sein.
ATMEL hat für solche Operationen bei den neueren CPUs extra ein
'virtulles' GPIO Register dort unten abgelegt (GPIOR0). Es kann mit
allen Bit-Befehlen angesteuert werden, die auch die I/O-Ports
unterstützen, nur das an diesem Register eben keine realen I/O Pinne
hängen.
Gruß, Ulrich