CRC-Kalkulation effizienter machen?

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

    Hinweis kann nach Kenntnisnahme deaktiviert werden!

    • CRC-Kalkulation effizienter machen?

      Hallo in die Runde!

      Im laufe der Jahre sind bei Bascom immer mehr CRC-Routinen oberhalb der üblichen CRC8 hinzu gekommen, aber leider noch keine CRC-Routine die "beliebig modifizierbar" wäre.
      Es scheitert weniger an dem Setzen andererer Generatorpolynome, als viel mehr solch Parameter wie Polynomlänge.

      Aktuell geht es bei mir um bestehende Übertragungsprotokolle die ich nachbauen will, hier anhand von Pocsag:

      Codewörter mit 32Bit Breite, davon 21Bit Nutzdaten, gefolgt von 10Bit CRC und zuletzt ein Parity-Bit.
      Etliche solcher Codewörter werden in einem DWORD-Array gesammelt. Mein Test-Datensatz besteht z.B. aus 50 solcher Codewörter, die geprüft werden sollen.

      Gebastelt habe ich mir folgendes:

      BASCOM Source Code

      1. Pruefen:
      2. Print "Es wurden ";Codewords;" Codewörter empfaangen, prüfe Parity:"
      3. i = 0 'i, j und k sind byte-Variablen für verschiedene Zwecke
      4. j = 0
      5. k = 0
      6. For i = 1 to Codewords
      7. Dwordbuffer = Codeword(i)
      8. Gosub Parity2
      9. If Parity = 0 then
      10. Print "CW ";i;" h";Hex(Dwordbuffer);" ist Even"
      11. k = k + 1
      12. else
      13. Print "CW ";i;" h";Hex(Dwordbuffer);" ist Odd"
      14. end If
      15. next
      16. Print "Die Parität ist über ";i;" Codewörter Even"
      17. For i = 1 to Codewords
      18. CRC = Codeword(i)
      19. Gosub PocCRC
      20. If CRC = 0 then
      21. Print "CW ";i;" h";Hex(Dwordbuffer);" CRC = ";CRC
      22. k = k + 1
      23. else
      24. Print "CW ";i;" h";Hex(Dwordbuffer);" CRC Fehler = ";CRC
      25. end If
      26. Next
      27. Print k;" Codewörter mit korrekter CTC"
      28. Daten = 0
      29. Return
      30. Parity2:
      31. 'Print "Parity2..."
      32. Pcheck = 0
      33. For j = 0 to 31
      34. If Dwordbuffer.j = 1 then Pcheck = Pcheck + 1
      35. Next
      36. ParitySingle = Pcheck / 2
      37. Parity = Frac(ParitySingle)
      38. Return
      39. PocCRC:
      40. Print "Codeword mit Parity = h";Hex(CRC);" und b";Bin(CRC)
      41. Shift CRC, Right, 1 'Entferne das Paritybit (LSB).
      42. 'Bit31 bleibt immer 0. das MSB (Adress/Nachrichtenbit) liegt nun auf Bit 30
      43. Print "Codewort ohne Parity = h";Hex(CRC);" und b";Bin(CRC)
      44. While CRC > 1024 'so lange Codeword > 10Bit groß...
      45. Select Case CRC
      46. Case &h00000000 to &h000007FF : L = 0
      47. Case &h00000800 to &h00000FFF : L = 1
      48. Case &h00001000 to &h00001FFF : L = 2
      49. Case &h00002000 to &h00003FFF : L = 3
      50. Case &h00004000 to &h00007FFF : L = 4
      51. Case &h00008000 to &h0000FFFF : L = 5
      52. Case &h00010000 to &h0001FFFF : L = 6
      53. Case &h00020000 to &h0003FFFF : L = 7
      54. Case &h00040000 to &h0007FFFF : L = 8
      55. Case &h00080000 to &h000FFFFF : L = 9
      56. Case &h00100000 to &h001FFFFF : L = 10
      57. Case &h00200000 to &h003FFFFF : L = 11
      58. Case &h00400000 to &h007FFFFF : L = 12
      59. Case &h00800000 to &h00FFFFFF : L = 13
      60. Case &h01000000 to &h01FFFFFF : L = 14
      61. Case &h02000000 to &h03FFFFFF : L = 15
      62. Case &h04000000 to &h07FFFFFF : L = 16
      63. Case &h08000000 to &h0FFFFFFF : L = 17
      64. Case &h10000000 to &h1FFFFFFF : L = 18
      65. Case &h20000000 to &h3FFFFFFF : L = 19
      66. Case &h40000000 to &h7FFFFFFF : L = 20
      67. End Select
      68. PolShift = Pocpolynom 'Generatorpolynom &h769 laden
      69. If L > 0 then
      70. Shift PolShift, Left, L 'Polynom an obersten Bit ausrichten
      71. end if
      72. Print "Shiftlänge = ";L;" und Ergebnis = b";Bin(Polshift)
      73. CRC = CRC XOR PolShift
      74. Print "Zwischenergebnis b";Bin(CRC)
      75. wend
      76. Return
      Display All


      Es wird also in der ersten Phase die Parity geprüft.
      Im zweiten Schritt wird die CRC jedes DWORD's geprüft.

      Im Prinzip funktioniert das auch....Protokollausdruck:

      Source Code

      1. Codeword mit Parity = h7A89C197 und b01111010100010011100000110010111 Korrekt
      2. Codewort ohne Parity = h3D44E0CB und b00111101010001001110000011001011 Korrekt
      3. Shiftlänge = 19 und Ergebnis = b00111011010010000000000000000000 Korrekt
      4. Zwischenergebnis b00000110000011001110000011001011 Korrekt
      5. Shiftlänge = 16 und Ergebnis = b00000111011010010000000000000000 Korrekt
      6. Zwischenergebnis b00000001011001011110000011001011 Korrekt
      7. Shiftlänge = 14 und Ergebnis = b00000001110110100100000000000000 Korrekt
      8. Zwischenergebnis b00000000101111111010000011001011 Korrekt
      9. Shiftlänge = 13 und Ergebnis = b00000000111011010010000000000000 Korrekt
      10. Zwischenergebnis b00000000010100101000000011001011 Korrekt
      11. Shiftlänge = 12 und Ergebnis = b00000000011101101001000000000000 Korrekt
      12. Zwischenergebnis b00000000001001000001000011001011 Korrekt
      13. Shiftlänge = 11 und Ergebnis = b00000000001110110100100000000000 Korrekt
      14. Zwischenergebnis b00000000000111110101100011001011 Korrekt
      15. Shiftlänge = 10 und Ergebnis = b00000000000111011010010000000000 Korrekt
      16. Zwischenergebnis b00000000000000101111110011001011 Korrekt
      17. Shiftlänge = 7 und Ergebnis = b00000000000000111011010010000000 Korrekt
      18. Zwischenergebnis b00000000000000010100100001001011 Korrekt
      19. Shiftlänge = 6 und Ergebnis = b00000000000000011101101001000000 Korrekt
      20. Zwischenergebnis b00000000000000001001001000001011 Korrekt
      21. Shiftlänge = 5 und Ergebnis = b00000000000000001110110100100000 Korrekt
      22. Zwischenergebnis b00000000000000000111111100101011 Korrekt
      23. Shiftlänge = 4 und Ergebnis = b00000000000000000111011010010000 Korrekt
      24. Zwischenergebnis b00000000000000000000100110111011 Korrekt
      25. Shiftlänge = 1 und Ergebnis = b00000000000000000000111011010010 Korrekt
      26. Zwischenergebnis b00000000000000000000011101101001 Korrekt
      27. Shiftlänge = 0 und Ergebnis = b00000000000000000000011101101001 Korrekt
      28. Zwischenergebnis b00000000000000000000000000000000 Perfekt
      29. CW 1 h00000000 CRC = 0
      Display All

      Soweit funktioniert alles, allerdings mit etwas suboptimaler Effizienz:
      Während der Parity-Check der 50 Dwörter gefühlt im einstelligen ms-Bereich durchrast, dauert die CRC-Berechnung über alle 50 Testdatensätze gefühlt 20 Sekunden. :sleeping:

      Läuft auf einem ATMEGA324PB mit Baudquarz auf 3,6864MHz.
      Freilich: Die UART-Ausgaben (115200Bd) mögen etwas bremsen und können freilich raus genommen werden.
      Aber die Rechenzeit ist derart brutal das es m.E. kaum was mit dem UART zu tun hat.
      Und in der Phase wo diese Routine oben läuft, macht der µC sonst nichts anderes nebenher.

      Ergo: Das DWORD-Array, das Kopieren von DWORD und die Parity prüfen läuft fix,
      Das was bremst muss irgendwas im unteren Teil, dem Label "PocCRC" sein.
      Also die Select Case-Funktion, die Verschiebug des Generatorpolynoms in DWORD PolShift, oder die XOR.Berechnung.

      Das solch eine CRC-Prüfung zufuß nicht im µs geht ist klar. Aber wünschenswert wäre in jedem Fall etwas im Bereich 10-100ms maximal statt knappe 20 Sekunden.
      Allerdings sehe ich den Flaschenhals gerade nicht...wo dran harkt es?

      Jürgen
    • Das Nadelöhr ist meist in dem Programmteil, der am häufigsten durchlaufen wird.
      Das dürfte wohl der While-Block ab Zeile 57 sein.

      Ohne große Mühe könnte man also mal den Codteil in den Zeilen Zeilen 61 bis 81 optimieren.

      BASCOM Source Code

      1. Select Case CRC
      2. Case Is < &h 800 : L = 0
      3. Case Is < &h100 : L = 1
      4. und nach diesem Schema fortsetzen.
      5. Case &h00001000 to &h00001FFF : L = 2
      6. Case &h00002000 to &h00003FFF : L = 3
      7. Case &h00004000 to &h00007FFF : L = 4
      8. Case &h00008000 to &h0000FFFF : L = 5
      9. Case &h00010000 to &h0001FFFF : L = 6
      10. Case &h00020000 to &h0003FFFF : L = 7
      11. Case &h00040000 to &h0007FFFF : L = 8
      12. Case &h00080000 to &h000FFFFF : L = 9
      13. Case &h00100000 to &h001FFFFF : L = 10
      14. Case &h00200000 to &h003FFFFF : L = 11
      15. Case &h00400000 to &h007FFFFF : L = 12
      16. Case &h00800000 to &h00FFFFFF : L = 13
      17. Case &h01000000 to &h01FFFFFF : L = 14
      18. Case &h02000000 to &h03FFFFFF : L = 15
      19. Case &h04000000 to &h07FFFFFF : L = 16
      20. Case &h08000000 to &h0FFFFFFF : L = 17
      21. Case &h10000000 to &h1FFFFFFF : L = 18
      22. Case &h20000000 to &h3FFFFFFF : L = 19
      23. Case &h40000000 to &h7FFFFFFF : L = 20
      24. End Select
      Display All

      Du kannst den Simulator bemühen, um die Laufzeit zu ermitteln von
      1. deinem aktuellen Code
      2. bei dem Code nach obigem Muster optimiert
      3. und Alternativ mit If ElseIf ElseIf usw.


      Dann entscheidest du dich für die schnellste.

      Vermutlich wird das aber nicht ausreichen.
      Von da sind weitere Optimierungen zu prüfen.

      Z.B. anstelle von
      ErgebnisSingle = dWordWert / 2
      zu rechnen kannst du auch den DWert einfach 1x rechts Shiften.

      Was ich jetzt nicht verstehe ist folgendes.

      Du hast mehrere DWord-Werte (in einem Array).
      Jeder einzelne Wert hat 21 Bit Nutzdaten, und wird abgesichert durch einen 10 Bit CRC Wert und noch zusätzlich mit einem Paritätsbit.
      Ich finde das schon ungewöhnlich. Aber kann ja sein.

      Von der Verschlüsselungsseite her betrachtet:
      Wenn ich nun 21 Bit Nutzdaten habe, dann würde ich doch von diesen die 10 Bit CRC Summe generieren und dann die Bits zusammen setzen und zum Schluss über Bit 31 bis 1 die Parität berechnen und in Bit 0 setzen.

      Zum entschlüsseln geht das dann umgekehrt. zuerst die Bits prüfen, von Bit 31 bis 0. Soweit machst du das ja auch. Dann muss ein bestimmtes Ergebnis, eben Odd oder Even heraus kommen.
      Das CRC musst du dann aber doch wieder von den höchsten 21 Bits berechnen oder nicht und dann mit dem gesendeten CRC vergleichen. Sehe ich das falsch?

      Vor längerem habe ich mal bezüglich CRC-Berechnung bei Wikipedia einen Eintrag gefunden. Da wurde haarklein erklärt, wie CRC berechnet wird.
      Wenn man das auf Bitebene macht und mit XOR und was man noch braucht, sollte das deutlich schneller gehen, wie in deinem Basic-Code.

      Vielleicht ist das für dich eine Inspirationsquelle.

      Nachtrag:
      Ich glaube dies war die Quelle.
    • Stell doch mal testweise so einen Vorteiler 8 ein.
      (gleiche Baudrate und nat. auch nur ein Achtel in der SW deklariert)
      Verschlechtert sich die Zeit für die Berechnung dann um fast eine Größenordnung oder
      nur um ein paar magere Prozentpunkte?


      Source Code

      1. CRC = &H0000_1000
      2. do
      3. For m = 1 to 99
      4. For n = 1 to 50
      5. incr CRC
      6. Select Case CRC
      7. Case &h00000000 to &h000007FF : L = 0
      8. Case &h00000800 to &h00000FFF : L = 1
      9. Case &h00001000 to &h00001FFF : L = 2
      10. Case &h00002000 to &h00003FFF : L = 3
      11. Case &h00004000 to &h00007FFF : L = 4
      12. Case &h00008000 to &h0000FFFF : L = 5
      13. Case &h00010000 to &h0001FFFF : L = 6
      14. Case &h00020000 to &h0003FFFF : L = 7
      15. Case &h00040000 to &h0007FFFF : L = 8
      16. Case &h00080000 to &h000FFFFF : L = 9
      17. Case &h00100000 to &h001FFFFF : L = 10
      18. Case &h00200000 to &h003FFFFF : L = 11
      19. Case &h00400000 to &h007FFFFF : L = 12
      20. Case &h00800000 to &h00FFFFFF : L = 13
      21. Case &h01000000 to &h01FFFFFF : L = 14
      22. Case &h02000000 to &h03FFFFFF : L = 15
      23. Case &h04000000 to &h07FFFFFF : L = 16
      24. Case &h08000000 to &h0FFFFFFF : L = 17
      25. Case &h10000000 to &h1FFFFFFF : L = 18
      26. Case &h20000000 to &h3FFFFFFF : L = 19
      27. Case &h40000000 to &h7FFFFFFF : L = 20
      28. End Select
      29. L_str = str (L)
      30. n_str = str (n)
      31. m_str = str (m)
      32. 'meine printbefehle;
      33. next n
      34. next m
      35. loop
      36. end
      Display All

      In dem Test ( nur zur Veranschaulichung ) bleibt es nat. bei L = 2 - aber - der Unterschied im Durchlauf zwischen 10MHz und 1.25MHz sind bei mir nur ca. 6% ->
      also die Ausgabe zum Display ist der größere Teil der Aufgaben (bei mir eben bei 9600Baud)

      The post was edited 2 times, last by port ().

    • Hallo in die Runde!

      Mit ein Kernproblem war offenbar der komplette Programmumfang.

      Da das Evaluationsboard zum SX1231 / SX1231h vom Semtech nicht mehr produziert wird, habe ich mir vor einiger Zeit zwei eigene Evaluationsboards zu den RFM69H Transceiver gebastelt nach groben Vorbild der Evaluationssoftware von Semtech.

      Quasi ein Mega324PB mit 24 LowCurrent-LED's und eben dem RFM69H Modul.
      Und das Bascom-Projekt hatte dann schnell mehrere tausend Zeilen an Unterfunktionen die aktuell nicht gebraucht wurden, das selbe mit etlichen ungenutzten Variablen.

      Hatte das gestern Abend noch weitgehend so aufgeräumt das nur die aktuellen Funktionen übrig blieben. Statt einer Flash-Auslastung von 89% sagt Bascom beim Combilieren nun 21%.

      Und siehe da: Er braucht für die CRC-Berechnung nur noch deutlich unter 1 Sekunde, eher ne halbe Sekunde.


      Michael wrote:

      Allein die 134 reinen Text-Zeichen, die in einem Durchlauf der ProCRC: anfallen, brauchen schon etwa 1,16 ms, da ist die Wiederholung bei While-Wend gar nicht mitgezählt.
      Jedes While-Wend bringt nochmal 0,643 ms mit.
      Bei 100 While-Schleifen hast du also 65 ms reine Textausgabe in der Routine.
      Das wäre absolut OK gewesen. Wobei dennoch die Frage bleibt ob es da effizientere Tricks gibt.


      Mitch64 wrote:

      Ohne große Mühe könnte man also mal den Codteil in den Zeilen Zeilen 61 bis 81 optimieren.
      Ok, werde ich mal versuchen.

      Mitch64 wrote:

      Was ich jetzt nicht verstehe ist folgendes.

      Du hast mehrere DWord-Werte (in einem Array).
      Jeder einzelne Wert hat 21 Bit Nutzdaten, und wird abgesichert durch einen 10 Bit CRC Wert und noch zusätzlich mit einem Paritätsbit.
      Ich finde das schon ungewöhnlich. Aber kann ja sein.
      Da hast du recht! Ich würde das so auch nicht machen. In eigenen Projekten habe ich mich bislang immer mit den CRC8 und CRC16-Funktionen von Bascom verlassen.

      Nur in diesem Fall muss ich berücksichtigen was Entwickler vor knapp 40 Jahren entwickelt haben und bis heute standardisiert ist.
      itu.int/dms_pubrec/itu-r/rec/m…584-2-199711-I!!PDF-E.pdf


      Mitch64 wrote:

      Zum entschlüsseln geht das dann umgekehrt. zuerst die Bits prüfen, von Bit 31 bis 0. Soweit machst du das ja auch. Dann muss ein bestimmtes Ergebnis, eben Odd oder Even heraus kommen.
      Das CRC musst du dann aber doch wieder von den höchsten 21 Bits berechnen oder nicht und dann mit dem gesendeten CRC vergleichen. Sehe ich das falsch?
      Umgekehrt, nämlich so wie du es zum Verschlüsseln geschrieben hast:
      Verschlüsseln vor dem senden: Die 10 CRC-Bits von den 21Nutzbits berechnen und anhängen = 31 Bit, zuletzt am Schluss das Paritibit = 32Bit.

      Entschlüsseln zuerst die Parität prüfen und das Paritybit im LSB verwerfen, übrig bleiben 31Bit. Dann so oft mit dem Generatorpolynom XOR bis Restwert = 0
      Bleibt ein Restwert von >0 liegt ein Bitfehler vor.

      Achja...und das mit 10Bit CRC + Parity ist nicht das Einzige an Hau.
      So werden, bei unverschlüsselter Informationsübertragung in diesen 21 übertragen: MSB-Bit.21 Unterscheidung ob nachfolgend eine Adresse (0) oder eine Nachricht (1) folgt.
      In den restlichen 20Bit wird dann i.d.R. ASCII mit 7Bit übertragen womit in einem solchen Codewort 2,86 Zeichen passen.
      Daher braucht es ein Array von verflixt vielen solcher 32Bit-Häppchen um sinnvollen Inhalt zu übertragen.

      Jürgen
    • Hallo!

      Pluto25 wrote:

      Schneller, da Bascom nicht warten muss bis der Usart ausgesprochen hat:Config Serialout = Buffered , Size = 'gross genug'
      was bei Deinen ca 100kb wohl nicht hin haut aber wenigstens kann er schon weiterrechnen während übertragen wird wodurch sich Berechnung und Ausgabe nicht mehr (völlig) addieren.
      Ok...UART-Buffer habe ich bislang nur für das einlesen des UART's benutzt, zuletzt bei nem GPS-Empfänger.
      Zum ausgeben bislang nicht
      Das mag auch daran liegen, das ich den UART in gefühlt 95% all meiner Projekte eher als Entwicklungstool nutze. Eben um zu sehen in welcher Schleife er gerade hängt

      Jürgen
    • @DG7GJ
      Biste schon schneller geworden mit deinem Code?

      Für deinen Parity-Check hätte ich dir folgende Routine anzubieten.

      BASCOM Source Code: Parity-Prüfung

      1. ' ----------------------------------------------
      2. ' Prüft das empfangene CodeWord auf Parität
      3. ' Parameter: value: CodeWord (DWord)
      4. ' Rückgabe: Parität (Byte)
      5. ' 0 bei Even und 1 bei Odd
      6. ' ----------------------------------------------
      7. Function CheckParity(Byref value as DWord) as Byte
      8. ' 2643 Takte
      9. ' Wenn i und k als globale Variablen verwendet werden
      10. ' k = 0
      11. ' For i = 0 to 31
      12. ' if value.i = 1 then Incr k
      13. ' Next
      14. ' CheckParity = k and 1
      15. ' 330 Takte
      16. ' In Assembler sind Variable i und k nicht notwendig. Register werden verwendet.
      17. LoadAdr value , X ' Adresse von Parameter nach Reg. X
      18. !Clr r16 ' Zähler für 1er
      19. !LDI r17,32 ' 32 Bits bearbeiten/shiften
      20. !LD r20,x+ ' Parameter ab Reg. r20 laden
      21. !LD r21,x+
      22. !LD r22,x+
      23. !LD r23,x
      24. _ParCheck_Loop:
      25. !LSR r23
      26. !ROR r22
      27. !ROR r21
      28. !ROR r20
      29. !BRCC _ParCheck_Next
      30. !INC r16 ' 1er zählen
      31. _ParCheck_Next:
      32. !DEC r17 ' Bitzähler
      33. !BRNE _ParCheck_Loop
      34. !ANDI r16,1
      35. LoadAdr CheckParity , X
      36. !ST x, r16
      37. End Function
      Display All
      Deine Ursprüngliche Parity-Routine brauchte 3342 Takte.
      Meine obige, wenn man die Basic-Variante verwendet noch 2643 Takte.

      In Assembler sind es 330 Takte, also rund 10x schneller als deine Routine.

      Wäre ja schon mal ein Angang.
    • Hallo!

      Hmm, mit Assembler habe ich mich noch nie auseinandergesetzt.
      Muss ich noch ein wenig grübeln wie dein Assembler-Code funktioniert.

      Denn das Dingen ist ja:
      Um das Pocsag-Projekt "anständig" zu machen mit einem RFM69H muss ich den Parity-Check in Echtzeit machen.

      Heißt:
      Der RFM69H erkennt das Dotting, immerhin über 500Bit 101010...und startet seine internen AFC und RSSI-Funktionen.
      Sobald er das Synchronisationswort empfängt, schaufelt er die Daten mit 1200Baud in sein FIFO.
      Mittels FIFO Level-INT hole ich die Daten in Häppchen von 32Bytes ab.
      Blöder weise aber erkennt der RFM69H kein Ende der Daten. Werden keine Nutzdaten mehr empfangen, landet in der selben Geschwindigkeit (1200Bd) Mülldaten im FIFO.

      Somit muss ich bei jedem 32Byte-Häppchen das ich aus dem FIFO hole die Parity checken um ein Indiz zu haben wo die Nutzdaten aufhören.
      Meine alte Parity-Prüfung war flott genug dafür - aber 10x schneller mit Assembler hört sich verlockend an.

      Auf der anderen Seite ist aber mein Projekt noch im reinen Versuchsstadium.
      Vielmehr will/wollte ich gucken, ob die günstigen SX1231h die auf den RFM69H sitzen prinzipiell Pocsag-tauglich sind.
      Für eine Endanwendung wird wahrscheinlich ein gänzlich anderer Funkchip zum Einsatz kommen. Entweder was moderneres von Semtech wie SX1261/2 oder SX1276/8 oder von Texas Instruments.

      Jürgen
    • Ist das Thema bei dir noch aktuell?

      Ich konnte mittlerweile den Code Testen (Simulator).
      Jetzt habe ich auch eine kompakte CRC-10 Routine, die ist in Basic geschrieben und benötigt ca. 6300 Takte pro Codeword (32 Bit).

      Du kannst das selber mal ausprobieren.

      Hier der Code und die neuen Routinen für
      - CheckParity()
      - CheckCRC()

      Bitte Rückmelden, ob der Code so funktioniert.

      Edit:
      Den Code sollte man auch hinzufügen, ich Bachel a_27_b277ca12

      BASCOM Source Code: Lauffähiger Beispielcode

      1. $regfile = "m324pbdef.dat"
      2. $crystal = 3686400
      3. $HWStack = 48
      4. $SWStack = 48
      5. $Framesize = 48
      6. Config SubMode = new ' Deklaration Routinen entfällt
      7. Config Base = 1
      8. Const True = 1
      9. Const False = 0
      10. Const CODEWORDSMAX = 7
      11. Dim CodeWord(CODEWORDSMAX) as DWord
      12. Dim CodeWords as Byte
      13. Dim DWordBuffer as DWord
      14. Dim CRC as DWord
      15. Dim i , j , k as Byte
      16. Dim Parity as Single
      17. Dim Daten as Byte
      18. Dim PCheck as Byte
      19. Dim ParitySingle as Single
      20. Dim L as Byte
      21. Dim PolShift as DWord
      22. Const POCPOLYNOM = &h769 ' Polynomfür CRC10 Berechnung
      23. ' eigene Routinen
      24. Dim Result as Byte
      25. 'Dim Param as Byte
      26. 'Param = &h7A
      27. ' ----------------------------------------------
      28. ' Prüft das empfangene CodeWord auf Parität
      29. ' Parameter: value: CodeWord (DWord)
      30. ' Rückgabe: Parität (Byte)
      31. ' 0 bei Even und 1 bei Odd
      32. ' ----------------------------------------------
      33. Function CheckParity(Byref value as DWord) as Byte
      34. ' 2643 Takte
      35. ' Wenn i und k als globale Variablen verwendet werden
      36. ' k = 0
      37. ' For i = 0 to 31
      38. ' if value.i = 1 then Incr k
      39. ' Next
      40. ' CheckParity = k and 1
      41. ' 330 Takte
      42. ' In Assembler sind Variable i und k nicht notwendig. Register werden verwendet.
      43. LoadAdr value , X ' Adresse von Parameter nach Reg. X
      44. !Clr r16 ' Zähler für 1er
      45. !LDI r17,32 ' 32 Bits bearbeiten/shiften
      46. !LD r20,x+ ' Parameter ab Reg. r20 laden
      47. !LD r21,x+
      48. !LD r22,x+
      49. !LD r23,x
      50. _ParCheck_Loop:
      51. !LSR r23
      52. !ROR r22
      53. !ROR r21
      54. !ROR r20
      55. !BRCC _ParCheck_Next
      56. !INC r16 ' 1er zählen
      57. _ParCheck_Next:
      58. !DEC r17 ' Bitzähler
      59. !BRNE _ParCheck_Loop
      60. !ANDI r16,1
      61. LoadAdr CheckParity , X
      62. !ST x, r16
      63. End Function
      64. ' ----------------------------------------------
      65. ' Prüft CRC des empfangenen CodeWords
      66. ' Parameter: value: CodeWord (DWord)
      67. ' Rückgabe: True (1), wenn CRC OK, sonst False (0)
      68. ' ----------------------------------------------
      69. Function CheckCRC(ByRef value as DWord) as Byte
      70. 'Function CheckCRC10(byval Input32 As DWord) As Byte
      71. Local I As Byte
      72. Local BitVal As Byte
      73. Local Crc As Word ' 10-Bit Register (max 1023)
      74. Local Poly As Word
      75. 'Local Mask As DWord
      76. Crc = 0
      77. Poly = POCPOLYNOM ' Polynom: 11101101001
      78. BitVal = 0
      79. ' Prüfe Bits von Bit 31 bis Bit 1 (Bit 0 wird ignoriert = Paritätsbit)
      80. For I = 31 To 1 Step -1
      81. ' Bit I zu prüfen
      82. BitVal = value.I
      83. ' MSB des CRC prüfen (Bit 9)
      84. If Crc.9 = 1 then
      85. ' MSB ist 1 ? nach links schieben + neues Bit + XOR
      86. Shift Crc, Left, 1
      87. Crc = Crc Or BitVal
      88. Crc = Crc Xor Poly
      89. Else
      90. ' MSB ist 0 ? nur schieben + neues Bit
      91. Shift Crc, Left, 1
      92. Crc = Crc Or BitVal
      93. End If
      94. Next I
      95. ' CRC auf 10 Bit beschränken (optional, da Word = 16 Bit)
      96. Crc = Crc And 1023 ' 1023 = &B1111111111
      97. ' Rückgabe: True (1) wenn CRC = 0, sonst False (0)
      98. If Crc = 0 Then
      99. CheckCRC = True ' OK
      100. Else
      101. CheckCRC = False ' Fehler
      102. End If
      103. End Function
      104. ' Init
      105. CodeWords = 1
      106. Codeword(_base) = &h7A89_C197
      107. ' ----------------------------------------------------------------------------
      108. ' Hauptschleife
      109. ' ----------------------------------------------------------------------------
      110. Do
      111. Gosub Pruefen ' Dein ursprünglicher Code 137303 Takte (mit Print)
      112. Break
      113. ' Neue Variante
      114. DWordBuffer = CodeWord(_base)
      115. Result = CheckParity(DWordBuffer) ' ca. 6900 Takte (bis zum nächten Break)
      116. If Result = 0 then
      117. Print "Parität ist Even!"
      118. Else
      119. Print "Parität ist Odd!"
      120. End If
      121. Result = CheckCRC(DWordBuffer)
      122. If Result = True then
      123. Print "CRC OK"
      124. Else
      125. Print "CRC nicht OK!"
      126. End If
      127. Break
      128. Loop
      129. Pruefen:
      130. Print "Es wurden ";Codewords;" Codewörter empfaangen, prüfe Parity:"
      131. i = 0 'i, j und k sind byte-Variablen für verschiedene Zwecke
      132. j = 0
      133. k = 0
      134. For i = 1 to Codewords
      135. Dwordbuffer = Codeword(i)
      136. Gosub Parity2 ' alte Variante 3342 Takte
      137. If Parity = 0 then
      138. Print "CW ";i;" h";Hex(Dwordbuffer);" ist Even"
      139. k = k + 1
      140. else
      141. Print "CW ";i;" h";Hex(Dwordbuffer);" ist Odd"
      142. end If
      143. next
      144. Print "Die Parität ist über ";i;" Codewörter Even"
      145. For i = 1 to Codewords
      146. CRC = Codeword(i)
      147. Gosub PocCRC ' alte Variante 109492 Takte
      148. If CRC = 0 then
      149. Print "CW ";i;" h";Hex(Dwordbuffer);" CRC = ";CRC
      150. k = k + 1
      151. else
      152. Print "CW ";i;" h";Hex(Dwordbuffer);" CRC Fehler = ";CRC
      153. end If
      154. Next
      155. Print k;" Codewörter mit korrekter CTC"
      156. Daten = 0
      157. Return
      158. Parity2:
      159. 'Print "Parity2..."
      160. Pcheck = 0
      161. For j = 0 to 31
      162. If Dwordbuffer.j = 1 then Pcheck = Pcheck + 1
      163. Next
      164. ParitySingle = Pcheck / 2
      165. Parity = Frac(ParitySingle)
      166. Return
      167. PocCRC:
      168. Print "Codeword mit Parity = h";Hex(CRC);" und b";Bin(CRC)
      169. Shift CRC, Right, 1 'Entferne das Paritybit (LSB).
      170. 'Bit31 bleibt immer 0. das MSB (Adress/Nachrichtenbit) liegt nun auf Bit 30
      171. Print "Codewort ohne Parity = h";Hex(CRC);" und b";Bin(CRC)
      172. While CRC > 1024 'so lange Codeword > 10Bit groß...
      173. Select Case CRC
      174. Case &h00000000 to &h000007FF : L = 0
      175. Case &h00000800 to &h00000FFF : L = 1
      176. Case &h00001000 to &h00001FFF : L = 2
      177. Case &h00002000 to &h00003FFF : L = 3
      178. Case &h00004000 to &h00007FFF : L = 4
      179. Case &h00008000 to &h0000FFFF : L = 5
      180. Case &h00010000 to &h0001FFFF : L = 6
      181. Case &h00020000 to &h0003FFFF : L = 7
      182. Case &h00040000 to &h0007FFFF : L = 8
      183. Case &h00080000 to &h000FFFFF : L = 9
      184. Case &h00100000 to &h001FFFFF : L = 10
      185. Case &h00200000 to &h003FFFFF : L = 11
      186. Case &h00400000 to &h007FFFFF : L = 12
      187. Case &h00800000 to &h00FFFFFF : L = 13
      188. Case &h01000000 to &h01FFFFFF : L = 14
      189. Case &h02000000 to &h03FFFFFF : L = 15
      190. Case &h04000000 to &h07FFFFFF : L = 16
      191. Case &h08000000 to &h0FFFFFFF : L = 17
      192. Case &h10000000 to &h1FFFFFFF : L = 18
      193. Case &h20000000 to &h3FFFFFFF : L = 19
      194. Case &h40000000 to &h7FFFFFFF : L = 20
      195. End Select
      196. PolShift = Pocpolynom 'Generatorpolynom &h769 laden
      197. If L > 0 then
      198. Shift PolShift, Left, L 'Polynom an obersten Bit ausrichten
      199. end if
      200. Print "Shiftlänge = ";L;" und Ergebnis = b";Bin(Polshift)
      201. CRC = CRC XOR PolShift
      202. Print "Zwischenergebnis b";Bin(CRC)
      203. wend
      204. Return
      Display All
    • Hallo Mitch!

      Mitch64 wrote:

      Ist das Thema bei dir noch aktuell?
      Jawoll, auch wenn ich mal wieder an mehreren Bascom-Projekten parallel werkel und dieses Projekt gestern pausierte.

      Einer meiner Evaluationsboards :
      Board2.jpg
      Hat ein Array an Testdaten mit anfangs 50 Dwords und seit Sonntag erweitert auf 84 Dwords und sendet diese bei 865MHz im Minutenzyklus aus dem Nachbarzimmer aus.
      Parallel daneben empfange ich die Aussendungen via SDR und einem Decodierprogramm "Poc32" um das gesendete Format zu prüfen.
      Das andere Evaluationsboard liegt neben mir und soll versuchen die Aussendungen möglichst Effizient zu empfangen.

      Und ne: Ich versuche da nicht dieses deutlich über 40 Jahre alte Protokoll zu erlernen um damit ernsthaft Daten zu übertragen.
      Das ginge mühelos und deutlich effizienter mit anderen Funkprotokollen.

      Mir ginge es eher um einen Decoder für die messtechnische Bewertung von Pocsag-Netzen, wo die Datendecodierrate und die RSSI nur die halbe Miete ist.
      Denn für anständige Messprotokolle braucht es auch zwingend die decodierten Netzdaten aus den ersten zwei Codewörtern einer Batch, dem Frame0.

      Und genau da wird es verflixt teuer und selten bei fertigen Lösungen.
      Da will ich mir daher zeitnah was eigenes bauen was mir solche Bewertungslogs ausgibt.


      Mitch64 wrote:

      Ich konnte mittlerweile den Code Testen (Simulator).
      Jetzt habe ich auch eine kompakte CRC-10 Routine, die ist in Basic geschrieben und benötigt ca. 6300 Takte pro Codeword (32 Bit).

      Du kannst das selber mal ausprobieren.
      Oh ja, probiere ich nachher mal aus.
      Als ich gestern die Assembler-Parityroutine ausprobieren wollte was das Forum hier ausgefallen wegen Zertifikatsablauf.
      Aber nun geht hier ja alles wieder.

      Jürgen