I2C Ablauf so korrekt?

#3826717
Lesenswert?

Ich habe mich jetzt mal in I2C eingelesen und frage mich ob ich so 
richtig denke.

Also, ich erteile dem Slave eine Adresse, nun habe ich das wie folgt 
verstanden:

Master:

I2C Start
I2C Schreibe Adresse + Write
I2C Schreibe byte
I2C Stop

Das ist ja die Übertragung.

Nun habe ich wie folgt verstanden das, sobald der Slave seine Adresse 
"verstanden" hat in einen ISR springt und dort dann die register, eins 
nach dem anderen einliest.

Ist das so richtig?

Demach könnte ich als "erstes" Byte eine länge der Daten senden und auf 
dem Slave dann eine schleife mit der Anzahl der länge laufen lassen, 
richtig?

Also auf dem Master:

Sende start
Sende adresse+write
Sende länge
Sende bytes in schleife
Sende checksumme
Sende stop

Und auf dem slave:
Empfange adresse
Springe ISR
Lese erstes byte (länge)
Führe schleife in anzahl der länge aus
Lese checksumme
Führe programm aus

Habe ich das so richtig verstanden? Dann muss ich nur noch gucken wie es 
vom slave zum master geht.

Danke euch schonmal.
#3827124
Lesenswert?

Tobias N. schrieb:
> Ich möchte halt atmega <-> atmega
>
> Ich prügel mich da schon durch *g*
>
> Mir ging es nur darum ob der "ablauf" so richtig ist!?


Richtig ist das was du als richtig definierst.
Einem Telefon ist es auch egal, ob du reinpfeifst oder deine Nachricht 
in Form von Rülpsern übermittelst. Das Telefon stellt den 
Übertragunskanal bereit, wie deine Botschaften dann aussehen, ist dein 
Bier (so etwas nennt man ein Protokoll)

Also: wenn du das so machen willst, dann mach das so. Nur das man beim 
Client keine Schleife machen wird. Wenn per I2C was reinkommt, dann 
'benachrichtigt' die Hardware ds Programm mit einem Interrupt. In diesem 
Interrupt entscheidest du dann, was das gerade eingetroffene Byte für 
eine Bedeutung hat und was du damit machst. Ist es das erste Byte in der 
Übertragung, dann speicherst du es dir als Länge der noch zu 
empfangenden Bytes ab, ist es nicht das erste Byte, dann speicherst du 
das Byte als Datenbyte ab und erniedrigst diesen Längenzähler um 1. Wird 
so der Längenzähler zu 0, dann weisst du, dass damit die Nachricht 
komplett übertragen wurde.

In den vielen Fällen muss man in der µC Programmierung weg von dieser 
'Ich mach was in einer Schleife' Denkweise. Man muss hin zu einer 'Ich 
wache gerade auf, finde diese Inforamtion vor, was mache ich damit ehe 
ich wieder schlafen gehe' Denkweise.
Gast #3827732
Lesenswert?

------

Arduino:

i2c avr <--> avr "mal eben machen" ist schon einfacher mit Arduino:
http://arduino.cc/en/Tutorial/MasterReader

------

AVR:

AVR311 PDF:    http://www.atmel.com/images/doc2565.pdf
AVR311 Software: http://www.atmel.com/Images/AVR311.zip (geht wohl mit 
avr-gcc nicht?!) ---> dann halt diese modifizierte hier:
https://github.com/kelvinlawson/avr311-twi-slave-gcc

AVR TWI Master und Slave Funtionen in C
Beitrag "AVR TWI Master und Slave Funtionen in C"
(Firma: Brainit GmbH) #3827760
Lesenswert?

Karl Heinz schrieb:
> Nur das man beim
> Client keine Schleife machen wird. Wenn per I2C was reinkommt, dann
> 'benachrichtigt' die Hardware ds Programm mit einem Interrupt. In diesem
> Interrupt entscheidest du dann, was das gerade eingetroffene Byte für
> eine Bedeutung hat und was du damit machst. Ist es das erste Byte in der
> Übertragung, dann speicherst du es dir als Länge der noch zu
> empfangenden Bytes ab, ist es nicht das erste Byte, dann speicherst du
> das Byte als Datenbyte ab und erniedrigst diesen Längenzähler um 1. Wird
> so der Längenzähler zu 0, dann weisst du, dass damit die Nachricht
> komplett übertragen wurde.

Jein. ich mach das immer etwas anders: Ich definiere mir einen 
Empfangspuffer mit einer definierten Größe, sodass die maximal erwartete 
Nachricht noch Platz hat. Danach empfange ich Byte für Byte, kümmere 
mich an der Stelle aber überhaupt nicht darum welche Bedeutung die Bytes 
haben (ob das erste Byte eine Länge oder eine Registernummer oder die 
relative Mondfeuchtigkeit ist, ist an der Stelle irrelevant). Solange 
ich noch Platz im Buffer für das gerade empfangene Byte habe, speichere 
ich das Byte und antworte ich mit ACK, hab ichs nicht mehr Platz, mit 
NACK.

Danach stelle ich den Buffer und die Länge des empfangenen Pakets der 
darüberliegenden Schicht zur Verfügung. Was die damit macht, ist mir 
auch wieder egal.

Tobias N. schrieb:
> ISR (TWI_vect)
> {
>   len = read_Ack(); // Erstes Byte ist die Länge.
>
>   for(i=0;i <len; i++)
>    {
>      buf[i] = read_Ack(); // Lese Byte für Byte ein und schreibe in
> Array
>    }
>   len = read_Nack(); // weiss nicht ob das wichtig ist
>   return buf;
> }

Da denkst du grad ziemlich verkehrt: die TWI-ISR wird für jeden Vorgang 
am TWI aufgerufen (adressierung, byte empfangen usw) da drinnen kannst 
du kein read_Ack() machen.
#3827885
Lesenswert?

Also in etwa so:
1
if (todo > 0)
2
{
3

4
if (todo == 1)
5
{
6
  addr = TWDR;
7

8
  if (addr == lese_addr)
9
  {
10
    todo = 2;
11
    sende ack;
12
  }
13

14
  if (addr == schreibe_addr)
15
  {
16
    todo = 3;
17
    sende ack;
18
  }
19
}
20

21
if (todo == 3)
22
{
23
  len = TWDR;
24
  array_len = 0;
25
  sende ack;
26
  todo = 4;
27
}
28

29
if (todo == 4)
30
  {
31
    data[array_len] = TWDR;
32
    array_len++;
33
    if(array_len == len)
34
      {
35
        sende nack;
36
      }
37
      else
38
      {
39
        sende ack;
40
      }
41
  }
42

43
if stopsignal => todo = 0;
44

45
}
46
else
47
{
48
  if startsignal -> setze todo = 1;
49
}

Nur mal so grob aber so in etwa sollte das ja dann sein, oder?
(Firma: Brainit GmbH) #3827901
Lesenswert?

Tobias N. schrieb:
> Nur mal so grob aber so in etwa sollte das ja dann sein, oder?

nein, eigentlich überhaupt nicht :-(

Am AVR (zumindest auf den "großen" wie ATmega) gibt dir die TWI-Hardware 
schon die Rahmenbedingungen für die State Machine vor, gesteuert über 
TWSR (TWI Status Register). Dazu gibts eine wunderbare Beschreibung mit 
wunderbaren Tabellen im Datenblatt. Arbeite das mal durch.

Wenn schon dann sähe es etwa so aus:
1
ISR(TWI_vect)
2
{
3
    // code based on tables 21.4..6 from ATmega328 data sheet
4

5
    // cache some volatile variables
6
    uint8_t index, length;
7

8
    switch (TW_STATUS) {
9

10
    case 0x00:      // Bus error due to an illegal START or STOP condition
11
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
12
  I2C_Busy = 0;    // transmission aborted
13
  I2C_Error = 1;    // set error flag
14
  break;
15

16
    case 0x60:      // own SLA+W has been received; ACK has been returned
17
    case 0x68:      // own SLA+W has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
18
    case 0x70:      // general call address has been received; ACK has been returned
19
    case 0x78:      // general call address has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
20
  I2C_Busy = 1;    // transmission started
21
  I2C_RxIndex = 0;  // reset packet index
22
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // send ACK on next byte
23
  break;
24

25
    case 0x80:      // previously addressed with own SLA+W; data has been received; ACK has been returned
26
    case 0x88:      // previously addressed with own SLA+W; data has been received; NAK has been returned
27
    case 0x90:      // previously addressed with general call; data has been received; ACK has been returned
28
    case 0x98:      // previously addressed with general call; data has been received; NAK has been returned
29
  index = I2C_RxIndex;  // local cache
30
  if (index < I2C_PACKETSIZE) {
31
      I2C_RxBuffer[index++] = TWDR;  // store received data
32
      I2C_RxIndex = index;  // write back cache
33
  }
34
  if (index < I2C_PACKETSIZE) {
35
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // send ACK on next byte
36
  } else {
37
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // no space left, send NAK on next byte
38
  }
39
  break;
40

41
    case 0xA8:      // own SLA+R has been received; ACK has been returned
42
    case 0xB0:      // own SLA+R has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
43
  I2C_Busy = 1;    // transmission started
44
  I2C_TxIndex = 0;  // reset packet index
45
  // fall through
46

47
    case 0xB8:      // data byte in TWDR has been transmitted; ACK has been received
48
  index = I2C_TxIndex;  // local cache
49
  length = I2C_TxLength;  // local cache
50
  if (index < length) {
51
      TWDR = I2C_TxBuffer[index++];  // transmit next byte
52
      I2C_TxIndex = index;  // write back cache
53
  } else {
54
      TWDR = 0;    // we have nothing more...
55
  }
56
  if (index < length) {
57
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // expect ACK
58
  } else {
59
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // last byte: expect NAK
60
  }
61
  break;
62

63
    case 0xA0:      // a STOP condition or repeated START condition has been received while still addressed as Slave
64
  I2C_Busy = 0;    // transmission ended
65
  if (I2C_RxIndex > 0) {
66
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // disable TWI until data has been processed
67
  } else {
68
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // re-enable TWI
69
  }
70
  break;
71

72
    case 0xC0:      // data byte in TWDR has been transmitted; NAK has been received
73
    case 0xC8:      // last data byte in TWDR has been transmitted (TWEA = 0); ACK has been received
74
  I2C_Busy = 0;    // transmission ended
75
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // re-enable TWI
76
  break;
77

78
    case 0xF8:      // no relevant state information available; TWINT = 0
79
  break;
80

81
    default:      // all other states
82
  I2C_Busy = 0;    // transmission aborted
83
  I2C_Error = 1;    // something strange happened
84
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
85
  break;
86
    }
87
}

Wie du vielleicht erkennst: I2C ist keine Anfängerkost...
(Firma: Brainit GmbH) #3827934
Lesenswert?

Tobias N. schrieb:
> In TWCR steht drinne ob Start oder adresse+R oder adresse+W also muss
> ich jedesmal nur das Register auslesen und auswerten :)

nein.

Tobias N. schrieb:
> Wird ja immer einfacher die ganze Sache

nein.

Bitte - lies dir im Datenblatt das Kapitel zu TWI, und danach die AVR311 
"Using the TWI module as I2C slave". Sonst wird das nix.

nochmal: LIES DAS! Vorher kriegst du von mir keine Antwort mehr.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren