Forum: Mikrocontroller und Digitale Elektronik STM32F107 Probleme mit I2C SCL


von Flo (Gast)


Lesenswert?

Grüß euch,

folgende Situation. Ein bestehender "Master" Mikrocontroller der Reihe 
AtXmega soll ersetzt werden durch einen STM32F107 (hauptsächlich 
aufgrund von Ethernet). Die "Slaves" bleiben aber (ebenfalls Controller 
der AtXmega Reihe) und es können auch keine Anpassungen an der Firmware 
durchgeführt werden.

Die Kommunikation läuft eigentlich. Aber nicht immer. Das Problem ist, 
dass die SCL Leitung von einem Gerät runter gezogen wird und nicht mehr 
freigegeben wird. Im aktuellen Test habe ich einen Master und zwei 
Slaves.  Nach bisheriger Recherche scheint der Master das Problem zu 
sein, denn starte ich nur die Slaves neu, bleibt SCL low. Starte ich den 
Master hingegen neu, geht SCL wieder hoch.

Ein Reintialisieren der I2C Peripherie im STM32 bringt nix, da bleibt 
SCL low. Das gibt für mich eigentlich keinen Sinn, da es nach einem 
Neustart ja wieder geht?

Wirklich debuggen und mitloggen wann genau der Fehler auftritt kann ich 
nicht, da er eher willkürlich passiert. Manchmal tritt er erst nach 
Stunden auf, manchmal bereits nach einer Minute. Zum teste setze ich 
permanent Werte auf dem Slave.

Beim STM32 habe ich den Error Interrupt für I2C aktiviert, jedoch tritt 
keiner auf. Auch die ganzen I2C Register weisen keine Auffälligkeit auf. 
Im I2C_SR1 Register sind die Bits BTF (Byte Transfer Finished) und TxE 
(Data Register Empty) gesetzt und im I2C_SR2 Register sind die Bits MSL 
(Master mode), BUSY (da SCL low) und TRA (Data Bytes Transmitted) 
gesetzt.

Die Kommunikation läuft mit 400 kHz und ich nutze auf dem STM32 HAL.

Jemand eine Idee was ich noch probieren könnte?

von Lona (Gast)


Lesenswert?

Es fehlt Schaltplan, Sourcecode und Fotos vom Aufbau!

von Joe F. (easylife)


Lesenswert?

Nutzen deine I2C Slaves Clock-Streching?
Ich habe irgendwo mal gelesen, dass der STM32 Probleme mit 
Clock-Stretching hat (bei Timeout)...

von Flo (Gast)


Lesenswert?

Lona schrieb:
> Schaltplan

Beim Schaltplan gibt es nicht viel zu sehen, was hier relevant wäre.
An jedem SCL und SDA Pin befindet sich ein 100 Ohm Widerstand in Reihe. 
Und dann gibts noch einen Pull Up bei SCL und SDA mit jeweils 4k7 Ohm.

Lona schrieb:
> Sourcecode

Wie schon erwähnt, nutze ich die HAL von STM.
1
/* transmit the command */
2
if(HAL_I2C_Master_Transmit(&hi2c1, (slv_nr<<1) & ~0x01, i2c_tx_buffer, tx_len, 100) != HAL_OK)
3
{
4
    response_error("Invalid Slave Number or Bus Error.");
5
}
6
7
/* receive the command */
8
if(HAL_I2C_Master_Receive(&hi2c1, (slv_nr<<1) & ~0x01, i2c_rx_buffer, rx_len, 100) != HAL_OK)
9
{
10
    response_error("Receiving failed.")
11
}

response_error() ist ein Macro, des gleichzeitig ein return enthält.


Und die Initialisierung von I2C:
1
/* I2C1 init function */
2
void MX_I2C1_Init(void)
3
{
4
5
  hi2c1.Instance = I2C1;
6
  hi2c1.Init.ClockSpeed = 400000;
7
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
8
  hi2c1.Init.OwnAddress1 = 0;
9
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
10
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
11
  hi2c1.Init.OwnAddress2 = 0;
12
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
13
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
14
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
15
  {
16
    _Error_Handler(__FILE__, __LINE__);
17
  }
18
19
}
20
21
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
22
{
23
24
  GPIO_InitTypeDef GPIO_InitStruct;
25
  if(i2cHandle->Instance==I2C1)
26
  {
27
  /* USER CODE BEGIN I2C1_MspInit 0 */
28
29
  /* USER CODE END I2C1_MspInit 0 */
30
  
31
    /**I2C1 GPIO Configuration    
32
    PB6     ------> I2C1_SCL
33
    PB7     ------> I2C1_SDA 
34
    */
35
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
36
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
37
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
38
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
39
40
    /* I2C1 clock enable */
41
    __HAL_RCC_I2C1_CLK_ENABLE();
42
43
    /* I2C1 interrupt Init */
44
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
45
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
46
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);
47
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
48
  /* USER CODE BEGIN I2C1_MspInit 1 */
49
50
  /* USER CODE END I2C1_MspInit 1 */
51
  }
52
}


Selbstverständlich ist das nicht der vollständige Quellcode. Den kann 
ich hier aber auch nicht posten da es mehrer tausend Zeilen Code 
verteilt über dutzende Dateien sind. Aber das ist der relevante I2C 
Teil.

von Flo (Gast)


Lesenswert?

Joe F. schrieb:
> Nutzen deine I2C Slaves Clock-Streching?

Ja tut er. Da such ich gleich mal ob ich was zu dem Thema finde.

von Joe F. (easylife)


Lesenswert?

Flo schrieb:
> Und dann gibts noch einen Pull Up bei SCL und SDA mit jeweils 4k7 Ohm.

Für 400 KHz werden 2.2K empfohlen (bei 3.3V).

Und du kannst ja mal ein Clock-Stretching Timeout provozieren, indem du 
mit einem Draht SCL eine Weile auf GND ziehst. Wenn dann nach dem 
Loslassen das Problem da ist, wird's wohl damit zusammenhängen.

: Bearbeitet durch User
von Lona (Gast)


Lesenswert?

Flo schrieb:
> Lona schrieb:
>> Schaltplan
>
> Beim Schaltplan gibt es nicht viel zu sehen, was hier relevant wäre.
> An jedem SCL und SDA Pin befindet sich ein 100 Ohm Widerstand in Reihe.
> Und dann gibts noch einen Pull Up bei SCL und SDA mit jeweils 4k7 Ohm.
>

Dann funktioniert das Ganze! Ausser du hast doch nicht die korrekte 
Hardware. Schaltplan und Foto bitte!


> Selbstverständlich ist das nicht der vollständige Quellcode. Den kann
> ich hier aber auch nicht posten da es mehrer tausend Zeilen Code
> verteilt über dutzende Dateien sind. Aber das ist der relevante I2C
> Teil.

Doch das geht! Du kannst die Dateien direkt anhängen!

von Ingo Less (Gast)


Lesenswert?

Schau mal in die Errata, beim F4 war da irgendwas nicht in Ordnung. Prüf 
das sicherheitshalber mal

von Flo (Gast)


Lesenswert?

Joe F. schrieb:
> Und du kannst ja mal ein Clock-Stretching Timeout provozieren, indem du
> mit einem Draht SCL eine Weile auf GND ziehst. Wenn dann nach dem
> Loslassen das Problem da ist, wird's wohl damit zusammenhängen.

Zu welche Zeitpunkt soll ich das am besten machen?

Ingo Less schrieb:
> Schau mal in die Errata, beim F4 war da irgendwas nicht in Ordnung. Prüf
> das sicherheitshalber mal

Ich habe einen F1. Aber ja, ins Errata habe ich schon geschaut und da 
gibts einige Probleme beim F1. Aber keiner der Fehler trifft auf meine 
Situation zu.

von Joe F. (easylife)


Lesenswert?

Flo schrieb:
> Joe F. schrieb:
>> Und du kannst ja mal ein Clock-Stretching Timeout provozieren, indem du
>> mit einem Draht SCL eine Weile auf GND ziehst. Wenn dann nach dem
>> Loslassen das Problem da ist, wird's wohl damit zusammenhängen.
>
> Zu welche Zeitpunkt soll ich das am besten machen?

Der Zeitpunkt sollte eigentlich keine Rolle spielen. Du strechest die 
Clock dadurch einfach künstlich per Hand. Es muss während dessen 
natürlich ständig Traffic auf dem Bus sein.

Den 100R in Reihe finde ich auch nicht so dolle, der LOW Pegel wird 
damit schon recht hoch.
Ich würde es mal mit 2.2K Pullups und max. 33R in Reihe (oder 0R) 
probieren.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Falls du ein Softwareproblem vermutest, probiere mal den Beispielcode 
von dieser Seite: http://stefanfrings.de/stm32/stm32f1.html#i2c

Ich habe ihn bisher nur auf einem STM32F103 ausprobiert, sollte aber 
auch bei Dir gehen. Zumindest compiliert er fehlerfrei.

von Flo (Gast)


Lesenswert?

Joe F. schrieb:
> Der Zeitpunkt sollte eigentlich keine Rolle spielen. Du strechest die
> Clock dadurch einfach künstlich per Hand. Es muss während dessen
> natürlich ständig Traffic auf dem Bus sein.

Habe ich jetzt mal probiert. Da scheint es ein Problem zu geben. Denn 
manchmal stört das ganze gar nicht, die Kommunikation geht nach einer 
kurzen Unterbrechung weiter. Aber manchmal setzt er wieder das BUSY Flag 
und eine weitere Kommunikation ist nicht möglich (obwohl beide Leitungen 
wieder High sind). Jedoch hilft hier eine Neuintialisierung der I2C 
Schnittstelle.

Joe F. schrieb:
> Ich würde es mal mit 2.2K Pullups und max. 33R in Reihe (oder 0R)
> probieren.

Hab die Pullups mal getauscht, ebenso auf denn 33R in Reihe gewechselt. 
Aber die Fehler treten dennoch auf.

Mittlerweile kann ich allerdings den Fehler reproduzieren. Und zwar 
tritt der Fehler nach 3-4 erfolgreich übertragenen Nachrichten auf. Also 
Master will etwas vom Slave lesen, das klappt 3-4 mal ohne Probleme. 
Dann gehts nicht mehr. Allerdings nur in dem Fall, wenn der Slave frisch 
bestromt wurde. Daher konnte ich jetzt auch das ganze mittels 
Logicanalyzer festhalten. Der Slave braucht über 10 ms nach jedem Byte, 
bevor er ein ACK schickt. Nach dem letzten Byte der Nachricht vom Master 
kommt auch noch ein ACK, aber SCL bleibt danach Low und der Slave 
verschickt nichts mehr.
Das spricht jetzt erstmal für einen Fehler vom Slave. Jetzt kommt jedoch 
das aber. Starte ich den Master neu, und am Slave wird nichts gemacht, 
funktioniert die Kommunikation anschließend ohne Probleme. Ein einfaches 
neu initialisieren der I2C Peripherie reicht nicht...

Stefan F. schrieb:
> Falls du ein Softwareproblem vermutest, probiere mal den Beispielcode
> von dieser Seite:

Ich weiß grad ehrlich gesagt nicht ob es SW oder HW ist. Werde es aber 
mal im Hinterkopf behalten.

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.