www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrupt Routine von C in Assembler umschreiben -> Hängt


Autor: Malte __ (malte) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe eine SPI Interrupt Routine in C, die auch funktioniert. Da aber 
der Stack im externem Speicher mit Waitstates liegt, ist die Routine 
effektiv langsamer als wenn ich polling verwenden würde. Da recht viele 
Daten über die Schnittstelle gehen, werden so durchaus 27% aller CPU 
Zyklen nur für den Interrupt verbraucht.
Ich habe die Routine in Assembler umgeschrieben. Der Code kommt mit 
weniger Registern aus und soll diese im schnellerem internem RAM sichern 
und sollte somit insgesamt rund doppelt so schnell sein.
Leider hängt die Verwendung der Assembler Routine meinen ATMega128 
komplett auf. Wo ist der Fehler? Das es nicht auf Anhieb komplett 
funktioniert, habe ich irgendwie erwartet, aber nicht dass der MCU 
hängt.

Der Code soll den Inhalt von fastbuff (32 Byte Größe) über SPI senden 
und sobald der Buffer übertragen ist, Timer3 aktivieren.

Die funktionierende C Routine:
/* a run takes approx: prologue: 39, calc: 17, epiloge: 39, sum: 95
 */
SIGNAL(SIG_SPI) {
  uint8_t fbct = fastbuffcnt;
  if (fbct < fastbuffmax) {
    SPDR = fastbuff[fbct];
    fbct++;
    fastbuffcnt = fbct;
  } else {
    TCNT3 = -100; //overflow in 100 clocks -> current SPI must have finished
    TCCR3B = 1<<CS30;
    cbi(SPCR, SPIE);
  }
}

der fehlerhafte Code:

uint8_t regbuff[4]; //faster than the external RAM
/* System clocks:
   prologue: 13
   code: 20
   epilogue: 13
   sum: 43
*/
//SIGNAL(SIG_SPI) __attribute__((naked));
ISR(SIG_SPI, ISR_NAKED) {
  asm volatile (
  //prologue
  "sts regbuff, r30""\n\t"
  "sts (regbuff)+1, r31""\n\t"
  "in r30, __SREG__""\n\t"
  "sts (regbuff)+2, r30""\n\t"
  "sts (regbuff)+3, r29""\n\t"
  //code
  "lds r29, fastbuffcnt""\n\t"   //SPDR = fastbuff[fastbuffcnt];
  "ldi r30, lo8(fastbuff)""\n\t"
  "ldi r31, hi8(fastbuff)""\n\t"
  "add r30, r29""\n\t"
  "clr r29""\n\t"
  "adc r31, r29""\n\t"
  "ld r29, Z""\n\t"
  "out %0, r29""\n\t"
  "lds r30, fastbuffcnt""\n\t"  // fastbuffcnt++;
  "inc r30""\n\t"
  "sts fastbuffcnt, r30""\n\t"
  "lds r31, fastbuffmax""\n\t"  // if (fastbuffermax =< fastbuffcnt ) {
  "cp r30, r31""\n\t"
  "brlo 1f""\n\t"
  "ldi r30, lo8(-100)""\n\t"    // TCNT3 = -100;
  "ldi r31, hi8(-100)""\n\t"
  "sts %1, r31""\n\t"
  "sts %2, r30""\n\t"
  "ldi r30,lo8(1)""\n\t"        // TCCR3B = 1<<CS30;
  "sts %3, r30""\n\t"
  "cbi %4,7""\n\t"              // cbi(SPCR, SPIE);
  "1:""\n\t"                    // }
  //epilogue
  "lds r29, (regbuff)+3""\n\t"
  "lds r30, (regbuff)+2""\n\t"
  "out __SREG__, r30""\n\t"
  "lds r31, (regbuff)+1""\n\t"
  "lds r30, (regbuff)+0"
  : : "M" (_SFR_IO_ADDR(SPDR)), "M" (_SFR_IO_ADDR(TCNT3H)),
             "M" (_SFR_IO_ADDR(TCNT3L)), "M" (_SFR_IO_ADDR(TCCR3B)),
             "M" (_SFR_IO_ADDR(SPCR)));
  reti();
}

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Malte __ schrieb:
> Da aber der Stack im externem Speicher mit Waitstates liegt

Das solltest du schleunigst ändern. Oder gibt es auch nur einen guten 
Grund dafür?

> Leider hängt die Verwendung der Assembler Routine meinen ATMega128
> komplett auf.

Das dürfte an den falschen "_SFR_IO_ADDR" liegen.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:

> Das dürfte an den falschen "_SFR_IO_ADDR" liegen.

Um es ausführlicher zu machen:  Nimmst Du STS/LDS usw., musst Du 
Ram-Adressen verwenden, also Labels ohne __SFR_IO_ADDR().  Nimmst Du 
I/O-Befehle wie IN/OUT/SBI etc., brauchst Du I/O-Adressen, also mit 
_SFR_IO_ADDR().

Autor: Malte __ (malte) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Malte __ schrieb:
>> Da aber der Stack im externem Speicher mit Waitstates liegt
>
> Das solltest du schleunigst ändern. Oder gibt es auch nur einen guten
> Grund dafür?
Ich verwende einen kooperativen Scheduler. Und alle Threads zusammen 
benötigen mehr Stack (derzeit in der Summe ~8KB) als interner RAM 
verfügbar ist.

>> Leider hängt die Verwendung der Assembler Routine meinen ATMega128
>> komplett auf.
>
> Das dürfte an den falschen "_SFR_IO_ADDR" liegen.
Hm, stimmt, danach hätte ich lange gesucht. Das generiert Adressen die 
0x20 zu groß sind, wenn die Adresse nur per sts erreichbar ist.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Malte __ schrieb:
> Hm, stimmt, danach hätte ich lange gesucht. Das generiert Adressen die
> 0x20 zu groß sind, wenn die Adresse nur per sts erreichbar ist.

Nein, 0x20 zu klein. ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.