Forum: Mikrocontroller und Digitale Elektronik STM32, i2c Daten verarbeiten..


von Daniel S. (sany)


Lesenswert?

Moin!

Ich arbeite derzeit an einer Kommunikation zwischen einem STM32F407 
(Master) und 6x STM32F103 (Slave) die über I2C im Interrupt / DMA 
Betrieb und einer RJ45 Verbindung kommunizieren sollen.

Der Master erkennt an den RJ45 Ports wo ein Slave angeschlossen wurde, 
da ein Pin auf 3.3V gezogen wird und somit ein Interrupt für den RJ45 
Port ausgelöst wird.

Da die Slave Platinen alle gleich sind, wird beim einstecken jedem Slave 
eine neue I2C Adresse zugewiesen, funktioniert auch prima.

Nun mache ich mir über die Kommunikation gedanken.

Der Master schickt einen Abragebefehl für die Softwareversion an den 
Slave, der Slave soll den Befehl erkennen und entsprechend mit der 
Softwareversion antworten.

Leider hängt mein Hirn etwas...

Um die Daten auf dem Slave zu empfangen nutze ich folgenden Code:
1
#define GET_VERSION 0x01
2
#define GET_VOLTAGE 0x02
3
4
uint8_t txData[6];
5
uint8_t RxData[6];
6
7
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
8
{
9
  if(TransferDirection == I2C_DIRECTION_TRANSMIT)
10
  {
11
    HAL_I2C_Slave_Seq_Receive_IT(hi2c, RxData, 6, I2C_FIRST_AND_NEXT_FRAME);
12
  }
13
  else
14
  {
15
    HAL_I2C_Slave_Seq_Transmit_IT(hi2c, txData, 6, I2C_FIRST_AND_LAST_FRAME);
16
  }
17
}
18
19
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
20
{
21
  rxCount++;
22
        process_data();
23
}
24
25
void process_data()
26
{
27
 switch(RxData[0])
28
 {
29
   case GET_VERSION:
30
     txData[0] = 0x1;
31
     txData[1] = 0x2;
32
     txData[2] = 0x3;
33
   break;
34
   case GET_VOLTAGE:
35
      txData[0] = 0x6;
36
      txData[1] = 0x7;
37
      txData[2] = 0x8;
38
      txData[3] = 0x9;
39
   break;
40
   default:
41
    break;
42
 }
43
}

So nun habe ich diverse Probleme, mit dem jetzigen Code kommt beim 
Master lediglich 6x 0x0 an.

Ich hatte auch schon die Variante,
1
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
2
{
3
  rxCount++;
4
        process_data();
5
        HAL_I2C_Slave_Seq_Transmit_IT(hi2c, txData, 6, I2C_FIRST_AND_LAST_FRAME);
6
}

Leider empfängt der Master dann null komma garnix, über den Analyzer 
sehe ich eben nur das auf den Slave geschrieben wird, aber kein Read...

Weiß jemand zufällig rat, oder stelle ich mich doof an?

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

Daniel S. schrieb:
> über den Analyzer sehe ich eben nur das
> auf den Slave geschrieben wird, aber kein Read...

Lass uns auch mal gucken, was du da siehst

: Bearbeitet durch User
von Daniel S. (sany)


Angehängte Dateien:

Lesenswert?

Ouh Sorry, hats nicht angehängt.

Bild 1:
Ist die Variante 1 mit:
Hier Empfängt der Master das vom Slave, schickt aber seltsamer weiße 
noch ein NACK mit hinterher.. ?!
1
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
2
3
{
4
5
  if(TransferDirection == I2C_DIRECTION_TRANSMIT)
6
7
  {
8
9
    HAL_I2C_Slave_Seq_Receive_IT(hi2c, RxData, 6, I2C_FIRST_AND_NEXT_FRAME);
10
11
  }
12
13
  else
14
15
  {
16
17
    HAL_I2C_Slave_Seq_Transmit_IT(hi2c, txData, 6, I2C_FIRST_AND_LAST_FRAME);
18
19
  }
20
21
}

Bild 2 ist die Variante 2:
1
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
2
3
{
4
5
  rxCount++;
6
7
        process_data();
8
9
        HAL_I2C_Slave_Seq_Transmit_IT(hi2c, txData, 6, I2C_FIRST_AND_LAST_FRAME);
10
11
}

Man sieht, der Master versucht zu lesen, erhält aber nix bei Bild 2... 
und der Mastercode bleibt stehen...

: Bearbeitet durch User
von Ali K. (teddy50)


Lesenswert?

Fürs Lesen sendet man normalerweise erstmal die Slave Adresse und danach 
ein Write auf die Registeradresse, danach ein Repeated Start, danach 
folgt direkt ein Read.

von Daniel S. (sany)


Lesenswert?

Ali K. schrieb:
> Fürs Lesen sendet man normalerweise erstmal die Slave Adresse und danach
> ein Write auf die Registeradresse, danach ein Repeated Start, danach
> folgt direkt ein Read.

Bitte?

Ich nutze die HAL-Bibliothek, warum sollte das bitte falsch sein?

Der Code für den Master:
1
uint16_t slaveADDR = 0x18<<1;
2
uint8_t TxData[6] = {0x2,0x2,0x3,0x4,0x5,0x6};
3
4
......
5
6
  /* USER CODE BEGIN WHILE */
7
  while (1)
8
  {
9
    /* USER CODE END WHILE */
10
11
    /* USER CODE BEGIN 3 */
12
13
    HAL_I2C_Master_Transmit(&hi2c2, slaveADDR, TxData, 6,1000);
14
    uint8_t rxData[6];
15
    while(HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY) {}
16
17
    HAL_I2C_Master_Receive(&hi2c2, slaveADDR, rxData, 6, 1000);
18
    HAL_Delay(1000);
19
  }
20
  /* USER CODE END 3 */

Es wird zu erst an den Slave geschrieben und dann die Daten vom Slave 
abgeholt, was soll denn bitte da nicht passen?

von Ali K. (teddy50)


Lesenswert?

Ich meine,dass es in der HAL eine Funktion, die sich WriteRead o.ä. 
nennt, gibt.
Schau mal bitte, habe es gerade nicht im Kopf.

von Daniel S. (sany)


Lesenswert?

Ali K. schrieb:
> Ich meine,dass es in der HAL eine Funktion, die sich WriteRead o.ä.
> nennt, gibt.
> Schau mal bitte, habe es gerade nicht im Kopf.

Achso, du meinst die HAL_I2C_Mem_Write / HAL_I2C_Mem_Read funktion.
Möchte aber beim Polling bleiben..

von Steve van de Grens (roehrmond)


Lesenswert?

Daniel S. schrieb:
> schickt aber seltsamer weiße noch ein NACK mit hinterher.. ?

Ein Nack wird nicht aktiv gesendet. Ein Nack kommt beim 9. Takt 
zustande, wenn der Empfänger das Byte nicht mit Ack bestätigt.

Das Nack hat den passiven High Pegel des Pull-Up Widerstandes.

: Bearbeitet durch User
von Ali K. (teddy50)


Lesenswert?

Daniel S. schrieb:
> Ali K. schrieb:
>> Ich meine,dass es in der HAL eine Funktion, die sich WriteRead o.ä.
>> nennt, gibt.
>> Schau mal bitte, habe es gerade nicht im Kopf.
>
> Achso, du meinst die HAL_I2C_Mem_Write / HAL_I2C_Mem_Read funktion.
> Möchte aber beim Polling bleiben..

Memread ist Polling.

von Harry L. (mysth)


Lesenswert?

Daniel S. schrieb:
> die über I2C im Interrupt / DMA
> Betrieb und einer RJ45 Verbindung kommunizieren sollen.

Daniel S. schrieb:
> Möchte aber beim Polling bleiben..

Passt nicht zusammen...merkste selber oder?

von Steve van de Grens (roehrmond)


Angehängte Dateien:

Lesenswert?

Mit der HAL kenne ich  ich  nicht aus, aber I²C habe ich öfters benutzt 
und debuggt.

Dein Bild von Variante 1 zeigt, dass der Master nach dem Read 0x18 
Kommando 6 Bytes liest. Danach beendet er die Übertragung mit NACK und 
STOP. Soweit alles gut.

In der zweiten Variante bestätigt der Slave das Read 0x18 Kommando 
ebenfalls ordentlich mit ACK. Doch danach hält jemand die Taktleitung 
auf LOW, gibt des Bus nicht mehr frei.  Die Spannende Frage ist, wer den 
Bus blockiert: Master oder Slave?

Trenne den Master oder den Slave vom Bus, der Pull-Up Widersdtand soll 
aber bleiben. Wenn der SCL Pegel dabei auf High wechselt, dann hat der 
abgetrennte Busteilnehmer den Bus blockiert. Ansonsten war es der 
andere.

Für eine etwas schnellere Analyse von Blockaden kann die angehängte 
Schaltung als Bus-Ersatz hilfreich sein. Wenn du magst, kannst du sie 2x 
aufbauen so dass du auch an SDA so eine Anzeige hast. Die flackernde LED 
signalisiert Aktivität auf dem Bus. Eine dauerhaft leuchtende 
signalisiert eine Blockierung. Damit kannst du das Programm Zeile für 
Zeile durch steppen und siehst sofort, ab wo der Bus hängt.

Im blockierten Zustand sagt dir der Spannungsabfall an den 47Ω 
Widerständen der SCL Leitung, welche Seite der Bösewicht ist. Auf der 
Seite wo Spannung am Widerstand abfällt ist die Blockade.

Was du auch tun kannst:

Prüfe im Debugger, wo deine Code-Ausführung hängen bleibt. Ich vermute 
in der Zeile

> while(HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY) {}

Schaue im Quelltext nach, was da genau abgefragt wird und vergleiche das 
mit der Doku im Datenblatt.

: Bearbeitet durch User
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.