Dies ist die aufgewärmte Version des Threads
Beitrag "Schwerer Bug in AVR-GCC 4.1.1" der gesperrt ist. Bislang
hat die ganz unten vorgeschlagene Lösung mit _asm__ __volatile_ ( "" :
: "memory" (x)) immer funktioniert. Nun habe ich trotz der clobber Liste
das Problem.
Folgender Code:
1
volatileuint8_t*pI2CBuff=&txbuffer[i*4];
2
// Folgende Anweisung verhindert, dass die Berechnung von pI2CBuff in den ATOMIC_BLOCK verzögert wird!
3
// https://www.mikrocontroller.net/topic/65923
4
__asm____volatile__(""::"memory"(pI2CBuff));
5
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
6
{
7
*pI2CBuff++=tmp[0];
8
*pI2CBuff++=tmp[1];
9
*pI2CBuff++=tmp[2];
10
*pI2CBuff++=tmp[3];
11
}
Was macht der Compiler (avrgcc 5.4.0, Optimierung -Os) daraus?
1
16e: 2f b7 in r18, 0x3f ; 63
2
170: f8 94 cli
3
172: f7 01 movw r30, r14
4
174: ee 0f add r30, r30
5
176: ff 1f adc r31, r31
6
178: ee 0f add r30, r30
7
17a: ff 1f adc r31, r31
8
17c: ef 59 subi r30, 0x9F ; 159
9
17e: ff 4f sbci r31, 0xFF ; 255
10
180: 00 83 st Z, r16
11
182: 19 83 std Y+1, r17 ; 0x01
12
184: 8a 83 std Y+2, r24 ; 0x02
13
186: 9b 83 std Y+3, r25 ; 0x03
14
188: 2f bf out 0x3f, r18 ; 63
Das heißt er berechnet die Adresse des Pointers pI2CBuff doch erst im
Atomic Block, d.h. nach dem cli. Weiß jemand wie man das verhindern
kann???
Andreas R. schrieb:> Das heißt er berechnet die Adresse des Pointers pI2CBuff doch erst im> Atomic Block, d.h. nach dem cli. Weiß jemand wie man das verhindern> kann???
Den Pointer selber volatile definieren, nicht nur das Ziel, auf welches
er zeigt.
volatile uint8_t* volatile pI2CBuff = &txbuffer[i*4];
> volatile uint8_t* volatile pI2CBuff = &txbuffer[i*4];
das führt aber dazu dass der Pointer selbst nicht mehr in den Registern
gehalten werden kann was zu noch ineffizienterem Code führt:
Falk B. schrieb:> Den Pointer selber volatile definieren, nicht nur das Ziel, auf welches> er zeigt.>> volatile uint8_t* volatile pI2CBuff = &txbuffer[i*4];
Dann berechnet der den Pointer nicht nur einmal, sondern gleich viermal
in dem Block. Und das zu Recht...
Andreas R. schrieb:> Weiß jemand wie man das verhindern> kann???
Neueren gcc verwenden? Mein kleines Testprogrämmchen mit gcc 10.1 hat
das Problem nicht. Wobei es vermutlich sehr vom nicht gezeigten Code
drumherum abhängt, was der gcc draus macht.
Ich würde es mal so probieren:
Oliver S. schrieb:> Wobei es vermutlich sehr vom nicht gezeigten Code> drumherum abhängt, was der gcc draus macht.
Der Code "drumherum" ist nicht so spannend; es wird ein ADC Wert und
eine CRC 16 in einen 4 byte temp buffer geschrieben und dieser danach
atomar in den Ausgangsbuffer des USI I2C Slaves (Martin Junghans
jtronics@gmx.de) an eine bestimmte Stelle kopiert.
1
volatileuint8_ttxbuffer[buffer_size];// Transmission buffer to be read from the master
Andreas R. schrieb:> Der Code "drumherum" ist nicht so spannend;
Ich würde da aber auf JEDEN Fall einen sinnvollen Kommentar ergänzen,
warum die beiden Pointer exakt so benutzt werden.
Das ist Käse: Der Input-Operand hat Constraints "m", "e", "o", "r" und
"y", ist also die Vereinigung all dieser Constraints. Das ist kaum das,
was du willst.
1) Wenn Speicher geklobbert werden soll, genügt ein Clobber auf memory:
1
__asm____volatile__("":::"memory");
2) Wenn nur ein bestimmtes Array-Object geclobbert werden soll, dann
1
__asm____volatile__("":"+m"(*pI2CBuff));
was aber natürlich nicht funktioniert, wenn pI2CBuff nur eine Adresse
ins Array ist.
3) In deinem Fall ist pI2CBuff aber nur eine einfache Variable, die in
ein Register passt. Ergo:
1
__asm____volatile__("":"+r"(pI2CBuff));
Es geht nämlich nicht um den Inhalt des Arrays, sondern um die
berechnete Adresse.