Interrupt Routine von C in Assembler umschreiben -> Hängt

OP Persönliche Seite #1478256
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:
1
/* a run takes approx: prologue: 39, calc: 17, epiloge: 39, sum: 95
2
 */
3
SIGNAL(SIG_SPI) {
4
  uint8_t fbct = fastbuffcnt;
5
  if (fbct < fastbuffmax) {
6
    SPDR = fastbuff[fbct];
7
    fbct++;
8
    fastbuffcnt = fbct;
9
  } else {
10
    TCNT3 = -100; //overflow in 100 clocks -> current SPI must have finished
11
    TCCR3B = 1<<CS30;
12
    cbi(SPCR, SPIE);
13
  }
14
}

der fehlerhafte Code:
1
uint8_t regbuff[4]; //faster than the external RAM
2
/* System clocks:
3
   prologue: 13
4
   code: 20
5
   epilogue: 13
6
   sum: 43
7
*/
8
//SIGNAL(SIG_SPI) __attribute__((naked));
9
ISR(SIG_SPI, ISR_NAKED) {
10
  asm volatile (
11
  //prologue
12
  "sts regbuff, r30""\n\t"
13
  "sts (regbuff)+1, r31""\n\t"
14
  "in r30, __SREG__""\n\t"
15
  "sts (regbuff)+2, r30""\n\t"
16
  "sts (regbuff)+3, r29""\n\t"
17
  //code
18
  "lds r29, fastbuffcnt""\n\t"   //SPDR = fastbuff[fastbuffcnt];
19
  "ldi r30, lo8(fastbuff)""\n\t"
20
  "ldi r31, hi8(fastbuff)""\n\t"
21
  "add r30, r29""\n\t"
22
  "clr r29""\n\t"
23
  "adc r31, r29""\n\t"
24
  "ld r29, Z""\n\t"
25
  "out %0, r29""\n\t"
26
  "lds r30, fastbuffcnt""\n\t"  // fastbuffcnt++;
27
  "inc r30""\n\t"
28
  "sts fastbuffcnt, r30""\n\t"
29
  "lds r31, fastbuffmax""\n\t"  // if (fastbuffermax =< fastbuffcnt ) {
30
  "cp r30, r31""\n\t"
31
  "brlo 1f""\n\t"
32
  "ldi r30, lo8(-100)""\n\t"    // TCNT3 = -100;
33
  "ldi r31, hi8(-100)""\n\t"
34
  "sts %1, r31""\n\t"
35
  "sts %2, r30""\n\t"
36
  "ldi r30,lo8(1)""\n\t"        // TCCR3B = 1<<CS30;
37
  "sts %3, r30""\n\t"
38
  "cbi %4,7""\n\t"              // cbi(SPCR, SPIE);
39
  "1:""\n\t"                    // }
40
  //epilogue
41
  "lds r29, (regbuff)+3""\n\t"
42
  "lds r30, (regbuff)+2""\n\t"
43
  "out __SREG__, r30""\n\t"
44
  "lds r31, (regbuff)+1""\n\t"
45
  "lds r30, (regbuff)+0"
46
  : : "M" (_SFR_IO_ADDR(SPDR)), "M" (_SFR_IO_ADDR(TCNT3H)),
47
             "M" (_SFR_IO_ADDR(TCNT3L)), "M" (_SFR_IO_ADDR(TCCR3B)),
48
             "M" (_SFR_IO_ADDR(SPCR)));
49
  reti();
50
}
#1478269
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.
#1478312
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().
OP Persönliche Seite #1478316
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren