Jau, gleich noch ein Problem hier :-(
Der RF230 bekommt Senderseitig die Aufgabe 4 Byte (0x99, 0xB1, 0x99,
0xB1) mit dem automatischen CRC-16 zu versehen und dann alles zu
verschicken (in Register PHY_TX_PWR das TX_AUTO_CRC_ON Bit setzen). Das
Registerbit ist gesetzt, da ich dessen Status hinterher überprüfe, dh.
die Nachrichten sollten mit CRC16 anhängend geschickt werden.
Das Generator-Polynom laut Datenblatt x^16 + x^12 + x^5 + 1 müsste nach
meiner Rechnung 0xEE11 == '1000.1000.0001.0001' sein.
Im PHR-Feld hab ich vor dem Senden eine 6 drin stehen (4 byte Payload, 2
byte CRC-Anhang, wie in Anleitung beschrieben).
Auf Empfängerseite kommt kein CRC_VALID, sobald der TRX_END Interrupt
aufgetreten ist, deswegen hab ich den durch das CRC16 erzeugten Anhang
ausgelesen und mit dem verglichen, was herauskommen sollte, wenn man die
obigen Daten bei dieser Seite eingibt
(http://www.flechtmann.net/crc/index.php).
Nachricht: 0x99B199B1 == '1001.1001.1011.0001.1001.1001.1011.0001'
Generatorpoly: 0xEE11 == '1000.1000.0001.0001'
=> CRC16-Anhang: '111.0110.0100.0101'
Der Empfänger bringt mir aber folgenden Anhang:
'0111.0110.0100.0101'
Dh. wenn man den Anhang um 1 Bit nach links schiebt stimmen nur die
ersten 5 und die letzen 3 Bit überein.. die 7 Bits dazwischen sind
murks..
Hilfe bitte?!
Grüsse und Danke fürs lesen
Oh oh.. seh grad.. das wurde mir schon mal beantwortet von Jörg..
Rev. A RF230 Chips können das nicht, nur die Rev. B ..
Beitrag "Re: AVR - SPI im MasterMode auch ohne Int-Flag erlaubt?"
"...Falls du noch einen AT86RF230 rev A hast, musst du ja ohnehin auch
noch die CRC-16 mit berechnen beim Empfang, das kann man bequem parallel
mit jedem neu gelesenene Byte ausführen, ohne dass man dadurch insgesamt
langsamer
wird. Beim rev B gibt's dann ein "CRC OK"-Bit, da muss man das nicht
mehr selbst machen. Ob du einen rev A oder B in deinem ZigBit hast,
erfährst du aus dem Versionsregister."
Ok, hat sich damit erledigt.. selbst ist die Frau ;-)
Kommando zurück.. ^^bin scheinbar recht verwirrt gewesen.
Den letzten Satz im Post drüber bitte wegdenken.
Also, da der Rev.A Chip das CRC nicht selber checkt, bzw das CRC_VALID
Bit nicht setzt, muss ich ja selber rechnen. Dann bekomm ich aber ein
Problem, weil das Ergebnis der Zu-Fuss-Rechnung nicht stimmt..
Na mal sehen was ich auf diesem Wege noch so entdecke. Erstmal noch ein
bisschen rumbröseln.. Falls jemand inzwischen ne Idee hat, ich bin ganz
Ohr :-)
Danke und Grüsse
Kannst du bitte mal die genaue Bytereihenfolge aufschreiben, die
du versendest, einschließlich der CRC-Bytes?
Im Moment ist mir das alles etwas konfus... Mir dünkt, dass du
darüber stolperst, dass die Bitreihenfolge bei 802.15.4 andersrum
ist als bei den meisten IEEE-802.x-Standards.
Für einen Frame mit der PSDU 0x99 0xb1 0x99 0xb1 errechne ich als
CRC 0xad75, d. h. der ganze Frame müsste 0x99 0xb1 0x99 0xb1 0x75 0xad
sein, damit die CRC-Prüfung ein OK ergibt.
Die Funktion _crc_ccitt_update() in der avr-libc ist übrigens geeignet,
die CRC-16 eines IEEE-802.15.4-Frames zu testen/ermitteln. Den dort
in der Doku enthaltenen Pseudocode habe ich mal zu folgendem kleinen
Progrämmchen (das ich wohl Axels µracoli als "contributed software"
spendieren werde) umgefusselt:
Wenn du das mit einem kompletten gültigen Frame aufrufst, muss die
CRC als 0x0000 gemeldet werden. Um das mal für das im IEEE
802.15.4-2006 genannte Beispiel zu zeigen:
Man beachte die unterschiedliche Bitreihenfolge im letzten Beispiel
zwischen dem, wie wir die Bits für gewöhnlich in Zahlen schreiben
und der Notation im 802.15.4-Standard.
Bisher hab ich nur 2 Byte verschickt mit selbstgestrickter CRC4. Für
Tests hab ich jetzt mal 0x13 und 0x36 genommen (1.0011.0011.0110), was
mit meinem CRC4 (CRC-Poly = '1011') zu 0x99 0xB1 wird
(1001.1001.1011.0001).
Im normalen Betrieb ändern sich die enthaltenen Nachrichten (laufende
Nummer, Zustände, Sender-Empfänger-Kennung, usw..) natürlich andauernd,
sind aber immer gleich lang.
Nun sind beim gleichzeitigen Betrieb mehrerer Module aber Probleme und
Fehlinterpretationen aufgetreten, die mein CRC4 manchmal nicht
rausgefiltert hat. Das darf aber nicht passieren.
Deswegen will ich jetzt 2x 2 byte schicken (immer noch CRC4 gesichert)
da hab ich schon mal 2-fache Redundanz und dann über alles drüber (0x99
0xB1 0x99 0xB1) das automatische CRC16 vom Chip. Da hoffe ich dann auf
genügend Sicherheit.
Also das PHY_AUTO_CRC Bit setze ich wie gesagt bei der Initialisierung.
Die nachfolgende spi_write_frame(byte1,byte2)-Funktion macht nun dieses
2x 2 byte versenden und erzeugt den Platz für den CRC16-Anhang (PHR=6).
Laut Datenblatt braucht man die 2 Byte für das FCS (CRC16-Anhang) nicht
mit downloaden.. hab ich aber auch schon getestet. Keine Veränderung.
1
// 1 Frame mit 4 byte Payload + CRC in den Speicher des RF230 schreiben =============
Das ist wie geschrieben Senderseitig, weiter kann ich dort ja nicht
reingucken.
Auf Empfängerseite hab ich dann wie oben angegegeben und wie in dem
anderen Post dargestellt (der mit dem SRAM Zugriff) die Bytes 5&6
ausgelesen (per normalem auslesen ;-) und angezeigt. Die sollten ja das
CRC16-Anhängsel, das beim Senden automatisch erzeugt wurde enthalten
(also 15Bit).. und bis auf ein paar Bits in der Mitte sieht das ja auch
schon passend aus.
Ich werd morgen.. äh, heute mein ich, angesichts der Uhrzeit, aber erst
in ein paar Stunden ;-).. mal deine Testnachricht und die aus dem
Datenblatt verschicken und dann sehen was der Empfänger dazu meint.
Dann seh ich klarer wo MSB und LSB stecken und was da sonst noch so
passiert.
Vielen Dank jedenfalls schon mal vorab für deine wie immer sehr
hilfreichen Erläuterungen zum Thema! :)
PS: ich denke die CRC16 Berechnung von der Website macht etwas anderes
als der Chip. Ich hab grad eben mal schnell das Beispielframe aus dem
Datenblatt da drüber gejagt.. die Ergebnisse stimmen nicht überein. Muss
ich aber nochmal nachgucken.. bin schon recht müde heut.
Ich seh grad.. in der Funktion oben^^ im letzten Post sind die beiden
letzten bytes noch verdreht.. Das war bei meinen Tests nicht so. Ich bin
hier an nem anderen Rechner und hab ne alte Version der Funktion
genommen.
Also Reihenfolge wie zu erwarten:
CMD=write frame
PHR=6
byte1
byte2
byte1
byte2
Grüsse
stimmt mit dem Beispiel auf S.48 im Datenblatt des RF230 überein :
1
"...Considering a 5 octet ACK frame. The MHR field consists of 0100.0000 0000.0000 0101.0110 .
2
The leftmost bit (b0) is transmitted first in time.
3
The FCS would be following 0010.0111 1001.1110 .
4
The leftmost bit (r0) is transmitted first in time...."
Ich hatte das im RF230 eingebaute CRC16 Generatorpolynom gestern falsch
von Polynomalschreibweise nach binär übersetzt - Asche auf mein Haupt
Die Nachricht
1
0x40:0x00:0x56
müsste also immer den Anhang
1
0x27:0x9E
ergeben, wenn man mit dem CRC16-GEneratorpolynom (0x01:0x10:0x21)
rangeht.
Wenn ich diese Test-Bytes nun durch den Senderchip (Rev.A) mit
automatischer CRC16-Erzeugung gebe (also PHR=5 und Payload:
0x40:0x00:0x56) dann kommt auf Empfängerseite folgendes an:
1
PHR: 0000.0101 = 0x05 ok
2
byte1: 0100.0000 = 0x40 ok
3
byte2: 0000.0000 = 0x00 ok
4
byte3: 0101.0110 = 0x56 ok
5
crc1: 1100.0101 = 0xC5 äh?
6
crc2: 0011.0001 = 0x31 äh?
Dh. Wirklichkeit und Datenblatt widersprechen sich hier bzw. ich bin zu
blöd..
Ich denke der Rev.A Chip kann nur den CRC16-Check nicht durchführen,
aber die automatische CRC16 Erzeugung beim Senden sollte doch klappen
oder?
Ich hab leider noch kein Datenblatt für die Rev.A Version gefunden.. wo
findet man die bei Atmel?
Dann weiter..
Wenn ich dein obiges 802.15.4 konformes Beispiel mit der Nachricht
1
0x02 0x00 0x6A
mit der Website berechne, komme ich auf
1
0xA3 0x8C bzw. 1010.0011 1000.1100
als CRC16 Anhang.
Deine Berechnung ergibt aber etwas ganz anderes, nämlich:
1
0xE4 0x79 bzw. 1110.0100 0111.1001
Das sieht mir nicht nur nach vertauschten oder invertierten Bits/bytes
aus..
Ich werd mal weiter mit dem Zeugs rumspielen.. irgend eine Logik muss ja
dahinter stecken.
Ok, jetzt hab ichs wohl gefunden (rotieren) und verstehe damit auch
deine Ausführungen, Jörg.. :-)
Die einzelnen zu sendenden Bytes des Frames werden rotiert MSB <-> LSB,
dann wird das CRC16 darüber gejagt, was den Anhang erzeugt. Dieser wird
dann wiederum rotiert MSB <-> LSB und das kommt dann im Empfänger an.
Wäre für mich jetzt noch interessant zu wissen, warum das so ist.. über
SPI kommt doch das MSB immer zuerst in den Framebuffer?.. und da im
Datenblatt des RF230 drin steht, dass der Upload-Pointer beim Senden
minimal genau an der gleichen Stelle wie der Sende-Pointer sein darf,
niemals kleiner, sonst gibts einen Sende-UnderRun-Interrupt, dachte ich,
dass das MSB auch zuerst gesendet wird?..
Warum also wird zum berechnen des CRC16-Anhanges jedes Byte rotiert?
Hat das Vorteile bei der CRC-Rechnung, oder gibts prinzipielle Ursachen?
Ich seh's noch nicht.. vielleicht stoß ich ja drauf, wenn ich das ganze
nun rückwärts programmieren muss.
Umsonst macht so was sicherlich keiner, oder? :-)
Danke für alles und schönes WE noch!
PS: für den stillen Mitleser die Zusammenfassung:
Die Bitreihenfolge im Standard ist einfach andersrum geschrieben, als
wir das normalerweise tun würden. Der besagte ACK-Frame, der als
Beispiel für die FCS-Berechnung genannt ist, beginnt mit 01000000,
aber wenn du dir den Standard anguckst, steht auf der linken Seite ein
"b0" drunter: Bit Nummer 0. Das heißt, das einzig gesetzte Bit in
diesem Octet ist Bit 1, folglich handelt es sich um die Zahl 0x02,
nicht 0x40.
Du musst gar nichts wirklich rotieren, du musst nur den
CRC-Algorithmus entsprechend anpassen (d. h. das Polynom selbst
rotieren). Wie ich dir schon schrob, macht die avr-libc-Funktion
_crc_ccitt_update() es exakt so, wie du es für IEEE 802.15.4 brauchst.
Analog auf der PC-Seite mein obiges Programmschnipsel, das weiter
nichts ist, als die compilierbare Form des Pseudo-Codes, der in der
Doku zu dieser Funktion sowieso schon enthalten war.
Übrigens kannst du beim kontinuierlichen Einlesen des Frames die
Wartezeiten, bis das SPI-Interface wieder das nächste Byte
reingeschoben hat, sinnvoll mit dem Updaten der CRC verbringen. Wenn
ich mich nicht verzählt habe, benötigt _crc_ccitt_update() 17
CPU-Takte, während das SPI minimal (d. h. höchste Taktrate und SPI2X
gesetzt) 16 CPU-Takte für das Reinschieben eines Bytes benötigt.
Damit hast du am Ende des Frames auch sofort die Entscheidung, ob die
CRC-16 OK ist.
Danke für die Tipps.. ich versuche grad den _crc_ccitt_update
Pseudo-Code zu verstehen.. wenigstens ein bisschen.
Die Vorgehensweise scheint ja hochoptimiert zu sein.. den ursprünglichen
CRC-Algorythmus kann ich im Prinzip gar nicht mehr ausmachen, höchstens
den Anfang und das Ende.. dazwischen scheint irgendwie komplett anders
zu laufen und vor allem verdammt kurz. Wahnsinn.
Das hab ich aber richtig verstanden, dass das CRC-Polynom
'x^16+x^12+x^5+1' da schon eingebaut ist, oder?
Jedenfalls bekomme ich bei sauberem Empfang am Ende 'crc == 0' raus,
nachdem ich alle empfangenen Bytes da durchgeschickt habe..
Und eingebaute Fehler in einem der Bytes verursachen 'crc != 0' ..
super.
Da müssen ja Mannjahre drin stecken in den paar Zeilen Code.. wenn ich
mir meine 350 cycles CRC3 dagegen so angucke :-D
Was solls, bin halt kein Informatiker - hab nur 2 rechte Hände :-)
Also nochmal herzliches Dankeschön für deine Antworten!
Wie immer sehr hilfreich.
Joan P. wrote:
> Danke für die Tipps.. ich versuche grad den _crc_ccitt_update> Pseudo-Code zu verstehen.. wenigstens ein bisschen.> Die Vorgehensweise scheint ja hochoptimiert zu sein.. den ursprünglichen> CRC-Algorythmus kann ich im Prinzip gar nicht mehr ausmachen, höchstens> den Anfang und das Ende..
Tut mir leid, ich bin auch kein Informatiker. Ich habe davon nur
verstanden, dass man sich ja letztlich nur um die Bits kümmern
muss, die beim Polynom 1 sind, da nur bei denen die XOR-Verknüpfung
einen Effekt hat. Entsprechend ist die sonst notwendige Schleife
für diese Bits entrollt worden.
> Das hab ich aber richtig verstanden, dass das CRC-Polynom> 'x^16+x^12+x^5+1' da schon eingebaut ist, oder?
Ja.
> Da müssen ja Mannjahre drin stecken in den paar Zeilen Code..
Ich denke, wenn man den ganzen Kram verstanden hat, hat man's in
einem Tag oder zweien geschrieben. Andererseits ist der Vorteil von
CRCs, dass man den Algorithmus nicht unbedingt verstanden haben muss
und sie trotzdem benutzen kann. ;-)