Forum: Mikrocontroller und Digitale Elektronik STM32, PCA8575 I2C Kommunikationsproblem


von Frank A. (_frank)


Lesenswert?

Guten morgen,

ich versuche z.Z. mit einem STM32f103 den IO expander PCA8575 zu 
betrieben.
Ich bekomme jedoch keine Daten geschrieben oder gelesen.
1
void i2c2_init()
2
{
3
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
4
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
5
6
  GPIO_InitTypeDef GPIO_InitStructure;
7
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
8
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
10
11
  GPIO_Init(GPIOB, &GPIO_InitStructure);
12
13
  I2C_DeInit(I2C2);
14
15
  I2C_InitTypeDef I2C_InitStructure;
16
  I2C_InitStructure.I2C_Mode          = I2C_Mode_I2C;
17
  I2C_InitStructure.I2C_DutyCycle     = I2C_DutyCycle_2;
18
  I2C_InitStructure.I2C_OwnAddress1   = 0;
19
  I2C_InitStructure.I2C_Ack           = I2C_Ack_Disable;
20
  I2C_InitStructure.I2C_AcknowledgedAddress  = I2C_AcknowledgedAddress_7bit;
21
  I2C_InitStructure.I2C_ClockSpeed       = 200;
22
23
  I2C_Init(I2C2,&I2C_InitStructure);
24
  I2C_Cmd(I2C2, ENABLE);
25
}
26
27
28
void PCA8575_setze_Ausgang(int16_t Ausgangsdaten, uint8_t Adresse)
29
{
30
  uint8_t first_data_byte    = (uint8_t)(Ausgangsdaten >> 8);
31
  uint8_t second_data_byte  = (uint8_t)Ausgangsdaten;
32
  uint8_t slave_adress    = (0x4 << 4) | (Adresse << 1) | (0);
33
34
35
  //warte auf I2C
36
  while(I2C_GetFlagStatus(I2C2,I2C_FLAG_BUSY));
37
  //Start
38
  I2C_GenerateSTART(I2C2, ENABLE);
39
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
40
  //Adresse
41
  I2C_Send7bitAddress(I2C2, slave_adress, I2C_Direction_Transmitter);
42
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 lesen und löschen
43
44
  //Daten senden
45
  I2C_SendData(I2C2, first_data_byte);
46
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
47
48
  //Daten senden
49
  I2C_SendData(I2C2, second_data_byte);
50
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
51
52
  I2C_AcknowledgeConfig(I2C2, ENABLE);
53
  I2C_GenerateSTOP(I2C2,ENABLE);
54
}
55
56
void PCA8575_lese_Eingang(uint8_t Adresse)
57
{
58
  uint8_t slave_adress    = (0x4 << 4) | (Adresse << 1) | (1);
59
  uint8_t Buffer_RX[4]    = {0};
60
61
  //warte auf I2C
62
  while(I2C_GetFlagStatus(I2C2,I2C_FLAG_BUSY));
63
  //Start
64
  I2C_GenerateSTART(I2C2, ENABLE);
65
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
66
  //Adresse
67
  I2C_Send7bitAddress(I2C2, slave_adress, I2C_Direction_Receiver);
68
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //EV6 lesen und löschen
69
70
  //Daten empfangen
71
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_SLAVE_BYTE_RECEIVED));
72
  Buffer_RX[0]=I2C_ReceiveData(I2C2);//daten 1
73
  I2C_AcknowledgeConfig(I2C2, ENABLE);
74
75
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_SLAVE_BYTE_RECEIVED));
76
  Buffer_RX[1]=I2C_ReceiveData(I2C2);//daten 2
77
78
  I2C_AcknowledgeConfig(I2C2, ENABLE);
79
  I2C_GenerateSTOP(I2C2,ENABLE);
80
81
}
Mir ist aufgefallen, dass die SDA Leitung auf Low ist. Ich habe gelesen, 
dass man hier 8 Takte per Hand auf die SCL Leitung gegeben soll. Jedoch 
bringt das nix.

Kann mir jemand helfen?

Danke und Gruß

von Frank A. (_frank)


Lesenswert?

Hallo

Hier nochmal der Link zum Datenblatt:
http://www.nxp.com/documents/data_sheet/PCA8575.pdf

Vielleicht kann mir ja einer sagen wie man das Diagramm auf Seite 8 
interpretieren soll?
Laut der Zeichnung braucht man am Ende keine Stop-Condition senden?

Das Diagramm zum Lesen ist mir noch unklarer. Was bedeutet denn "data 
from port 0" und "data into port 0"?


Vielen Dank und Gruß

von Bernhard S. (b_spitzer)


Lesenswert?

Der I2C-Bus braucht immer die STOP-Bedingung, wenn eine Übertragung 
beendet wurde. Das erste Timing-Diagramm ist für Kontinuierliche 
Ausgabe, da könnte man ohne erneute Adressübertragung beliebig lange 
Daten rausschreiben.
Beim Timing-Diagramm zum Lesen ist halt mit angegeben, wann sich die 
externen Daten am Baustein ändern dürfen und zu welchen Zeitpunkten die 
Daten gesampled werden.
Die Adressberechnung in den Funktionen ist nur dann Sinnvoll, wenn Du 
mehrere Bausteine auf einem Bus betreiben willst. Mit nur einem Baustein 
würde ich da Konstanten setzen, das ist etwas klarer. Wie werden die 
Funktionen in der Applikation aufgerufen - besonders die übergebene 
Adresse? Passt die zur Beschaltung der Hardware?
Deine Lesefunktion schreibt in den Buffer[], der als lokale Variable 
deklariert ist. Da wirst Du wohl von außen kaum drankommen...

von Frank A. (_frank)


Angehängte Dateien:

Lesenswert?

Vielen Dank für deine Antwort.

Das mit dem Stop habe ich mir fast gedacht. Sende ich ja auch.

Das mit dem Timing Diagramm macht Sinn.

Die Adressberechnung ist tatsächlich drin weil ich zwei Bausteine habe. 
16 Ausgänge und 16 Eingänge. Der dritte IC ist z.Z. nicht angeschlossen.

Der Aufruf erfolgt wie folgt im main:
1
uint16_t daten_out = 0xffaa;
2
PCA8575_setze_Ausgang(daten_out, 0);
3
4
PCA8575_lese_Eingang(1);

Die Lese-Funktion hat keinen Rückgabewert, das ist korrekt. Ich halte 
z.Z. immer nach der Stop-Bedingung mit dem Debugger an und gucke mir die 
Werte an.
Ich komme aber gar nicht bis zum Ende, da das Programm ja wie erwähnt 
schon vorher stehen bleibt.

Den Hardwareaufbau habe angehängt.

Gruß Frank

von Bernhard S. (b_spitzer)


Lesenswert?

Mein Pin- und Adresskompatibler PCA9555 funktioniert problemlos. Der hat 
als Unterschied noch Port-Direction-Register, die in init gesetzt 
werden.
Ich betreibe da ein LDC und ein Tastenkreuz dran.

Dass SDA auf 0 liegt ist nicht korrekt. Da musst Du mal die Hardware auf 
Kurzschlüsse oder Dein Programm auf ungereimtheiten Checken (als 
"Energiesparer" schaltet man gerne mal komplette Ports auf 0 und 
deaktiviert eventuell Zweitfunktionen damit...)
An welcher Stelle bleibt das Programm hängen? Was siehst Du in den 
Statusregistern des I2C-Controllers?

von Frank A. (_frank)


Lesenswert?

Hallo Bernhard,

vielen Dank für deine Antwort.
Ich habe nochmal die Hardware überprüft, konnte aber keine Fehler oder 
Kurzschlüsse feststellen.

Das Problem ist weiterhin, dass die SDA Leitung auf Null ist. Das wird 
auch durch das Busy Bit im SR2 Register angezeigt.

Dadurch bleibt das Programm natürlich schon an der ersten Zeile
1
while(I2C_GetFlagStatus(I2C2,I2C_FLAG_BUSY));
hängen. Auch auskommentieren bringt ja nix, dann bleibt er bei der 
nächsten while-Schleife hängen.

Die weiteren Register habe ich überprüft, ich konnte aber keine 
Besonderheiten feststellen.

Ich verstehe nicht wieso die Leitung auf low ist obwohl ich noch keine 
Kommunikation begonnen habe. Ach das Takten "per Hand" hat wie oben 
schon beschrieben nicht funktioniert.

Hast du vielleicht noch eine Idee?

von Bernhard S. (b_spitzer)


Lesenswert?

Wie sind denn die Pins konfiguriert? (Welches Gehäuse)

Ansonsten hat hier scheinbar jemand ein ähnliches Problem:
Beitrag "TPA81 an STM32F103 I2C Problem"

von Frank A. (_frank)


Angehängte Dateien:

Lesenswert?

Hallo Bernhard,

ich habe nochmal ein wenig probiert und bin einen Schritt weiter 
gekommen.
Das Problem, dass der Bus schon zu Beginn Busy ist, ist behoben.
Jetzt bleibt das Programm an folgender Stelle hängen:
1
  //warte auf I2C
2
  while(I2C_GetFlagStatus(I2C2,I2C_FLAG_BUSY));
3
  //Start
4
  I2C_GenerateSTART(I2C2, ENABLE);
5
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
Er sollte eigentlich die Start-Bedingung senden, bleibt aber in der 
letzten while Schleife hängen. Im Anhang einmal der Verlauf auf dem 
Ossi.

Ich prüfe jetzt nochmal genau die Flags, vielleicht habe ich da etwas 
übersehen.

Hat vielleicht noch jemand eine Idee?


Danke und Gruß Frank

von Frank A. (_frank)


Lesenswert?

Hab die Register überprüft.
Die zwei entscheidenden Bits, die auch in der letzten while Schleife 
abgefragt werden, sind im Status Register 2:
- Bit 1 Busy
- Bit 0 MSL

Auf diese beiden Bits wird abgefragt, sie sind jedoch nicht gesetzt.
Stellt sich die Frage warum nicht.

Laut Referenz Manual sollen beide Bits per Hardware gesetzt werden.

von Rolf (Gast)


Lesenswert?

Hallo Frank,

ich bin auf der Suche nach der Lösung des Problems, dass das MSL Bit 
beim Setzen einer Start-Bedingung nicht gesetzt wird, auf deinen Thread 
gestoßen.
Ich konnte leider von selbst keine Lösung dafür finden, bin aber auf den 
Thread von Sylvia H. (sandy) gestoßen.

Beitrag "stm32 Cortex I2C : Master zieht SCL auf Masse"

Mit den weiter unten angehängten Headerfiles und kleinen Anpassungen 
funktioniert die I2C2 Schnittstelle in meinem Projekt.
Vielleicht helfen dir die Datein ebenfalls.
Falls du schon eine andere Lösung gefunden hast, wäre ich durchaus auch 
an deinem Ansatz interessiert.

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.