STM32Fxxx: Tieferes Verständnis des I2C Interface

Gast #4382865
Lesenswert?
• ▲
▼
Hallo,

ich habe mich nun 3 Abende lang in die I2C eingearbeitet um sie wirklich 
zzu verstehen, da sie erheblich komplexer ist als zb die eines AVR oder 
PIC.
Dabei ist es nachfolgende wichtig zu erwähnen, dass ich mit der 
StdPeriphLib arbeite, also nicht auf Registerebene, da ich das 
unleserlich finde.

Folgende Code habe ich geschrieben bzw aus einer Vorlage umgeschrieben, 
der auch funktioniert. Jetzt gilt es zu klären WARUM er funktioniert und 
WIE, da einiges eher nach Trial & Error ablief.

Die Routine adressiert ein E2PROM 24LC512 und liest dort genau ein Byte 
aus.

Es geht um die Zeilen hier:
1
// NACK einstellen E2PROM anzuzeigen, dass keine weiteren Daten angefordert sind
2
        I2C_AcknowledgeConfig(I2C3, DISABLE);
3
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_RECEIVED)!=0)
4
        return 0xff;
5

6
        // Stop Bedingung erzeugen NACH dem nächsten Lesezugriff
7
        I2C_GenerateSTOP(I2C3, ENABLE);
8
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_RECEIVED)!=0)
9
        return 0xff;
10

11
        // Datenbyte auslesen
12
        Data = I2C_ReceiveData(I2C3);

Das sieht erstmal falsch aus, denn die Reihenfolge ist ja wie im Bild 
sichtbar anders. Wieso liest man das Datenbyte aus, NACHDEM man NACK und 
STOP gesendet hat? Ich vermute, dass es so ist, dass man die 
Statemachine im STM32 so konfiguriert, dass er diese Dinge beim NÄCHSTEN 
Buszugriff ausführt, da das Timing ja stimmen muss, die Ereignisse 
laufen ja nicht synchron mit der Software ab, sondern werden durch die 
Hardware gesteuert.

Jetzt frage ich mich allerdings, wieso die Zeile

if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_RECEIVED)!=0)
        return 0xff;

da rein muss und nach welchem der Befehle oben wirklich der Buszugriff 
ausgeführt wird. D.h. was ist Konfiguration und was ist der Zugriff? Das 
Auslesen des datenbytes ist bloss das Lesen eines Registers, das Byte 
ist also schon eingetroffen. Aber bei welchem Befehl oben ist das 
passiert?

Ich weiss, dass viele nur fertige Libs verwenden, die ja auch 
funktionieren aber ich möchte eben genau verstehen wie das so abläuft 
:-)

gruss,
Christian
1
// Hilfsroutine fuer Eventabfrage
2
static uint8_t I2C_WaitForByteTransmitted(uint32_t event)
3
{
4
        uint32_t timeout = I2C_TIMEOUT_MAX;
5

6
        while(!I2C_CheckEvent(I2C3, event)) {
7
      if ((timeout--) == 0) return 0xFF;
8
    }
9
    return 0;
10
}
11

12
// Adresse aus E2PROM lesen
13
uint8_t Read_E2PROM(uint16_t Addr)
14
{
15
        uint8_t Data = 0;
16
        uint8_t upper_addr,lower_addr;
17

18
        lower_addr = (uint8_t)((0x00FF) & Addr);
19
        Addr = Addr>>8;
20
        upper_addr = (uint8_t)((0x00FF) & Addr);
21

22
        /* -------- E2PROM Adresszeiger auf Zieladresse setzen ------ */
23

24
        // Erzeuge START Bedingung
25
        I2C_GenerateSTART(I2C3, ENABLE);
26
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_MODE_SELECT)!=0)
27
        return 0xff;
28

29
        // Adressiere das E2PROM
30
        I2C_Send7bitAddress(I2C3, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
31
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=0)
32
        return 0xff;
33

34
        // Adresse als 2 x 8 Bit senden
35
        I2C_SendData(I2C3,upper_addr);
36
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=0)
37
        return 0xff;
38

39
        I2C_SendData(I2C3, lower_addr);
40
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=0)
41
        return 0xff;
42

43
        // AF Flag evtl löschen
44
        I2C3->SR1 |= (uint16_t)0x0400;
45

46
        /* -------- E2PROM Lesemodus (MASTER Receiver Mode)------ */
47

48
       // Erzeuge START Bedingung
49
        I2C_GenerateSTART(I2C3, ENABLE);
50
        if (I2C_WaitForByteTransmitted( I2C_EVENT_MASTER_MODE_SELECT)!=0)
51
        return 0xff;
52

53
        // Adressiere das E2PROM
54
        I2C_Send7bitAddress(I2C3, MEM_DEVICE_READ_ADDR, I2C_Direction_Receiver);
55
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=0)
56
        return 0xff;
57

58
        // NACK einstellen E2PROM anzuzeigen, dass keine weiteren Daten angefordert sind
59
        I2C_AcknowledgeConfig(I2C3, DISABLE);
60
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_RECEIVED)!=0)
61
        return 0xff;
62

63
        // Stop Bedingung erzeugen NACH dem nächsten Lesezugriff
64
        I2C_GenerateSTOP(I2C3, ENABLE);
65
        if (I2C_WaitForByteTransmitted(I2C_EVENT_MASTER_BYTE_RECEIVED)!=0)
66
        return 0xff;
67

68
        // Datenbyte auslesen
69
        Data = I2C_ReceiveData(I2C3);
70

71
        return Data;
72
}
Angehängte Dateien:
Gast #4400309
Lesenswert?
• ▲
▼
Christian J. schrieb:
> 3 Abende lang in die I2C eingearbeitet um sie wirklich
> zzu verstehen, da sie erheblich komplexer ist als zb die eines AVR oder
> PIC.
Ach was..

Christian J. schrieb:
> Jetzt gilt es zu klären WARUM er funktioniert und
> WIE

Um zu verstehen was da gemacht wird schau dir die Register vom I2C im 
manual an!
http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf
Auf S. 840 wird beschrieben was dein Code eigentlich macht und S.851 ff 
erklärt die Register dazu.
Deine "Hilfsroutine fuer Eventabfrage" schaut sich die dort 
beschriebenen Register an.
Gast #4400936
Lesenswert?
• ▲
▼
Peter D. schrieb:
> Lesen und NACK senden ist eine Aktion (= 9 Takte), die kann man nicht
> trennen.
> Außerdem rufst Du Libfunktionen auf und greifst nicht direkt auf das I2C
> zu.
> Entweder die Lib merkt sich das Datenbyte oder ein STOP ändert das
> Datenbyte nicht.

Ist schon alles klar. Das Datenblatt hat geholfen. Man muss sich nur 
bewusst werden, dass es nicht eine "Registermaschine" ist wie beim AVR 
und PIC sondern eine komplette Statemachine, die mit Anweisungen 
gefüttert wird und die dann automatisch diese abarbeitet. Die 
Reihenfolge der Befehle muss nicht die sein, wie es wirklich passiert. 
Tatsächlich wird erst NAK gesendet, dann Byte gelesen und dann kommt das 
Stop hinterher. Sieht man auch auf dem Oszi. Und jede Aktion löst ein 
Event aus, was man abfragen kann.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.