Hallo zusammen, ich möchte einen Mikrocontroller als erstes über den Inhalt des ROMs eine Checksumme bilden und das Programm nur dann ausführen, wenn alles in Ordnung ist. Ich denke, dass bekommt man hin. Jetzt ist nur die Frage, kennt jemand ein Programm, welches die Checksumme über die zu programmierende bin/hex-Datei berechnet und dann an den Schluss der bin/hex-Datei schreibt. Ein Beispiel: Ein uC hat 8192 Byte Speicher. Die letzten zwei Byte werden so berechnet, dass die Summe (16bit) über alle Bytes 0x0000 ergibt. Das Programm muss also die Checksumme über 8190 Byte berechnen 0x0000 - 0x1FFD und dann an in die bin/hex-Datei an der Adresse 0x1FFE und 0x1FFF die Checksumme schreiben. Das ganze sollte noch über Befehlszeile programmierbar sein, dass heißt, die Software wird in den built Prozess mit eingebunden. Ich weiß, dass es so etwas gibt und ich hatte auch mal so eine Software, aber wie es eben so ist, über die Jahre in denen ich mich privat nicht mit uCs beschäftigt habe, kam der Dateifresser (man muss ja nicht alles aufheben). Viele Grüße heiha
Google kaputt? "checksum calculator hex" gibt eine ganze Reihe von Resultate!
heiha schrieb: > ich möchte einen Mikrocontroller als erstes über den Inhalt des ROMs > eine Checksumme bilden und das Programm nur dann ausführen, wenn alles > in Ordnung ist. Wenn ich es richtig verstanden habe: Der µC soll die Checksum über sein Flash bilden? Und dann seinen Code ausführen, wenn diese Checksum in Ordnung ist? > Ich denke, dass bekommt man hin. Nicht so einfach. Das ist stark Prozessor-abhängig, ob und wie das geht. Von welchem µC sprichst Du denn? Und das blödeste: Um festzustellen, ob der µC seinen Code ausführen darf, muss er seinen Code (zum Ermitteln der Checksum) ausführen! Was machst Du denn, wenn der vermutete Flash-Fehler genau in der Checksum-Ermittlungsroutine steckt? Dann kann alles mögliche passieren. > Jetzt ist nur die > Frage, kennt jemand ein Programm, welches die Checksumme über die zu > programmierende bin/hex-Datei berechnet und dann an den Schluss der > bin/hex-Datei schreibt. Auch das ist nicht trivial: Die Bin- und Hex-Dateien haben einen komplett anderen Aufbau. Bei der Hex-Datei könnten zum Beispiel Daten für 0x0000 bis 0x1000 (Text-Section) drinstehen und dann nochmal 0x1A00 bis 0x2000 (8192) für eine Data- oder eine zweite Text-Section. Erstmal bekommst Du dann Deine zwei Bytes gar nicht mehr reingequetscht, zum zweiten hat die Hex-Datei eventuell ein "Loch", deren Inhalt nicht bekannt ist. Dann ist es eine ziemlich blöde Idee, eine Checksum einer Hex-Datei mit der Checksum eines Flash-Inhalts zu vergleichen. Insgesamt: Vergiss es. Jedenfalls so allgemein formuliert, wie Du Dir das vorstellst.
:
Bearbeitet durch Moderator
Ok, es ist Freitag heute und ich habe gute Laune ;-) Ein kleines Python3-Skript dass einfach die 16-bit Checksumme generiert und an eine Eingabedatei hinten dran kleckert:
1 | #!/usr/bin/python3
|
2 | import sys |
3 | |
4 | def main(argv): |
5 | with open(argv[1], "rb") as fp: |
6 | data = fp.read() |
7 | |
8 | checksum = 65536 - sum(data) % 65536 |
9 | |
10 | check_hi = checksum // 256 |
11 | check_lo = checksum % 256 |
12 | |
13 | with open(argv[2], "wb") as fp: |
14 | fp.write(data) |
15 | fp.write(bytes([check_hi, check_lo])) |
16 | |
17 | if __name__ == '__main__': |
18 | if len(sys.argv) < 3: |
19 | print("Use " + sys.argv[0] + "input_file output_file") |
20 | else: |
21 | main(sys.argv) |
:
Bearbeitet durch User
Eric B. schrieb: > Ein kleines Python3-Skript dass einfach die 16-bit Checksumme generiert > und an eine Eingabedatei hinten dran kleckert: Nett, aber hast Du Dir mal eine Hex-Datei angeschaut? Da stehen Adressen, Inhalte und Checksums drin. Du darfst laut Aufgabenstellung nur die Checksum der Inhalte bilden. Denn nur diese landen im Flash! Dann musst Du noch einen neuen Record vor dem End of File Record (Typ 01) einfügen, die Checksum über die Checksum bilden und diese als Record-Checksum mitsamt dem kompletten Record wegschreiben. Aber bloß nicht am Ende der Datei! Dann stehts nämlich hinter dem End-Of-File-Record und wird ignoriert! Wenn Du diese Hürden überwunden hast, fehlt dann noch das µC-Programm: Bilden einer Checksum über den Flash-Speicher, obwohl der µC gar nicht weiß, welche Bereiche seines Flashs überhaupt mit der Hex-Datei beschrieben wurden. Aua! Also insgesamt - egal wie schön Deine "Lösung" aussieht: Sie ist nicht anwendbar. Einfach, weil die Aufgabenstellung schon unsinnig ist. EDIT: Auch bei einer Bin-Datei ist die "Lösung" nicht anwendbar. Denn das Klatschen von 2 zusätzlichen Bytes veranlasst das Brenner-Programm nicht, diese beiden im Flash an der geforderten Stelle 8192 (das Ende des Flashs) zu positionieren.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Wenn Du diese Hürden überwunden hast, fehlt dann noch das µC-Programm: > Bilden einer Checksum über den Flash-Speicher, obwohl der µC gar nicht > weiß, welche Bereiche seines Flashs überhaupt mit der Hex-Datei > beschrieben wurden. Aua! Naja, wenn sich dieser Checksum immer an der Adresse 8190 befindet, weiss der uC von wo bis wo gerechnet werden muss, das sollte also keinen allzugrossen Problem darstellen. PC kann die Hex-Datei Zeile für Zeile einlesen, die letzten 2 ASCII Zeichen sind Checksum, bis zum Record mit 01 (EOF) werden diese Byteweise addiert, dann wird die neue Zeile mit Adresse 8190 rein- geschrieben, danach EOF Zeile.
heiha schrieb: > Ein Beispiel: Ein uC hat 8192 Byte Speicher. Die letzten zwei Byte > werden so berechnet, dass die Summe (16bit) über alle Bytes 0x0000 > ergibt. Das Programm muss also die Checksumme über 8190 Byte berechnen > 0x0000 - 0x1FFD und dann an in die bin/hex-Datei an der Adresse 0x1FFE > und 0x1FFF die Checksumme schreiben. Wie Frank M. schon gesagt hat, mit einer .hex Datei ist das keine Gute Idee (wegen der ausgelassenen Speicherbereiche, die dann im Flash einen unbekannten Inhalt haben). Wenn dann geht das nur über ein .bin File. Da du ja den Algorithmus der Checksummen-Bildung für den uC eh programmieren musst verstehe ich allerdings nicht so ganz, worin das Problem besteht, diesen Algorithmus in ein kleines Programm einzubauen, der dir das .bin File patched. bin_file_einlesen(); checksumme_bilden(); letzte_bytes_patches(); bin_file_wegschreiben();
:
Bearbeitet durch User
Marc V. schrieb: > Naja, wenn sich dieser Checksum immer an der Adresse 8190 befindet, > weiss der uC von wo bis wo gerechnet werden muss, das sollte also > keinen allzugrossen Problem darstellen. Ich sage ja nicht, dass es prinzipiell für einen konkreten µC unlösbar ist. Der TO formulierte seine Aufgabenstellung jedoch sehr allgemein. Allgemein ist das nicht lösbar. Deshalb schrieb ich: > Nicht so einfach. Das ist stark Prozessor-abhängig, ob und wie das geht. > Von welchem µC sprichst Du denn? Marc V. schrieb: > PC kann die Hex-Datei Zeile für Zeile einlesen, die letzten 2 ASCII > Zeichen sind Checksum, bis zum Record mit 01 (EOF) werden diese > Byteweise addiert, dann wird die neue Zeile mit Adresse 8190 rein- > geschrieben, danach EOF Zeile. Ja, natürlich geht das, aber nicht mit Erics Programm. Es müssen die Inhalte interpretiert und anschließend manipuliert werden. Das Dumme ist nur, dass in den wenigsten HEX-Dateien genau 8190 Bytes stehen, sondern weniger. Das einzige, was Du vielleicht voraussetzen kannst, dass an den nicht-beschriebenen Flash-Speicherstellen 0xFF stehen. Wenn Du diese mit in die Checksum einbeziehst, kann es vielleicht funktionieren. Deshalb schrieb ich: > Auch das ist nicht trivial: ... Fazit: Der TO macht es sich viel zu einfach. Man kann eine Lösung für einen speziellen µC entwickeln... und hoffen, dass das Flash vor dem Brennen auch komplett mit 0xFF initialisiert wurde. Sonst kannst Du gar nichts aussagen über den Flash-Bereich, der nicht programmiert wird. Und damit wäre auch eine Checksum über den Flash nicht aussagekräftig.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Nett, aber hast Du Dir mal eine Hex-Datei angeschaut? Ja, zu oft würde ich sogar sagen. Frage war aber nach bin/hex: heiha schrieb: > ein Programm, welches die Checksumme über die zu > programmierende bin/hex-Datei berechnet und dann an den Schluss der > bin/hex-Datei schreibt. Und für bin ist das Skript bestens geeignet; hex überlasse ich dir als Übung fürs WE ;-)
:
Bearbeitet durch User
Folgende Lösung finde ich recht übersichtlich und universell: - ein Array der Größe des Flashs anlegen - das Array mit dem Reset-Wert des Flashs initialisieren - die Hex-Datei in das Array einlesen - über das Array die Checksum bilden und in die letzten Bytes schreiben - aus dem kompletten Array eine Hex- oder Bin-Datei erzeugen. In dem Fall ist es egal, wie die Hex-Datei aufgebaut ist bzgl. Reihenfolge und Lücken, und ob das Flash gelöscht wurde. Die Ergebnis-Datei enthält ja das komplette Flash - egal wie groß das Programm vorher war.
Ich werfe mal srec_cat zum Manipulieren der Dateien in den Raum. Geht auch für intel hex und binaries. Einfache Checksummen gehen wohl auch. Frank M. schrieb: > Das Dumme ist > nur, dass in den wenigsten HEX-Dateien genau 8190 Bytes stehen, sondern > weniger. Das einzige, was Du vielleicht voraussetzen kannst, dass an den > nicht-beschriebenen Flash-Speicherstellen 0xFF stehen. Nicht nur dort, sondern bei den Programmen, die ich so kenne, gibt man den Inhalt der Löcher an. Ist ja ein übliches "Problem". Da der TO seinen Prozessor kennt, sollte er auch seinen Flasher/Bootloader kennen. Es ist zumindest unüblich, dass die Löcher einen zufälligen Wert bekommen.
Eric B. schrieb: > Ein kleines Python3-Skript dass einfach die 16-bit Checksumme generiert Leider ist die Checksumme nicht brauchbar. Fuer deine Checksumme ist es egal ob da die Bytes in der Reihenfolge
1 | 0x01 0x02 0x03 |
stehen, oder
1 | 0x03 0x01 0x02 |
Das ist aber fuer das Programm/den Controller nicht egal. Damit bietet die Checksumme keine Sicherheit. Hier mal eine crc16_ccitt:
1 | uint16_t crc16_ccitt(uint32_t len, uint8_t* p_input, uint16_t seed) { |
2 | static const uint16_t crc_ccitt_table[] = { |
3 | /* 0 1 2 3 4 5 6 7 */
|
4 | /* 8 9 a b c d e f */
|
5 | /* 00 */ 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, |
6 | 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, |
7 | /* 10 */ 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, |
8 | 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, |
9 | /* 20 */ 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, |
10 | 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, |
11 | /* 30 */ 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, |
12 | 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, |
13 | /* 40 */ 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, |
14 | 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, |
15 | /* 50 */ 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, |
16 | 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, |
17 | /* 60 */ 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, |
18 | 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, |
19 | /* 70 */ 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, |
20 | 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, |
21 | /* 80 */ 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, |
22 | 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, |
23 | /* 90 */ 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, |
24 | 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, |
25 | /* a0 */ 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, |
26 | 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, |
27 | /* b0 */ 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, |
28 | 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, |
29 | /* c0 */ 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, |
30 | 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, |
31 | /* d0 */ 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, |
32 | 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, |
33 | /* e0 */ 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, |
34 | 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, |
35 | /* f0 */ 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, |
36 | 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0, |
37 | };
|
38 | |
39 | uint16_t crc = seed; |
40 | |
41 | if (len > 0) { |
42 | for( uint32_t i = 0; i < len; i++ ) { |
43 | crc = (uint16_t) ( (crc << 8) ^ crc_ccitt_table[ (crc >> 8) ^ p_input[i] ]); |
44 | }
|
45 | }
|
46 | |
47 | return crc; |
48 | }
|
Test:
1 | int main(void) { |
2 | uint8_t x[2] = {0x01, 0x02}; |
3 | uint8_t y[2] = {0x02, 0x01}; |
4 | |
5 | printf("Checksumme fuer x: 0x%x\n", crc16_ccitt(2, x, 0)); |
6 | printf("Checksumme fuer y: 0x%x\n", crc16_ccitt(2, y, 0)); |
7 | |
8 | return 0; |
9 | }
|
Ausgabe:
1 | Checksumme fuer x: 0x1373 |
2 | Checksumme fuer y: 0x7643 |
Die gleichen Eingabewerte, andere Reihenfolge -> andere Checksumme. Eine Checksumme, bei der ein vordefinierter Wert rauskommen soll (0x0000) macht fuer mich nur wenig sinn. Ist ja aber am Ende nicht mein Bier. Da ist jetzt schon mal ne CRC die Positionsabhaengig ist, und ob das ganze dann noch auf 0 gerechnet wird oder nicht, kann ja jeder machen wie er lustig ist.
Deutlich einfacher ist, wenn der µC beim ersten Start die Checksumme seines Flash Speichers bildet und im EEprom ablegt. Bei allen folgenden Starts vergleicht er die Checksummen.
Moi, Dazu muss er aber auch ein EEPROM oder vergleichbares haben. In manchem Compiler/Linker ist ein solches Feature schon fest eingebaut. Hatte zb. mal IAR compiler fuer 78K0R am wickel. Da schreibt man ins Linker cmd File rein, ueber welchen Bereich was fuer eine Checksumme berechnet werden soll und wo sie abgelegt werden soll. Vorteil ist da, dass der Compiler/Linker ja schon wusste, ob der µC little oder big endian sehen will (beim speichern der CRC). Kann man natuerlich auch einfach vorher festlegen, und die Routine im µC muss die CRC aus dem vereinbarten Speicher so herauslesen. Man kann natuerlich hingehen, und der routine eine Kofigurationstabelle mitgeben. Dann kann man beliebige Bereiche berechnen oder auslassen. Das externe Tool muss dann natuerlich diese Tabelle ebenfalls extrahieren und die CRCs berechnen und einpatchen. Natuerlich duerfen die CRCs nicht in einem Bereich liegen ueber den eine CRC berechnet wird. Es sei denn eine eigene CRC nur ueber die CRCs. Diese CRC darf dann aber in keinem anderen Bereich liegen ueber den eine CRC gebildet wird. Aber das Speicherlayout muss ja sowieso irgendwann mal festgelegt werden. Wenn man einen Bootloader hat, kann es guenstig sein, den nicht mit zu pruefen. Der ist oft ein eigenes Projekt und kann auch in verschiedenen Versionen vorliegen. Die aber alle akzeptabel sein koennen.
Stefan U. schrieb: > Deutlich einfacher ist, wenn der µC beim ersten Start die Checksumme > seines Flash Speichers bildet und im EEprom ablegt. Bei allen folgenden > Starts vergleicht er die Checksummen. Was soll der Quatsch? Das ist Unfug, da beim ersten Start bereits ein Fehler vorliegen könnte.
Stefan U. schrieb: > Deutlich einfacher ist, wenn der µC beim ersten Start die Checksumme > seines Flash Speichers bildet und im EEprom ablegt. Das schützt vor alterndem Flash, aber nicht vor defekt geflashter Firmware. Zudem will man in der Regel nur bestimmte Sections prüfen (.text, .data und vllt .startup). Der Rest vom Flash kann ja von z.B. einer EEPROM-Emulation genutzt werden. Nur der Linker weiß, welche Sections wo im Flash liegen, in einer Hex/Bin steht das nicht mehr drin. Also geht sowas nicht sauber. > Bei allen folgenden Starts vergleicht er die Checksummen. Das heißt, wenn die Checksumme im EEPROM nicht mehr stimmt, dann wird sie aktualisiert? Sehr gute Idee. :-)
> Das ist Unfug, da beim ersten Start bereits ein > Fehler vorliegen könnte. Um dies auszusch.ießen macht man in meinen Kreisen ohnehin immer eine Funktionskontrolle, bevor man das Produkt an den Kunden übergibt. Ein Gerät ungetestet zu übergeben, wo man lediglich doppelt sicher ist, dass die Firmware erfolgreich "gebrannt" wurde, halte ich für fragwürdig. > Das heißt, wenn die Checksumme im EEPROM nicht mehr stimmt, > dann wird sie aktualisiert? Das habe ich nicht gemeint. Ich wiederhole nochmal: > beim ersten Start die Checksumme seines Flash Speichers bildet ^^^^^^ damit meine ich im Werk im Rahmen der Funktionskontrolle. > Bei allen folgenden Starts vergleicht er die Checksummen. Das passiert beim Kunden. Von "aktualisieren" habe ich nichts geschrieben.
heiha schrieb: > Die letzten zwei Byte > werden so berechnet, dass die Summe (16bit) über alle Bytes 0x0000 > ergibt Das ist antürlich die einfachste Möglichkeit, braucht nur ein paar Byte Programm, aber auch die unsicherste, CRC ist erheblich sicherer. Bei einem PC werden Zusatz-ROMs so geprüft, aber da gibt es einen laufenden PC, der eine Meldung ausgibt, dass auf der Karte xx ein Fehler vorliegt. Ein Embedded System, dessen Software korrupt ist, kann das nicht, es erhebt sich also die Frage, was tun im Fehlerfall. Nichts tun ist eine schlechte Option, schon weil ein Prozessor niemals nichts tut. Das Mindeste wäre, die Peripherie in einen sicheren Zustand zu versetzen bzw. nicht anzufassen, denn nach einem Reset sollte/muss sie in einem solchen Zustand sein. Dazu würde ich mindestens eine LED zur Fehlermeldung einschalten. Die Software von Programmern kann meistens die Prüfsumme bilden, die hat man früher auf einen kleinen Zettel geschrieben und auf die Eproms geklebt, für den Kundendienst. Georg
Georg schrieb: > Das ist antürlich die einfachste Möglichkeit, braucht nur ein paar Byte > Programm, aber auch die unsicherste, CRC ist erheblich sicherer. CRC gut, wenn einem die Recourcen dafür nicht kümmern. Für einen simplen Check des Applikationscodes z.B. durch einen Bootloader, ist m.E. CRC aber Overkill. Ein Bootloader soll kompakt sein und muss in einen bestimmten Speicherbereich passen, u.U. zählt da jedes Byte. Und dann muss der Bootloader ja im Wesentlichen nur feststellen, ob überhaupt ein gültiges Applikationsprogramm im Speicher steht, damit er nicht ins "Nirwana" bootet. Die typischen Fehlerszenarien kann eine CRC nicht besser handlen, als eine simple Summe: - Applikation noch gar nicht geladen: kein Problem für CRC oder Summe - Applikation nur teilweise geladen (z.B. Abbruch beim Ladevorgang): gibt einen Zufallswert, sowohl bei CRC, als auch bei der Summe. Damit stehen sowohl bei 16-Bit CRC, als auch 16-Bit Summe die Chancen 1:65535, daß ein "false Positive" herauskommt. - einzelne Bitfehler durch Flash-Alterung: da dürften eher einzelne Bits umkippen (von 0 nach 1), was eine Prüfsumme mit ziemlicher Sicherheit auch merkt. Daß sich im Speicher plötzlich zwei Bytes vertauschen, was eine CRC merkt, aber eine Summe nicht, tritt wohl eher nicht ein. Nachteil einer CRC wäre noch, daß der Bootvorgang ein paar ms länger dauert, als mit der Summe. Freilich, wenn es um Sicherheit gegen Code-Manipulation z.B. durch Hacker/Raubkopierer o.ä. geht, bietet eine simple Summe keinen Schutz.
Thomas E. schrieb: > CRC gut, wenn einem die Recourcen dafür nicht kümmern. CRC braucht nicht viel. Man kann natürlich die ganz schnelle Lösung nehmen mit ein Byte pro Iteration, dazu braucht man dann eine 256-Tabelle. Oder die ganz langsame Lösung ohne Tabelle und 1 Bit pro Iteration. Dazwischen gibt's als feinen Kompromiß auch noch 1 Nibble pro Iteration, dazu braucht man nur eine Tabelle der Länge 16. Benchmarks (auch auf µC!) und diversen Code, alles sehr schön aufbereitet, gibt es hier: http://create.stephan-brumme.com/crc32/
S. R. schrieb: > Nur der Linker weiß, welche Sections wo im Flash liegen, in einer > Hex/Bin steht das nicht mehr drin. Also geht sowas nicht sauber. Ich kenne das ganz einfach so: - Binfile einlesen. - Auffüllen mit 0xFF bis zu einer gewissen Grenze (also wenn die Firmware z.B. 180K ist, dann bis 200K auffüllen). - Das ist natürlich auch in der Firmware so konfiguriert, so daß sie weiß, wo die Checksumme liegen wird. - Dann eine CRC über den Bereich berechnen abzüglich der letzten zwei bzw. vier Bytes (CRC-16 bzw. CRC-32). - Das byteweise in die letzten Bytes schreiben (um Endianess-Probleme auszuschließen). - Das zusammen mit der konfigurierten Startadresse im Flash als Hexfile ausspucken. Das ist völlig normal in Systemem, die industrielle Zuverlässigkeitsanforderungen erfüllen sollen. Natürlich kann man einen Teil des EEPROMs auch noch für Daten verwenden, wenn man die nur selten schreibt (Abnutzung). Das geht dann aber auch im Linkerscript, und dementsprechend weiß man, wo was liegt. Man muß die Sektionen nicht hintereinander starten, sondern man kann im Linkerfile auch eine Sektion an einer sauberen Blockadresse starten lassen. Für die Daten nimmt man dann eine eigene CRC im Datenbereich, das ist Teil der Definition des Datenformates.
Nop schrieb: > CRC braucht nicht viel. Aber eine Summierung braucht eben noch weniger (keine Tabellen, keine Schiebe-Loops für jedes Wort, nur eine(!) Operation pro Wort bzw. grad mal eine zusätzliche Addition auf einem 8-Bitter für den Übertrag. Wenn man von der CRC keine nennenswerten Vorteile für die geforderte Aufgabe hat, wozu sollte man es dann komplizierter, als nötig, machen?
Thomas E. schrieb: > man von der CRC keine nennenswerten Vorteile für die geforderte Aufgabe > hat, wozu sollte man es dann komplizierter, als nötig, machen? Das Nichtbenutzen einer Checksumme hat sogar noch weniger Aufwand, allerdings auch eine noch geringere Entdeckungswahrscheinlichkeit. Es kommt halt drauf an, welchen Grad an Zuverlässigkeit man will bzw. was von entsprechenden Normen vorgegeben ist. Bei entsprechend langer Betriebsdauer sind übrigens mehrfache Bitfehler durchaus wahrscheinlich, weil das gesamte Flash seine Daten ja relativ einheitlich verliert.
Nop schrieb: > Bei entsprechend langer Betriebsdauer sind übrigens mehrfache Bitfehler > durchaus wahrscheinlich, weil das gesamte Flash seine Daten ja relativ > einheitlich verliert. Ja, wie hoch ist wohl die Wahrscheinlichkeit, daß z.B. genau bei 512 Bytes die MSBs von 0 nach 1 wechseln, damit bei einer 16-Bit Prüfsumme zufällig das Gleiche 'rauskommt? Technisch spricht m.E. nichts für eine nennenswerte Wahrscheinlichkeit, daß sich zufällige Bitfehler in der Summe gegenseitig aufheben. Es ist ja nun auch nicht so, daß in der Praxis Flashspeicher ständig an Alzheimer leiden. Wenn man professionell programmiert und sich durch Vorgaben an irgendwelche Normen halten muss, ist es vielleicht etwas Anderes - der TO hat aber nichts von ISO-Zertifikation o.ä. geschrieben. Nop schrieb: > Das Nichtbenutzen einer Checksumme hat sogar noch weniger Aufwand, > allerdings auch eine noch geringere Entdeckungswahrscheinlichkeit. Reine Rethorik - da kann man auch sagen, wenn man sich als Fussgänger die Ampel sparen will, kommt man noch schneller über die Straße, wenn man sich auch noch spart, nach dem Verkehr zu schauen. Ein Erzieher mit 'ner Horde Kinder im Schlepptau sollte sich natürlich an die Norm halten und den Weg über die Ampel nehmen...
:
Bearbeitet durch User
Thomas E. schrieb: > Ja, wie hoch ist wohl die Wahrscheinlichkeit, daß z.B. genau bei 256 > Bytes die MSBs von 0 nach 1 wechseln Muß es auch nicht. Es kann z.B. auch sein, daß zwei verschiedenartige Bits in selber Bitposition entgegengesetzt kippen, und da 1+0=0+1, ist das schon nicht mehr detektierbar. Deswegen ist die Hamming-Distanz der arithmetischen Summe eben nur zwei, egal wieviel Bit die Checksumme hat. Eine CRC-k hingegen sinkt erst ab einer Datenbitmenge von 2^k auf eine Hammingdistanz von 2. Eine CRC-16 wird also ab 8kbyte sinnfrei, da nimmt man sinnigerweise CRC-32. Die Berechnungskosten einer CRC werden übrigens auch maßlos übertrieben, die sind bei gescheiter Implementation eher sowas wie das Vierfache einer arithmetischen Checksumme. Als Kompromiß gäbe es dazwischen natürlich auch noch Fletcher und Adler. Ansonsten empfehle ich mal z.B. das hier: https://users.ece.cmu.edu/~koopman/thesis/maxino_ms.pdf Das Einzige, was man niemals verwenden sollte, ist die Xor-Checksumme. Ist genauso teuer wie Addieren, aber nur halb so gut. Zudem ist es auch falsch, daß CRC die Bootzeit zwingend verlängern würde. Man kann die Checksumme beim Booten abprüfen, man kann derlei aber auch in Idle-Zeiten machen, etwa in Delay-Routinen oder im Idle-Task. Dann muß eben 10 Sekunden nach dem Booten ein grünes Lämpchen angehen, wenn alles OK ist. Das ist technisch geradezu trivial machbar, indem man den Zähler und die Zwischen-CRC in der Prüfroutine als static markiert und immer nur so und soviel Bytes pro Aufruf gescannt werden.
Ist Euch schon aufgefallen, dass der TO sich nach seinem Posting nicht mehr in die Diskussion eingeklinkt hat... Ihr könnt natürlich weiter diskutieren... aber ich glaube hier war nur ein Troll unterwegs.
Nop schrieb: > Es kann z.B. auch sein, daß zwei verschiedenartige > Bits in selber Bitposition entgegengesetzt kippen Kann es? Das ist halt die Frage: was passiert mit den Floating Gates der Flash Speicherzellen über die Jahre, wenn der Flash-Speicher altert? Laden oder entladen sich die Gates möglicherweise? Löschen oder Programmieren sich die Bits über die Jahre eher? Oder übertägt ein Transistor seine Gate-Ladung vielleicht sogar auf einen anderen? Nur im letzen Fall scheint es mir plausibel, daß zwei verschiedene Speicherzellen gleichzeitig in genau entgegengesetzte Richtung kippen - scheint mir doch eher unwahrscheinlich. Ich tippe eher darauf, daß sich Fehler, wenn sie auftreten, eher in der gleichen Richtung zeigen. Im Übrigen schreiben wir hier offenbar von verschiedenen Ziel-Applikationen: Nop schrieb: > man kann derlei > aber auch in Idle-Zeiten machen Deine scheint nicht die des Themenstarters zu sein: heiha schrieb: > ich möchte einen Mikrocontroller als erstes über den Inhalt des ROMs > eine Checksumme bilden und das Programm nur dann ausführen, wenn alles > in Ordnung ist.
Stefan U. schrieb: > Ein Gerät ungetestet zu übergeben, wo man lediglich doppelt sicher ist, > dass die Firmware erfolgreich "gebrannt" wurde, halte ich für > fragwürdig. Fehler in der Firmware kann man durch testen ausschließen. Fehler durch Alterung kann man durch dein Verfahren ausschließen. Fehler durch falsch (v.a. unvollständig) gebrannte Firmware halte ich für das größere Problem, wenn die Geräte öfter mal mit Updates versorgt werden - und dagegen schützt dein Ansatz nicht (bzw. nur dann, wenn der EEPROM-Inhalt erhalten bleibt, was nicht immer wünschenswert ist). Nop schrieb: >> Nur der Linker weiß, welche Sections wo im Flash liegen, in einer >> Hex/Bin steht das nicht mehr drin. Also geht sowas nicht sauber. > > Ich kenne das ganz einfach so: Ja klar, in der Firmware den zu prüfenden Bereich und den Ort der Prüfsumme hart codieren geht natürlich. Ist aber nicht besonders flexibel und schon garnicht universell. Wenn es das nicht sein muss, okay. > Natürlich kann man einen Teil des [Flashs] auch noch für Daten verwenden, > wenn man die nur selten schreibt (Abnutzung). Das geht dann aber auch im > Linkerscript, und dementsprechend weiß man, wo was liegt. Das sieht man dem Hexfile aber auch nicht mehr an. Der Linker weiß das, aber der weiß auch, wo Code und Daten im Flash liegen... > Man muß die Sektionen nicht hintereinander starten, > sondern man kann im Linkerfile auch eine Sektion an > einer sauberen Blockadresse starten lassen. Und wenn man die wieder im Voraus festlegt, wie du das oben mit der Größe des zu prüfenden Bereichs gemacht hat, dann ist das wieder etwas anderes, als wenn man (im allgemeinen Fall) davon ausgeht, dass die Daten auf dem nächsten Block starten. Nur der Linker kennt die genauen Adressen, es sei denn, du zwingst ihn (und die Firmware) dazu, dir bereits vorher bekannte Adressen zu benutzen. Dann - und auch nur dann - kannst du einfach auf dem Hexfile rumspielen.
> Fehler durch falsch (v.a. unvollständig) gebrannte Firmware halte ich > für das größere Problem, wenn die Geräte öfter mal mit Updates versorgt > werden ... und dagegen schützt dein Ansatz nicht Richtig. Aber dann kommt ein Bootloader mit ins Spiel. Ich dene, dem TO ging es nicht um dieses Szenario.
Thomas E. schrieb: > Kann es? Das ist halt die Frage: was passiert mit den Floating Gates der > Flash Speicherzellen über die Jahre, wenn der Flash-Speicher altert? Weiß ich jetzt nicht, aber plausibel wäre es natürlich, daß sie von selber früher oder später einen Zustand mit minimaler Energie einnehmen wollen, was dann je nach Aufbau logisch 0 oder logisch 1 wäre. Es ist aber nicht das einzige Fehlermuster. Die Software wird ja nicht in den Controller gebeamt, sondern typisch von einem PC in den Controller gespielt. Da hat man dann noch viel mehr Fehlermöglichkeiten. RAM-Bits können etwa kippen, wenn die Datei im Arbeitsspeicher ist, und die meisten Leute kaufen ja keine ECC-Boards. > Im Übrigen schreiben wir hier offenbar von verschiedenen > Ziel-Applikationen: Nein, denn dem TO schwebte eine bestimmte Implementierung vor - aber wie so oft in diesem Forum kann es durchaus sein, daß das nur daher kommt, daß er auf die Alternative nicht kam, obwohl sie ggf. durchaus auch einsetzbar wäre. Man kann natürlich auch beide Ansätze kombinieren.
S. R. schrieb: > Nur der Linker kennt die genauen Adressen, es sei denn, du zwingst ihn > (und die Firmware) dazu, dir bereits vorher bekannte Adressen zu > benutzen. Auch nicht. Man kann ja auch in der Firmware Variablen benutzen, die überhaupt erst vom Linker erzeugt werden. Bei der Init-Kopierschleife für die DATA-Sektion macht man das normalerweise so.
Richtig, aber diese Adressen siehst du dem Hexfile dann nicht mehr an, kannst also das Hexfile nicht mehr zuverlässig nachträglich manipulieren (um z.B. eine Checksumme einzutragen). Das war ja der Punkt.
S. R. schrieb: > Richtig, aber diese Adressen siehst du dem Hexfile dann nicht mehr an Ja das wird schwieriger. Andererseits werden diese Variablen ja im Linkerscript ermittelt, und man kann damit in ebendiesem Script sogar rechnen, um etwa Bereichsüberläufe beim Linken anzuwarnen. Also müßte man sie doch auch ausgeben können? Im simpelsten Fall in eine Datei, welche dann das CRC-Buildscript einlesen könnte. Zugegeben, das wird aufwendiger, weswegen die Methode mit dem Auffüllen und der festen Adresse auch die ist, welche ich in der Praxis als einzige wiederholt angetroffen habe (und auch selber verwende).
Was übersehe ich hier? Ich wollte einfach eine struct für die ersten Bytes des Hexfiles definieren. Ein Element darin wäre das CRC-Wort, ein anderes die höchste Adresse im Flash. Damit muss ich nichts auffüllen, das Hexfile wird 1:1 so gebrannt. Der Bootloader und das Anwendungsprogramm auf dem uC und das CRC-Generator-Programm könnten alle diese struct benutzen. Damit dürfte es keine Missverständnisse geben, auch wenn im Hexfile keinerlei Metadaten drin sind (die struct enthält ja alles, was man braucht). Ich muss nur dafür sorgen, dass dieser Header auch ganz am Anfang landet. Aber irgendetwas muss ja immer auf eine feste Adresse gelinkt werden. Aber wodurch könnten Lücken im Hexfile entstehen? Warum sollte der Linker Code und Daten nicht lückenlos packen? Na gut, ich mag manche Sachen auf 16 Byte Grenzen aligned haben, aber diese kleinen Löcher können doch leicht vom Linker, bei der Hexfile-Erzeugung oder vom CRC-Generator-Programm aufgefüllt werden?
eagle user schrieb: > Ich wollte einfach eine struct für die ersten Bytes des Hexfiles > definieren. Ein Element darin wäre das CRC-Wort, ein anderes > die höchste Adresse im Flash. Die ersten Bytes im Hexfile gehen prinzipiell nicht, weil der Adressraum reserviert ist (Vektortabelle u.ä.). Außerdem musst du dann die Adresse der Struct im Linkerscript genau festlegen, sonst kann der Linker sie beliebig irgendwo im Flash speichern. Aber ob du nun die Adresse einer Struct festlegst, oder die beiden Werte anderweitig festlegst, spielt keine Rolle. eagle user schrieb: > Aber wodurch könnten Lücken im Hexfile entstehen? Warum sollte der > Linker Code und Daten nicht lückenlos packen? Weil er vielleicht im Linkerscript dazu aufgefordert wurde, Löcher zu lassen. Wir sind uns alle einig, dass dein Ansatz funktioniert, wenn du irgendetwas (in deinem Fall: Die Adresse der Struct.) vorher festlegst. Kein Problem.
S. R. schrieb: > eagle user schrieb: >> Ich wollte einfach eine struct für die ersten Bytes des Hexfiles >> definieren. Ein Element darin wäre das CRC-Wort, ein anderes >> die höchste Adresse im Flash. > > Die ersten Bytes im Hexfile gehen prinzipiell nicht, weil der Adressraum > reserviert ist (Vektortabelle u.ä.). Ja, z.B. 0 bis 0x3F, dann würde die struct bei 0 beginnen und meine Daten bei 0x40. > Außerdem musst du dann die Adresse der Struct im Linkerscript > genau festlegen Na klar, das muss ich ja für den reservierten Adressraum sowieso immer. Beim STM32 kann ich meine Daten sogar in den unbenutzten Plätzen der Vektortabelle unterbringen:
1 | typedef struct vector_struct { |
2 | uint32_t *top_of_stack; // 0 initial SP |
3 | isr *crt0; // 1 initial PC |
4 | isr *css_nmi; // 2 Clock security |
5 | isr *hard_fault; // 3 |
6 | isr *mem_fault; // 4 |
7 | isr *bus_fault; // 5 |
8 | uint32_t magic; // 6 = Usage Fault, do not enable! |
9 | uint32_t crc; // 7 |
10 | uint32_t *image_end; // 8 |
11 | char *name; // 9 |
12 | uint32_t image_build; // 10 |
13 | isr *svc; // 11 |
14 | isr *debug; // 12 |
15 | char *syslog_text; // 13 |
16 | isr *pendsv; // 14 |
17 | isr *systick; // 15 |
18 | isr *interrupts[128-16]; |
19 | } vector_struct; |
20 | _Static_assert (sizeof(vector_struct) == 512, " Bad struct size"); |
> eagle user schrieb: >> Aber wodurch könnten Lücken im Hexfile entstehen? Warum sollte der >> Linker Code und Daten nicht lückenlos packen? > > Weil er vielleicht im Linkerscript dazu aufgefordert wurde, Löcher zu > lassen. Aber warum sollte man das tun?
eagle user schrieb: > Beim STM32 kann ich meine Daten sogar in den unbenutzten Plätzen der > Vektortabelle unterbringen Klar kannst du das. Aber das ist keine saubere, überall funktionierende Lösung, sondern ein "ugly hack". Wird aber funktionieren. eagle user schrieb: >> Weil er vielleicht im Linkerscript dazu aufgefordert wurde, Löcher zu >> lassen. > Aber warum sollte man das tun? Der TO hat nicht spezifiziert, dass er es nicht tun wollte...
Hallo zusammen, Ja ich war wirklich "off", das soll aber nicht heißen, dass ich den Treat nicht verfolgt habe. 38 Antworten, da haut es einen ja um. Vielen, vielen Dank für die ganzen Zeilen. Ja, ich weiß, dass eine CRC besser ist als eine Checksumme die einfach daraus besteht, die Bytes zusammen zu zählen. Ich weiß aber auch dass das Tool, dass ich damals verwendet habe, beides konnte. Wollte es aber nicht komplizierter machen als nötig. Ja, ich weiß auch, dass eine hex-Datei nicht vollständig beschrieben ist, aber die Lücken füllt man mit 0xFF auf. Dann erhält man eine bin-Datei. Oder es gibt compiler, bei denen man angibt, wie groß die Datei sein soll, und dann schreibt er die hex-Datei vollständig. Ja, ich weiß, dass man ein kleines Programm schreiben kann, welches die Aufgabe löst. Aber auch ganz ehrlich, dass ist Jahre her, dass ich so ein Programm geschrieben habe, welches sich mit Kommandozeile "fernsteuern" lässt. Das muss ich mir nicht antun. Ich habe nicht einmal eine Entwicklugnsumgebung auf dem Rechner und werde hier sicher jetzt auch nicht damit anfangen. Das war aber nicht die Frage, sondern: Kennt jemand so ein Programm. Da ich jetzt alle eträge durchgelesen habe, war bisher nur ein Vorschlag dabei. Der IAR compiler für einen 74kxx Controller brachte so etwas mit. Dann gehe ich davon aus, dass dieses Tool auch bei anderen Compilern von IAR integriert war. Noch weitere Vorschläge, hat jemand mal so ein Progrämmchen geschrieben? Viele Grüße heiha P.S.: Nochmal, ich bi überwältigt von der Resonanz. Tolle Truppe hier!
Eric B. schrieb: > Google kaputt? "checksum calculator hex" gibt eine ganze Reihe von > Resultate! Hallo Eric B., ja ich kann die Suchmaschine google bedienen. Deine Frage ist nur doof und provokant. Nein, ich werde Dich jetzt nicht fragen, ob Du nicht lesen kannst. Ich glaube, Du hast meine Frage technisch nicht verstanden. Ist nicht schlimm, niemand muss alles wissen, aber frag' mich das nächste mal einfach, bevor Du so etwas schreibst. Viele Grüße heiha
Frank M. schrieb: > Insgesamt: Vergiss es. Jedenfalls so allgemein formuliert, wie Du Dir > das vorstellst. Hallo Frank M., wer wird den die Flinte gleich ins Korn werfen. Ich hatte doch geschrieben, dass die uC Sache die einfachste auf der Welt ist. Jeder der einen uC halbwegs verstanden hat, bekommt das hin. Das ist nicht mehr als eine for-Schleife die 8192 mal durchlaufen wird und jeweils das Byte mit dem Zeiger der Schleifenkonstante in einer 16-bit Summe zusammen zählt. Am Ende vergleiche ich die Summe mit 0, das war's. Der Fokus lag auf dem Programm auf dem PC, es muss die hex-Datei einlesen, in eine binäre Array mit 8192 byte umwandeln (Lücken mit 0xFF füllen) die Checksumme bilden und dann an die letzten zwei Stellen des Arrays schreiben. Als Resultat bekommt man eine hex-Datei die vollständig ist und wenn man die Bytes alle zusammen zählt kommt 0 raus. Das Tool, dass ich damals hatte, konnte man über Kommandozeile fernsteuern. Beispiel "tool.exe test1.hex 0x2000 Checksumme 16 0x1FFE". Das wurde dann in die "Toolchain" des compilers eingebunden und man musste sich da kein Kopp mehr drum machen. Das hat vor 13 Jahren so funktioniert. Jeden Abend, an dem ich programmiert habe 100 mal. Und jetzt bin ich auf der suche nach so einem Programm. Viele Grüße heiha
Steffen R. schrieb: > Ich werfe mal srec_cat zum Manipulieren der Dateien in den Raum. Geht > auch für intel hex und binaries. Einfache Checksummen gehen wohl auch. Ich korrigiere meine Aussage von vorhin. Hier ist noch mal ein Vorschlag, den ich mir gleich anschauen werde. Viele Grüße heiha
Bin jetzt auch registriert. Bei dieser Resonanz eine Wertschätzung dieses Forums. Grüße heiha
heiha schrieb: > Noch weitere Vorschläge, hat jemand mal so ein Progrämmchen geschrieben? 1. Im Linker-File eine Section am Ende deines Flashs definieren, welche die Referenz-Checksumme beinhalten soll 2. Im Linker-File eine Section definieren welche den gesamten Flash (bis auf die vorige Section) umfasst und den Linker anweisen ungenutzte Speicherbereiche mit einem Wert deiner Wahl zu füllen (siehe z.B. https://mcuoneclipse.com/2014/06/23/filling-unused-memory-with-the-gnu-linker/) 3. Im Code den Referenzwert über die Section referenzieren und den Check wunschgemäß implementieren (siehe z.B. https://mcuoneclipse.com/2012/11/01/defining-variables-at-absolute-addresses-with-gcc/) 4. Firmware kompilieren und linken 5. Script (o.ä.) schreiben, welches die Checksumme über die Nutzdaten des HEX-Files (exklusive der unter 1. definierten Section) bildet und diese im HEX-File an die in 1. definierte Section patched
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.