Forum: Mikrocontroller und Digitale Elektronik Cortex I2C zu kurze Impulsdauer


von Sylvia H. (sandy)



Lesenswert?

Hi,
ich habe folgendes Problem:
Ich versuche gerade eine I2C Kommunikation zwischen 2 Boards her zu 
stellen. Auf einem Board läuft ein ATXMEGA16 auf dem anderen ein Cortex 
STM32f103.
Nun ist es so, das der Cortex mit anderen Cortexen, und der ATXMAGA mit 
anderen ATXMEGAS gut kommunizieren kann. Der Cortex kann auch per 
Interrupt empfangen, was der ATXMEGA auf den I2C Bus sendet.
Nun das Problem:
Sobald der Cortex etwas auf den Bus sendet, steigt der ATXMEGA aus. Für 
ein paar Byte sendet der ATXMEGA noch seine ACK, dann aber zieht er SCL 
auf low, und reagiert nicht mehr. Der Cortex wartet dann endlos auf 
Event 8.2

 EV8 software sequence is managed before the current byte transfer 
completes */
while ((I2Cx->SR1 & 0x00004) != 0x000004)

und nichts geht mehr.
Mesungen mit dem Oszi haben folgende Details gezeigt:
Beide senden mit ca 400 kHz, aber der Cortex hat eine geringere 
Impulsbreite als der ATXMEGA.
Wenn der Cortex ein Byte verschickt, ist die Startcondition wesentlich 
kürzer als die des ATXMEGA, auch geht SDL zwischen 2 Byte beim Cortex 
nur ganz kurz auf High.

Ich sehe das so, dass der ATXMEGA mit den kürzeren clk Impulsen, der 
kurzen Startbedingung und dem kurzen zwischen High der SDL Leitung nicht 
zurechtkommt.
Wie kann ich den Cortex so konfigurieren, das er besser an den ATXMEGA 
angepasst ist? (Auf die Programmierung des ATXMEGA habe ich keinen 
Einfluss)

Hier mal meine Cortex gepollte Senderoutine. Ich habe es übrigens auch 
mit DMA und Interrupgesteuertem senden versucht, aber auch Erfolglos
1
Status I2C_Master_BufferWrite(I2C_TypeDef* I2Cx, uint8_t* pBuffer,
2
    uint32_t NumByteToWrite, I2C_ProgrammingModel Mode,
3
    uint8_t SlaveAddress)
4
5
{
6
  __IO uint32_t temp = 0;
7
  __IO uint32_t Timeout = 0;
8
if (I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY))
9
    I2C_GenerateSTOP(I2C2, ENABLE);
10
/* Enable Error IT (used in all modes: DMA, Polling and Interrupts */
11
  I2Cx->CR2 |= I2C_IT_ERR;
12
13
  Timeout = 0xFFFF;
14
    /* Send START condition */
15
    I2Cx->CR1 |= CR1_START_Set;
16
    /* Wait until SB flag is set: EV5 */
17
    while ((I2Cx->SR1 & 0x0001) != 0x0001) {
18
      if (Timeout-- == 0)
19
        return Error;
20
    }
21
22
    /* Send slave address */
23
    /* Reset the address bit0 for write*/
24
    SlaveAddress &= OAR1_ADD0_Reset;
25
    Address = SlaveAddress;
26
    /* Send the slave address */
27
    I2Cx->DR = Address;
28
    Timeout = 0xFFFF;
29
    /* Wait until ADDR is set: EV6 */
30
    while ((I2Cx->SR1 & 0x0002) != 0x0002) {
31
      if (Timeout-- == 0)
32
        return Error;
33
    }
34
35
    /* Clear ADDR flag by reading SR2 register */
36
    temp = I2Cx->SR2;
37
    /* Write the first data in DR register (EV8_1) */
38
    I2Cx->DR = *pBuffer;
39
    /* Increment */
40
    pBuffer++;
41
    /* Decrement the number of bytes to be written */
42
    NumByteToWrite--;
43
    /* While there is data to be written */
44
    while (NumByteToWrite) {
45
      /* Poll on BTF to receive data because in polling mode we can not guarantee the
46
       EV8 software sequence is managed before the current byte transfer completes */
47
      while ((I2Cx->SR1 & 0x00004) != 0x000004)
48
        ;
49
      //while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
50
      /* Send the current byte */
51
      I2Cx->DR = *pBuffer;
52
      /* Point to the next byte to be written */
53
      pBuffer++;
54
      NumByteToWrite--;
55
    }
56
    /* EV8_2: Wait until BTF is set before programming the STOP */
57
    while ((I2Cx->SR1 & 0x00004) != 0x000004)
58
      ;
59
    /* Send STOP condition */
60
    I2Cx->CR1 |= CR1_STOP_Set;
61
    /* Make sure that the STOP bit is cleared by Hardware */
62
    while ((I2Cx->CR1 & 0x200) == 0x200)
63
      ;
64
return Success;
65
66
}

von Sven Wagner (Gast)


Lesenswert?

Reduziere doch mal testweise die I2C-Geschwindigkeit auf 100 kHz.

Grüße
Sven

von Sylvia H. (sandy)


Lesenswert?

Sven Wagner schrieb:
> Reduziere doch mal testweise die I2C-Geschwindigkeit auf 100 kHz.

hab ich schon versucht, hat nichts gebracht.

Laut I2C Spezifikation hält sich der Cortex an die Mindestbreiten von 
Impulsdauer, Startbedingungsdauer und Dauer zwischen den Übertragungen. 
Es ist zwar immer hart an der Grenze, aber die Mindestbedingungen werden 
einghalten.
Daher befürchte ich, dass das Problem doch in meiner Cortex 
Programmierung liegt.....

Die Diskussion geht schon länger, sie ist unter dem Thread
"stm32 Cortex I2C : Master zieht SCL auf Masse"
zu finden.......

von Olaf (Gast)


Lesenswert?

> Es ist zwar immer hart an der Grenze, aber die Mindestbedingungen
> werden einghalten.

> Daher befürchte ich, dass das Problem doch in meiner Cortex
> Programmierung liegt.....

Das verstehe ich nicht. Wenn sich der Cortex an die Spezifikation haelt 
dann ist doch ganz offensichtlich die Gegenseite Murks. Also setze dort 
einen Controller ein der sich auch an die Spezifikation haelt.

BTW: Ich habe den Eindruck als wenn ein gelegentliches Weghaengen von 
Slaves bei I2C vollkommen normal ist. Aber natuerlich nicht andauernd!
Daher sollten die am I2C-Bus beteiligten Controller das erkennen und die 
Uebertragung neu aufsetzen. Oder besser noch, man verzichtet auf dieses 
Protokoll.

Olaf

von Willi (Gast)


Lesenswert?

Olaf schrieb:
> Oder besser noch, man verzichtet auf dieses
> Protokoll.

Das ist schon was Wahres dran :-)

Wäre es Dir möglich, die Cortex-Routinen so zu ändern, dass SCL und SDA 
per Software geschaltet werden. Damit könntest Du das Timing nach 
Belieben einstellen und sehen, WER der Böse im Spiel ist. Wenn es so 
funktionieren sollte, wäre der Slave aus dem Schneider.

von Sylvia H. (sandy)


Angehängte Dateien:

Lesenswert?

Olaf schrieb:
> Das verstehe ich nicht. Wenn sich der Cortex an die Spezifikation haelt
> dann ist doch ganz offensichtlich die Gegenseite Murks. Also setze dort
> einen Controller ein der sich auch an die Spezifikation haelt.

ja das blöde ist halt, ich habe gestern mal versucht 2 Cortexe 
miteinander sprechen zu lassen, und hatt dort das gleiche Phänomen: 
Einer alleine sendet munter auf den I2C bus, wird ein zweiter 
angeschlossen ist tot hose. Mal wird SCL gleich auf Low gezogen, mal 
bleibt SCL auf high, aber immer ist funkstille auf dem Bus, weil im 
entsprechenden Register des Cortex das Busy Flag gesetzt wird.

Willi schrieb:
> Wäre es Dir möglich, die Cortex-Routinen so zu ändern, dass SCL und SDA
> per Software geschaltet werden.

ich denke nicht, dass das geht. Normalerweise schreibt man in Register, 
wartet auf Flags, und der Rest macht die Hardware....
Aber so langsam hab ich den Eindruck, das mit meinen Libs was nicht 
stimmt.
Im Anhang mal die Libs die ich benutzt habe, vielleicht hat ja jemand 
von euch schon Erfahrung mit diesen Libs gemacht, ob da was nicht so 
richtig funktioniert.....

von Willi (Gast)


Lesenswert?

Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"

Sylvia H. schrieb:
> ich denke nicht, dass das geht. Normalerweise schreibt man in Register,
> wartet auf Flags, und der Rest macht die Hardware....

Genau das solltest Du nicht machen. Du brauchst eine stabile Referenz, 
die sich nicht auf 'fremde' Hardware stützt.
Es gab Zeiten, da hatten nur wenige µCs IIC-Module, sodass man den 
Bus-Master per Sofware impementieren mußte. Im einfachsten Fall war der 
Slave ein EEPROM.

Eine reine Software-Lösung ist beispielsweise hier zu finden:
Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"

Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare 
zuzuziehen :-)

von Sylvia H. (sandy)


Lesenswert?

Willi schrieb:
> Eine reine Software-Lösung ist beispielsweise hier zu finden:
> Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"
>
> Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare
> zuzuziehen :-)

Sieht interessant aus, wenn alle Stricke reissen werd ich mal das 
Toggeln von Hand ausprobieren....

von Uwe (Gast)


Lesenswert?

Hi!
lese das schon ne ganze Weile mit und werde das Gefühl nicht los das da
2 Master auf dem Buss rumplappern und keiner einen Rückzieher macht
(wer die meisten low's hat ist Sieger) Eins ist Fakt(meine ich 
jedenfalls) Wärend einer Unterhaltung auf dem Bus ist nur ein Master 
zugelassen. Treffen sich 2 Master muss einer aufgeben. Ist irgendwo ein 
Collisionsflag vorhanden was man auswerten sollte?
Leider bastel ich (noch) nicht mit Cortex und es ist auch nur ein 
Bauchgefühl, aber manchmal......

Viel Erfolg, Uwe

von Sylvia H. (sandy)


Lesenswert?

Uwe schrieb:
> Treffen sich 2 Master muss einer aufgeben. Ist irgendwo ein
> Collisionsflag vorhanden was man auswerten sollte?

Das war ein super Hinweis, ich habe mal in meiner (VON STM ZUR VERFÜGUNG 
GESTELLT !!!) Lib nachgeschaut, und bei der Auswertung des Arbitration 
Lost Flags einen Fehler entdeckt, dort wird das falsche Bit 
zurückgesetzt! Man kann sich echt auf nichts mehr verlassen........
Ob das die Lösung ist weis ich nicht, bin im Moment gerade zuhause und 
schreiben an meiner Bachelorarbeit. Aber am Montag schau ich sofort nach 
was die Korrektur bringt !

von Sylvia H. (sandy)


Lesenswert?

hab den Fehler behoben, hat leider nichts verändert :=(

von Peter D. (peda)


Lesenswert?

Willi schrieb:
> Eine reine Software-Lösung ist beispielsweise hier zu finden:
> Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"

Vorsicht, SW-I2C ist oft nur für dumme Slaves.
MC-Slaves benötigen noch das SCL-Stretching, da sie langsamer sind.
Läßt sich aber einfach in den SCL-Macros nachrüsten.


Willi schrieb:
> Es ist natürlich ein bißchen Tipperei, aber besser, als sich graue Haare
> zuzuziehen :-)

Am besten ausdrucken, einscannen und OCR laufen lassen.
Nur Warmduscher nehmen Ctrl+c, Ctrl+v.


Peter

von Sylvia H. (sandy)


Lesenswert?

Hi Leute,
nachdem ich tagelange Tests durchgeführt, ungefähr 1000000 mal alle
Register des Cortex kontrolliert, die I2C Spezifikation und das Cortex
Datasheet (sammt Errata) auswendig kann ;=) ....
Hier die Lösung des Problemes:
Die Von STM bereitgestellte Library für "Optimized I2C Exmples" (an2824)
weist folgende ausschlaggebende Fehler auf:

I2C2_ER_IRQHandler :
-  Es fehlte die Behandlung folgender Error-Flags:
PECERR,TIMEOUT,SMBALERT
-  ARLO: Das Flag wurde zum Zurücksetzen mit einer falschen Maske
verundet
-  BERR: obwohl im Errata steht, es müsste nur in einer „noisy
environment“ folgendes programmiert werden, hat es sich herausgestellt,
dass man dies auch in einer ganz normalen Umgebung machen muss:
(übrigens, das Errata hat hier auch einen Fehler, man bräuchte wohl auch
noch ein Errata zum Errata…..)
Wenn ein BERR auftritt, und das START Bit ist gesetzt, muss I2C resettet
werden indem man in CR1 das SWRST Bit setzt. Aber Achtung, nicht
vergessen I2C2 danach wieder zu Initialisieren! Sonst läuft I2C2 weiter,
hat aber alle Register auf den Wert 0 gesetzt!!!!
Danach noch E2C Event Interrupts einschalten, und alles ist wieder ok:
1
/* If BERR = 1 */
2
  if ((SR1Register & 0x0100) == 0x0100) {
3
4
    I2C2->SR1 &= 0xFEFF;
5
6
    if((I2C2->CR1 & 0x0100)== 0x0100){ //is START bit set? 
7
       /* Peripheral under reset */
8
      I2C2->CR1 |= CR1_SWRST_Set;   //Errata S. 25
9
      I2C_LowLevelInit(I2C2);
10
       /* Enable the selected I2C interrupts */
11
       I2C2->CR2 |= I2C_IT_EVT;
12
    }
13
14
    SR1Register = 0;
15
  }

I2C_Master_BufferWrite:
Wenn der Master etwas auf den Bus schreiben möchte und die
Startbedingung gesetzt hat, dann wartet er auf Event 5.
Sollte in dieser Wartezeit ein BERR auftreten, wartet er endlos, deshalb
muss ein Timeout gesetzt werden. Kommt er in den Timeout, muss man hier
auch wieder I2C2 reseten, neu Initialisieren und den Event Interrupt
einschalten, genauso wie oben in der BERR = 1 Routine.

Dies sind die Fehler, die ich in der Firmaware gefunden habe. Was lerne
wir daraus? Mann kann echt auf nichts mehr verlassen, noch nicht mal auf
den Hersteller.....

Des Weiteren ist ein 10 kOhm pullup Widerstand wesentlich zu hoch.

Nun läufts auf dem I2C2 Bus !

Grüße von
Sylvia

von Willi (Gast)


Lesenswert?

Sylvia H. schrieb:
> Was lerne
> wir daraus? Mann kann echt auf nichts mehr verlassen, noch nicht mal auf
> den Hersteller.....

Das war doch schon immer so :-)
Wenn scheinbar fertige Programme funktionieren und die LED lustig 
blinkt, ist es schön. Wenn nicht, die Routinen besser selber schreiben 
und Stück für Stück verstehen und testen.

Viele Demo-Programme sind so mit Kommentaren verstopft, dass man sie 
garnicht mehr nachvollziehen kann. Auch ein Programmierstil, der 
möglichst komplexe Strukturen verwendet, um zwei bis drei Bits zu 
setzen, ist für Einsteiger nicht hilfreich.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Sylvia H. schrieb:
> obwohl im Errata steht,

s/a/um/

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.