Forum: Compiler & IDEs Zu viele pop/push bei Interruptaufruf -> Optimierung?


von Martin Mörtl (Gast)


Lesenswert?

Hallo,

ich arbeite mit Atmel Studio 6.2 und bin in meinem Programm auf eine 
unerwartetes Zeitverhalten gestossen. Schnell hab ich den Fehler 
entdeckt.
Es liegt an dem Handling des Interrupt. Es werden viel zu viele push und 
pop gemacht. Egal welche optimize Option ich verwende.

Lediglich R24/R25/R28/R29 wird im Code verwendet.

Gibt es eine Möglichkeit hier Einfluss auf die push und pop zu nehmen?

Vielen Dank und schönen Vatertag
Martin Mörtl

Disassembler:
1
00000360  PUSH R1    Push register on stack 
2
00000361  PUSH R0    Push register on stack 
3
00000362  IN R0,0x3F    In from I/O location 
4
00000363  PUSH R0    Push register on stack 
5
00000364  CLR R1    Clear Register 
6
00000365  IN R0,0x3B    In from I/O location 
7
00000366  PUSH R0    Push register on stack 
8
00000367  PUSH R18    Push register on stack 
9
00000368  PUSH R19    Push register on stack 
10
00000369  PUSH R20    Push register on stack 
11
0000036A  PUSH R21    Push register on stack 
12
0000036B  PUSH R22    Push register on stack 
13
0000036C  PUSH R23    Push register on stack 
14
0000036D  PUSH R24    Push register on stack  * Used
15
0000036E  PUSH R25    Push register on stack  * Used
16
0000036F  PUSH R26    Push register on stack 
17
00000370  PUSH R27    Push register on stack 
18
00000371  PUSH R28    Push register on stack  * Used
19
00000372  PUSH R29    Push register on stack  * Used
20
00000373  PUSH R30    Push register on stack 
21
00000374  PUSH R31    Push register on stack 
22
  flashData |=0b01000000;
23
00000375  LDS R24,0x015E    Load direct from data space 
24
00000377  ORI R24,0x40    Logical OR with immediate 
25
00000378  STS 0x015E,R24    Store direct to data space 
26
  PORTA = flashData;
27
0000037A  OUT 0x02,R24    Out to I/O location 
28
  OCR0B = flashCompare;
29
0000037B  LDS R24,0x015D    Load direct from data space 
30
0000037D  OUT 0x28,R24    Out to I/O location 
31
  flashData = eeprom_read_byte(flashDataAdress++);
32
0000037E  LDS R28,0x0100    Load direct from data space 
33
00000380  LDI R29,0x01    Load immediate 
34
00000381  ADD R29,R28    Add without carry 
35
00000382  STS 0x0100,R29    Store direct to data space 
36
00000384  MOV R24,R28    Copy register 
37
00000385  LDI R25,0x00    Load immediate 
38
00000386  RCALL PC+0x0492    Relative call subroutine 
39
00000387  STS 0x015E,R24    Store direct to data space 
40
  flashCompare = eeprom_read_byte(flashDataAdress++);
41
00000389  SUBI R28,0xFE    Subtract immediate 
42
0000038A  STS 0x0100,R28    Store direct to data space 
43
0000038C  MOV R24,R29    Copy register 
44
0000038D  LDI R25,0x00    Load immediate 
45
0000038E  RCALL PC+0x048A    Relative call subroutine 
46
0000038F  STS 0x015D,R24    Store direct to data space 
47
  if (flashCompare == 255)
48
00000391  CPI R24,0xFF    Compare with immediate 
49
00000392  BRNE PC+0x04    Branch if not equal 
50
    flashDataAdress = EEPROM_SEQUENCE_START;
51
00000393  LDI R24,0x20    Load immediate 
52
00000394  STS 0x0100,R24    Store direct to data space

von Peter II (Gast)


Lesenswert?

Martin Mörtl schrieb:
> Gibt es eine Möglichkeit hier Einfluss auf die push und pop zu nehmen?

ja. du darfst keine Funktionen in der ISR aufrufen.

eeprom_read_byte

wird wohl das Problem sein.

von Roland P. (pram)


Lesenswert?

Bist du sicher, dass nur R24/R25/R28/R29 verwendet werden?
1
00000386  RCALL PC+0x0492    Relative call subroutine

Ansonsten kannst du die interruptfunktion evtl. "naked" deklarieren, 
dann must du dich um das pushen/popen selber kümmern (welch ein 
Wortspiel)

https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.htm

Gruß
Roland

von Yalu X. (yalu) (Moderator)


Lesenswert?

Da du im Interrupthandler eine weitere Funktion aufrufst, müssen auch
alle diejenigen Register gepusht werden, die von dieser Funktion
überschrieben werden könnten. Wenn diese Funktion tatsächlich nur ganz
wenige Register überschreibt, schießt der Compiler mit der Pusherei
natürlich über das Ziel hinaus.

Du kannst ihm bei der Optimierung dadurch helfen, dass du die
aufgerufene Funktion in die gleiche Quelldatei (oder in ein Headerfile,
dass von der Quelldatei eingebunden wird) schreibst. Dann sieht der
Compiler, welche Register tatsächlich überschrieben werden, und pusht
nur diese.

PS: Ich sehe gerade, dass die aufgerufene Funktion in einer Bibliothek
liegt, wodurch der obige Tipp schwieriger umzusetzen ist. Aber wozu
musst du das EEPROM in jedem Interruptaufruf lesen? Das kostet doch nur
unnötig Zeit. Lies das EEPROM einmal während der Intilialisierungsphase
aus und speichere die Werte in einer globalen Variable, auf die der
Interrupthandler Zugriff hat.

von (prx) A. K. (prx)


Lesenswert?

Sobald in einer ISR eine Funktion aufgerufen wird muss der Compiler alle 
"callee saved" Register sichern, da er nicht weiss, welche Register 
diese Funktion verwendet. Und das sind eben recht viele.

Es sollte aber nicht schwer fallen, diese EEPROM-Funktionen durch 
direkten Zugriff zu ersetzen.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> musst du das EEPROM in jedem Interruptaufruf lesen? Das kostet doch nur
> unnötig Zeit.

Lesen ist harmlos - zumindest wenn man es direkt macht.

von Martin M. (martinmoertl)


Lesenswert?

Hallo,

Danke für die Tips:

1. Im EEPROM liegt ein Bitmuster das ausgegeben werden soll. Es werde 8 
PWM's erzeugt mit einem Timer. Timer zählt bis 100 und der COMPA kommt 
immer, wenn sich einer der Kanäle ändert. Das ist der Grund warum ich 
immer aus dem EEPROM lese und um eine Adresse weiter springe. Muster und 
Comparewert liegen hintereinander im EEPROM
1
flashData = eeprom_read_byte(flashDataAdress++);
2
flashCompare = eeprom_read_byte(flashDataAdress++);

2. eeprom_read_byte: Habe keine JUMP gesehen der da raus springt.

3. RCALL PC+0x????: Auch hier wird nur R24 und R25 verwendet.
1
00000818  SBIC 0x1F,1    Skip if bit in I/O register cleared 
2
00000819  RJMP PC-0x0001    Relative jump 
3
0000081A  OUT 0x22,R25    Out to I/O location 
4
0000081B  OUT 0x21,R24    Out to I/O location 
5
0000081C  SBI 0x1F,0    Set bit in I/O register 
6
0000081D  CLR R25    Clear Register 
7
0000081E  IN R24,0x20    In from I/O location 
8
0000081F  RET     Subroutine return

4. Ich probiere es wie vorgeschlagen, die EEPROM Daten in ein ARRAY zu 
laden und das ganze nochmal zu versuchen. Dauert ein wenig bis ich das 
gemacht hab.

Danke schon mal. Feedback gibts später

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Du kannst ihm bei der Optimierung dadurch helfen, dass du die
> aufgerufene Funktion in die gleiche Quelldatei (oder in ein Headerfile,
> dass von der Quelldatei eingebunden wird) schreibst. Dann sieht der
> Compiler, welche Register tatsächlich überschrieben werden, und pusht
> nur diese.

Das bring beim GCC aber nur dann was, wenn Inlining stattfindet d.h. 
kein Funktionsaufruf mehr stattfindet.  Wenn die Funktion nicht 
geinlinet wird, dann nutzt GCC den bekannten, kleineren Fußabdruck der 
Funktion nicht im Aufrufer aus.

von (prx) A. K. (prx)


Lesenswert?

Martin Mörtl schrieb:
> 3. RCALL PC+0x????: Auch hier wird nur R24 und R25 verwendet.

Aber das weiss der Compiler nicht, wenn er die ISR übersetzt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
> Das bring beim GCC aber nur dann was, wenn Inlining stattfindet

Davon, dass die Funktion geinlinet wird, bin ich jetzt mal
stillschweigend ausgegangen ;-)

Aber du hast schon recht, eine entsprechende Anmerkung wäre nützlich
gewesen.

von Martin M. (martinmoertl)


Lesenswert?

Geschafft. Umstellt auf RAM data[] und ich fahre mit einem Pointer 
drüber.
push/pop klappt, wobei ein reserviertes Register auch noch gesichert 
wird. ???

Vielleicht würde noch ein Zugriff mit data[i] was bringen. wenn ich noch 
lust hab hole ich das später nach.
Unten ist der Vergleich von vorher zu nacher. Warum allerdings die push 
und pop vorher nicht gepasst haben kann ich mir nicht erklären. Es 
wurden keine Funktionen aufgerufen. Der Optimierer hat da was 
zusammengefaßt was wo anders auch noch zum Einsatz kam.

Jetzt schaut es besser aus mit meinen 36kHz PWM's.

1 Frage noch:

Wie kann man explizit für diese Interruptroutine das push und pop 
komplett abschalten? Der Link funktioniert von oben nicht.

Danke für die Hilfe

Ausgangscode
1
  flashData |=0b01000000;
2
  
3
  PORTA = flashData;
4
  OCR0B = flashCompare;
5
  
6
  flashData = eeprom_read_byte(flashDataAdress++);
7
  flashCompare = eeprom_read_byte(flashDataAdress++);
8
  
9
  if (flashCompare == 255)
10
  {
11
    // Sequence am Ende und wieder an den Anfang
12
    flashDataAdress = EEPROM_SEQUENCE_START;
13
  }
14
15
TAKTE   BEFEHLE
16
2  00000360  PUSH R1    Push register on stack 
17
2  00000361  PUSH R0    Push register on stack 
18
1  00000362  IN R0,0x3F    In from I/O location 
19
2  00000363  PUSH R0    Push register on stack 
20
1  00000364  CLR R1    Clear Register 
21
1  00000365  IN R0,0x3B    In from I/O location 
22
2  00000366  PUSH R0    Push register on stack 
23
2  00000367  PUSH R18    Push register on stack 
24
2  00000368  PUSH R19    Push register on stack 
25
2  00000369  PUSH R20    Push register on stack 
26
2  0000036A  PUSH R21    Push register on stack 
27
2  0000036B  PUSH R22    Push register on stack 
28
2  0000036C  PUSH R23    Push register on stack 
29
2  0000036D  PUSH R24    Push register on stack  * Used
30
2  0000036E  PUSH R25    Push register on stack  * Used
31
2  0000036F  PUSH R26    Push register on stack 
32
2  00000370  PUSH R27    Push register on stack 
33
2  00000371  PUSH R28    Push register on stack  * Used
34
2  00000372  PUSH R29    Push register on stack  * Used
35
2  00000373  PUSH R30    Push register on stack 
36
2  00000374  PUSH R31    Push register on stack         39
37
    flashData |=0b01000000;
38
2  00000375  LDS R24,0x015E    Load direct from data space 
39
1  00000377  ORI R24,0x40    Logical OR with immediate 
40
2  00000378  STS 0x015E,R24    Store direct to data space 
41
    PORTA = flashData;
42
1  0000037A  OUT 0x02,R24    Out to I/O location 
43
    OCR0B = flashCompare;
44
2  0000037B  LDS R24,0x015D    Load direct from data space 
45
1  0000037D  OUT 0x28,R24    Out to I/O location 
46
    flashData = eeprom_read_byte(flashDataAdress++);
47
2  0000037E  LDS R28,0x0100    Load direct from data space 
48
1  00000380  LDI R29,0x01    Load immediate 
49
1  00000381  ADD R29,R28    Add without carry 
50
2  00000382  STS 0x0100,R29    Store direct to data space 
51
1  00000384  MOV R24,R28    Copy register 
52
1  00000385  LDI R25,0x00    Load immediate 
53
10 00000386  RCALL PC+0x0492    Relative call subroutine 
54
2  00000387  STS 0x015E,R24    Store direct to data space 
55
    flashCompare = eeprom_read_byte(flashDataAdress++);
56
1  00000389  SUBI R28,0xFE    Subtract immediate 
57
2  0000038A  STS 0x0100,R28    Store direct to data space 
58
1  0000038C  MOV R24,R29    Copy register 
59
1  0000038D  LDI R25,0x00    Load immediate 
60
10 0000038E  RCALL PC+0x048A    Relative call subroutine 
61
2  0000038F  STS 0x015D,R24    Store direct to data space 
62
    if (flashCompare == 255)
63
1  00000391  CPI R24,0xFF    Compare with immediate 
64
2  00000392  BRNE PC+0x04    Branch if not equal 
65
      flashDataAdress = EEPROM_SEQUENCE_START;
66
1  00000393  LDI R24,0x20    Load immediate 
67
2  00000394  STS 0x0100,R24    Store direct to data space 
68
  }
69
2  00000396  POP R31    Pop register from stack 
70
2  00000397  POP R30    Pop register from stack 
71
2  00000398  POP R29    Pop register from stack 
72
2  00000399  POP R28    Pop register from stack 
73
2  0000039A  POP R27    Pop register from stack 
74
2  0000039B  POP R26    Pop register from stack 
75
2  0000039C  POP R25    Pop register from stack 
76
2  0000039D  POP R24    Pop register from stack 
77
2  0000039E  POP R23    Pop register from stack 
78
2  0000039F  POP R22    Pop register from stack 
79
2  000003A0  POP R21    Pop register from stack 
80
2  000003A1  POP R20    Pop register from stack 
81
2  000003A2  POP R19    Pop register from stack 
82
2  000003A3  POP R18    Pop register from stack 
83
2  000003A4  POP R0    Pop register from stack 
84
1  000003A5  OUT 0x3B,R0    Out to I/O location 
85
2  000003A6  POP R0    Pop register from stack 
86
1  000003A7  OUT 0x3F,R0    Out to I/O location 
87
2  000003A8  POP R0    Pop register from stack 
88
2  000003A9  POP R1    Pop register from stack 
89
2  000003AA  RETI     Interrupt return 
90
91
134 CLK        INNEN 56 CLK

Optimiert bzw über RAM *ptr rauscht nun über meinen Speicher
1
  PORTA = *ptr++ |0b01000000;    // Änderung für Frame auf dauer high
2
  OCR0B = *ptr++;          // Comparewert setzen
3
  if (OCR0B == 255)        // Überprüfen ob Ende der Sequenz erreicht, dann Pointer zurücksetzen auf Anfang
4
  {
5
    ptr = data;
6
  }
7
TAKTE   BEFEHLE
8
2  00000342  PUSH R1    Push register on stack 
9
2  00000343  PUSH R0    Push register on stack 
10
1  00000344  IN R0,0x3F    In from I/O location 
11
2  00000345  PUSH R0    Push register on stack 
12
1  00000346  CLR R1    Clear Register 
13
1  00000347  IN R0,0x3B    In from I/O location 
14
2  00000348  PUSH R0    Push register on stack 
15
2  00000349  PUSH R24    Push register on stack 
16
2  0000034A  PUSH R25    Push register on stack 
17
2  0000034B  PUSH R30    Push register on stack 
18
2  0000034C  PUSH R31    Push register on stack     19
19
    PORTA = *ptr++ |0b01000000;    // �nderung f�r Frame auf dauer high
20
2  00000379  LDS R30,0x015B    Load direct from data space 
21
2  0000037B  LDS R31,0x015C    Load direct from data space 
22
1  0000037D  MOVW R24,R30    Copy register pair 
23
2  0000037E  ADIW R24,0x01    Add immediate to word 
24
2  0000037F  STS 0x015C,R25    Store direct to data space 
25
2  00000381  STS 0x015B,R24    Store direct to data space 
26
2  00000383  LDD R24,Z+0    Load indirect with displacement 
27
1  00000384  ORI R24,0x40    Logical OR with immediate 
28
1  00000385  OUT 0x02,R24    Out to I/O location 
29
    OCR0B = *ptr++;          // Comparewert setzen
30
2  00000386  LDS R30,0x015B    Load direct from data space 
31
2  00000388  LDS R31,0x015C    Load direct from data space 
32
1  0000038A  MOVW R24,R30    Copy register pair 
33
2  0000038B  ADIW R24,0x01    Add immediate to word 
34
2  0000038C  STS 0x015C,R25    Store direct to data space 
35
2  0000038E  STS 0x015B,R24    Store direct to data space 
36
2  00000390  LDD R24,Z+0    Load indirect with displacement 
37
1  00000391  OUT 0x28,R24    Out to I/O location 
38
    if (OCR0B == 255)        // �berpr�fen ob Ende der Sequenz erreicht, dann Pointer zur�cksetzen auf Anfang
39
1  00000392  IN R24,0x28    In from I/O location 
40
1  00000393  CPI R24,0xFF    Compare with immediate 
41
2  00000394  BRNE PC+0x07    Branch if not equal 
42
      ptr = data;
43
1  00000395  LDI R24,0x5D    Load immediate 
44
1  00000396  LDI R25,0x01    Load immediate
45
2  00000397  STS 0x015C,R25    Store direct to data space 
46
2  00000399  STS 0x015B,R24    Store direct to data space 
47
  }
48
2  00000373  POP R31    Pop register from stack 
49
2  00000374  POP R30    Pop register from stack 
50
2  00000375  POP R25    Pop register from stack 
51
2  00000376  POP R24    Pop register from stack 
52
2  00000377  POP R0    Pop register from stack 
53
1  00000378  OUT 0x3B,R0    Out to I/O location 
54
2  00000379  POP R0    Pop register from stack 
55
1  0000037A  OUT 0x3F,R0    Out to I/O location 
56
2  0000037B  POP R0    Pop register from stack 
57
2  0000037C  POP R1    Pop register from stack 
58
2  0000037D  RETI     Interrupt return 
59
60
77 CLK innen 39 CLK
              Orginal  Optimiert
Overhead      2 x 39   2 x 19                              51% gespart
Funktion        56       39                                30% gespart
Summe          134       77        Faktor 1,74 schneller / 43% gespart

Jetzt ist der Ergeiz geweckt. Es befinden sich immer noch unnötige 
Befehle beim Einsprung und auch beim Verlassen.

RESERVED 0x3B und SREG 0x3F wird gerettet. Ersteres macht nicht wiklich 
sinn. Wäre nochmal 2 x 3 Takte.
Eigentlich bräuchte ich gar keine push und pop, denn das ist der 
niederwertigste Interrupt und mein Hauptprogramm besteht aus while(1);
1
2  00000342  PUSH R1    Push register on stack 
2
2  00000343  PUSH R0    Push register on stack 
3
1  00000344  IN R0,0x3F    In from I/O location 
4
2  00000345  PUSH R0    Push register on stack 
5
1  00000346  CLR R1    Clear Register 
6
1  00000347  IN R0,0x3B    In from I/O location 
7
2  00000348  PUSH R0    Push register on stack
8
9
11 CLK

von Peter II (Gast)


Lesenswert?

ist bei dir ptr volatile? Wenn ja warum?

von micha54 (Gast)


Lesenswert?

Hallo,

CLR setzt die Flags, daher muss SREG gesichert werden.

Gruß,
Michael

von (prx) A. K. (prx)


Lesenswert?

1
__attribute__((naked))

von (prx) A. K. (prx)


Lesenswert?

micha54 schrieb:
> CLR setzt die Flags, daher muss SREG gesichert werden.

Nicht wenn dabei ausschliesslich ein while(1); unterbrochen wird.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn es wirklich so zeitkritisch ist, daß noch nichma SREG gesichert 
werden darf, dann schreib das Zeugs in Assembler.  Die Funktion ist 
einfach genug dafür.

avr-gcc sichert SREG in jeder ISR, egal ob es verändert wird oder nicht.

von Martin M. (martinmoertl)


Lesenswert?

Hallo,

Danke nochmal für die Hilfe. Ich habs in Assembler gemacht. 31+2 Takte
Hier die Lösung, um vielleicht dem einen oder anderem eine Hilfe zu 
geben.

1. __attribute__((naked)) --> Der Interrupt springt ohne irgendwas zu 
machen hier rein. PUSH/POP und RET(i) nicht vergessen

2. Die Adresse von data wird in R26,R27 X vom Compiler gesetzt (ldi)

3. R2 beinhaltet Variable die nur im Register gehalten wird.

4.   PORTA = data(p++) |0b01000000;    // Ausgabe
     OCR0B = data(p++);                // Comparewert setzen
     if (OCR0B == 255)                 // Am Ende von vorne beginnen
     {
         p = 0;
     }
1
__attribute__((naked))
2
ISR(TIMER0_COMPB_vect)  // Nach entsprechendem Comparewert der Sequenze
3
{
4
  asm volatile(
5
  
6
  "push r0 \n\t"
7
  "in r0,0x3f \n\t"
8
  "push r0 \n\t"    // 2 + 5
9
  
10
  "clr r1 \n\t"
11
  "add r26,r2 \n\t"
12
  "adc r27,r1 \n\t"
13
  "ld r25,x+ \n\t"
14
  "ori r25,0x40 \n\t"
15
  "out 0x02,r25 \n\t"
16
  "ld r25,x+ \n\t"
17
  "out 0x28,r25 \n\t"
18
  "ldi r16,2 \n\t"
19
  "add r2,r16 \n\t"
20
  "cpi r25,0xff \n\t"
21
  "brne L_dl1%= \n\t"
22
  "clr r2 \n\t"
23
  "L_dl1%=: \n\t"          // 17
24
  //"sbi 0x02,6 \n\t"  
25
26
  "pop r0 \n\t"
27
  "out 0x3f,r0 \n\t"
28
  "pop r0 \n\t"    // 5
29
  "reti \n\t"    // 2
30
  
31
  : //output
32
  : //input
33
    [ioReg] "M" (_SFR_IO_ADDR(TCCR1B)),
34
    [value] "x" (data)
35
  );       // 31 Takte
36
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stellt sich nur die Frage, warum du Input-Operanden angibst, sie aber 
nicht verwendest...

Solcher Code wird wesentlich besser wartbar, wenn du ihm ein eigenes 
Assembler-Modul spendierst, etwa so:
1
#define __SFR_OFFSET 0
2
#include <avr/io.h>
3
4
.text
5
6
.type TIMER0_COMPB_vect, @function
7
.global TIMER0_COMPB_vect
8
9
TIMER0_COMPB_vect:
10
11
    push r0
12
    in   r0, SREG
13
    push r0
14
15
    clr  r1
16
    add  r26, r2
17
    adc  r27, r1
18
    ld   r25, X+
19
    ori  r25, 1 << 6
20
    out  PORTA, r25
21
    ld   r25, X+
22
    out  OCR0B, r25
23
    ldi  r16, 2
24
    add  r2, r16
25
    cpi  r25, 0xff
26
    brne 1f
27
    clr  r2
28
1:
29
    sbi  PORTA, 6  
30
31
    pop  r0
32
    out  SREG, r0
33
    pop  r0
34
    reti
35
.size TIMER0_COMPB_vect, .-TIMER0_COMPB_vect

Zudem ist gemäß GCC-Doku in einer naked-Funktion ausschließlich 
Inline-Assembler ohne Operanden erlaubt.

Dann verstehe ich nicht, warum du R0 und SREG sicherst?  Das 
Hauptprogramm besteht doch nur aus einer leeren Endlosschleife?

In dem Fall brauchst du überhaupt keine Register zu sichern, und anstatt 
R2 bieten sich bessere Register an, um Werte zu addieren.

Die Abstände zwischen den Adressen, an denen die Daten aus dem Array 
gelesen werden, werden ständig größer (der Adresse wächst quadratisch). 
Ist das wirklich so gewollt? Und wozu Pin 6 des Ports setzen, wenn es 
oben schon durch das ORI gesetzt wurde?

von m.n. (Gast)


Lesenswert?

Johann L. schrieb:
> Solcher Code wird wesentlich besser wartbar, wenn du ihm ein eigenes
> Assembler-Modul spendierst, etwa so:

Ich will ja nicht der Spielverderber sein, aber im Interrupt 
irgendwelche ungesicherten Register zu verwenden, ist grob daneben.
Das funktioniert nur dann, wenn man das komplette Programm in Assembler 
schreibt und genau festlegt, welches Register welche Funktion hat.

von Martin M. (martinmoertl)


Lesenswert?

Ja Dein Einwand ist sehr berechtigt.
Die Variable ist im C einem Register zugewiesen.

Mein Hauptprogramm besteht aus
1
while(1);

Ansonsten tummelt es sich nur in den Timer-Interrupts die nicht 
gleichzeitg kommen können...

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.