Ich habe eine Schleife geschrieben, welche, falls die normale
Ausführungsbedingung innerhalb einer bestimmten Zeit nicht false wird,
durch ein Timeout beendet werden soll. Diese ist folgendermaßen
realisiert:
--- Keine Quelldatei -----------------------------------------------------------
7
0000029A CPI R24,0xE8 Compare with immediate
8
0000029B LDI R18,0xFD Load immediate
9
0000029C CPC R25,R18 Compare with carry
10
0000029D BRNE PC-0x07 Branch if not equal
11
0000029E RJMP PC+0x0004 Relative jump
Die Schleife wird offenbar nicht beendet, wenn timeout>=65000 ist.
So ich den Assembler Code richtig interpretiere zeigt sich mir als Grund
hierfür, dass die Überprüfung ob timeout<65000 ist als signed
durchgeführt wird, obwohl beide Werte 16-Bit unsigned sein sollten. Da
der Wertebereicht bei 16-Bit signed Zahlen nur bis 32767 reicht,
erscheint es mir plausiebel dass timeout immer kleiner als 65000 ist.
Relativiert sich dies wieder da eventuell beide Zahlen als signed
behandelt werden?
Ich habe wenig Erfahrung mit Assembler, jedoch iritiert mich diese
Codestelle in Verbindung mit dem Verhalten beim Debugging.
Vielleicht könnte jemand mit etwas mehr Erfahrung in Assembler eine
Einschätzung geben ob dies eine korrekte Optimierung des Compilers ist
oder ob hier wirklich etwas faul ist oder Fehler meinerseits auffallen.
Ich verende Atmel Studio 6.1.
ein Gast schrieb:> So ich den Assembler Code richtig interpretiere
Ich denke nicht, dass du ihn richtig interpretierst.
Gib aber bitte mal ein vollständiges, compilierbares Beispiel.
ein Gast schrieb:> 0000029A CPI R24,0xE8 Compare with immediate> 0000029B LDI R18,0xFD Load immediate> 0000029C CPC R25,R18 Compare with carry> 0000029D BRNE PC-0x07 Branch if not equal> 0000029E RJMP PC+0x0004 Relative jump> [/avrasm]>> Die Schleife wird offenbar nicht beendet,
offenbar doch.
doc0856.pdf RTFM...
Oliver
ein Gast schrieb:> So ich den Assembler Code richtig interpretiere zeigt sich mir als Grund> hierfür, dass die Überprüfung ob timeout<65000 ist als signed> durchgeführt wird,
Nein. Der BRLT Befehl testet TWINT von TWCR. Ist nämlich Bit 7.
timeout wird dahinter mit BRNE getestet, weil der Compiler merkt, dass
dieser Test hier äquivalent zu U< ist.
>Gib aber bitte mal ein vollständiges, compilierbares Beispiel.
Ich habe zusammenkopiert, was ich für relevant halte.
Der Timeout in in den weiteren I²C-Funktionen identisch realisiert.
1
#include<avr/io.h>
2
#define I2C_PORT PORTC
3
#define SDA PC1
4
#define SCL PC0
5
6
chari2c_init(void)
7
{
8
I2C_PORT|=(1<<SDA)|(1<<SCL);//use internal pullup resistors instead of external ones. In external ones are present this line has to be removed / commented out.
9
TWBR=100;//set SCL speed to F_CPU/(16+2*TWBR)
10
TWSR=TWSR&252;//make sure prescaler bits are cleared to keep the additional prescaler out of the equation above.
11
return0;
12
}
13
14
chari2c_start(void)
15
{
16
uint16_ttimeout=0;
17
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);//generate START condition (TWINT ~ do command, TWSTA ~ command for Startcondition, TWEN ~ enable I2C unit)
18
while((!(TWCR&(1<<TWINT)))&&(timeout<65000U)){timeout++;}//wait as long as I2C unit is busy
19
if(timeout>=65000U)
20
{
21
TWCR|=(1<<TWSTO)|(1<<TWINT);
22
TWCR=(1<<TWEA)|(1<<TWINT)|(1<<TWEN);
23
}
24
if(!(TWSR&0x18))return1;//check if start condition actually occurred, otherwise return 1
ein Gast schrieb:> Der Timeout in in den weiteren I²C-Funktionen identisch realisiert.
Der funktioniert aber auch, wie dir andere schon erklärt haben.
Hier mal der generierte Assemblercode, den ich für -mmcu=atmega16
bekomme. Ich habe mal ein paar Kommentare eingefügt.
1
i2c_start:
2
/* prologue: function */
3
/* frame size = 0 */
4
/* stack size = 0 */
5
.L__stack_usage = 0
6
ldi r24,lo8(-92)
7
out 0x36,r24 ; TWCR = ...
8
ldi r24,0 ; timeout = 0 // timeout liegt in r[25:24]
9
ldi r25,0
10
rjmp .L3
11
.L5:
12
adiw r24,1 ; timeout++
13
.L3:
14
in __tmp_reg__,0x36 ; Test von TWINT in TWCR
15
sbrc __tmp_reg__,7 ; sieht hier etwas anders aus als bei