Hallo zusammen,
ich habe einen eigenen Bootloader auf dem ATmega1284 erstellt, der beim
Einschalten des Controllers startet, und den CRC über den gesamten Flash
berechnet.
Ist dieser gültig wird die Anwendung gestartet.
Nun habe ich das Problem, dass das prüfen ca 1 - 2 Sekunden beansprucht.
Da die Application erst danach startet schaut das ganze recht unschön
aus.
Gibt es eine Möglichkeit die berechnung zu beschleunigen oder gibt es
eine schnellere Möglichkeit den CRC über den gesamten Flash zu
berechnen?
Compiler ist VisualGDB.
APP_END_ADR = 0x1EFFD
Ich verwende dazu folgenden Codeabschnitt:
Ich würde vorschlagen eine 8-Bit-CRC zu verwenden. Die lässt sich
naturgemäß auf einem 8-Bit-Controller mindestens doppelt so schnell
rechnen. Vermutlich noch schneller. Mit geschickter Wahl der
Polynomkoeffizienten kann man dann die Rechenaufwände der einzelnen
Byterunden noch einmal reduzieren.
Andreas schrieb:> ich habe einen eigenen Bootloader auf dem ATmega1284 erstellt, der beim> Einschalten des Controllers startet, und den CRC über den gesamten Flash> berechnet.> Ist dieser gültig wird die Anwendung gestartet.
Das ist doch schon vom Konzept her völliger Schwachsinn. Wenn der
Bootloader wissen möchte, ob die Anwendung "gültig" ist, dann muss er
natürlich nur einen Prüfsumme über den Flashbereich bilden, in dem die
Anwendung im Flash liegt.
Dazu muss er wissen (und sich merken, auch wieder im Flash) wo die
Anwendung beginnt und wie groß sie ist.
Bei einem ATMega ist das ziemlich einfach unzusetzen. Bei einem Tiny
wird's kitzliger, denn da muß der Bootloader, um funktionieren zu
können, die Anwendung manipulieren (zwei Bytes davon, den Inhalt des
Resetvektors).
C-hater schrieb:> Das ist doch schon vom Konzept her völliger Schwachsinn. Wenn der> Bootloader wissen möchte, ob die Anwendung "gültig" ist, dann muss er> natürlich nur einen Prüfsumme über den Flashbereich bilden, in dem die> Anwendung im Flash liegt.
Stimmt. Aber auch ein AVR kann einen größeren Flash-Bereich in DEUTLICH
unter 1s mittels CRC16 prüfen. Dazu darf man natürlich KEINEN Seriellen
Algorithmus nehmen, sondern einen mit Tabelle, hier sinnvollerweise mit
256 Einträgen a 2 Byte. OK, das ist TEUER in einem Bootloader.
Alternativ nur mit Nibblebreite und 16er Tabelle. In ASM geht das flott.
Hey, das war DEIN Stichwort! ;-)
Es hängt natürlich davon ab wie schnell deine CRC Funktion ist. mit
einer Tabelle lässt sich das auf Kosten des Speicherplatzes schon
schneller machen, die braucht dann aber bis zu 512Bytes im Flash, wird
also nicht in deinen Bootloader passen.
https://stackoverflow.com/questions/22432066/how-to-use-table-based-crc-16-code
edit: zu spät
Markus M. schrieb:> Was macht den die Funktion "_crc16_update()" alles?
Berechnet die CRC für das nächste Byte.
> Und was macht "pgm_read_byte_far()"?
Liest ein Byte aus dem Flash über einen FAR-Pointer (>64kB).
Falk B. schrieb:> Stimmt. Aber auch ein AVR kann einen größeren Flash-Bereich in DEUTLICH> unter 1s mittels CRC16 prüfen.
Natürlich. Es macht eben nur keinerlei Sinn, also warum sollte man das
wider jede Vernunft trotzdem tun?
> In ASM geht das flott.> Hey, das war DEIN Stichwort! ;-)
Nicht wirklich. Egal in welcher Sprache ich programmiere: ich
programmiere nur das, was sinnvoll ist. Und natürlich habe ich eine
(recht) schnelle CRC16-Routine im Bestand. Die kommt übrigens ohne fette
Lookup-Table aus. Ist eigentlich eher ein Abfallprodukt aus der
Verbesserung von V-USB. Setzt halt möglichst effizient den Algorithmus
um, den USB für DATA-Packets verwendet.
Laufzeitmäßig weniger effizent als was mit Lookup, aber immerhin schnell
genug, um innerhalb von V-USB ab ca. 16MHz Systemtakt zu funktionieren.
Kostet exakt 23Takte/Byte.
Danke für eure Antwort.
Genau, die beiden Methoden stammen aus der AVR lib.
Die crc update funktion ist auch in ASM geschrieben.
C-hater schrieb:> Andreas schrieb:>>> ich habe einen eigenen Bootloader auf dem ATmega1284 erstellt, der beim>> Einschalten des Controllers startet, und den CRC über den gesamten Flash>> berechnet.>> Ist dieser gültig wird die Anwendung gestartet.>> Das ist doch schon vom Konzept her völliger Schwachsinn. Wenn der> Bootloader wissen möchte, ob die Anwendung "gültig" ist, dann muss er> natürlich nur einen Prüfsumme über den Flashbereich bilden, in dem die> Anwendung im Flash liegt.>> Dazu muss er wissen (und sich merken, auch wieder im Flash) wo die> Anwendung beginnt und wie groß sie ist.>> Bei einem ATMega ist das ziemlich einfach unzusetzen. Bei einem Tiny> wird's kitzliger, denn da muß der Bootloader, um funktionieren zu> können, die Anwendung manipulieren (zwei Bytes davon, den Inhalt des> Resetvektors).
Ok, da habe ich etwas missverstande. Ich dachte das macht man eigentlich
mit einem CRC.
Muss die Prüfsumme über den gesamten Flash Bereich oder nur über die
Applikation gebildet werden?
Welches Prüfsummenverfahren wird denn hier üblicherweise genutzt bzw.
hat jemand einen Link wo ich einen schnellen algorithmus finden kann?
CRC ist schon i.O.
Es gibt von Intel ein paper zu schnellem CRC... Deren verfahren nennen
sie slice-by-8.
Im Prinzip machst du dir eine lookup table in der von dir gewünschten
größe und XORst dann wörter zur gesammtCRC.
Beim AVR müssten 16bit passen, wenn ich mich an die Architektur richtig
erinnere (kann der nicht 16bit PGM in 2 register laden ?)
Das müsste dann deutlich <1s gehen...
Wie breit die CRC (16/32bit) ist übrigens verhältnismäßig unerheblich da
du im Endeffekt nur XOR machst.
Eine Übersicht zu unterschiedlichen CRC Implementierungen findet sich
übrigens hier: https://create.stephan-brumme.com/crc32/
73
Andreas schrieb:> Ok, da habe ich etwas missverstande. Ich dachte das macht man eigentlich> mit einem CRC.
Sachen wie die Prüfung, ob Code gültig ist, macht man tatsächlich z.B.
per CRC. Das hast du nicht falsch verstanden.
> Muss die Prüfsumme über den gesamten Flash Bereich oder nur über die> Applikation gebildet werden?
Hier ist dein "Verständnisproblem". Natürlich braucht (und sollte) man
zur Überprüfung der App nur den Bereich des Flash betrachten, in dem sie
liegt. Alles andere ist doch so dermaßen unlogisch, dass es schon weh
tut, wenn jemand auf irgendwas anderes kommt...
Ich tippe mal: Troll. Recht gut getarnt, aber nicht perfekt. Meine
Troll-KI kann dich nicht wirklich sehen, ich schon. Geht halt nix über
Eigen-Intelligenz.
Andreas schrieb:> Danke für eure Antwort.>> Genau, die beiden Methoden stammen aus der AVR lib.
Das sind Funktionen, ist ja "nur" C, kein C++.
> Die crc update funktion ist auch in ASM geschrieben.
Ja, aber der Aufruf muss ja auch noch ein wenig berechnen.
pgm_read_byte_far(). Wird nicht extrem ineffizient sein, aber naja.
Ich hab mal schnell was zusammengestrickt, ich komme auf 55 Takte/Byte,
macht bei 128kB und 16 MHz auf ~7,2M Takte, also ~450ms. Naja.
Das ist nur ein Konzept, die Tabelle habe ich jetzt nicht ausgerechnet.
Falk B. schrieb:> Ich hab mal schnell was zusammengestrickt, ich komme auf 55 Takte/Byte
Tja, so ist das, wenn man Codeffizienz einem Compilergott opfert. Da
werden sogar potentiell schnellere Algorithmen im Endeffekt leicht mal
erheblich langsamer als potentiell weniger schnelle.
No mercy. Asm rules. All the time in the past and forever in the future.
That's a natural law!
C-hater schrieb:>> Ich hab mal schnell was zusammengestrickt, ich komme auf 55 Takte/Byte>> Tja, so ist das, wenn man Codeffizienz einem Compilergott opfert.
Dir ist schon aufgefallen, daß mein Beispiel in ASM ist? Klar, um LÄNGEN
schlechter als deine Schöpfungen, aber immerhin schneller als der Status
Quo.
> No mercy. Asm rules. All the time in the past and forever in the future.> That's a natural law!
Mensch bist du COOOOOOOL!! Pubertät ist nicht immer einfach, gelle?
Hier mal die serielle Variante, die leider oder zum Glück fast genau so
schnell wie die Nibble-Variante ist. Denn das Schieben um 4 Bit ist bei
mehreren Bytes auf dem AVR auch wieder relativ langsam, selbst die
Tricks mit swap und Maskierung bringen da nix. Die serielle Variante
braucht 56 Takte/Byte, ist aber einfacher und braucht weniger Speicher,
keinerlei RAM.
Falk B. schrieb:> Ich hab mal schnell was zusammengestrickt, ich komme auf 55 Takte/Byte
Die Lib in crc16.h des AVR-GCC ist inline-Assembler (23 Zyklen) und
braucht mit Loop-Overhead zusammen 41 Zyklen.
Die CRC-CCITT ist mit 17 Zyklen etwas kürzer.
Peter D. schrieb:> Die Lib in crc16.h des AVR-GCC ist inline-Assembler (23 Zyklen) und> braucht mit Loop-Overhead zusammen 41 Zyklen.> Die CRC-CCITT ist mit 17 Zyklen etwas kürzer.
Das widerspricht aber der Wahrnehmung des OP, der von 1-2s Verzögerung
berichtet. OK, kann ein Meßfehler sein.
Wo findet man den Quelltext?
Falk B. schrieb:> Hier mal die serielle Variante, die leider oder zum Glück fast> genau so> schnell wie die Nibble-Variante ist. Denn das Schieben um 4 Bit ist bei> mehreren Bytes auf dem AVR auch wieder relativ langsam, selbst die> Tricks mit swap und Maskierung bringen da nix. Die serielle Variante> braucht 56 Takte/Byte, ist aber einfacher und braucht weniger Speicher,> keinerlei RAM.
Vielen Dank dir, das werde ich testen!
C-hater schrieb:> Ich tippe mal: Troll. Recht gut getarnt, aber nicht perfekt. Meine> Troll-KI kann dich nicht wirklich sehen, ich schon. Geht halt nix über> Eigen-Intelligenz.
Ja da hast du recht, den Troll haben wir jetzt gefunden mit solchen
Kommentaren. Da haben wir wieder so einen DAU sitzen...
Falk B. schrieb:> Das widerspricht aber der Wahrnehmung des OP, der von 1-2s Verzögerung> berichtet. OK, kann ein Meßfehler sein.
Also wenn ich die CRC berechnung auskommentiere habe ich keinen
Verzögerung und ansonsten macht der Bootloader auch aktuell nichts.
Andreas schrieb:> Falk B. schrieb:>> Hier mal die serielle Variante, die leider oder zum Glück fast>> genau so>> schnell wie die Nibble-Variante ist. Denn das Schieben um 4 Bit ist bei>> mehreren Bytes auf dem AVR auch wieder relativ langsam, selbst die>> Tricks mit swap und Maskierung bringen da nix. Die serielle Variante>> braucht 56 Takte/Byte, ist aber einfacher und braucht weniger Speicher,>> keinerlei RAM.>> Vielen Dank dir, das werde ich testen!
Jain. Die Variante ist dahin nicht getestet, ob sie die korrekte CRC
berechnet. Ich war zu faul zu prüfen, ob die originale CRC nach links
oder rechts arbeitet. Kommt in den nächsten Tagen. Mit der Funktion
kannst du aber prüfen, wie schnell sie arbeitet, da ist die
Schieberichtung egal.
>> Das widerspricht aber der Wahrnehmung des OP, der von 1-2s Verzögerung>> berichtet. OK, kann ein Meßfehler sein.>> Also wenn ich die CRC berechnung auskommentiere habe ich keinen> Verzögerung und ansonsten macht der Bootloader auch aktuell nichts.
OK. Trotzdem sollte man versuchen, genauer zu messen. Schalte ein IO-Pin
von der CRC-Berechnung ein und danach wieder aus. Das kann man per Oszi
oder Logicanalyzer messen.
Falk B. schrieb:> pgm_read_byte_far(). Wird nicht extrem ineffizient sein, aber naja.
Da kann man die ersten 64kB pgm_read_byte nutzen, und nur für den
Bereich darüber das dafür benötigten pgm_read_byte_far einsetzen. Das
spart auch wieder einige Takte.
Oliver
Hmm, wenn ich deine Funktion compiliere und im Simulator laufen lasse,
komme ich auf ~5,3M Takte und ~333ms. Ok, in meinem Flash steht fast
nix, was dann bei der CRC oft den etwas kürzeren Pfad bewirkt, aber das
sind keine Größenordnungen. Außerdem scheint der Assemblercode schon
recht kompakt, das kriegt man manuell kaum besser hin, außer unserem one
and only C-hater ;-)
Oliver S. schrieb:> Falk B. schrieb:>> pgm_read_byte_far(). Wird nicht extrem ineffizient sein, aber naja.>> Da kann man die ersten 64kB pgm_read_byte nutzen, und nur für den> Bereich darüber das dafür benötigten pgm_read_byte_far einsetzen. Das> spart auch wieder einige Takte.>> Oliver
Das ist auch eine gute Idee, danke.
Falk B. schrieb:> Hmm, wenn ich deine Funktion compiliere und im Simulator laufen> lasse,> komme ich auf ~5,3M Takte und ~333ms. Ok, in meinem Flash steht fast> nix, was dann bei der CRC oft den etwas kürzeren Pfad bewirkt, aber das> sind keine Größenordnungen. Außerdem scheint der Assemblercode schon> recht kompakt, das kriegt man manuell kaum besser hin, außer unserem one> and only C-hater ;-)
Das hört sich doch schon super an. Ich denke mit einer Prüfsumme wirds
warscheinlich auch nicht mehr kürzer werden oder?
Andreas schrieb:>> Da kann man die ersten 64kB pgm_read_byte nutzen, und nur für den>> Bereich darüber das dafür benötigten pgm_read_byte_far einsetzen. Das>> spart auch wieder einige Takte.>>>> Oliver>> Das ist auch eine gute Idee, danke.
Nicht wirklich. Wenn man sich den ASM-Code anschaut, kostet
pgm_read_byte_far() keine Zusatztakte, denn ELPM ist genau so schnell
wie lpm und das Register RAMPZ muss nur einmalig geschrieben werden. OK,
hier wird es immer wieder beschrieben und auch Z immer wieder neu
geladen, das könnte man in einer manuellen ASM-Funktion optimieren.
Was mir nicht klar ist, wieso die CRC-Berechnung so funktioniert, wie
sie dort beschrieben ist. Es wird am Anfang das neue Datenbyte mit der
CRC XOR-verknüpft und dann nur die einzelnen Bits nach und nach
geschoben und XOR-verknüpft oder nicht. Funktioniert das SO wirklich?
Ich kenne das anders, uns zwar das die einzelnen Bits immer nacheinander
in das Byte geschoben werden müssen, wenn man das so seriell bearbeitet.
Aus crc16.h
1
/** \ingroup util_crc
2
Optimized CRC-16 calculation.
3
4
Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)<br>
5
Initial value: 0xffff
6
7
This CRC is normally used in disk-drive controllers.
8
9
The following is the equivalent functionality written in C.
10
11
\code
12
uint16_t
13
crc16_update(uint16_t crc, uint8_t a)
14
{
15
int i;
16
17
crc ^= a;
18
for (i = 0; i < 8; ++i)
19
{
20
if (crc & 1)
21
crc = (crc >> 1) ^ 0xA001;
22
else
23
crc = (crc >> 1);
24
}
25
26
return crc;
27
}
28
29
\endcode */
30
31
static__inline__uint16_t
32
_crc16_update(uint16_t__crc,uint8_t__data)
33
{
34
uint8_t__tmp;
35
uint16_t__ret;
36
37
__asm____volatile__(
38
"eor %A0,%2""\n\t"
39
"mov %1,%A0""\n\t"
40
"swap %1""\n\t"
41
"eor %1,%A0""\n\t"
42
"mov __tmp_reg__,%1""\n\t"
43
"lsr %1""\n\t"
44
"lsr %1""\n\t"
45
"eor %1,__tmp_reg__""\n\t"
46
"mov __tmp_reg__,%1""\n\t"
47
"lsr %1""\n\t"
48
"eor %1,__tmp_reg__""\n\t"
49
"andi %1,0x07""\n\t"
50
"mov __tmp_reg__,%A0""\n\t"
51
"mov %A0,%B0""\n\t"
52
"lsr %1""\n\t"
53
"ror __tmp_reg__""\n\t"
54
"ror %1""\n\t"
55
"mov %B0,__tmp_reg__""\n\t"
56
"eor %A0,%1""\n\t"
57
"lsr __tmp_reg__""\n\t"
58
"ror %1""\n\t"
59
"eor %B0,__tmp_reg__""\n\t"
60
"eor %A0,%1"
61
:"=r"(__ret),"=d"(__tmp)
62
:"r"(__data),"0"(__crc)
63
:"r0"
64
);
65
return__ret;
66
}
> Das hört sich doch schon super an.
Steht aber im Widerspruch zu deinen Beobachtungen. Miss die Zeit GENAU
mittels Oszi oder Logicanalyzer.
> Ich denke mit einer Prüfsumme wirds> warscheinlich auch nicht mehr kürzer werden oder?
CRC IST eine Prüfsumme, wenn gleich eine mathematisch komplexere. Du
meinst wahrscheinlich eine einfache Prüfsumme, die wirklich nur addiert
oder die Parität berechnet. Die ist schon schneller, dafür aber deutlich
schlechter in der Fehlererkennung. Aber auch eine 16 Bit CRC ist für
128kB Flash eigentlich zu klein, da sollte man eher mit 32 Bit arbeiten,
wenn das Thema Fehlererkennung wirklich ernst genommen wird.
Falk B. schrieb:> OK,> hier wird es immer wieder beschrieben und auch Z immer wieder neu> geladen, das könnte man in einer manuellen ASM-Funktion optimieren.
Mit hätte hätte Fahrradkette hätte der TO seine ganzen Probleme erst gar
nicht.
Zudem kann die erste Schleife unterhalb der 64kB Grenze mit einem 16 Bit
Schleifenzähler laufen, die darüber braucht einen 32bit Zähler. Sind
auch wieder ein paar Takte Unterschied.
Oliver
Oliver S. schrieb:> Mit hätte hätte Fahrradkette hätte der TO seine ganzen Probleme erst gar> nicht.
Ohne eine solide Messung weiß man gar nichts.
> Zudem kann die erste Schleife unterhalb der 64kB Grenze mit einem 16 Bit> Schleifenzähler laufen,
Stimmt.
> die darüber braucht einen 32bit Zähler.
Nö, in ASM geht das auch mit 24 Bit. Außerdem kann das der AVR in ASm
auch in Hardware, elpm R1, Z+ funktiniert wunderbar und kostet KEINERLEI
Zusatztakte.
> Sind> auch wieder ein paar Takte Unterschied.
Nö, nicht in ASM, wenn man weiß was man tut. Und das Macro in crc16.h
ist Inline Assembler, wenn gleich das nicht die Schleife für die
Datenbytes enthält.
Ok, hier nochmal explizit die Frage zur CRC-Berechnung, auch wenn sie
nicht direkt zum Thema passt. Ist die Berechnung in der crc16.h korrekt?
1
/** \ingroup util_crc
2
3
Optimized CRC-16 calculation.
4
Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)<br>
5
Initial value: 0xffff
6
This CRC is normally used in disk-drive controllers.
7
The following is the equivalent functionality written in C.
8
\code
9
uint16_t
10
crc16_update(uint16_t crc, uint8_t a)
11
{
12
int i;
13
crc ^= a;
14
for (i = 0; i < 8; ++i)
15
{
16
if (crc & 1)
17
crc = (crc >> 1) ^ 0xA001;
18
else
19
crc = (crc >> 1);
20
}
21
return crc;
22
}
23
24
\endcode */
25
26
static__inline__uint16_t
27
28
_crc16_update(uint16_t__crc,uint8_t__data)
29
{
30
31
uint8_t__tmp;
32
uint16_t__ret;
33
34
__asm____volatile__(
35
"eor %A0,%2""\n\t"
36
"mov %1,%A0""\n\t"
37
"swap %1""\n\t"
38
"eor %1,%A0""\n\t"
39
"mov __tmp_reg__,%1""\n\t"
40
"lsr %1""\n\t"
41
"lsr %1""\n\t"
42
"eor %1,__tmp_reg__""\n\t"
43
"mov __tmp_reg__,%1""\n\t"
44
"lsr %1""\n\t"
45
"eor %1,__tmp_reg__""\n\t"
46
"andi %1,0x07""\n\t"
47
"mov __tmp_reg__,%A0""\n\t"
48
"mov %A0,%B0""\n\t"
49
"lsr %1""\n\t"
50
"ror __tmp_reg__""\n\t"
51
"ror %1""\n\t"
52
"mov %B0,__tmp_reg__""\n\t"
53
"eor %A0,%1""\n\t"
54
"lsr __tmp_reg__""\n\t"
55
"ror %1""\n\t"
56
"eor %B0,__tmp_reg__""\n\t"
57
"eor %A0,%1"
58
:"=r"(__ret),"=d"(__tmp)
59
:"r"(__data),"0"(__crc)
60
:"r0"
61
);
62
return__ret;
63
}
Ich habe sowohl das Inline-ASM Macro als auch die im Kommentar
dargestellte C-Funktion mit ein paar Daten getestet, beide liefern das
gleiche Ergebnis. Aber das entspricht nicht der mir bekannten
CRC-Berechnung. Das hier ist meiner Meinung nach falsch.
1
crc^=a;
Das kann man nicht einfach so am Anfang tun. Der meiner Meinung nach
korrekte Algorithmus sieht so aus. Man muss bei serieller CRC-Berechnung
jedes Bit einzeln reinschieben und das XOR machen. Damit kommt natürlich
eine ganz andere CRC-Prüfsumme zu stande.
1
uint16_t
2
crc16_update(uint16_tcrc,uint8_ta)
3
{
4
inti;
5
for(i=0;i<8;++i)
6
{
7
if(crc&1){
8
crc=(crc>>1);
9
if(data&1)crc|=0x8000;// LSB in MSB kopieren
10
crc^=0xA001;
11
}else{
12
crc=(crc>>1);
13
if(data&1)crc|=0x8000;// LSB in MSB kopieren
14
}
15
data>>=1;
16
}
17
returncrc;
18
}
Welche Rechnung ist korrekt? Die Rechnung oben habe ich auch schon für
oneWire benutzt und das Ergebnis war korrekt. In der crc16.h gibt es
dafür auch ein ASM-Macro, welches das gleiche Konzept anwendet und damit
falsche Ergebnisse liefert. Hat schon mal einer die crc16.h in der
realen Welt geprüft?
Falk B. schrieb:>> die darüber braucht einen 32bit Zähler.>> Nö, in ASM geht das auch mit 24 Bit.
Wäre aber unsinnig, denn in ASM reicht die 16Bit des Z-Registers mit lpm
rN, Z+. Einmal rum, dann RAMPZ gesetzt, und noch ´ne Runde. Wenn du
schon mit ASM hier rumprahlst, dann wenigstens richtig.
Oliver
MaWin O. schrieb:>> Das kann man nicht einfach so am Anfang tun.>> Doch, kann man.
Toll, und warum?
Mein Wissen beruht hier rauf, der Klassiker
http://www.ross.net/crc/download/crc_v3.txt
Und auch wenn dort die vielen Spielarten mit reflected etc. dargestellt
sind, ist die Variante mit direktem XOR der Daten dort nicht zu finden.
Naja. Die verschiedenen Online CRC Tools spucken alle das gleiche
Ergebnis für meine Test aus.
CRC-16 Modbus mit Polynom 0x8005 und 0xFFFF initialwert, Ein- und
Ausgang reflektiert. Testdaten
Oliver S. schrieb:>> Nö, in ASM geht das auch mit 24 Bit.>> Wäre aber unsinnig, denn in ASM reicht die 16Bit des Z-Registers mit lpm> rN, Z+. Einmal rum, dann RAMPZ gesetzt, und noch ´ne Runde. Wenn du> schon mit ASM hier rumprahlst, dann wenigstens richtig.
Du hast es nötig. Man muss RAMPZ nicht nach einer Runde rum setzen, das
geht alles in einer Schleife.
Falk B. schrieb:>>> Das kann man nicht einfach so am Anfang tun.>>>> Doch, kann man.>> Toll, und warum?> Mein Wissen beruht hier rauf, der Klassiker>> http://www.ross.net/crc/download/crc_v3.txt
Hmm, das hier scheint mir ein Hinweis zu sein.
1
These facts, combined with the XOR property
2
3
(A xor B) xor C = A xor (B xor C)
4
5
mean that message bytes need not actually travel through the W/4 bytes
6
of the register. Instead, they can be XORed into the top byte just
7
before it is used to index the lookup table. This leads to the
8
following modified version of the algorithm.
9
10
11
+-----<Message (non augmented)
12
|
13
v 3 2 1 0 Bytes
14
| +----+----+----+----+
15
XOR----<| | | | |
16
| +----+----+----+----+
17
| ^
18
| |
19
| XOR
20
| |
21
| 0+----+----+----+----+ Algorithm
22
v +----+----+----+----+ ---------
23
| +----+----+----+----+ 1. Shift the register left by
24
| +----+----+----+----+ one byte, reading in a new
25
| +----+----+----+----+ message byte.
26
| +----+----+----+----+ 2. XOR the top byte just rotated
27
| +----+----+----+----+ out of the register with the
28
+----->+----+----+----+----+ next message byte to yield an
29
+----+----+----+----+ index into the table ([0,255]).
30
+----+----+----+----+ 3. XOR the table value into the
31
+----+----+----+----+ register.
32
+----+----+----+----+ 4. Goto 1 iff more augmented
33
255+----+----+----+----+ message bytes.
Das funktioniert auch mit dem seriellen Algorithmus. Der Rest des
ASM-Macro, welche für die CRC16 mit 0xA001 KEINERLEI Verzweigungen
enthält ist somit vermutlich eine Handoptimierung der XORs auf dieses,
spezielle Polynom.
Ok, hier die kleine Optimierung, wenn man die Schleife um die CRC in ASM
per Hand gestaltet. Macht 33 Takte/Byte. Die eigentliche, trickreiche
CRC-Berechnung braucht 23 Takte, habe ich einfach kopiert. Die Variante
in C mit Inline-ASM Macro ist nicht sooo viel schlechter mit 41
Takte/Byte.
Mach's halt wie die Großen: während der CRC-Berechnung eine Animation
abspielen. Dauert dann zwar noch länger, aber der Anwender ist
beschäftigt, findet das evtl gar noch "geil". Alternativ einen
Screenshot der Anwendung darstellen bevor man mit dem langsamen Kram
loslegt ... den Anwendern ist antrainiert worden, dass das ganz normal
ist, wenn in den ersten paar Sekunden/Minuten nichts geht.
Foobar schrieb:> Mach's halt wie die Großen: während der CRC-Berechnung eine> Animation> abspielen. Dauert dann zwar noch länger, aber der Anwender ist> beschäftigt, findet das evtl gar noch "geil". Alternativ einen> Screenshot der Anwendung darstellen bevor man mit dem langsamen Kram> loslegt ... den Anwendern ist antrainiert worden, dass das ganz normal> ist, wenn in den ersten paar Sekunden/Minuten nichts geht.
Ja, das hatte ich mir tatsächlich auch schon überlegt, da das wirklich
oft gemacht wird.
Falk B. schrieb:> Ok, hier die kleine Optimierung, wenn man die Schleife um die CRC> in ASM> per Hand gestaltet. Macht 33 Takte/Byte. Die eigentliche, trickreiche> CRC-Berechnung braucht 23 Takte, habe ich einfach kopiert. Die Variante> in C mit Inline-ASM Macro ist nicht sooo viel schlechter mit 41> Takte/Byte.
Vielen Dank für eure Hilfe!
Werde die ASM routine von Falk als Basis nutzen, eventuell noch etwas
verändern und diesen dann nutzen. Der liefert gute Ergebnisse.
Vielen Dank.