Hallo Leute,
ich brauche eine frische Idee!
uCOS-II läuft auf mega128, WinAVR-20070525. Das Gerät hat
Command-Line-Interface, da hantiere ich ziemlich viel mit printf und
ROM-strings rum.
warum soll
das System abstürzen?
Es gibt ausreichend Stack (sieht man mit JTAG ICE). Es gibt nur 1 Task
(bei diesem Test) und Rx/Tx UART-Fifos (Interrupt-gesteuert), die
scheinbar ok sind, immerhin kann ich Tabellen-Köpfe und sonstigen
multi-Kb ASCII-Art-Kram ganz ok printen.
Gibt es was besonderes über sprintf_P? Nutzt diese Funktion vielleicht
den HEAP, den ich nicht organiziert habe? Oder einen globalen Bereich
statt Task-Stack, womit mein uCOS-II nicht mehr klar kommt?
Warum nimmst du sprintf_P() wenn dein format string doch im RAM steht?
Nimm sprintf(). Wenn der Ziel-String im ROM steht, nimm %S statt %s
(und ignoriere GCCs Warnung über einen angeblichen wchar_t *, ich habe
noch nicht rausgefunden, wie man ihm das abgewöhnen kann).
Jörg Wunsch wrote:
> Warum nimmst du sprintf_P() wenn dein format string doch im RAM steht?
Wie meinst du das?
Der OP schrieb:
char FMT_NAMEVALUE [] PROGMEM =" PARAM1=%d\r\n";
uint8_t value;
sprintf_P(&PrnBuf[0], FMT_NAMEVALUE, value); /* name=%d */
ist m.M. doch in Ordnung? Oder hab ich grade ein Blackout?
Ich weiss, dass es ga-a-anz viel bei einem RTOS passieren kann. Aber wo
ist es diesmal??
Wenn der Context-Switch alle Register und RAMPZ und dazu noch SPH und
SPL speichert und wiederherstellt, wenn ich über 256 bytes Reserve im
Task Stack habe, was passiert dieser Funktion (sodass sie kracht):
In den Zeilen 113 bis 120 soll der Stack aufgeräumt werden, indem der
Stackpointer auf den Wert gesstzt wird, den er vor dem Ablegend der
Argumente von sprintf_P hatte.
Da es sich um einen atomaren Zugriff auf SPH und SPL handeln muss,
müssen die Interrupts gesperrt werden.
ABER die Interrupts werden IMHO eine Anweisung zu früh freigegeben.
Das untere Byte des Spackpointers ist noch nicht restauriert.
So sähe es für mich sinnvoller aus
1
116 0024 0FB6 in __tmp_reg__,__SREG__
2
117 0026 F894 cli
3
118 0028 9EBF out __SP_H__,r25
4
119 002c 8DBF out __SP_L__,r24
5
120 002a 0FBE out __SREG__,__tmp_reg__
Eigentlich ist IMHO schon das Sperren der Interrupts (Zeile 116-117) vor
dem Auslesen des 16-Bit Stackpointers (Zeile 113-115) sinnvoll, wenn man
AVR072: Accessing 16-Bit Registers beachtet.
Du suchst an der falchen Ecke. sprintf, und die avr-libc funktionieren
ohne das RTOS einwandfrei.
Dein Problem der Zeilen 113ff ist keins:
Beitrag "Re: Compilerbug bei AVR-GCC ?: Stack Pointer und Interrupts"
Um das Problem zu lösen, wäre ein anständiger Simulator hilfreich.
Leider sind die sourcen des RTOS nicht im Netz zu finden, sonst könnte
man es mal in VMLAB laufen lassen.
Oliver
Nein, das ist kein Problem. Auch wenn es nirgends dokumentiert ist,
2
hat Atmel dem Compilerschreiber mal irgendwann bestätigt, dass die
3
Interruptfreigabe in der Tat und garantiert erst einen Befehl
4
verspätet erfolgt, d.h. der Befehl direkt nach einer Zuweisung an das
5
SREG, bei dem das I-Bit wieder gesetzt wird, wird selbst bei einem
6
anhängigen Interrupt noch ausgeführt.
Beitrag "Re: Compilerbug bei AVR-GCC ?: Stack Pointer und Interrupts"
Und "Why are interrupts re-enabled in the middle of writing the stack
pointer?" in der FAQ der avr-libc?
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_spman
Beim SEI ist das Verhalten bzgl. des unmittelbar folgenden ASM-Befehls
im Manual "8-Bit AVR Instruction Set" dokumentiert (SEI - Sets the
Global Interrupt Flag (I) in SREG (Status Register). The instruction
following SEI will be executed before any pending interrupts.)
Eine entsprechende Doku von Atmel beim OUT SREG,... habe ich nicht
gesehen und so bleibt meine Grundskepsis ;-)
Es wäre mal interessant, ob ein gepatchtes Binary (out
_SREG_,__tmp_reg__ zu SEI gepatcht) die gleichen Probleme zeigt.
Leider habe ich kein Binary, welches die Probleme hat, aber vielleicht
kann m_bedded den Test machen?
BTW. Was passiert eigentlich bei sprintf_P mit nur zwei Parametern?
Bei nur zwei Parametern wird obige Methode zur Stackkorrektur nicht
verwendet. Stattdessen werden klassische POPs gemacht (Zeile 107-110).
Stefan "stefb" B. wrote:
> Eigentlich ist IMHO schon das Sperren der Interrupts (Zeile 116-117) vor> dem Auslesen des 16-Bit Stackpointers (Zeile 113-115) sinnvoll, wenn man> AVR072: Accessing 16-Bit Registers beachtet.
Das ist Unfug. Da habe ich nicht ausreichend überlegt ;-)
Oliver wrote:
> Um das Problem zu lösen, wäre ein anständiger Simulator hilfreich.> Leider sind die sourcen des RTOS nicht im Netz zu finden, sonst könnte> man es mal in VMLAB laufen lassen.
Grundsätzlich kann man die Sourcen zur Evaluation bekommen und zwar
FREE. Allerdings muss man sich bei http://www.micrium.com/ registrieren
und kann dann 45 Tage testen.
>Grundsätzlich kann man die Sourcen zur Evaluation bekommen
Hab mich mal registriert, und mir das mal angesehen. Vielleicht brauch
ich ja auch mal ein uCOS auf eine AVR, wenn ich bisher auch nicht
wüsste, wofür.
Das sieht allerdings schlecht aus.
Downloadbar sind ist nur die aktuelle V 2.85, und für die gibt es keinen
avr-gcc port. Die verfügbaren gcc-ports benötigen v2.70, dafür gibt es
die sourcen nicht mehr zum download.
Das es vom avr-gcc-port eine aktuellere Version auf
https://www.ee.lut.fi/staff/Julius.Luukko/ucos-ii/avr/download.shtml
gibt, hast du aber mitbekommen? Die Vorversion hatte da einen bug
https://www.ee.lut.fi/staff/Julius.Luukko/ucos-ii/avr/bugs.shtml
Wie gesagt, wenn du alle sourcen hast, wäre ein Versuch mit VMLAB nicht
verkehrt. Das gibts im Netz, ist nicht ganz fertig, aber das, was geht,
ist ganz ok. Und weil die VMLAB-Entwickler die Stelle zu OUT SREG in den
AVR-DOCS auch nicht gefunden haben, simuliert VMLAB das auch nicht
richtig. Abhilfe schafft
Beitrag "VMLAB Interrupt zu früh, Stackpointer falsch"
Oliver
Jörg Wunsch wrote:
> Ab da werden die Argumente vom Stack bewertet. Die ersten beiden> Argumente werden in Registern übergeben.
Das sehe ich anders, zumindest bei meinen beiden Übersetzungen oben.
In meinen beiden Assemblerlistings für 3 bzw. 2 Argumente werden niemals
Argumente in den Registern übergeben. Alle Argumente werden per PUSH auf
den Stack gegeben. Die verwendete Optimierung war -Os.
Bei einer Funktion mit variabler Argumentliste wie es sprintf_P ist,
macht das IMHO auch Sinn.
Der Unterschied zwischen 3 und 2 Argumenten ist die Art, wie die
Argumente wieder vom Stack abgereinigt werden - bei 2 Argumenten mit POP
und bei 3 Argumenten mit einer Stackpointermanipulation inklusive
Interruptsperrung.
Ich bezog die zwei Argumente auf die Adresse des Puffers und den
Formatstring. Die sind noch nicht variabel.
Kann aber auch sein, dass es durch die unterschiedliche Methode
der Übertragung auf den Stack ist.