Forum: Mikrocontroller und Digitale Elektronik Einige Verständnis Fragen zum TWI (I²C)


von Martin K. (thereallife)


Lesenswert?

Moin moin,
ich befasse mich momentan mit dem TWI bus des ATMEGA32A, ich hab das 
Datenblatt schon durch und auch den Forum Artikel, wirklich verstanden 
habe ich es allerdings nicht.
Ich hab mir ne Libary hier aus dem Forum genommen und bin den Code Zeile 
für zeile durchgegangen und habe versucht zu verstehen...
Dabei sind einige Fragen aufgekommen die Ich euch gerne Stellen würde.
Der Code Funktioniert an sich, (ich arbeite zur Zeit nur am Slave) Der 
Master ist ein ARduino Mega2560 dort habe ich den Code Fix auf 50 
gelegt, allerdings bekomme ich manchmal nahezu abwechselnd 100 oder 50, 
bzw grade habe ich ihn auf 20 gelegt, manchmal bekomme ich 20, dann 40 
und hin und wieder 100?! irgendwas liegt also noch nicht ganz grade...
Meine ganzen Verständnis Frqagen habe ich als Kommentar reingemacht...

Ich hoffe ihr könnt mir etwas helfen damit der "Knoten" platzt

Liebe Grüße und schonmal danke im Vorraus

Martin

So hier erstmal der Arduino Code
1
#include <Wire.h>
2
3
void setup()
4
{
5
  Wire.begin(); 
6
}
7
8
byte x = 20;
9
10
void loop()
11
{
12
  Wire.beginTransmission(50); // transmit to device #4
13
  Wire.write(x);              // sends one byte  
14
  Wire.endTransmission();    // stop transmitting
15
  delay(500);
16
}

Und hier der ATmegaCode
Main:
1
#define LED1    PD2
2
#define LED2    PD3
3
#define LED3    PD4
4
#define LED4    PD5
5
#define LED5    PD6
6
#define LED6    PD7
7
#define LED_DDR    DDRD
8
#define LED_PORT  PORTD
9
10
#include <avr/io.h>
11
#include <stdio.h>
12
#include <avr/interrupt.h>
13
14
#ifndef F_CPU
15
#define F_CPU 8000000L
16
#endif
17
18
#include <stdio.h>
19
#include <util/delay.h>
20
#include <string.h>
21
#include "TWISlave.h"
22
#include "UART.h"
23
24
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
25
26
int main (void)
27
{
28
  uint8_t i=0;
29
  uint8_t j=0;
30
  uint8_t byte[8];
31
  uint8_t TWIS_ResonseType;
32
  cli();
33
  stdout = &mystdout;
34
  long baud = 9600L;
35
  UART_Init(baud);
36
  TWISlave_Init(50, 100000);
37
  printf("Hallo");
38
  LED_DDR = (_BV(LED1)) | (_BV(LED2)) |(_BV(LED3)) | (_BV(LED4));
39
  LED_PORT = _BV(LED1);
40
  while (1)
41
  {
42
    if (TWISlave_ResonseRequired(&TWIS_ResonseType))
43
    {
44
      switch (TWIS_ResonseType)
45
      {
46
        case TWISlave_ReadBytes:
47
          LED_PORT = _BV(LED2);
48
          // also in TWIS_ResonseType steht nun der Wert des TWSR Registers, 
49
          // wenn ich es Richtig verstanden habe, sind die ersten 7 Bit dort die Adresse,
50
          // TWIS_ReadByte wurde ja mit 0x60 definiert, was Binär 1100 000 heißt,
51
          // Warum hab ich nur 7 Bit?! stimmt meine heximal rechner nicht?
52
          // aber ok die 2te eins sagt er soll lesen?! warum macht man nicht einfach nur 01?
53
          for (i = 0; i<7; i++)
54
          {
55
            byte[i] = TWISlave_ReadAck();
56
            // Die Daten von TWDR kommen ins byte[i] array
57
            printf ("Byte gelesen: %d\n", byte[i]);
58
            // Hier wird gleich ausgegeben
59
          }
60
          byte[7] = TWISlave_ReadNack();
61
          printf ("Byte gelesen: %d\n", byte[7]);
62
          TWISlave_Stop();
63
          // ansich war ich bisher der meinung wir übertragen Bit für Bit, aber diese Schleife sieht mir eher danach aus
64
          // das man bytes übertragt und wenn ich das richtig sehe, lässt er sich 7 Bytes schicken und sagt beim 8ten ok ich hab genug?! 
65
          break;
66
        case TWISlave_WriteBytes:
67
          LED_PORT = _BV(LED3);
68
          // selbes spiel wie oben, TWISlave_WriteBytes ist als 0xA8 definiert
69
          // Binär also 1010 1000 warum sind das jetzt 8 Bit? aber ich nehme mal an es geht wieder nur um die 0 an zweiter stelle?!
70
          for (i = 0; i<8; i++)
71
          {
72
            TWISlave_Write(j++);
73
            printf("Bytes gesendet: %d\n", j-1);
74
          }
75
          TWISlave_Stop();
76
          break;
77
      }
78
    }
79
    i++;// wozu hier das i++?
80
  }
81
  return 0;
82
}

Die Funktions Slave Datei:
1
#include <stdio.h>
2
#include <avr/interrupt.h>
3
#ifndef F_CPU
4
#define F_CPU 8000000L
5
#endif
6
7
uint8_t TWISlave_Init(uint8_t Adresse, uint32_t Bitrate)
8
{
9
  TWBR = ((F_CPU/Bitrate)-16)/2;
10
  if (TWBR < 11) 
11
  {
12
    return 0;
13
  }
14
  TWAR = (Adresse << 1);
15
  TWCR = (1<<TWEN) | (1<<TWEA); // aktiviert TWI und erkennt Adresse an?!
16
  return 1;
17
}
18
19
uint8_t TWISlave_ResonseRequired(uint8_t * TWI_ResonseType)
20
{
21
  *TWI_ResonseType = TWSR; // Vom Code klar, aber was steht in TWSR? Ist dort die angesprochene Adresse? + 8te und 9te bit drin?
22
  // Muss ich ihm nicht hier gleich aufm 9ten Bit auch sogan Hallo! ich bin da (ACK) ?
23
  return TWCR & (1<<TWINT); // Warum wird TWCR zurückgegeben?
24
}
25
26
uint8_t TWISlave_ReadAck(void)
27
{
28
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
29
  // als erstes Löscht er das TWINT bit. 
30
  // mit dem Setzen von TWEN wird TWI aktiviert?
31
  // warum muss dies nochmal gemacht werden? Eigentlich haben wir das doch schon im INIT gemacht.
32
  // TWEA laut datenblatt heißt das er seine Adresse anerkennt?!
33
  // Im Forum (http://www.mikrocontroller.net/articles/AVR_TWI) steht allerdings das er erst dann bereit für eine Datenübertragung ist 
34
  // jedenfall wenn ich das richtig verstehe...
35
  while (!(TWCR & (1<<TWINT)));
36
  // WEnn ich das Richtig verstehe ist TWINT ja ein Interrupt, was so ähnlich wie eine Clock ist.
37
  // also wartet er in diesem Fall solange bis das Flag wieder da ist, um daraufhin die Daten aus dem Register zu lesen?
38
  return TWDR;
39
  // Ins TWDR Register müssten wenn das TWINT flag gesetzt wurde die Daten anliegen?
40
  // Liege ich richtig wenn ich sage das TWDR Register ist zum Übertragen von Daten und zum empfangen?
41
  
42
}
43
44
uint8_t TWISlave_ReadNack (void)
45
{
46
  TWCR = (1<<TWINT) | (1<<TWEN);
47
  // Ok gleiches Spiel wie bei ReadAck, bis auf das er nicht TWEA auf 1 setzt.
48
  // ist das der entscheidende Unterschied zwischen ack und nack?
49
  // Ich dachte eigentlich er würde das 9te bit auf null für ack und auf 1 lassen für nack?!
50
  while (!(TWCR & (1<<TWINT)));
51
  return TWDR;
52
}
53
54
uint8_t TWISlave_Stop()
55
{
56
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO) | (1<<TWEA);
57
  // OK Interrupt flag löschen
58
  // TWEN = TWI aktivieren?!
59
  // TWSTO also im Datenblatt stand, das beide eigentlich auf 0 sein müssen damit der
60
  // Slave auf seine Adresse reagiert, Stopt man also über TWSTO das ganze?
61
  // gut das ich TWEA noch nicht verstanden habe wissen wir ja bereits...^^ 
62
}
63
64
TWISlave_Write(uint8_t byte)
65
{
66
  TWDR = byte; // gut hier scheint sich meine Vermutung von Vorhin zu bestätigen 
67
  // TWDR ist sozusagend zwischen puffer für sender und empfänger
68
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
69
  // ok TWINT löscht das Flag um zu sagen kann losgehen
70
  // TWEN um TWI zu aktivieren
71
  // und TWEA hab ich immer noch nicht verstanden...^^
72
  while (!(TWCR & (1<<TWINT)));
73
}

und zuletzt die include datei
1
#ifndef _TWISlave
2
#define _TWISlave
3
4
#define  TWISlave_ReadBytes    0x60
5
#define  TWISlave_WriteBytes    0xA8
6
7
uint8_t TWISlave_Init(uint8_t, uint32_t);
8
uint8_t TWISlave_ResonseRequired(uint8_t *);
9
uint8_t TWISlave_ReadAck(void);
10
uint8_t TWISlave_ReadNack(void);
11
void TWISlave_Stop(void);
12
void TWISlave_Write(uint8_t);
13
14
#endif

von San L. (zwillingsfreunde)


Lesenswert?

Martin Kathke schrieb:
> // also in TWIS_ResonseType steht nun der Wert des TWSR
> Registers,
>           // wenn ich es Richtig verstanden habe, sind die ersten 7 Bit
> dort die Adresse,
>           // TWIS_ReadByte wurde ja mit 0x60 definiert, was Binär 1100
> 000 heißt,
>           // Warum hab ich nur 7 Bit?! stimmt meine heximal rechner
> nicht?
>           // aber ok die 2te eins sagt er soll lesen?! warum macht man
> nicht einfach nur 01?

Hm, zitieren scheint hier ein wenig komisch zu sein, aber egal.

Doch doch, deine Hexadezimal Rechnung stimmt. Allerdings sagt die zweite 
eins nicht dass er lesen soll. Soweit ich das richtig im Kopf habe sind 
die ersten 7 Bits die Adresse, das achte Bit dann entweder eine 0 oder 
1, welche jeweils aussagt ob gelesen oder geschrieben wird.

Martin Kathke schrieb:
> // ansich war ich bisher der meinung wir übertragen Bit für Bit

Jain. In dem Sinne überträgt man immer nur Bit für Bit, allerdings sind 
die meisten I2C Librarys so geschrieben dass man direkt ein Byte an die 
Sendefunktion übertragen kann.

Martin Kathke schrieb:
> Binär also 1010 1000 warum sind das jetzt 8 Bit? aber ich nehme mal an
> es geht wieder nur um die 0 an zweiter stelle?!

Nein.
Bei TWI ist es üblich dass das erste Byte 7 Adressbits enthält und ein 
Bit das Information dafüber leifert ob gelesen oder geschrieben wird. 
Sämtliche Daten die danach folgen können als vollständige Bytes gewertet 
werden, sprich, es werden in der Tat 8 Bits mit Informationen 
übertragen.

Martin Kathke schrieb:
> // Muss ich ihm nicht hier gleich aufm 9ten Bit auch sogan Hallo! ich
> bin da (ACK) ?

Im das ACK musst du dich in der Regel nicht kümmern.

Martin Kathke schrieb:
> WEnn ich das Richtig verstehe ist TWINT ja ein Interrupt, was so ähnlich
> wie eine Clock ist.

Uff, nein. Interrupt mit einem Clock zu vergleichen ist falsch. Du musst 
dir das so vorstellen:
Die meisten Programme sind Prozedual Programmiert. Sprich, der genaue 
Ablauf vom Programm ist definiert (von oben nach unten).
Nehmen wir mal an, du hast noch irgendwelche Delays eingebaut und ein 
kompletter Programmdurchlauf dauert mehrere Sekunden. In dieser Zeit 
kann dein TWI Slave tausende von Bytes senden, welche beim uC komplett 
verloren gingen. Da helfen nun die Interrupts.
Interrupts sind Programmunterbrechnungen. Sie werden durch bestimmte 
Ereignisse ausgelösst (Beispielsweise dem Empfang eines Bytes per TWI). 
Ist das der fall, dann springt der uC an eine definierte Stelle im 
Programm, der ISR (interrupt Service Routine). Dies ist ein Programmteil 
den du selbst schreiben kannst und der jedesmal aufgerufen wird, wenn 
irgend ein Ereigniss einen Interrupt auslöst. Ist dieser Programmteil 
durchlaufen, so geht der Controller wieder an den Punkt den Programms 
zurück, indem er unterbrochen wurde.

Ein solcher Interrupt kann von diversen Quellen ausgelöst werden. Im 
Grunde genommen ist es also nichts anderes als eine Art Unterbrechnung 
des Hauptprogramms. Ohne Interrupts würde sogut wie kein Programm 
funktionieren. Für eine etwas bessere Erklärung, Google sonst mal 
danach. Da findet man tolle Erklärungen.


Auf die anderen deiner Fragen will ich nicht zusehr eingehen, da ich 
eher mit PIC's als mit Atmel Arbeite und mich somit nicht sonderlich mit 
den ganzen Registern usw. auskenne. Desweiteren möchte ich anmerken dass 
ich mir bei meinen Antworten nicht zu 100 % sicher bin, allerdings denke 
ich, so falsch sind sie nicht. Vielleicht korrigiert mich ja der ein 
oder andere noch an einem Punkt.

Trotzdem hoffe ich, dass ich dir bereits ein bisschen helfen konnte.

Gruss

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Martin Kathke schrieb:
> // TWIS_ReadByte wurde ja mit 0x60 definiert, was Binär 1100 000 heißt,
> // Warum hab ich nur 7 Bit?! stimmt meine heximal rechner nicht?
> // aber ok die 2te eins sagt er soll lesen?! warum macht man
> nicht einfach nur 01?

  Weil die führende Null ausgeblendet wurde = 0xb0110 0000

Martin Kathke schrieb:
> // selbes spiel wie oben, TWISlave_WriteBytes ist als 0xA8 definiert
> // Binär also 1010 1000 warum sind das jetzt 8 Bit? aber ich
> nehme mal an es geht wieder nur um die 0 an zweiter stelle?!

 Ich glaube du hast die Reihenfolge der bits falsch verstanden

 | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
 |                ADRESSE                         | R/W  |

von Martin K. (thereallife)


Lesenswert?

San Lue schrieb:
> Doch doch, deine Hexadezimal Rechnung stimmt. Allerdings sagt die zweite
> eins nicht dass er lesen soll. Soweit ich das richtig im Kopf habe sind
> die ersten 7 Bits die Adresse, das achte Bit dann entweder eine 0 oder
> 1, welche jeweils aussagt ob gelesen oder geschrieben wird.

Marc Vesely schrieb:
> Ich glaube du hast die Reihenfolge der bits falsch verstanden
>
>  | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
>  |                ADRESSE                         | R/W  |

Danke, ja da habe ich falsch herum gedacht
aber warum vergleicht man dann nicht nur das 8te bit?

Wenn ich das jetzt richtig verstanden habe liegt ja dann im TWSR die 
adresse + das lese / schreibe bit. Wenn dieser wert aus dem TWSR dann 
mit einem fixen Wert verglichen wird, müsste der Fixe wert doch 
eigentlich auch die Adresse enthalten?! sonst kann es ja eigentlich 
nicht zu einer übereinstimmung kommen?!

San Lue schrieb:
> Im das ACK musst du dich in der Regel nicht kümmern.

Ok, aber nur in diesem Fall oder? also beim ansprechen vom master an den 
Slave richtig?

San Lue schrieb:
> Uff, nein. Interrupt mit einem Clock zu vergleichen ist falsch. Du musst
> dir das so vorstellen:

Danke für deine ausführliche erklärung wie ein Interrupt funktioniert, 
das hatte ich allerdings schon verstanden, ich versteh nur diesen Bezug 
auf das I²C nicht so ganz..
Momentan stell ich mir das so vor:
User löscht den twint, und gibt der hardware befehle wenn die hardware 
die befehle durch hat setzt sie wieder den twint und man weiß das man 
nun fortfahren kann...

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Martin Kathke schrieb:
> Danke für deine ausführliche erklärung wie ein Interrupt funktioniert,
> das hatte ich allerdings schon verstanden

Genau das bezweifle ich ernsthaft, wenn ich folgendes lese:

Martin Kathke schrieb:
> User löscht den twint, und gibt der hardware befehle wenn die hardware
> die befehle durch hat setzt sie wieder den twint und man weiß das man
> nun fortfahren kann...

Du verwechselst warten auf das Flag "twint" ohne Interrupts, und echte 
Interrupt-programmierung, wo man sich um das Flag normalerweise gar 
nicht kümmert...

von Martin K. (thereallife)


Lesenswert?

Michael Reinelt schrieb:
> Du verwechselst warten auf das Flag "twint" ohne Interrupts, und echte
> Interrupt-programmierung, wo man sich um das Flag normalerweise gar
> nicht kümmert...

Der Code ist doch ohne Interrupts?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Martin Kathke schrieb:
> Der Code ist doch ohne Interrupts?

Ja, schon. Was aber vermutlich das problem ist.

Speziell bei TWI werde ich nie verstehen, warum alle zwanghaft 
versuchen, das "zu Fuß" auszuprogrammieren. Es geht mit Interrupts echt 
viel einfacher, weil einem der Interrupt schon die halbe State Machine 
abnimmt (naja, die halbe ist vielleicht etwas optimistisch..)

Es gibt dazu zwei ANs von Atmel, 311 und 315, da ist das eigentlich sehr 
gut erklärt.

Auch wenn I2C mit Interrupts anfangs etwas komplex aussieht: hast du das 
einmal geblickt, hast du I2C am AVR ein für allemal begriffen. Wenn man 
das dann noch sauber in eine "Library" (sprich: ein .c und .h-File) 
packt, ist das einbinden von I2C in ein weiteres projekt eine Frage von 
wenigen minuten.

von Martin K. (thereallife)


Lesenswert?

Michael Reinelt schrieb:
> Es gibt dazu zwei ANs von Atmel, 311 und 315, da ist das eigentlich sehr
> gut erklärt.

würde ich mir sehr gerne anschauen,
Müsstest du mir aber bitte mal sagen was Ans bedeuted^^
ANs 311 Atmel führt bei google nämlich ins nichts :D

von C++ (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Speziell bei TWI werde ich nie verstehen, warum alle zwanghaft
> versuchen, das "zu Fuß" auszuprogrammieren.

Software I2C ist bei vielen Leuten beliebt da sich so erstens jeder 
Pegelwechsel im Debuggingmodus ganz einfach anzeigen lässt.

Ein zweiter "Vorteil" ist, dass die Pins frei wählbar sind.

Bin da aber der gleichen Meinung wie du, lieber Hardware Interface 
benutzen, wenn es schon zur Verfügung steht.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Martin Kathke schrieb:
> Michael Reinelt schrieb:
>> Es gibt dazu zwei ANs von Atmel, 311 und 315, da ist das eigentlich sehr
>> gut erklärt.
>
> würde ich mir sehr gerne anschauen,
> Müsstest du mir aber bitte mal sagen was Ans bedeuted^^
> ANs 311 Atmel führt bei google nämlich ins nichts :D

AN steht für "Application Note"

AVR311 und AVR315 findet Herr Google mit Sicherheit...

von Martin K. (thereallife)


Lesenswert?

Michael Reinelt schrieb:
> hast du das
> einmal geblickt, hast du I2C am AVR ein für allemal begriffen.

genau das ist mein Problem, ich blicks noch nicht...

von San L. (zwillingsfreunde)


Lesenswert?


: Bearbeitet durch User
von Martin K. (thereallife)


Lesenswert?

Michael Reinelt schrieb:
> AN steht für "Application Note"
>
> AVR311 und AVR315 findet Herr Google mit Sicherheit...

alles klar,
ja das da nen avr vorgehört war mir nicht ganz klar,
habs mit atmel probiert^^

ich werds mir mal durchlesen hoffentlich blick ichs dann!

von Marc V. (Firma: Vescomp) (logarithmus)


Angehängte Dateien:

Lesenswert?

Martin Kathke schrieb:
> ich werds mir mal durchlesen hoffentlich blick ichs dann!

 Habe dir meine Library drangehängt, allerdings sind die Routinen
 zur Fehler- und Statusbehandlung nicht dabei - das ist ja
 Anwenderspezifisch, aber du kannst das Prinzip erkennen - Dabla
 durchlesen, entsprechend der Statusmeldung bestimmte Aktion vornehmen.
 In der Library habe ich eine Bremse für defekte Chips eingebaut weil
 der Status gepollt wird, keine ISR.
 Und hier ein Beispiel wie du Daten aus DS1307 (RTC) auslesen kannst
;* Y-Reg ist Zeiger auf Parameter Stack
;* Y + 0 = Wieviele Bytes man einlesen will
;* Y + 1 = Startadresse im DS1307
;* Die gelesenen Bytes befinden sich im I2C_Buffer

DataFromDS1307:
    rcall  DoI2CStart
    ldi  r17, C_DS1307_w      ;* DS1307 adresa
    rcall  I2cwbyte
    ldd  r17, Y+1        ;* Adresse
    rcall  I2cwbyte

    rcall  I2cstart
    ldi  r17, C_DS1307_r
    rcall  I2cwbyte
    rcall  DoI2CRead
    ret

DoI2CStart:  ldi  zl, low(I2C_Buff)
    ldi  zh, high(I2C_Buff)
    sts  I2C_BuffPos, zl
    sts  I2C_BuffPos+1, zh
    rcall  I2cstart
    ret

DoI2CRead:  ldd  r24, Y+0      ;* Wieviel
    andi  r24, 0x3F      ;* Fur alle Fälle...
    cpi  r24, 0x02
    brlo  I2C_NACK      ;* Wenn es nur 1 Byte ist, NACK senden und das 
war's
    dec  r24
    std  Y+0, r24
    rcall  I2C_ACK        ;* Byte einlesen, ACK senden ( für nächstes 
Byte )
    rjmp  DoI2CRead

I2C_ACK:  rcall  I2crbyte_ACK
I2C_A1:    lds  xl, I2C_BuffPos      ;* Zeiger auf momentane Position
    lds  xh, I2C_BuffPos+1
    st  X+, r17        ;* Empfangenes Byte schreiben
    sts  I2C_BuffPos, xl
    sts  I2C_BuffPos+1, xh    ;* Neue Position merken
    ret

I2C_NACK:
    rcall  I2crbyte_NACK
    rcall  I2C_A1
    rcall  I2cstop
    ret

 P.S. In der i2c_Lib habe ich in 'I2cstop' das prüfen auf TWINT
 rausgeschmissen, kann natürlich wieder reingeschmissen werden...

 P.P.S. Status bearbeitung fur Slave habe ich nicht, weil ich meine
 chips nie als Slaven laufen lasse...

: Bearbeitet durch User
von Martin K. (thereallife)


Lesenswert?

Marc Vesely schrieb:
> Habe dir meine Library drangehängt

Danke dir,
ich kann nur Assembler leider nicht lesen, ich hab erst vor 2 Monaten 
mit C und Microcontrollern angefangen, wenn ich die Zeit hab werd ich 
das aber auch mal lernen... ;)

Martin Kathke schrieb:
> Wenn ich das jetzt richtig verstanden habe liegt ja dann im TWSR die
> adresse + das lese / schreibe bit. Wenn dieser wert aus dem TWSR dann
> mit einem fixen Wert verglichen wird, müsste der Fixe wert doch
> eigentlich auch die Adresse enthalten?! sonst kann es ja eigentlich
> nicht zu einer übereinstimmung kommen?!

kann mir jmd das vielleicht noch beantworten?

: Bearbeitet durch User
von Andreas H. (ahz)


Lesenswert?

Martin Kathke schrieb:
> Martin Kathke schrieb:
>> Wenn ich das jetzt richtig verstanden habe liegt ja dann im TWSR die
>> adresse + das lese / schreibe bit. Wenn dieser wert aus dem TWSR dann
>> mit einem fixen Wert verglichen wird, müsste der Fixe wert doch
>> eigentlich auch die Adresse enthalten?! sonst kann es ja eigentlich
>> nicht zu einer übereinstimmung kommen?!
>
> kann mir jmd das vielleicht noch beantworten?

Nein, weil Deine Annahme falsch ist.

Das TWSR ist das TWI Status Register. Da steht die Adresse nicht drin 
(vgl. ATMEGA32A(L) DS (2503Q-AVR-02/11), Seite 178).

Wenn Du das TWAR Register meinst, da steht zwar die Slave Adresse in den 
Bits 8..1 aber die hast DU als Programmierer da rein geschrieben, damit 
der Baustein im Slave-Betrieb sich angesprochen fühlt.

Mit Bit 0 dieses Register enablest Du dann noch ggf. die "general call 
address", d.h. der Baustein reagiert im Slave-Betrieb zusätzlich (!) auf 
die I2C Adresse 0.

Grüße
Andreas

P.S.: RTFDS ;-)
      A.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Martin Kathke schrieb:
>> Wenn ich das jetzt richtig verstanden habe liegt ja dann im TWSR die
>> adresse + das lese / schreibe bit. Wenn dieser wert aus dem TWSR dann
>> mit einem fixen Wert verglichen wird, müsste der Fixe wert doch
>> eigentlich auch die Adresse enthalten?! sonst kann es ja eigentlich
>> nicht zu einer übereinstimmung kommen?!
>
> kann mir jmd das vielleicht noch beantworten?

Die Adresse steht im TWAR (falls du Slave bist), als Master sendest du 
die Adresse des gewünschten Slave mit dem ersten byte (General Call 
lassen wir mal außen vor), TWAR wird im Master-Betrieb nicht verwendet.

TWSR ist das Status Register, dazu gibts im Datenblatt eine wunderschöne 
Tabelle was die einzelnen Werte bedeuten. Adresse findest du da drinnen 
jedenfalls keine.

ich fürchte aber ich versteh deine Frage nicht wirklich :-)

: Bearbeitet durch User
von Martin K. (thereallife)


Lesenswert?

Michael Reinelt schrieb:
> TWSR ist das Status Register, dazu gibts im Datenblatt eine wunderschöne
> Tabelle was die einzelnen Werte bedeuten. Adresse findest du da drinnen
> jedenfalls keine.

Die habe ich grade entdeckt und werde die jetzt mal schritt für schritt 
durchgehen, vielleicht bringt das ja endlich licht ins dunkle...

Ich melde mich nochmal

Grüße
und Danke euch ;)

von Martin K. (thereallife)


Lesenswert?

Verstehe ich diese definierung richtig?

• Bit 3 – TWWC: TWI Write Collision Flag
The TWWC bit is set when attempting to write to the TWI Data Register – 
TWDR when TWINT is low. This flag is
cleared by writing the TWDR Register when TWINT is high.

Kleiner auszug ausm Forum Artikel:
. TWDR kann nur aktualisiert werden, wenn TWINT gesetzt ist, andernfalls 
kommt es zu einem Fehler, TWWC (TWI Write Collision Bit) wird gesetzt. 
Um die Daten zu senden, muss TWINT erneut gelöscht werden.

Also Wenn ich etwas in TWDR Register schreiben möchte, muss ich zuerst 
TWINT clearen, danach das TWWC Bit setzen und dann ins TWDR Register 
schreiben,
Abschließend nochmal TWINT clearen, jetzt sollte er die Daten ins TWDR 
Register übernommen haben und das TWWC Bit löscht sich durch das 
abschließende TWINT clearen, richtig?

Dadurch das ich endlich die Register erklärung entdeckt habe, versteh 
ich das ganze solangsam, (daran hats halt größtenteils gehackt, aber 
wieder was gelernt im Datenblatt weiter runterscrollen hilft...^^)

Hat jmd eine simple Libary für TWI mit Interrupts die ich mir anschauen 
könnte und durchgehen kann?
Die von Atmel hab ich mir bereits angeschaut aber die sind meinem 
Programmierstil weit vorraus wodurch ich da ordentlich ausgebremst werde 
um zu verstehen was da überhaupt passiert...^^
Daher wäre es super wenn jmd was für mich in C hätte ;)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Martin Kathke schrieb:
> Hat jmd eine simple Libary für TWI mit Interrupts die ich mir anschauen
> könnte und durchgehen kann?

 Noch einfacher ?
 Wohl kaum.
 Sehe das mal so:
 Was deine jetzige Library macht, ist polling, also Abfrage aus dem
 Programm heraus. Wenn du mit der Operation fertig bist, prüfst du
 TWSR register auf Status der Operation.
 Mit ISR ist alles dasselbe, nur prüfst du TWSR am Anfang der ISR auf
 Status, damit du überhaupt weisst, warum du in ISR gelandet bist.
 TWI und SPI sind sehr einfach und übersichtlich, auch kann TWI mit
 400KHz relativ schnell sein - kaum jemand arbeitet da mit ISR.
 Da du aber unbedingt im Slave-Modus arbeiten willst, mag ISR die
 bessere Lösung sein. Da es sich aber um 2 MEGAS handelt, ist SPI
 viel besser für so etwas - schneller, nach dem Erkennungs Byte sogar
 doppelt so schnell wie alles andere das auf die selbe Geschwindigkeit
 deklariert ist.

von Martin K. (thereallife)


Lesenswert?

Marc Vesely schrieb:
> Da es sich aber um 2 MEGAS handelt

Das ist nur vorüber gehend, später sind es 1 master mega und 4 slaves,
aber danke dirwas du geschrieben hast, hat das ganze schon recht klar 
gemacht

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.