Hallo, ich habe folgendes Problem: Derzeit programmiere ich an einem Hardware I2C-Slave der von einer C-Control 2 ausgelesen werden soll. Folgender Ablauf ist momentan eingestellt: 1. C-Control schickt START Condition mit der Adresse des ICs 2. C-Control gibt ACK oder NACK zurück. Wenn ich nun das C-Control Programm starte tut der Slave nichts ( kein Sprung in die ISR ). Wenn ich allerdings SDA und SCL vertausche kommen wirre Werte beim Slave an ( 0xFF ). Die C-Control gibt in beiden Fällen NACK zurück. Meine Frage: Ist der Slave-Code vom Prinzip richtig oder liegt´s wohl eher an der Schaltung ? Danke im vorraus! Grüße, Patrick
Kinder Kinder, könnten wir uns vielleicht mal um wichtige Dinge kümmern, wie zum Beispiel darum, warum Patricks Code nicht funktioniert ? Ich experimentiere auch grade mit der TWI rum (allerdings als Master), deswegen versuch ich mal meine Ideen anzubringen: Du setzt das Bit TWINT im TWCR-Register; laut Datenblatt (vom ATmega16) musst du im Slave Receive-Mode dieses Bit zurücksetzen (siehe Seite 190ff.). In das TWAR-Register kommt die Adresse, auf die der Slave antworten soll (welchen Wert hat 'addr' in deinem Code ?? Haste da evtl. die Initialisierung vergessen ?). Über das TWEA-Bit kannst du steuern, ob empfangene Pakete mit der richtigen Adresse bestätigt werden sollen (TWEA=1) oder nicht (TWEA=0). Jau, probier das mal alles aus bzw. überprüfe es, und dann schaun wir mal weiter, ob sich evtl. schon mehr tut. Grüße, Mario
Danke Mario für deinen Einsatz. Ich hoffe wir können jetzt geregelte Bahnen gehen ;-) Also: "addr" wird bei dem init_i2c() befehl übergeben, siehe: init_i2c(62); // Starte Slave mit Adresse "62" TWINT: Zitat aus dem Datenblatt: "The TWINT Flag must be cleared by software by writing a logic one to it." TWEA: Ist so konfiguriert dass der ATMega antwortet wenn er angeprochen wird (1) Grüße
Danke an Andreas für die "Reinigung" dieses Threads :-) Sorry, dass mit der Adressübergabe hatte ich echt übersehen; hab wohl meine Brille ned geputzt ... Du hast schon Recht, nach TWINT muss man ne 1 schreiben, um das Flag zu löschen. Was aber, wenn das Flag bereits vorher gelöscht war ? Das geht aus dem Datenblatt nicht ganz klar hervor. Ich hab es so interpretiert, dass man das Flag nur dann auf diese Weise löschen muss, wenn es vorher von der Hardware gesetzt wurde. Ich beziehe mich auch auf den bereits erwähnten Abschnitt über den Slave Receive-Mode, wo ja drinsteht, welche Werte man schreiben muss, und da steht für TWINT auch ne 0 ! Probier's doch mal aus, was passiert, wenn du TWINT bei der Initialisierung NICHT setzt. Grüße, Mario
Hallo Mario, danke für den Tip, aber leider bringt das nicht-setzen des TWINT Bits nicht den gewünschten Erfolg. Grüße, Patrick
Mittlerweile habe ich den Application Note Code von Atmel soweit
umgebaut, dass ich ein ACK zurückbekomme.
Allerdings ist der Datenempfang immer noch nicht drin.
Die ISR mit dem ganzen Error Handling habe ich auskommentiert und
folgendes geschrieben:
SIGNAL(SIG_2WIRE_SERIAL){
PORTB=0xFF;
static unsigned char TWI_bufPtr;
uart_puts("SR: ",0);
uart_puti(TWSR,2);
uart_puts("\r\n",0);
uart_puts("DR: ",0);
uart_puti(TWDR,10);
uart_puts("\r\n",1);
TWI_Start_Transceiver( );
}
PORTB wid auf 0xFF geschaltet und über den UART wird auch was
ausgegeben. Allerdings ist das Statusregister auf 0 und das
Datenregistert auf 129 ?!
mit TWI_Start_Transceiver() wird folgendes gemacht:
void TWI_Start_Transceiver( void )
{
while ( TWI_Transceiver_Busy() ); // Wait until TWI is
ready for next transmission.
TWI_statusReg.all = 0;
TWI_state = TWI_NO_STATE ;
TWCR = (1<<TWEN)| // TWI Interface
enabled.
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt
and clear the flag.
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Prepare to ACK next
time the Slave is addressed.
(0<<TWWC); //
}
Grüße
Anmerkung: beim puti ist der 2. Parameter die base für die Umrechnung des INTs in einen String ( siehe itoa() ). Grüße
wie lange braucht die "Uart_put.." zum arbeiten? Kann es sein, dass die länger braucht, als deine Übertragung braucht, sprich: es gibt einen Überlauf? Andere Funktionen von ISR aus aufrufen ist sehr unschön. Nimm deine Daten und schreibe sie in einen Puffer, der dann in der Main an die Uart-Funktionen übergeben wird.
In meinem alten Code habe ich das schonmal probiert, da gab´s keinen besseren Effekt. Bin aber gerade dabei das umzustricken. Grüße
Hab das Ganze mal so umfunktioniert:
SIGNAL(SIG_2WIRE_SERIAL){
PORTB=0xFF;
static unsigned char TWI_bufPtr;
twsr_back=TWSR;
switch (TWSR)
{ ........... // TWI Application Note von Atmel
Wenn ich nun in einer Vorschleife immer folgendes mache:
if(twsr_back!=0){
uart_puti(twsr_back,2);
uart_puts("\n\r",1);
}
Passiert nichts.
In die ISR springt der Controller aber nach wie vor. Ein ACK wird auch
zurückgegeben.
Grüße
Gast
#225176
Hi Mania habe auch schon mal ne Slave programmiert. Schau dir mal den Code im Anhang an. Habe da nen paar Unterroutienen. In dem Hauptprogramm wird dann abgefragt, ob der Controller adrressiert worden ist. MFG Alex
Hallo Alex, danke für deinen Code, werde ich später mal testen. Aber eine kurze Frage: Warum setzt du das Bitrate Register ? Das sollte doch bei einem reinen Slave überflüssig sein oder ? Der Slave reagiert ja auf den SCL Puls vom Master. Grüße
Gast
#225178
Hi Patrik, ich habe das Bitrate Register gesetzt, da der Prozessor bei meinem Projekt sowohl als Slave als auch Master arbeitet. Wenn der Prozessor als reiner Slave arbeiten soll, brauchst du das natürlich nicht. Mann könnte das auch mit I2C-Interrupt programmieren, dann muss man im hauptprogramm das TWI-Flag nicht ständig abfragen..... Ich hoffe du kannst mit dem Quelltext was anfangen. mfg Alex
Ok, das erklärt natürlich einiges. Wenn du aber im Modus "// I2C-Slave-Mode Daten lesen" bist brauchste doch am Ende auch kein i2c.stop zu senden oder ? Das macht im Regelfall auch der Master. Grüße
Gast
#225180
Nein, wenn der Prozessor in Slave Modus ist, braucht der Slave keine Stopbedingung zu senden, du musst aber in dem Statusrgister des Prozessors gewisse Bits setzten damit der Prozessor wieder auf bereitschaft geht. du könntest dir dafür noch ne extra Routine schreiben, mit der Stop routine gehts auch :-)
Wunderbar, danke! Ich werde die Anlage jetzt mal an den Logic Analyzer klemmen und testen ob da alles mit rechten Dingen vor geht. Grüße
Habe nebenbei mal deinen Code ausprobiert, funktioniert leider auch nicht. Grüße
Gast
#225183
Ich darf vielleicht auch as beisteuern - ist zwar wiedermal "nur" FastAVR, aber aus C übernommen.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
hier kannst Du sehr schön sehen, bei welchem Wert im TWSR du die einzelnen Bits im TWCR setzen musst. die einzelnen Bedingungen sind oben im Program als Konstanten gesetzt (habe ich jetzt nicht rüberkopiert, stehen ja dahinter. Gruß axelR.
Wenn in meinem TWSR mal was stehen würde .... ;-)
Auch nach längerem hin&her steht immer noch nichts in meinem TWSR. Der IC wird korrekt angesprochen , springt in die ISR, aber es ist nichts im TWSR. Was kann da los sein ? Grüße
Gast
#225186
Das ist komisch! irgentein Wert sollte drinn stehen, und wenn's nur 0xF8 ist.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
ich habe die Konstanten nochmal rauskopiert.
Gast
#225187
habe ich wirklich!
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
Gast
#225188
sowas...
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
Die Konstanten habe ich auch in dem Sourcecode von der Application Note super dokumentiert und eingebunden. Wenn ich mir aber in der ISR das TWSR sichere und danach ausgeben lasse kommt 0 raus. Die Start/Stop Condition sieht auf dem Bus aber gut aus. Controller habe ich momentan 2 Stück ( beides ATMega8 ) an nem 3,6864 MHz Quarz die ich beide ausprobiere. UART etc. funktioniert wunderbar.
So, Problem(e) gelöst! Es waren mehrere Faktoren die eine Rolle gespielt haben: 1. Ich habe versucht nur die ISR laufen zu lassen ohne das neue Aufrufen von TWI_start_receiver(). In der ISR von Atmel wird nach der Bearbeitung des TWI Prozesses TWEN auf 0 gesetzt. Daher habe ich ein low auf meine SDA Leitung bekommen worauf die CC2 dachte: ACK! 2. TWAR: Die Adressierung mittels TWAR funktioniert nicht ganz wie beim Datenblatt beschrieben. Normalerweise muss ja die Adresse ab dem 1. Bit geschrieben werden. Das funktioniert allerdings nicht .... Die Adresse schreibe ich jetzt ab dem 0. Bit und schon kann der Slave korrekt adressiert werden. Grüße
Gast
#225191
Hallöchen! versuche verzweifelt einen TWI Slave Receiver in WinAVR -C auf Interrupt-Basis zu programmieren. Leider funzt des nicht so wirklich. Also wenn ich den Master einschalte, springt er in die ISR rein. Mehr passiert nicht. Das TWSR hat immer 0 als Wert. Sieht hier jemand einen Fehler im Programm?
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.