Forum: Mikrocontroller und Digitale Elektronik STM32Fxxx: Tieferes Verständnis des I2C Interface


von Christian J. (Gast)


Angehängte Dateien:

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
}

von ff (Gast)


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.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Wieso liest man das Datenbyte aus, NACHDEM man NACK und
> STOP gesendet hat?

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.

von Christian J. (Gast)


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.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Tatsächlich wird erst NAK gesendet, dann Byte gelesen

Nö.
Man bereitet vor, daß nach dem Lesen ein NACK gesendet wird.
Wie gesagt, der Master taktet immer alle 9 Bits am Stück.
D.h. es gibt nach den 8 Datenbits keinen extra Interrupt, wo man sich 
überlegen könnte, ob nun NACK oder ACK.

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.