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


von Malte _. (malte) Benutzerseite


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
}

von Stefan E. (sternst)


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.

von Hc Z. (mizch)


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().

von Malte _. (malte) Benutzerseite


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.

von Stefan E. (sternst)


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. ;-)

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.