Forum: Compiler & IDEs Idee zur Fehlersuche gesucht


von Olaf (Gast)


Lesenswert?

Ich brauche mal eine Idee zur Fehlersuche. :-)

Folgender etwas komplizierter Sachverhalt. Ich habe mir den neuen gcc, 
newlib und binutils runtergeladen um einen Crosscompiler fuer SH2A zu 
backen. (unter Linux)

Das hat auch vollkommen problemlos funktioniert. Dann habe ich das 
Linkerscript passend zu meiner Hardware abgeaendert und einen eigenen 
Startupcode geschrieben. (Stack setze und bss nullen) CPU ist SH7262

Ich kann problemlos folgendes laufen lassen:

[..]
rs232_init(BAUD_115200);

  do
    {
      led_off(); i=400000; while(i--);

      rs232_printf("Wert: %x\r",0xaa);
      led_on(); i=400000;  while(i--);
    }
  while(1);

Das fuehrt dazu das etwa einmal pro Sekunde meine LED blinkt und der 
erwartete Text auf der seriellen Schnittstelle rauskommt. Mit anderen 
Worten es sieht so aus als wenn mein Compiler schon ganz gut laeuft da 
ja bereits eine ganze Menge Dinge problemlos laufen. (z.B die 
printf-funktion, stack, variablen)

Als naechstes wollte ich die Interrupts in Betrieb nehmen. Dazu muss man 
folgendes wissen. Die SH7262 kennt einmal ganz normale Interruptaufrufe 
wie ihr sie alle kennt. Also alle Register auf den Stack, IRQ, alles 
wieder runter, reti.
Sie kennt aber noch einen zweiten Modi. Alle Register der CPU sind 16mal 
vorhanden. Man kann nun bei jedem Interrupt, aber auch nur bei 
bestimmten Interruptleveln einfach nur die Banks umschalten. 
(Geschwindigkeitsvorteil)
Der gcc unterstuetzt beide Moeglichkeiten!

Wenn ich Interrupts verwenden will dann muss ich die Funktion in eine 
Tabelle eintragen, die Adresse in einem speziellen Register eintragen, 
dem Interrupt einen Level zuweisen und Interrupts fuer diesen Level 
freigeben.

Das habe ich mit einem TimerIRQ gemacht. Der TimerIRQ kommt mit 76kHz. 
Ich zaehle dort bis 76000 und gebe etwas auf die RS232 aus oder lasse 
eine LED blinken, egal was.
Und es funktioniert!

 set_imask(14);                  //IRQ erlauben
 led_on();

Obiges schaltet die IRQs ein. Alles was im IRQ laeuft wird gemacht. Die 
CPU stuerzt also nicht ab! Aber das Hauptrogramm steht! Starte ich den 
IRQ nicht so laeuft das Hauptprogramm ohne Probleme. Ich habe auch schon 
beide moeglichen Interruptaufrufarten ausprobiert. Jedesmal dasselbe 
Ergebnis. Ich habe mir den Source den den der Compiler erzeugt 
angeschaut und er sieht auch unauffaellig aus.

Jemand eine Idee woran das liegen kann?

Olaf

von sudo (Gast)


Lesenswert?

Olaf schrieb:
> Jemand eine Idee woran das liegen kann?

Die CPU verbringt 100% ihrer Zeit in der Interrupt-Routine, und hat 
deswegen keine Zeit mehr für main()?

von Olaf (Gast)


Lesenswert?

> Die CPU verbringt 100% ihrer Zeit in der Interrupt-Routine, und hat
> deswegen keine Zeit mehr für main()?

Gut! Da bin ich gerade auch drauf gekommen. :-)

Genauer gesagt ich habe einfach mal in meiner Interruptroutine den 
Interrupt abgeschaltet und schon laeuft das Hauptprogramm.

Ich habe mich im uebrigen in obigen Post vertan. Nicht der IRQ laeuft 
72kHz sondern das ist die Frequenz des Timers und der laeuft immer bis 
72. Es sollte also ein IRQ 1ms auftreten.

Interessanterweise sieht meine IRQfunktion derzeit so aus:


  TestTicker++;

  if (TestTicker>72000)
    {

      rs232_printf("aba[%i]\r",counter++);
          TestTicker=0;


       if (counter == 15)
            {
              INTC.IPR10.BIT._CMT0 = 1; //1= sehr niedrige Prioritaet, 
15= sehr hoch
              rs232_printf("Selbstmord\r");

            }

    }


Das fuehrt zu einer Ausgabe etwa einmal pro Sekunde. Mit anderen Worten 
der Timer laeuft viel schneller als ich es erwarte. Das ist in sofern 
uberraschend weil ich die Timerfunktion von einem anderen Project das 
ich fuer den Renesascompiler geschrieben habe, uebernommen habe. Dies 
sind also getestet und lauffaehig.
Jetzt habe ich aber ebenfalls von Renesas die Definition der internen 
Register der CPU uebernommen. Das wurde zwar problemlos uebersetzt, aber 
ich vermute das dort irgendwo ein Zugriff in falsche Wordbreite auf ein 
Register erfolgt oder etwas in der Art. Ich habe gerade auch mal das 
Compareregisters des Timers auf einen anderen Wert gesetzt ohne das dies 
die Ausgabegeschwindigkeit beinflusst hat.

Jedenfalls bin ich erstmal weiter.

Da erwartet man den Fehler in den tiefsten Untiefen und dann ist es 
etwas so banales... :-)

Olaf

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Funktionen wie printf sollte man nie aus einem Interrupthandler heraus 
aufrufen, auch nicht Funktionen, die mehrere Bytes an eine serielle 
Schnittstelle o.ä. ausgeben.

von Ronny (Gast)


Lesenswert?

> Funktionen wie printf sollte man nie aus einem Interrupthandler heraus
> aufrufen, auch nicht Funktionen, die mehrere Bytes an eine serielle
> Schnittstelle o.ä. ausgeben.

Mal etwas genauer:

Man sollte den Interrupt so schnell wie möglich verlassen. Aber gerade 
auf kleineren Controllern mit wenig RAM wird printf oft ungepufftert 
verwendet, d.h. printf wartet bis der gesamte String über die UART raus 
gepurzelt ist. Bei niedrigen Baudraten kann das schon etwas dauern ;)

9600 Baud, 10 Zeichen bedeuten dann etwas über 8ms(!) bis der Interrupt 
beendet ist!

Wenn es unbedingt eine Datenausgabe braucht, dann wären putchar() und 
Konsorten deutlich günstiger. Am besten ist ein Portpin wenn es nur 
darum geht zu signalisieren wann der IRQ angesprungen und verlassen 
wird.

von Olaf (Gast)


Lesenswert?

> Funktionen wie printf sollte man nie aus einem Interrupthandler heraus
> aufrufen, auch nicht Funktionen, die mehrere Bytes an eine serielle
> Schnittstelle o.ä. ausgeben.

Das weiss ich! War aber nur ein Test um zu sehen ob ueberhaubt was 
laeuft.

Mittlerweile laeuft uebrigens alles. Fehler sass wie immer vor dem 
Bildschirm. Ich war der Meinung eine laufende Funktion zu testzwecken 
aus meinem Renesasverzeichnis kopiert zu haben, habe aber wohl 
versehentlich aus einer aelteren Programmversion kopiert und da hatte 
ich wohl vergessen im Interrupt das Ueberlaufflag des Timers zu 
loeschen. Deshalb ging die Kiste sofort wieder im Interrupt.

Man denkt nur nicht daran das der Fehler so einfach sein kann wenn man 
einen neuen Compiler erstmals in Betrieb nimmt, gerade vor dem 
Hintergrund das der SH7262 bei den Interrupts viele Moeglichkeiten 
bietet etwas falsch zu machen.

> Mal etwas genauer:

Ich mache es normalerweise so das mein printf alles in eine Fifo wirft 
und die dann vom Interrupt Zeichenweise gelehrt wird. Aber erstmal muss 
mein System hier ueberhaubt funktionieren. Das war etwas komplizierter 
weil ich den Linker dazu bringen musste vor jedem Code einen Header zu 
erzeugen wo Groesseninformation des Codes, Zieladresse, Einsprungadresse 
und Magicnummer drin stehen. Sonst laedt mein Bootloader den Code nicht 
von der SD-Karten.
Aber nachdem ich jetzt alles laufen habe kann ich ja mal was dickeres 
rueberziehen. :-)

Olaf

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
Noch kein Account? Hier anmelden.