STM32F103RFT6 I2C2 keine Funktion

OP #8010529
Lesenswert?

Hallo auch, ich brüte schon seit ein paar Tagen an der I2C Kommunikation (mit EEPROM, Display) an einem STM32F103RFT6. Die Pins PB10/11 führen die Signale SCL/SDA des 2. I2C Interfaces (I2C2). Pullups 3.6k sind dran. Selbst in einem minimalsten Testprogramm regt sich an den Leitungen nichts, dauerhafter Highpegel. Im Debugger sind alle notwendigen Register der RCC, GPIOB und I2C2 korrekt gesetzt. Gleiches Testprogramm für I2C1 konfiguriert, läuft ohne Probleme. Ich habe schon sämtliche Errata's und "googles" durch, nichts gefunden. Meine Hoffnung liegt nun hier. Hat jemand eine evtl Lösung?

OP #8010540
Lesenswert?

Patrick schrieb:

Laut Datenblatt liegen I2C2 SCL/SDA an Pin 29/30 für LQFP-64. Nicht, das versehentlich bei LQFP-100 geguckt wurde und 47/48 vewendet wird.

Einwand berechtigt, ist aber korrekt angeschlossen (SCL: pin 29, PB10 und SDA: pin 30, PB11) Getestet wurde auf 2 verschiedenen Boards mit dem gleichen negativen Ergebnis.

Kilo S. schrieb:

Sollen wir Hellsehen?

Zeig deinen CODE!

Der Code für die Initialisierung, Nutzung der I2C-Schnittstellen dürfte den Wissenden bekannt sein. Es wurde mit verschiedenen Tests geprüft: Bare-Metal, HAL, StdPeripherie, auch mit STMCube erzeugter Code, alles mit gleichem Ergebnis. Das Ding rührt sich nicht.

#8010542
Lesenswert?

Bernd S. schrieb:

Patrick schrieb:

Laut Datenblatt liegen I2C2 SCL/SDA an Pin 29/30 für LQFP-64. Nicht, das versehentlich bei LQFP-100 geguckt wurde und 47/48 vewendet wird.

Einwand berechtigt, ist aber korrekt angeschlossen (SCL: pin 29, PB10 und SDA: pin 30, PB11) Getestet wurde auf 2 verschiedenen Boards mit dem gleichen negativen Ergebnis.

Gut, an der Hardware liegt es nicht.

Bernd S. schrieb:

Kilo S. schrieb:

Sollen wir Hellsehen?

Zeig deinen CODE!

Der Code für die Initialisierung, Nutzung der I2C-Schnittstellen dürfte den Wissenden bekannt sein. Es wurde mit verschiedenen Tests geprüft: Bare-Metal, HAL, StdPeripherie, auch mit STMCube erzeugter Code, alles mit gleichem Ergebnis. Das Ding rührt sich nicht.

Gut, die Software ist auch ausgeschlossen.

Also muss der Bug im Silizium des Chips sitzen - denn an dir bzw. deiner Schaltung (die du geheim hältst) und deinem Code (den du ebenfalls geheim hältst) kann es schließlich nicht liegen. Beides ist schließlich garantiert fehlerfrei - es stammt ja schließlich von dir. Ergo können wir dir hier nicht weiterhelfen.

: Bearbeitet durch User
#8010548
Lesenswert?

Ah, der fehlerfreie perfekte Mensch erbarmt sich zu uns ins niedere Forum auf der Suche nach Hilfe die ja unmöglich auf einen seiner Fehler zurückzuführen sind!

Langsam aber sicher sind doch 90% der Menschheit noch zu doof einen Schuh vol pisse auszuleeren, bei dem die Anleitung dazu auf der Sohle steht!

Goodbye, TROLL!

OP #8010549
Lesenswert?

Stefan S. schrieb:

Gut, die Software ist auch ausgeschlossen.

Also muss der Bug im Silizium des Chips sitzen - denn an dir bzw. deiner Schaltung (die du geheim hältst) und deinem Code (den du ebenfalls geheim hältst) kann es schließlich nicht liegen. Beides ist schließlich garantiert fehlerfrei - es stammt ja schließlich von dir. Ergo können wir dir hier nicht weiterhelfen.

Dabei ist der Code garnicht von mir (CubeMX)

Angehängte Dateien:
Beitrag #8010552 wurde vom Autor gelöscht.
OP #8010558
Lesenswert?

Kilo S. schrieb:

Ah, der fehlerfreie perfekte Mensch erbarmt sich zu uns ins niedere Forum auf der Suche nach Hilfe die ja unmöglich auf einen seiner Fehler zurückzuführen sind!

Schwachsinn, habe ich nie behauptet. Warscheinlich ist mein Ersuchen doch nur für Leute mit entsprechendem Wissen geeignet!

hier noch ein weiterer Test , nutzt die StdPeriph lib.

Angehängte Dateien:
#8010565
Lesenswert?

1
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
2
{
3
  GPIO_InitTypeDef GPIO_InitStruct = {0};
4

5
  if(hi2c->Instance == I2C2)
6
  {
7
    /* Clocks */
8
    __HAL_RCC_GPIOB_CLK_ENABLE();
9
    __HAL_RCC_I2C2_CLK_ENABLE();
10
    __HAL_RCC_AFIO_CLK_ENABLE();
11

12
    /* I2C2 GPIO Configuration: PB10=SCL, PB11=SDA */
13
    GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
14
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
15
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
16
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
17
  }
18
}

falsch initialisiert!

F1 benutzt keine Alternate-Function Nummern (GPIO_AF4_I2C2 existiert hier nicht)

Beitrag #8010567 wurde von einem Moderator gelöscht.
OP #8010574
Lesenswert?

Kilo S. schrieb:

__HAL_RCC_AFIO_CLK_ENABLE();

ist auch richtig, kann weggelassen werden, ändert aber ebenfalls nix. Damit auch die letzten Zweifel ausgeräumt werden: Testumgebung: Visual Studio mit Extension VisualDGB (Compiler GCC) Wie schon gesagt: in der Hardware-Registeransicht sind alle Register von I2C2, GPIOB, RCC korrekt gesetzt, aber es passiert nichts. Ich kan sehen, dass beim Sendeversuch, d.h. I2C2->DR das zu sendende Datum erhält, es bleibt jedoch beim nächsten Singlestep stehen (im Gegenzug zum Test mit I2C1)

#8010580
Lesenswert?

CubeMX setzt CR2 oft nur für I2C1 korrekt.

1
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
2

3
I2C2->CR2 = 36;   // APB1 Clock in MHz

I2C2 kann mit JTAG/SWD Pins kollidieren, wenn AFIO falsch konfiguriert ist.

1
__HAL_RCC_AFIO_CLK_ENABLE();
2

3
//und ob irgendwo remapped wurde
4
AFIO->MAPR

teste mal:

1
printf("CR2=%lu\n", I2C2->CR2);
2
printf("APB1=%lu\n", HAL_RCC_GetPCLK1Freq());

Wenn du mir diese drei Werte gibst, sag ich dir sofort den Fehler:

RCC->CFGR I2C2->CR2 GPIOB->CRH

: Bearbeitet durch User
#8010606
Lesenswert?

Prüfe:

1
uint32_t busy = I2C2->SR2 & I2C_SR2_BUSY;

Wenn ≠0 → Ursache gefunden.

Typische Gründe:

Slave hält SDA

Pull-ups fehlen / zu schwach

vorheriger Reset mitten im Transfer

Debugger Stop während I2C aktiv.

Fix (offizieller ST Workaround)

1
I2C2->CR1 |= I2C_CR1_SWRST;
2
I2C2->CR1 &= ~I2C_CR1_SWRST;

Vor Init Bus freitakten:

1
// SCL manuell toggeln wenn SDA LOW
2
for(int i=0;i<9;i++)
3
{
4
   SCL_HIGH();
5
   delay();
6
   SCL_LOW();
7
   delay();
8
}

Direkt nach Init:

1
printf("SR2 = %04X\n", I2C2->SR2);

Ausgabe:

1
SR2 = 0002

BUSY Flag gesetzt, Ursache bestätigt.

Füge direkt nach Init ein:(Schnelllösung)

1
if(I2C2->SR2 & I2C_SR2_BUSY)
2
{
3
   I2C2->CR1 |= I2C_CR1_SWRST;
4
   I2C2->CR1 &= ~I2C_CR1_SWRST;
5
}

das sollte selbst mit kaputten slaves laufen:

1
void I2C2_Robust_Init(void)
2
{
3
    GPIO_InitTypeDef GPIO_InitStruct = {0};
4

5
    /* 1. Clocks aktivieren */
6
    __HAL_RCC_GPIOB_CLK_ENABLE();
7
    __HAL_RCC_I2C2_CLK_ENABLE();
8
    __HAL_RCC_AFIO_CLK_ENABLE();
9

10
    /* 2. Pins erstmal als GPIO OpenDrain (manuelle Bus Recovery) */
11
    GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
12
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
13
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
14
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
15

16
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10|GPIO_PIN_11, GPIO_PIN_SET);
17
    HAL_Delay(1);
18

19
    /* 3. Bus freitakten falls Slave hängt */
20
    if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)) // SDA LOW?
21
    {
22
        for(int i=0;i<9;i++)
23
        {
24
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
25
            HAL_Delay(1);
26
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
27
            HAL_Delay(1);
28
        }
29
    }
30

31
    /* STOP Condition erzwingen */
32
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
33
    HAL_Delay(1);
34
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
35
    HAL_Delay(1);
36
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
37
    HAL_Delay(1);
38

39
    /* 4. I2C Hardware Reset */
40
    I2C2->CR1 |= I2C_CR1_SWRST;
41
    HAL_Delay(1);
42
    I2C2->CR1 &= ~I2C_CR1_SWRST;
43

44
    /* 5. Pins auf I2C Alternate Function */
45
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
46
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
47

48
    /* 6. Peripheral Disable */
49
    I2C2->CR1 &= ~I2C_CR1_PE;
50

51
    /* 7. Timing konfigurieren */
52
    I2C2->CR2 = 36;        // APB1 MHz
53
    I2C2->CCR = 180;       // 100kHz @36MHz
54
    I2C2->TRISE = 37;      // laut Datenblatt
55

56
    /* 8. Peripheral Enable */
57
    I2C2->CR1 |= I2C_CR1_PE;
58

59
    /* 9. Dummy Read SR2 → Flags reset */
60
    (void)I2C2->SR2;
61

62
    /* 10. BUSY prüfen */
63
    if(I2C2->SR2 & I2C_SR2_BUSY)
64
    {
65
        /* letzter Rettungsversuch */
66
        I2C2->CR1 &= ~I2C_CR1_PE;
67
        HAL_Delay(1);
68
        I2C2->CR1 |= I2C_CR1_PE;
69
    }
70
}
OP #8011459
Lesenswert?

Bernd S. schrieb:

Kilo S. schrieb:

Prüfe:

soweit geprüft! anbei Auszug aus dem Quellcode. Seltsam ist, dass die eingebaute Scannerfunktion tatsächlich die beiden angeschlossenen Slaves auch mit den richtigen Adressen findet. Das Testprogramm eetest() läuft einmal durch und bleibt dann beim nächsten Durchlauf in der single_write(0x20, 0x15) hängen, wartet auf ein gesetztes TXE Bit, was nicht kommt.

Wie zu sehen, die I2C-Funktionen sind in einer Klasse enthalten.

Angehängte Dateien:
#8011661
Lesenswert?

Der F1 ist da pingelig.

1
void CI2C::single_write(uint8_t addr, uint8_t data)
2
{
3
    m_pI2C->CR1 |= CR1_START_Set;
4
    while (!(m_pI2C->SR1 & I2C_SR1_SB));
5

6
    I2C_Send7bitAddress(m_pI2C, m_slaveadress, I2C_Direction_Transmitter);
7

8
    while (!(m_pI2C->SR1 & I2C_SR1_ADDR));
9

10
    volatile uint32_t tmp;
11
    tmp = m_pI2C->SR1;
12
    tmp = m_pI2C->SR2;
13
    (void)tmp;
14

15
    while (!(m_pI2C->SR1 & I2C_SR1_TXE));
16

17
    m_pI2C->DR = addr;
18
    while (!(m_pI2C->SR1 & I2C_SR1_BTF));
19

20
    m_pI2C->DR = data;
21
    while (!(m_pI2C->SR1 & I2C_SR1_BTF));
22

23
    m_pI2C->CR1 |= CR1_STOP_Set;
24
}

Hier:

1
while (!(m_pI2C->SR1) | !(m_pI2C->SR2)) {}

Problem:

| statt ||

prüft das ganze Register statt Flags

ADDR wird nie gelöscht

Der Scanner funktioniert nur zufällig.

Dritter versteckter Bug

In readByte():

1
m_pI2C->DR = (address << 1) + 0x00;

Das ist Write-Adresse, nicht Read.

Read müsste sein:

1
(address << 1) | 1

So weit so gut...

OP #8012095
Lesenswert?

Kilo S. schrieb:

versuchs mal hiermit...

Hier mal die Resultate aus deinem Beispiel: Er spricht wieder!!! da ich auf dem Testboard ein EEPROM habe, dass eine 16bit Adresse verlangt, (FM64LC64) habe ich die read/write funktionen noch entsprechend ergänzt und siehe da, was man reinschreibt, kommt auch wieder raus. Jetzt muss ich nur noch ergründen, warum mein Code rum zickt Schon mal Danke Kilo S.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren