Hallo,
ich habe ein Problem mit der Funktion ltoa.
In folgendem Progammcode wir die Zahl "-234567" auf dem LCD
rückwärts ausgegeben.
Die LCD-Ausgabe mit lcd_puts funktioniert. Offensichtlich wird der
String von der Funktion ltoa in der falschen Reihenfolge erstellt.
1
chartext[12];// String
2
3
lcd_init(LCD_DISP_ON);// initialize display, cursor off
4
lcd_clrscr();// clear display and home cursor
5
lcd_puts("V 0.1b");// put string to display (line 1)
6
lcd_gotoxy(0,1);// move cursor to position 1 on line 2
7
ltoa(-234567,text,10);
8
lcd_puts(text);// put string to display
Die Ausgabe auf den Display:
V 0.1b
765432-
Was mache ich falsch?
Ziemlich sicher ein Bug. In der originalen Version von ltoa wird der
string tatsächlich umgekehrt in ein array geschrieben. Am Schluss der
Funktion wird der String dann umgedreht:
...
conv_finished:
st Z, _zero_reg_ ; terminate string
pop a_val_hlo ; restore &string as return value
pop a_val_hhi
pop r28 ; restore r28
XJMP _U(strrev) ; reverse string
.endfunc
...
Ich habe mit WinAVR-20080110 angefangen und dann ein Update auf
WinAVR-20100110 durchgeführt. Bei beiden Versionen hatte ich das gleiche
Ergebnis.
Der Prozessor ist ein ATtiny26.
Ich habe mir inzwischen damit geholfen, den String rückwärts auszugeben.
Gruß
Joachim
Joachim schrieb:> Ich habe mir inzwischen damit geholfen, den String rückwärts auszugeben.
Das ist eine unbefriedigende Lösung, denn sie bedeutet, dass das
eigentliche Problem nicht behoben ist.
Bei derartigen Basisfunktionen kannst du davon ausgehen, dass sie
fehlerfrei in der Library sind. Wenn da etwas aussergewöhnliches
passiert, dann deutet das auf einen Fehler irgendwo in deinem Programm
hin, der unentdeckt geblieben ist.
Das ist richtig, das Problem habe ich weder gefunden noch behoben.
Der betroffene Quelltext ist recht einfach:
1
ltoa(-234567,text,10);
2
lcd_puts(text);// put string to display
Die Zahl wurde vom Compiler vermutlich richtig als HEX-Wert in das
Listing übernommen (alle Ziffern tauchen anschließend wieder im Ergebnis
auf).
Die Funktion lcd_puts() stammt aus einer viel benutzten LCD-Bibliothek.
Ich habe die Funktion überprüft, indem ich die Zeichen des Strings in
einer Schleife Byte für Byte übertragen und jede Stelle separat
adressiert habe.
Der erzeugte Assemblercode enthält offensichtlich eine Routine zum
reversieren.
Beim Übersetzen für andere Controller (ATmega8 und ATmega32) hat sich
die Länge des Codes geändert. Das ist aber auf andere Interruptvektoren
und komfortablere Assemblerbefehle zurückzuführen. Die Funktion habe ich
nicht identisch wiedergefunden.
Evtl. hat ja wirklich noch niemand diese Funktion beim ATtiny26
probiert?
U. U. habe ich auch irgendwelche Flags falsch gesetzt?
Echte Compilerfehler sind selten, meistens sitzt das Problem vor dem
Computer. Ich bin zumindest nicht auf ein Problem gelaufen, dass außer
mir bereits alle kennen.
Joachim schrieb:> Das ist richtig, das Problem habe ich weder gefunden noch behoben.> Der betroffene Quelltext ist recht einfach:
Das Problem könnte genausogut auch irgendwo ganz anders stecken.
Du siehst nur die Symptome. Das bedeutet aber nicht, dass die Ursache
ebenfalls hier zu finden ist.
Das ltoa-Problem besteht in der fehlenden Stringumkehrung beim ATtiny26.
Im Web ist dazu nichts zu finden.
Wenn nun die Funktion ltoa nicht funktioniert, dann bestehen gute
Aussichten, dass auch die Funktion itoa nicht richtig arbeitet.
Mit einem kurzen Test konnte das gezeigt werden.
Da die Funktion itoa häufiger gebraucht wird, sind auch schon mehrere
Anwender darüber gestolpert. (Ich bin nun nicht mehr allein mit dem
Problem).
Hier nennt man das "strange behavior":
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=68073&start=0
Das Problem beim ATtiny26 wurde einfach durch Einsatz eines ATmega128
behoben.
Auch hier ist das Problem mit itoa aufgetreten. 1234 wird als 4321
ausgegeben:
http://www.elektroda.pl/rtvforum/topic1511704.html
Hier schiebt es der Programmierer auf seine mangelnden Kenntnisse:
Beitrag "lcd_putint falsche Ausgabe"
und 2003 hat man das Problem auch schon beobachtet:
Beitrag "bei verwendung von itoa alles verkehrtherum"
Der Compiler erzeugt für einen ATmega16 den gleichen Code, wie für einen
ATtiny26. Der Code funktioniert auf dem ATmega16, nicht jedoch auf dem
ATtiny26. Daraus könnte man ableiten, dass der Code in Ordnung ist und
der Prozessor nicht richtig arbeitet.
Dazu wurde der Code der Stringumkehrung extrahiert und als separates
Assemblerprogramm eingebunden. Die Kommentare zeigen was passiert.
(siehe Anlage)
Hier der problematische Teil des Codes:
1
cp r26, r30 ; Stelle fest, ob Z > X,
2
cpc r27, r31
3
brcs schleife2 ; Wenn Z > X, Bytes austauschen
4
ret
Z und X sind Registerpaare, mit denen indirekt RAM adressiert wird. Da
der ATtiny nur 128 Byte RAM hat, kann kein Seitenüberlauf auftreten. Es
reicht deshalb aus, r26 und r30 zu vergleichen. Der Befehl cpc ist
unnütz. Insoweit könnte man von einem Compilerfehler sprechen.
Nach der Auskommentierung des cpc-Befehls arbeitet die Stringumkehrung
auf dem ATtiny26 einwandfrei.
Der cpc-Befehl scheint aber nach meinen ersten Versuchen nicht
ordentlich zu arbeiten und das Carry-Bit nicht in den Vergleich zu
übernehmen, aber das ist eine andere Baustelle.
Gruß
Joachim
Die Frage ist eher, wieso sind r27, r31 nicht richtig initialisiert.
Also was übergibt der Aufrufer an strrev().
Und gibt es vielleicht eine Unterscheidung/Optimierung innerhalb AVR-GCC
die bei kleinen AVRs von 16-Bit Pointern auf 8-Bit-Pointer
runterschaltet.
Das Problem kann ja ohne weiteres bei weiteren Funktionen zu schlagen.
Joachim schrieb:> Das ltoa-Problem besteht in der fehlenden Stringumkehrung beim ATtiny26.> [...]> Der Compiler erzeugt für einen ATmega16 den gleichen Code, wie für einen> ATtiny26. Der Code funktioniert auf dem ATmega16, nicht jedoch auf dem> ATtiny26. Daraus könnte man ableiten, dass der Code in Ordnung ist und> der Prozessor nicht richtig arbeitet.
In der neuesten Version der avr-libc ist strrev in asm implementiert:
http://cvs.savannah.gnu.org/viewvc/avr-libc/libc/string/strrev.S?revision=1.8&root=avr-libc&view=markup> Dazu wurde der Code der Stringumkehrung extrahiert und als separates> Assemblerprogramm eingebunden. Die Kommentare zeigen was passiert.> (siehe Anlage)>> Hier der problematische Teil des Codes:>
1
> cp r26, r30 ; Stelle fest, ob Z > X,
2
> cpc r27, r31
3
> brcs schleife2 ; Wenn Z > X, Bytes austauschen
4
> ret
5
>
> Z und X sind Registerpaare, mit denen indirekt RAM adressiert wird. Da> der ATtiny nur 128 Byte RAM hat, kann kein Seitenüberlauf auftreten. Es> reicht deshalb aus, r26 und r30 zu vergleichen. Der Befehl cpc ist> unnütz. Insoweit könnte man von einem Compilerfehler sprechen.
Nein, offenbar nicht. Bestenfalls eine "missed Optimization in der
avr-libc".
> Nach der Auskommentierung des cpc-Befehls arbeitet die Stringumkehrung> auf dem ATtiny26 einwandfrei.>> Der cpc-Befehl scheint aber nach meinen ersten Versuchen nicht> ordentlich zu arbeiten und das Carry-Bit nicht in den Vergleich zu> übernehmen, aber das ist eine andere Baustelle.
NACK. Wenn es Versionen des ATtiny26 gibt, die einen Hardware-Bug haben,
dann darf CPC nicht so verwendet werden. Die Register werden als
16-Bit-Register initialisiert, so wie die ABI es für Zeiger vorsieht:
diese sind 16 Bit groß, einen Sonderfall für 8-Bit-Pointer kennt avr-gcc
nicht.
Mit meiner jetzigen Konfiguration kann ich den Fehler nicht
nachvollziehen:
WinAVR-20081205 (der Version aus der Arduino IDE 0022)
_AVR_LIBC_VERSION_STRING_ "1.6.4"
Auch in der folgenden Konfiguration gibt es keine Auffälligkeiten:
WinAVR-20100110 (die Letzte von Sourceforge)
_AVR_LIBC_VERSION_STRING_ "1.6.7"
Projektoptionen: Default (-Os) von AVR Studio 4.16 (build 628)
@ Joachim
Kannst du eine komplette Minimalsource geben, die den Fehler noch zeigt?
Hallo,
Stefan B. schrieb:> Die Frage ist eher, wieso sind r27, r31 nicht richtig initialisiert.
In meinem Text habe ich nur drei Zeilen des Anhangs wiedergegeben.
Gleich zu Anfang der Routine werden r26:r27 und r30:r31 eindeutig mit
dem übergebenen Parameter geladen.
Stefan B. schrieb:> Also was übergibt der Aufrufer an strrev().
An strrev wird die Adresse des Strings übergegeben, der umgekehrt werden
soll.
Johann L. schrieb:> In der neuesten Version der avr-libc ist strrev in asm implementiert:
Der Code entspricht m. E. dem, der aktuell für den ATtiny26 erzeugt
wird.
Ich habe das Assemblerprogramm aus dem .lss -Listing herauskopiert.
Die Wurzel des Übels scheint mir im cpc-Befehl zu liegen. Dieser "reicht
das Carry-Bit nicht durch".
Nachdem ich cpc r27, r31 auskommentiert hatte, habe ich den cp r26, r30
in cpc r26, r30 umgestellt und einmal ein CLC und dann ein SEC
vorangestellt.
Beides funktionierte.
Der Befehl cpc müsste auf dem ATtiny26 noch einmal intensiver untersucht
werden.
Stefan B. schrieb:> Mit meiner jetzigen Konfiguration kann ich den Fehler nicht> nachvollziehen:>> WinAVR-20081205 (der Version aus der Arduino IDE 0022)> AVR_LIBC_VERSION_STRING "1.6.4"
Wichtig ist der Prozessor. Der Fehler wurde bisher nur auf dem ATtiny26
beobachtet. Die WinAVR Version ist unerheblich. Ich habe den Fehler bei
WinAVR-20080110 und WinAVR-20100110 beobachtet. 2003 war der Fehler
offensicht bereits vorhanden. Ich halte es deshalb für sehr
wahrscheinlich, dass alle WinAVR-Versionen von 2003 bis heute betroffen
sind.
Falls Du wirklich einen ATtiny26 hast, der den Fehler nicht zeigt, wäre
der Date-Code des ICs interessant.
Gruß
Joachim
@ Stefan B.
Ich vermute, dass Du eine Simulation benutzt hast.
Die wird keinen Fehler zeigen.
Wenn ich das fehlerhafte Programm erst für einen ATtiny26 und dann für
einen ATmega16 übersetze und anschließend beide .lss-Dateien mit
Microsoft Word vergleiche, dann stelle ich fest, dass der entsprechende
Programmteil identisch ist!
Ich will das noch mal auf einem ATmega16 praktisch testen, um
nachzuweisen, dass sich die Controller bei identischem Code verschieden
verhalten.
Eine Minimalversion stelle ich noch zusammen.
Gruß
Joachim
Ja, ich habe nur die Simulation.
Wenn die Toolchain den Pointer richtig 16-Bit an die itoa() und die den
richtig 16-Bit an strrev() übergibt und nur bei paar Attiny26 auf der
Welt (bisher) ein Fehler bei CPC auftritt... liegt es vielleicht an
dem einen Attiny26.
Es ist also richtig und wichtig, dass du nach anderen Berichten und nach
dem Datecode des Attiny26 forschst. Vielleicht ist es ein
Produktionsfehler. Steht etwas in dem Errata-Abschnitt des Datenblatts?
Welcher Datecode hat dein Attiny26?
Vielleicht können die Leute aus
Beitrag "Bleiakku-Lader 12/24V" noch etwas beitragen. Dort
wurde ein Attiny26 benutzt.
Stefan B. schrieb:> ... und nur bei paar Attiny26 auf der> Welt (bisher) ein Fehler bei CPC auftritt...
Ich würde sagen: "... beobachtet wurde".
Ich besitze zwei ATtiny26 mit der Aufschrift:
ATTINY26-16PU 0743
Im Datenblatt ist ein Codefehler festgehalten. Und zwar in
REV1477D-05/03 Punkt 14 und REV1477D-10/03 Punkt 9.
Beides hat aber nichts mit dem hier betrachteten Fall zu tun.
Hast du denn inzwischen ein Minimalbeispiel? Etwa strrev() direkt
aufrufen und anhand des Ergebnisses ne LED an/aus, so daß Fehler
anderswo (LCD, out of RAM, ...) ausgeschlossen werden können.
Zumindest für einige Versionen des ATtiny26 funktioniert kein LPM Rd,
Z+, ditto für LPM Rd, Z; siehe zB in den Errata oder auch EW15952 in
http://supp.iar.com/FilesPublic/UPDINFO/004793/ew/doc/infocenter/iccavr.htm
Damit wird womöglich im Startup-Code die .data-Section nicht richtig
initialisiert.
AFAIK gibt es für dieses Erratum keinen Workaround in den GNU-Tools bzw.
der avr-libc
Hallo Joachim,
ich habe noch nie mit der Funktion Itoa() gearbeitet und diesen Bitrag
nur überflogen, aber wenn ich das richtig verstehe macht sie aus einem
Integer einen String. Jetzt setzt du einen zahlenwert -234567 ein. Ein
Uint hat einen Maximalwert von 65536, ein signed int geht von -32767 bis
32768. Also ist deine Zahl zu groß, Itoa() kann nur was falsches
rausgeben. Schon mal mit "-23456" versucht, um Itoa() zu prüfen?
MFG Markus
Ich wollts ja erst nicht glauben, aber das ist definitiv ein Hardwarebug
im ATtiny26.
Ich hab dann nen ATtiny261 reingesteckt und der läuft einwandfrei.
Ich hab nichtmal neu compiliert, also das gleiche Hexfile vom ATtiny26
reingebrannt.
Anbei mein Testprogramm.
Peter
Joachim schrieb:> Der Prozessor ist ein ATtiny26.> Ich habe mir inzwischen damit geholfen, den String rückwärts auszugeben.
Ich würd dann doch eher zu nem ATtiny261 raten, so teuer sind die ja
nicht.
Ein "falsches" Programm zu schreiben, ist keine gute Lösung.
Vielleicht bist Du auch schon knapp mit Speicher und könntest eh nen
Attiny461 oder 861 gut gebrauchen.
Peter
@Joachim und Peter
Meine Hochachtung und vielen Dank für diesen Einsatz. Derlei HW-Bugs
sind unheimlich schwer zu finden und zu beweisen. Mit solchen Threads
steigt der Wert dieses Forums für uns Entwickler ganz enorm an.
Erst einmal vielen Dank Peter!
Ich hatte vor, den Code auf einem ATmega16 zu überprüfen. Dazu hätte ich
das ganze auf einer anderen Hardware laufen lassen müssen.
Dein Ansatz ist um einiges eleganter. Mit dem Verwenden zweier
pinkompatibler Controller ist der fehlerhafte Controller leichter zu
bestimmen und das Risiko einer abweichenden Hardware sicher
auszuschalten.
Da meine bevorzugten Elektronikversender nur den Attiny26 im Programm
haben, hatte ich keinen neueren 261, 461 etc. zur Hand.
Meine Vermutung, dass der cpc-Befehl fehlerhaft ist, hat sich als falsch
erwiesen. Der cpc-Befehl arbeitet so wie es sein soll.
Der Befehl ld r23, Z+ weist einen gravierenden Fehler auf.
Z wird um 1 erhöht und das HOB von Z wird überraschend auf 0 gesetzt!
Ein Testprogramm dazu im Anhang.
Um den Fehler sehen zu können muss das Programm auf einem ATtiny26
laufen. Eine Simulation reicht sicher nicht aus.
Damit ist der ursächliche Fehler gefunden.
Das Auskommentieren des cpc-Befehls in der strrev-Funktion der
Bibliothek ist sicher eine brauchbare Umgehung für den ATtiny26.
Evtl. finden die Compilerbauer ja auch eine andere Lösung.
Gruß
Joachim
Joachim schrieb:> Z wird um 1 erhöht und das HOB von Z wird überraschend auf 0 gesetzt!
Möglicherweise hat ein übereifriger Designcompiler hier festgestellt,
dass das höhere Adressbyte von Z ja nie benutzt werden kann, sodass
es egal ist, auf welchen Wert man dieses Register setzt.
> Das Auskommentieren des cpc-Befehls in der strrev-Funktion der> Bibliothek ist sicher eine brauchbare Umgehung für den ATtiny26.
Leider wird die avr-libc nicht pro einzelnem Controller compiliert,
sondern die Controller werden zu relativ groben Familien zusammen-
gefasst. Daher ist es nicht ohne weiteres möglich, nur beim ATtiny26
(oder etwa nur bei Controllern mit <= 128 Byte SRAM) diesen Befehl
wegzulassen.
Jörg Wunsch schrieb:> Leider wird die avr-libc nicht pro einzelnem Controller compiliert,> sondern die Controller werden zu relativ groben Familien zusammen-> gefasst. Daher ist es nicht ohne weiteres möglich, nur beim ATtiny26> (oder etwa nur bei Controllern mit <= 128 Byte SRAM) diesen Befehl> wegzulassen.
Damit ist der Attiny26 aber immer noch kaputt, d.h. falls irgendwo
Arithmetik/Vergleiche > 1 Byte gemacht wird, geht's sehr wahrscheinlich
in die Hose -- und das sind ja nicht nur Zeiger. Je nach Ausgeberoutine
werden damit auch falsche Werte angezeigt; zudem ist nicht mal klar, ob
alle Versionen des ATtiny26 betroffen sind.
Vorstellbar als Hack in iotn26.h ist ein
1
asm(".macro cpc a b");
2
asm(".warning ...");
3
asm(".endm");
Aber am wichtigsten ist, daß der Fehler nachgewiesen ist. Wenn in der
Zufunft wieder jemand Huddel mit einem ATtiny26 hat, klingeln bestimmt
bei irgendjemand hier zumindest die Glocken und es muss nicht erst ewig
gesucht werden.
Johann L. schrieb:> Aber am wichtigsten ist, daß der Fehler nachgewiesen ist. Wenn in der> Zufunft wieder jemand Huddel mit einem ATtiny26 hat, klingeln bestimmt> bei irgendjemand hier zumindest die Glocken und es muss nicht erst ewig> gesucht werden.
Man (also: jemand, der davon betroffen ist) sollte zumindest mal einen
Bugreport bei Atmel öffnen.
Langsam, langsam ...
Mit so einem Fehler ist das nicht so einfach.
Anfangs habe ich festgestellt, dass die Begrenzung der Pointerberechnung
auf 8 Bit den Fehler behebt. (durch das auskommentieren von cpc ...) Das
ist aber nicht unbedingt ein Compilerfehler.
Im nächsten Schritt habe ich festgestellt, dass der Pointer zur
indirekten Adressierung Z, bei dem Postincrement-Befehl Z+ überraschend
im HOB auf 0 gesetzt wird. Das ist überraschend und nicht dokumentiert.
Es ist aber nicht zwingend ein Controller-Fehler. Der ATtiny 26 verfügt
über einen SRAM-Bereich, der von 0x00 bis 0x5f adressiert wird. Register
zur indirekten Adressierung sollten deshalb sinnvollerweise auch nur auf
diesen erlaubten Bereich zugreifen. Wenn das alle tun, fällt niemandem
auf, wenn das HOB des Pointers <> 0 ist.
Es sollte deshalb niemand ein Problem mit dem Verhalten des Z+ Befehls
haben.
Die Frage ist nun, weshalb der Maschinencode den String nicht mit 0x005f
adressiert. Das HOB der Stringadresse wird im Controller dynamisch
ermittelt.
Und das geht so:
Zuerst wird der Stackpointer auf die letzte Speicherstelle gesetzt. Beim
Attiny26 wird der 8Bit-Stackpointer korrekt auf 0x5f gesetzt. Das
"HOB-Register des Stackpointers" ist nicht definiert, weil es nicht
benötigt wird und 8 Bit gut ausreichen.
Das Hauptprogramm liest dann den 16-Bit-Stackpointer!, zieht die Länge
des benötigten Speichers ab und setzt den Stackpointer unter den
benötigten Speicher. Die Adresse des definierten Strings liegt nun über
dem Stackpointer und seine Adresse setzt sich aus dem berechneten LOB
und dem HOB aus dem nicht definierten Inhalt des
HOB-Stackpointer-Registers zusammen.
Der Befehl Z+ funktioniert immer dann einwandfrei, wenn die
Speicherseite 0 angesprochen wird. Da das HOB-Stackpointer-Register beim
ATtiny26 beim Lesen nicht definierte Werte liefert, wird eine
Speicherseite <> 0 angesprochen (d.h. HOB <>0), was offensichtlich sogar
gelegentlich funktioniert. Beim Lesen eines nichtdefinierten Registers
besteht aber kein Anspruch auf die Ausgabe eines bestimmten Wertes.
Zusammenfassend:
1. CPC ist in Ordnung. Das Auskommentieren ist nur eine Umgehung.
2. Z+ verhält sich ungewohnt und undokumentiert, ist aber logisch
konsequent.
3. Der vom Compiler generierte Code liest einen 16 Bit Stackpointer aus
einem 8 Bit Stackpointerregister und einem nicht definierten Register
(das auf größeren Controllern als HOB des Stackpointers definiert ist)
So wird der Stackpointer gesetzt (korrekt):
ldi r28, 0xDF ; 223
out 0x3d, r28 ; 61
So wird er am Anfang von main ausgelesen:
in r28, 0x3d ; 61 ; ok
in r29, 0x3e ; 62 ; reserviertes ATtiny26 Register
Nach dieser Erkenntnis würde ich nun doch für einen Compilerfehler
plädieren.
Karl heinz Buchegger schrieb:> Das Problem könnte genausogut auch irgendwo ganz anders stecken.> Du siehst nur die Symptome. Das bedeutet aber nicht, dass die Ursache> ebenfalls hier zu finden ist.
Karl Heinz hat in weiser Voraussicht recht gehabt.
Gruß
Joachim
Joachim schrieb:> So wird er am Anfang von main ausgelesen:> in r28, 0x3d ; 61 ; ok> in r29, 0x3e ; 62 ; reserviertes ATtiny26 Register>> Nach dieser Erkenntnis würde ich nun doch für einen Compilerfehler> plädieren.
"Das haben wir aber schon immer so gemacht." ;-) Auf jedem anderen
AVR funktioniert das auch (auch auf den kleinen mit 128 oder weniger
Byte SRAM).
Eigentlich sollte das egal sein, was im oberen Byte des Zeigers drin
steht, denn da dieses Byte für die Adressierung des SRAMs nicht
benötigt wird, sollte es einfach ignoriert werden. Damit ist es
wiederum auch wurscht, ob das Auslesen des nicht vorhandenen SPH nun
0, 0xff oder 42 ergibt.
Wenn der ATtiny26 das nicht ignoriert und "auf nichts" zugreift,
wenn das obere Byte != 0 ist, dann würde ich das zumindest unter
"surprisingly unexpected behaviour" einsortieren.
Das paßt dann sehr gut mit dem Datenblatt zusammen:
Datasheet Revision History:
9. Removed LPM Rd, Z+ from “Instruction Set Summary” on page 171. This
instruction is not supported in ATtiny26.
Also auch beim LPM-Befehl wird Z+ fehlerhaft berechnet und daher hat man
diesen Befehl einfach wieder "gestrichen".
Statt:
Z = Z + 1;
wird also ausgeführt:
Z = (Z + 1) & 0x00FF;
Atmel hätte besser den Fehler korrigieren sollen, anstatt Befehle zu
entfernen.
Peter
Peter Dannegger schrieb:> Atmel hätte besser den Fehler korrigieren sollen, anstatt Befehle zu> entfernen.
Eine neue Chiprevision kostet halt deutlich mehr als eine neue
Datenblattrevision. ;-) Da es außerdem den ATtiny261 als de-facto-
Nachfolger gibt, wird keiner mehr die Summen für einen neuen
Maskensatz für den alten IC in die Hand nehmen.
Joachim schrieb:> Zusammenfassend:> 1. CPC ist in Ordnung. Das Auskommentieren ist nur eine Umgehung.
Nein. CPC ist nicht in Ordnung, zumindest nach obigen Ergebnissen.
Wer sagt dir, daß das Byte, das per CPC verglichen wird, zu einer
Adresse gehört? Es kann ebenso zur 16-Bit Arithmetik eines Skalars
gehören (Fixed-Point, Integer mit 16, 24, 32, ... Bits).
Ein richtiger Workaround für diesen Silicon-Bug hätte im Assembler
avr-as zu geschehen, z.B.
1
mov R0, Ra
2
sbc R0, Rb
anstatt
1
cpc Ra, Rb
und einem Fatal Error falls Rb = R0.
Ein WA im Compiler ist aufwändiger und fängt weniger Stellen, z.B. keine
in (Inline-)Assembler, und damit auch keine wie im strrev der avr-libc.
Da strrev per ltoa -- also nicht unwahrscheinlich -- benutzt wird, würde
ich vorschlagen, diesen WA für mcu=avr2 direkt in die avr-libc
einzubauen, oder was auch immer grep cpc zu Tage fördert. Ich weiß ja
nicht, wie langsam die Mühlen bei den avr-binutils mahlen... aber wenn
sie so fix sind wie die von avr-gcc, dann gibt es nie einen WA für
diesen Bug im Prozessorkern -- um so übler, da er nicht bei den Errata
auftaucht.
Die Initialisierung von SP geschieht im Startup-Code, und dort könnte
SPH explizit mit Null geladen werden (section .init2 in crttn26.[oS]).
@ Johann L.
Der Fehler ist hier eine Verkettung mehrerer Umstände.
Wenn ich den 16-bit-Vergleich am Ende der strrev-Routine zu einem
8-bit-Vergleich mache, dann verdecke ich das Problem und das Programm
funktioniert.
Da der angesprochene Vergleich korrekt ist und auf allen anderen AVR's
funktioniert, ist entweder, wie von mir Anfangs fälschlicherweise
festgestellt der CPC-Befehl fehlerhaft oder die Eingangsdaten stimmen
nicht.
Hier stimmen die Eingangsdaten nicht, weil der Z+ Befehl das HOB des
Vektors überraschend auf 0 gesetzt hat. Da ein Zeiger auf das RAM im
ATtiny immer 0 im HOB stehen haben muss, ist es kein wirklicher Fehler,
wenn bei Z+ das HOB auf 0 gesetzt wird.
Der Fehler liegt an dieser Stelle darin, dass das HOB des Vektors nicht
bereits vorher auf 0 stand.
Und das ist darauf zurückzuführen, dass die RAM-Adresse gebildet wurde,
in dem man darauf vertraute dass ein nicht definiertes Register beim
Lesen 0 ausgibt. Auch wenn die anderen AVR's offensichtlich 0 ausgeben,
ist es ein Risiko darauf zu vertrauen und das generell vorauszusetzen.
Die Beseitigung des Mangels sollte man an der Quelle durchführen. Dort,
wo zu Beginn der main-Routine die höchste Speicheradresse festgestellt
wird, ist das HOB auf 0 zu setzen und nicht aus dem Stackpointer zu
lesen.
Beim Setzen des Stackpointers wurde das ATtiny26-individuell korrekt
gemacht. Zu Beginn der main-Routine sollte das auch ATtiny26-individuell
machbar sein.
Gruß
Joachim
Jörg Wunsch schrieb:> Wenn der ATtiny26 das nicht ignoriert und "auf nichts" zugreift,> wenn das obere Byte != 0 ist, dann würde ich das ....
Es ist schon so, dass der ATtiny26 das HOB beim Zugriff auf das SRAM
ignoriert. Das SRAM wird entsprechend oft gespiegelt.
Das geht solange gut, bis vor einem Vergleich zweier Zeiger der eine
Zeiger nach einem Z+ Befehl mit & 0x00FF maskiert wurde.
Der Vergleich muss schiefgehen und das Programm liefert eine
Fehlfunktion.
Johann L. schrieb:> Die Initialisierung von SP geschieht im Startup-Code, und dort könnte> SPH explizit mit Null geladen werden (section .init2 in crttn26.[oS]).
Das Laden eines reservierten Registers kann gut gehen, ist aber
ebenfalls keine dokumentierte Funktion. Der ATtiny26 hat nur einen
8-Bit-Stackpointer!
An der Stelle, wo ich einen 16-Bit-Zeiger aus einem 8-Bit-Stackpointer
lade, muss die Korrektur ansetzen.
Es scheint wirklich nur der ATtiny26 betroffen zu sein.
Der ATtiny13 und ATtiny2313 wären zwar auch Kandidaten, aber die haben
den "LPM Rd, Z+" Befehl, also sollten sie funktionieren.
Peter
Joachim schrieb:> @ Johann L.> wie von mir Anfangs fälschlicherweise> festgestellt der CPC-Befehl fehlerhaft
Ok, hatte ich oben wohl überlesen. Was bedeutet eigentlich HOB? Bei der
Suche finde ich da bestenfalls "House of Boys" :-)
Das wird "high order byte" sein, also der höherwertige teil der Adresse.
Peter
Frauenhaus ist mir ein Begriff, aber das es sowas auch für Männer gibt
war mir neu.
Ich verwende seit Jahren
HOB für high order Byte
und
LOB für low order Byte.
Offensichtlich hat sich das aber nicht allgemein durchgesetzt. Hat
jemand andere geeignetere Begriffe dafür?
Zurück zum Thema
Hier noch einmal der fehlerhafte Code: