Forum: Mikrocontroller und Digitale Elektronik STm32Fxxx: I2C Hardware Experten gesucht


von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe da vor 2 Jahren mal ein Thread gehabt, der aber nicht zu Ende 
geführt wurde. Bin seit 2 Tagen an der I2C Statemaschine eines STM32F103 
dran, um richtige und verständliche EEPROM Routinen zu schreiben. Habe 
einen Logic Analyser mit dran und kann mit das Ganze auch anschauen.

Falls hier jemand ist, der sich schon INTENSIV mit dem Thema befasst hat 
und vor allem selbst den Code geschrieben hat, der möge doch mal bitte 
hier schreien.

Bytes schreiben klappt soweit ganz gut, auch mit dem Polling. Bytes 
lesen liefert zwar richtige Ergebnisse aber mich stört das 255+NAK im 
Bild. Da geht zeit bei flöten, der Stop müsste eigentlich direkt 
dahinter kommen.

Code aus dem Netz gibt es zwar aber auch da sind Fehler drin, weil da 
eine "serielle Denke" am Werk war, zb bei

uint8_t i2c_receive_nack()

stand ursprünglich noch ein i2c_stop() dahinter, so wie man es von einem 
AVR her kennt. Fakt ist aber, dass wir es hier mit einer sehr komplexen 
Multi-Master fähigen Statemachine zu tun haben, die ein ganzes Netzwerk 
betreiben kann und die VORHER gefüttert wird und die dann ihr Programm 
auf dem Bus runterspult.

Mein Hauptanliegen ist, ob ich das richtig codiert habe und vor allem, 
ob ich das richtig verstanden habe?

Ich frage mich zb immer noch was das "Event 5" auslöst? Ich frage es 
zwar aber aber mein Code bleibt da hängen, wenn das EEPROM mit seinem 
internetn Zyklus befasst ist.

Gruss,
Christian
1
/* ---------------------------------------------------------------
2
   Schreibt ein Byte in eine einzelne Adresse
3
   Eingabe: Nr. des EEPROMs (0 und 1)
4
            16 Bit Adresse
5
            8 Bit Datenwort
6
   --------------------------------------------------------------*/
7
uint8_t EE_WriteByte(uint8_t EE, uint16_t adr, uint8_t data)
8
{
9
    uint8_t lower_addr, upper_addr;
10
11
    // EEPROM 1 oder 2?
12
    switch (EE) {
13
        case 0: EE = E1_WR_ADR;
14
                break;
15
        case 1: EE = E2_WR_ADR;
16
                break;
17
    }
18
19
    lower_addr = (uint8_t)((0x00FF) & adr);
20
    adr = adr>>8;
21
    upper_addr = (uint8_t)((0x00FF) & adr);
22
23
    // Wait until I2C1 is not busy anymore
24
    //while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
25
26
    // ACK ein
27
    I2C_AcknowledgeConfig(I2C1, ENABLE);
28
29
    do {
30
        /* Erzeuge START Bedingung */
31
        I2C_GenerateSTART(I2C1, ENABLE);
32
        if (I2C_WaitForEvent(200, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
33
            return ERROR;
34
        // Adressiere das E2PROM
35
        I2C_Send7bitAddress(I2C1, EE, I2C_Direction_Transmitter);
36
     } while (I2C_WaitForEvent(200, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
37
38
39
    // Adresse als 2 x 8 Bit senden
40
    i2c_transmit(upper_addr);
41
    i2c_transmit(lower_addr);
42
43
    // Sende Datum
44
    i2c_transmit(data);
45
46
    // Sende I2C3 STOP Condition
47
    i2c_stop();
48
49
    return SUCCESS;
50
51
}
52
53
/* ---------------------------------------------------------------
54
   Ein Byte aus E2PROM lesen
55
   Eingabe: Adresse 16 Bit
56
   ------------------------------------------------------------- */
57
uint8_t EE_Read_Byte(uint8_t EE, uint16_t adr)
58
{
59
    uint8_t ee_read_adr, ee_write_adr;
60
    uint8_t lower_addr, upper_addr, data;
61
62
    lower_addr = (uint8_t)((0x00FF) & adr);
63
    adr = adr>>8;
64
    upper_addr = (uint8_t)((0x00FF) & adr);
65
66
    // EEPROM 1 oder 2?
67
    switch (EE) {
68
        case 0: ee_write_adr = E1_WR_ADR;
69
                ee_read_adr  = E1_RD_ADR;
70
                break;
71
        case 1: ee_write_adr = E2_WR_ADR;
72
                ee_read_adr  = E2_RD_ADR;
73
                break;
74
    }
75
76
    /* -------- E2PROM Lesemodus (MASTER Receiver Mode)------ */
77
78
    // Adressiere das E2PROM auf zu lesende Speicherstelle
79
    i2c_start();
80
    i2c_address_direction(ee_write_adr, I2C_Direction_Transmitter);
81
    i2c_transmit(upper_addr);
82
    i2c_transmit(lower_addr);
83
84
    // Umschalten in Lesemodus
85
    i2c_start();
86
    i2c_address_direction(ee_read_adr, I2C_Direction_Receiver);
87
    data = i2c_receive_nack();
88
89
    return (data);
90
91
}
1
/* ---------- Empfange ACK ------------*/
2
uint8_t i2c_receive_ack()
3
{
4
    // Enable ACK of received data
5
    I2C_AcknowledgeConfig(I2C1, ENABLE);
6
    // Wait for I2C EV7
7
    // It means that the data has been received in I2C data register
8
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
9
    // Read and return data byte from I2C data register
10
    return I2C_ReceiveData(I2C1);
11
}
12
13
/* ---------- Empfange NACK ------------*/
14
uint8_t i2c_receive_nack()
15
{
16
    // ACK bei empfangenen Daten abschalten
17
    I2C_AcknowledgeConfig(I2C1, DISABLE);
18
    // Warte fuer EV7 = Daten sind empfangen worden
19
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
20
21
    // Stop direkt danach erzeugen
22
    I2C_GenerateSTOP(I2C1, ENABLE);
23
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
24
25
    // Read and return data byte from I2C data register
26
    return I2C_ReceiveData(I2C1);
27
}

von Erdowahn (Gast)


Angehängte Dateien:

Lesenswert?

Ich kann Dir nur insofern helfen, indem ich funktionierenden Code zum 
auslesen eines LM75-Temperatur-Sensors anbiete. Vielleicht hilfts.

Gruß, der Erdowahn

von Christian J. (Gast)


Lesenswert?

Danke, den kenne ich schon.  Ist wohl aus den Beispielen.
Habe ihn aber beiseitige gelegt, weil da noch DMA als zusätzliche 
Erschwernis mit hinzu kommt.

geht mir mhr um so einfache Dinge warum eine einfache Abfrage der SM im 
i2c_start(), ob sie beschäftigt ist

while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

schon einen Hänger verursacht an der Stelle, weil die Schleife nie 
verlassen wird.

von Erdowahn (Gast)


Lesenswert?

[OT]
Bin jetzt zu faul zum suchen,aber warst Du nicht der selbe, bei denm es 
an der RTC geklemmt hat?
[/OT]

von Erdowahn (Gast)


Lesenswert?

Erdowahn schrieb:
> denm

Ich gehe ins Bett! 8-(

von Christian J. (Gast)


Lesenswert?

Hallo,

ich schieb den nochmal hoch, da ich mich nach langer Pause mal wieder 
damit befassen wollte.

Wer kennt sich richtig gut aus mit der I2C State Machine des STM32F103 ? 
Wo welche Events abgefragt und ausgelöst werden müssen, wo Timeout und 
wo nicht usw. Ich habe funktionierenden Code laut Analyzer aber der 
hängt sich auch ab und an mal einfach auf, Bumms.... Event kommt nicht, 
alles steht still und das geht nicht.

Diese Statemachine ist nicht trivial, vor allem nicht wenn man auf 
maximalen Durchsatz gehen will, Pageing optimiert nutzt. Und 
Softwarelösungen kommen mir nicht ins Haus, wenn ich eine Top Hardware 
habe, die im DMA arbeiten kann.

Gruss,
Christian

von Felix F. (wiesel8)


Angehängte Dateien:

Lesenswert?

So machs ich. Hat bis jetzt immer wunderbar funktioniert.

mfg

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Super! Danke Dir! Ich schau mir das mal in Ruhe genau an und gleiche es 
mit meinem Code ab.

Berücksichtigst Du auch die Zykluszeit fürs Schreiben oder nimmst du 
einfach einen festen Wert, zb 3-4ms. Ich schreibe quasi alles mit 
Pagewerite, sobald es mehr als 2 Bytes sind.

Weiterhin schafft man es, grad beim Debuggen so ein E2PROM auch intern 
abzuschiessen, so dass es gar nicht mehr reagiert. Man muss nur eine 
Sequenz mittendrin abbrechen, dann ist die interne Statemachine 
durcheinander. Dafür habe ich noch keine Lösung ausser ON/OFF der ganzen 
Schaltung.

von Klaus (Gast)


Lesenswert?

Christian J. schrieb:
> Weiterhin schafft man es, grad beim Debuggen so ein E2PROM auch intern
> abzuschiessen, so dass es gar nicht mehr reagiert. Man muss nur eine
> Sequenz mittendrin abbrechen, dann ist die interne Statemachine
> durcheinander. Dafür habe ich noch keine Lösung ausser ON/OFF der ganzen
> Schaltung.

Beitrag "Re: I2C hängt sich auf"

MfG Klaus

von Christian J. (Gast)


Lesenswert?

Klaus schrieb:

> Christian J. schrieb:
>> Weiterhin schafft man es, grad beim Debuggen so ein E2PROM auch intern
>> abzuschiessen, so dass es gar nicht mehr reagiert. Man muss nur eine
>> Sequenz mittendrin abbrechen, dann ist die interne Statemachine
>> durcheinander. Dafür habe ich noch keine Lösung ausser ON/OFF der ganzen
>> Schaltung.
>
> Beitrag "Re: I2C hängt sich auf"
>
> MfG Klaus

Ähm.... wie kann man sich das genau vorstellen, dieses "Wackeln"? Das 
Schaltwerk meiner Waschmaschine ist dafür nämlich auch anfällig. Da 
nützt kein normaler Start mehr was. Und bei einer Statemachine wie der 
Prime Cell des STM32 kannste die Leitungen eh nicht manuell ansteuern, 
musst sie vorher abkoppeln. Die versteht nur die regulären Abläufe.

von Christian J. (Gast)


Lesenswert?

@Felix: Kannst mal auch die header Datei dazu posten?

von Christian J. (Gast)


Lesenswert?

@Felix:

Habe jetzt 2 Stunden versucht deinen Code zum Laufen zu kriegen. Ist 
noch ein kleiner Bug drin, nämlich dass

 // Generate I2C stop condition
    I2C_GenerateSTOP(I2C_KANAL, ENABLE);
    // Wait until I2C stop condition is finished
    while (I2C_GetFlagStatus(I2C_KANAL, I2C_FLAG_STOPF));

die stop Condition nicht auf Ausführung überprüft wird.

Auch hier ist ein Unterschied, nämlich die Verwendung von I2C-CheckEvent 
und I2C_FlagStatus.

// Start-Sequence
    I2C_GenerateSTART(I2Cx, ENABLE);

    timeout = I2C1_TIMEOUT;
    while(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_SB)) {
        if(timeout != 0)
            timeout--;
        else
            return(I2C1_Timeout(I2Cx, -1));
    }

 I2C_GenerateSTART(I2Cx, ENABLE); löst nämlich ein Event aus.


Du verwendest kein Pagewrite, deine Byte Write Routine wird daher Fehler 
melden, wenn du zu schnell schreibst, denn dann antwortet das Eprom 
nicht solange der Schreibzyklus nicht beendet ist.

Da habe ich das eingebaut, der hämmert solange eine Start Cond. raus, 
bis das Ding endlich antwortet.

/* Warte bis I2C Interface frei */
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    /* ACK ein */
    I2C_AcknowledgeConfig(I2C_KANAL, ENABLE);

    do {
        /* Erzeuge START Bedingung ---- FIXXXME */
        I2C_GenerateSTART(I2C_KANAL, ENABLE);
        if (I2C_WaitForEvent(200, I2C_EVENT_MASTER_MODE_SELECT) != 
SUCCESS)
            return ERROR;
        // Adressiere das E2PROM
        I2C_Send7bitAddress(I2C_KANAL, EE, I2C_Direction_Transmitter);
     } while (I2C_WaitForEvent(200, 
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);

von Klaus (Gast)


Lesenswert?

Christian J. schrieb:
> Ähm.... wie kann man sich das genau vorstellen, dieses "Wackeln"?

Pin von SCL zum Ausgang machen, dann High, dann Low, dann High ...

Die Statemachine im Slave zuende takten

MfG Klaus

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.