Forum: Mikrocontroller und Digitale Elektronik I2C Slave Reciever


von Ppp M. (sanic)


Angehängte Dateien:

Lesenswert?

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

von Mario R. (mario001) Benutzerseite


Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

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

von Mario R. (mario001) Benutzerseite


Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

Hallo Mario,

danke für den Tip, aber leider bringt das nicht-setzen des TWINT Bits
nicht den gewünschten Erfolg.

Grüße,
Patrick

von Ppp M. (sanic)


Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

Anmerkung: beim puti ist der 2. Parameter die base für die Umrechnung
des INTs in einen String ( siehe itoa() ).

Grüße

von Rahul D. (rahul)


Lesenswert?

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.

von Ppp M. (sanic)


Lesenswert?

In meinem alten Code habe ich das schonmal probiert, da gab´s keinen
besseren Effekt.
Bin aber gerade dabei das umzustricken.

Grüße

von Ppp M. (sanic)


Lesenswert?

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

von alex (Gast)


Angehängte Dateien:

Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

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

von alex (Gast)


Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

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

von alex (Gast)


Lesenswert?

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 :-)

von Ppp M. (sanic)


Lesenswert?

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

von Ppp M. (sanic)


Lesenswert?

Habe nebenbei mal deinen Code ausprobiert,
funktioniert leider auch nicht.

Grüße

von AxelR. (Gast)


Lesenswert?

Ich darf vielleicht auch as beisteuern - ist zwar wiedermal "nur"
FastAVR, aber aus C übernommen.
1
'#################### I2C-Interrupt ########################
2
Interrupt TWI(), Save All
3
Select Case TWSR
4
            'Slave receive codes
5
Case TW_SR_SLA_ACK        '0x60 
6
GoTo twi_78                         
7
Case TW_SR_ARB_LOST_SLA_ACK       '0x68
8
GoTo twi_78                           
9
Case TW_SR_GCALL_ACK        '0x70
10
GoTo twi_78                           
11
Case TW_SR_ARB_LOST_GCALL_ACK      '0x78
12
twi_78:
13
  TWI_State = TWI_SLAVE_RX
14
  TWI_RXD_INDEX = 0
15
            'has receive byte and return ACK
16
  $Asm
17
  ldi r16, (1<<TWIE | 1<<TWINT| 1<<TWEA | 1<<TWEN)
18
  out TWCR, r16
19
  $EndAsm
20
Case TW_SR_DATA_ACK        '0x80
21
GoTo twi_90
22
Case TW_SR_GCALL_DATA_ACK      '0x90
23
twi_90:
24
  
25
  TWI_RXDATA(TWI_RXD_INDEX)= TWDR    'get previously received data
26
27
  Incr TWI_RXD_INDEX
28
  If TWI_RXD_INDEX < TWI_BUF_SIZE And TWI_RXD_INDEX < MAX_RX_TWI_BYTE
29
Then  'check rx-buffer state
30
            'has receive byte and return ACK
31
    $Asm
32
    ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEA | 1<<TWEN)
33
    out TWCR, r16
34
    $EndAsm
35
  Else
36
            'has receive byte and return NACK
37
    TWI_RXD_INDEX = 0
38
    $Asm
39
    ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEN )
40
    out TWCR, r16
41
    $EndAsm
42
  End If
43
Case TW_SR_DATA_NACK        '0x88
44
GoTo twi_98                                   
45
Case TW_SR_GCALL_DATA_NACK      '0x98
46
twi_98:    
47
            'has receive byte and return NACK
48
  $Asm
49
  ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEN |1<<TWSTO)
50
  out TWCR, r16
51
  $EndAsm
52
                      
53
54
Case TW_SR_STOP          '0xA0
55
  
56
57
  TWI_RXD_INDEX = 0
58
  
59
  twi_rx_handle()        'neue I2C-Daten liegen vor
60
  
61
  $Asm
62
  ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEA | 1<<TWEN)
63
  out TWCR, r16
64
  $EndAsm
65
  
66
  TWI_STATE = TWI_IDLE
67
            'switch to SR mode with SLA ACK
68
                    
69
  
70
  
71
72
Case TW_ST_SLA_ACK
73
  GoTo twi_b0
74
Case TW_ST_ARB_LOST_SLA_ACK
75
twi_b0:  
76
    
77
  TWI_STATE = TWI_SLAVE_TX
78
  TWI_TXD_INDEX = 0
79
  GoTo twi_b8
80
Case TW_ST_DATA_ACK
81
twi_b8:
82
      
83
  TWDR = TWI_TXDATA(TWI_TXD_INDEX)
84
85
86
  Incr TWI_TXD_INDEX
87
  If TWI_TXD_INDEX < TWI_BUF_SIZE  Then          $Asm
88
    ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEA | 1<<TWEN)
89
    out TWCR, r16
90
    $EndAsm
91
  Else
92
    $Asm
93
    ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEN)
94
    out TWCR, r16
95
    $EndAsm
96
  End If
97
Case TW_ST_DATA_NACK
98
GoTo twi_c8
99
Case TW_ST_LAST_DATA
100
twi_c8:  
101
    TWI_TXD_INDEX =  0
102
  TWI_STATE =TWI_IDLE
103
  $Asm
104
  ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEA | 1<<TWEN)
105
  out TWCR, r16
106
  $EndAsm
107
GoTo end_ints
108
Case TW_NO_INFO      '0xF8
109
GoTo end_ints
110
Case TW_BUS_ERROR
111
    TWI_STATE = TWI_IDLE
112
  $Asm
113
  ldi r16, (1<<TWIE | 1<<TWINT | 1<<TWEA | 1<<TWSTO | 1<<TWEN)
114
  out TWCR, r16
115
  $EndAsm      
116
end_ints:
117
118
End Select
119
120
121
end_twi:
122
End Interrupt

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.

von Ppp M. (sanic)


Lesenswert?

Wenn in meinem TWSR mal was stehen würde .... ;-)

von Ppp M. (sanic)


Lesenswert?

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

von AxelR. (Gast)


Lesenswert?

Das ist komisch!
irgentein Wert sollte drinn stehen, und wenn's nur 0xF8 ist.
1
'Slave Receiver Codes
2
Const TW_SR_SLA_ACK        = &h60
3
Const TW_SR_ARB_LOST_SLA_ACK  = &h68
4
Const TW_SR_GCALL_ACK      = &h70
5
Const TW_SR_ARB_LOST_GCALL_ACK  = &h78
6
Const TW_SR_DATA_ACK      = &h80
7
Const TW_SR_GCALL_DATA_ACK    = &h90
8
Const TW_SR_DATA_NACK      = &h88
9
Const TW_SR_GCALL_DATA_NACK    = &h98
10
Const TW_SR_STOP        = &hA0
11
'Slave Transmitter Codes
12
Const TW_ST_SLA_ACK        = &hA8
13
Const TW_ST_ARB_LOST_SLA_ACK  = &hB0
14
Const TWCR_CMD_MASK        = &h0F
15
Const TWSR_STATUS_MASK      = &hF8
16
Const TW_ST_DATA_ACK      = &hB8
17
Const TW_ST_DATA_NACK      = &hC0
18
Const TW_ST_LAST_DATA      = &hC8
19
Const TW_NO_INFO        = &hF8
20
Const TW_BUS_ERROR        = &h00

ich habe die Konstanten nochmal rauskopiert.

von AxelR. (Gast)


Lesenswert?

habe ich wirklich!
1
'Slave Receiver Codes
2
Const TW_SR_SLA_ACK        = &h60
3
Const TW_SR_ARB_LOST_SLA_ACK  = &h68
4
Const TW_SR_GCALL_ACK      = &h70
5
Const TW_SR_ARB_LOST_GCALL_ACK  = &h78
6
Const TW_SR_DATA_ACK      = &h80
7
Const TW_SR_GCALL_DATA_ACK    = &h90
8
Const TW_SR_DATA_NACK      = &h88
9
Const TW_SR_GCALL_DATA_NACK    = &h98
10
Const TW_SR_STOP        = &hA0
11
'Slave Transmitter Codes
12
Const TW_ST_SLA_ACK        = &hA8
13
Const TW_ST_ARB_LOST_SLA_ACK  = &hB0
14
Const TWCR_CMD_MASK        = &h0F
15
Const TWSR_STATUS_MASK      = &hF8
16
Const TW_ST_DATA_ACK      = &hB8
17
Const TW_ST_DATA_NACK      = &hC0
18
Const TW_ST_LAST_DATA      = &hC8
19
Const TW_NO_INFO        = &hF8
20
Const TW_BUS_ERROR        = &h00

von AxelR. (Gast)


Lesenswert?

sowas...
1
//Slave Receiver Codes
2
Const TW_SR_SLA_ACK        = &h60
3
Const TW_SR_ARB_LOST_SLA_ACK  = &h68
4
Const TW_SR_GCALL_ACK      = &h70
5
Const TW_SR_ARB_LOST_GCALL_ACK  = &h78
6
Const TW_SR_DATA_ACK      = &h80
7
Const TW_SR_GCALL_DATA_ACK    = &h90
8
Const TW_SR_DATA_NACK      = &h88
9
Const TW_SR_GCALL_DATA_NACK    = &h98
10
Const TW_SR_STOP        = &hA0
11
'Slave Transmitter Codes
12
Const TW_ST_SLA_ACK        = &hA8
13
Const TW_ST_ARB_LOST_SLA_ACK  = &hB0
14
Const TWCR_CMD_MASK        = &h0F
15
Const TWSR_STATUS_MASK      = &hF8
16
Const TW_ST_DATA_ACK      = &hB8
17
Const TW_ST_DATA_NACK      = &hC0
18
Const TW_ST_LAST_DATA      = &hC8
19
Const TW_NO_INFO        = &hF8
20
Const TW_BUS_ERROR        = &h00

von Ppp M. (sanic)


Lesenswert?

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.

von Ppp M. (sanic)


Lesenswert?

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

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

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?

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.