Ich habe ein Phänomen mit WinAVR-20080610 + AStudio. Wie es für mich
aussieht, hat -Os etwas zu viel wegoptimiert.
Ein Mega32 soll ein SPI-Slave sein, der 16 Bytes Daten zur Abholung
bereitstellt. Alles ganz einfach: im ewigen Zyklus wird SlaveSelect
überwacht (wenn 1->0, Zähler auf 0 setzen). Und im ISR(SPI_STC_vect) den
Zähler inkrementieren und das nächste Byte in SPDR geladen.
Dies funktioniert auch in Hardware, wenn die Optimierung ausgeschaltet
ist. Wird aber -Os benutzt, passiert folgendes. Der Zähler wird im
ewigen Zyklus nicht mehr auf 0 gesetzt. Scheinbar hält der Compiler die
Anweisung "SpiBufPtr = 0" für eine ohne Auswirkung, obwohl eine ISR eben
diesen Zähler nutzt.
Was mach' ich bloß falsch?
Hier Ausschnitt aus main():
1 | while(1)
|
2 | {
|
3 | cli();
|
4 | //SPI slave select edge (nSS falling edge)
|
5 | if (!(PINB & 0x10)) {
|
6 | if (prev_nSS) {
|
7 | PrepSpiSndBuf();
|
8 | SpiBufPtr = 0; // <---- diese Anweisung fehlt nachher
|
9 | SPDR = SpiSndBuf[SpiBufPtr];
|
10 | }
|
11 | prev_nSS = 0;
|
12 | } else {
|
13 | prev_nSS = 1;
|
14 | }
|
15 |
|
16 | if (SpiBufPtr > PKT_SIZE-1) { //receive buffer full
|
17 | ReadSpiRecBuf();
|
18 | }
|
19 | sei();
|
20 | }
|
Und so wurde es übersetzt:
1 | while(1)
|
2 | {
|
3 | cli();
|
4 | 296: f8 94 cli
|
5 | //SPI slave select edge (nSS falling edge)
|
6 | if (!(PINB & 0x10)) {
|
7 | 298: b4 9b sbis 0x16, 4 ; 22
|
8 | 29a: 02 c0 rjmp .+4 ; 0x2a0 <main+0x3a>
|
9 | 29c: 81 e0 ldi r24, 0x01 ; 1
|
10 | 29e: 04 c0 rjmp .+8 ; 0x2a8 <main+0x42>
|
11 | if (prev_nSS) {
|
12 | 2a0: 88 23 and r24, r24
|
13 | 2a2: 11 f0 breq .+4 ; 0x2a8 <main+0x42>
|
14 | PrepSpiSndBuf();
|
15 | SpiBufPtr = 0;
|
16 | SPDR = SpiSndBuf[SpiBufPtr];
|
17 | 2a4: 9f b9 out 0x0f, r25 ; 15
|
18 | 2a6: 80 e0 ldi r24, 0x00 ; 0
|
19 | }
|
20 |
|
21 | if (SpiBufPtr > PKT_SIZE-1) { //receive buffer full
|
22 | ReadSpiRecBuf();
|
23 | }
|
24 | sei();
|
25 | 2a8: 78 94 sei
|
26 | 2aa: f5 cf rjmp .-22 ; 0x296 <main+0x30>
|