Forum: Mikrocontroller und Digitale Elektronik I2C IOExpander macht mich wahnsinnig


von Markus M. (mmax)


Angehängte Dateien:

Lesenswert?

Hallo,

Habe heute den ganzen Tag damit verbracht einem MCP23009 IOExpander via 
I2C von einem STM32F103 anzusprechen - leider geht noch immer nichts. 
Vielleicht kann hier mir jemand einen Ratschlag geben.

Grundsätzlich funktioniert die Kommunikation via I2C.

Problem 1: IOs werden nicht gesetzt.
Problem 2: IOs einlesen geht auch nicht.

Zu 1: Am Ausgang hängt eine LED. Kathode am GPIO, dann Vorwiderstand 
dann GND. Zuerst setzte ich via mcp23009_setIODirection(0x00) alle IOs 
als Ausgang. Siehe Bild scope_0.png.

Versuche ich danach via mcp23009_writeIOs(0x02) den GPIO2 zu setzen, tut 
sich nichts. Geschrieben wird auf das Register OLAT (0x0A). Siehe Bild 
scope_2.png. Im DB steht: "A write to this register modifies the output 
latches that modifies the pins configured as outputs."

Das sollte doch so passen, oder muss sonst noch etwas gemacht werden?

Zu 2: Die Reihenfolge wie man die Eingänge wieder liest, ist für mich 
nicht ganz nachvollziehbar. Im DB, ist folgende Zeichnung (Siehe Bild 
protocol.png) angegeben. In der Routine mcp23009_readIOs(), mach ich 
folgendes:
- START
- Schreibe Adresse mit Write Bit
- Schreibe 0x0A (GPIO Register)
- RESTART
- Schreibe Adresse mit Read Bit
- Lese mit ACK
- Lese mit NACK (Hier stollen die IOs stehen)
- STOP

Aber irgendwie passt da was nicht. Es werden auch immer zu viele Bytes 
zurückgeschickt, egal ob ich mit NACK quittiere. Eventuell stimmt das 
RESTART nicht oder die Reihenfolge also solches. Siehe Bild scope_3.png

Vielleicht könnte sich mal jemand den Code anschauen und da Tips geben. 
Bin für jede Hilfe dankbar.

Danke,
Max

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Markus M. schrieb:
> Kathode am GPIO, dann Vorwiderstand dann GND.

Sieht falsch aus, wenn es wirklich so ist.

von pegel (Gast)


Lesenswert?

Wie hast du ADDR beschaltet?

von Klaus (Gast)


Lesenswert?

Markus M. schrieb:
> Es werden auch immer zu viele Bytes
> zurückgeschickt, egal ob ich mit NACK quittiere

Das verstehe ich nicht. Bei I2C wird nichts geschickt. Der Master 
taktet soviele Bytes aus dem Slave, wie er will. Von alleine kommt 
nichts vom Slave. Sind zu viele Bytes auf dem Bus, liest der Master zu 
viele.

pegel schrieb:
> Wie hast du ADDR beschaltet?

Muß richtig sein, der Slave liefert ein ACK

MfG Klaus

von Markus M. (mmax)


Lesenswert?

Klaus schrieb:
> Markus M. schrieb:
>> Es werden auch immer zu viele Bytes
>> zurückgeschickt, egal ob ich mit NACK quittiere
>
> Das verstehe ich nicht. Bei I2C wird nichts geschickt. Der Master
> taktet soviele Bytes aus dem Slave, wie er will. Von alleine kommt
> nichts vom Slave. Sind zu viele Bytes auf dem Bus, liest der Master zu
> viele.

Ja, du hast recht. Von alleine kann der Slave nichts schicken - der 
Master gibt ja den Takt vor. Hier nochmal der "Netto"-Code, ohne meine 
Unterfunktionen:
1
// START
2
while( I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) );
3
I2C_GenerateSTART(I2C1, ENABLE);
4
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) );
5
6
// Address und Write Bit
7
I2C_Send7bitAddress(I2C1, 0x40, I2C_Direction_Transmitter);
8
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) );
9
10
// Transmit Byte
11
I2C_SendData(I2C1, 0x09);
12
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) );
13
14
// RESTART
15
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING) );
16
I2C_GenerateSTART(I2C1, ENABLE);
17
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) );
18
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) );
19
20
// Address und Read Bit
21
I2C_Send7bitAddress(I2C1, 0x40, I2C_Direction_Receiver);
22
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) );
23
24
// Receive with ACK
25
I2C_AcknowledgeConfig(I2C1, ENABLE);
26
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED) );
27
I2C_ReceiveData(I2C1);
28
29
// Receive with NACK
30
I2C_AcknowledgeConfig(I2C1, DISABLE);
31
while( !I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED) );
32
io_data = I2C_ReceiveData(I2C1);
33
34
// STOP
35
I2C_GenerateSTOP(I2C1, ENABLE);
36
while( I2C_GetFlagStatus(I2C1,I2C_FLAG_STOPF) );

Fällt dir da was auf?

> pegel schrieb:
>> Wie hast du ADDR beschaltet?
>
> Muß richtig sein, der Slave liefert ein ACK

Ja, die Adresse passt. Der ADDR Pin liegt auf GND.

von Markus M. (mmax)


Angehängte Dateien:

Lesenswert?

pegel schrieb:
> Sieht falsch aus, wenn es wirklich so ist.

Beschaltung sieht so aus. Müsste schon passen, oder?

Vielleicht noch einen Pull-Down auf die Interrupt-Leitung (INT) zum MC.

von Philipp K. (philipp_k59)


Lesenswert?

Der Expander hat doch Open-Drain Pins.. die Schalten nach Masse.

bedeutet normalerweise das man die Dioden an Plus legen muss und minus 
über den Expander schaltet.

falls die Dioden danach negiert sind lässt sich das mit IO-Direction 
ändern

von Horst (Gast)


Lesenswert?

Markus M. schrieb:
> Beschaltung sieht so aus.

Mal abgesehen vom i2c, warum gönnst Du der grünen LED keinen 
Vorwiderstand? Und 5Ohm für die blaue mag zwar rechnerisch passen, 
praktisch ist der aber zu klein.

von Peter D. (peda)


Lesenswert?

Markus M. schrieb:
> Beschaltung sieht so aus.

Bei 220µA Pullup sollten die LEDs nicht sonderlich hell sein.

von Markus M. (mmax)


Lesenswert?

Philipp K. schrieb:
> Der Expander hat doch Open-Drain Pins.. die Schalten nach Masse.
>
> bedeutet normalerweise das man die Dioden an Plus legen muss und minus
> über den Expander schaltet.
>
> falls die Dioden danach negiert sind lässt sich das mit IO-Direction
> ändern

Oje, ich befürchte du hast recht. Da hab ich das DB schlecht gelesen 
grrrr

Ich bin extra vom PCF8574 auf diesen umgestiegen weil ich die Versorgung 
schalten muss. Hatte das auch mit dem MCP23008 am Steckbrett getestet 
und dachte dass der MCP23009 das auch kann.

Danke für den Hinweis. Jetzt werde ich doch den 08er im kleinen QFN 
Package nehmen müssen.

Damit sollte das erste Problem schon mal behoben sein.

von Stefan F. (Gast)


Lesenswert?

2k Ohm Pull-Ups ist auffälig wenig, bist du sicher, daß dein Chip genug 
Strom liefern kann? Ich würde das mal analog mit einem Oszilloskop 
prüfen.

von Markus M. (mmax)


Lesenswert?

Stefan U. schrieb:
> 2k Ohm Pull-Ups ist auffälig wenig, bist du sicher, daß dein Chip genug
> Strom liefern kann? Ich würde das mal analog mit einem Oszilloskop
> prüfen.

Bei 2k schaut das Signal nicht so schlecht aus ... werde aber auf 4k7 
aufstocken.

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe das auch probiert.
I2C Pullups 10k. GP0 und GP1 -> Kathode LED -> R -> VCC.
Dann habe ich es auf Steckbrett mit Reset Leitung und ohne probiert.
Dabei ist mir aufgefallen das die sehr empfindlich ist.
Der Reset erfolgt schon wenn man den isolierten Draht berührt.
Habe dann ein STM32 Pin dazu verwendet.
Die LEDs leuchten mit der Übertragung wie im Bild.

von Hurra (Gast)


Lesenswert?

Markus M. schrieb:
> Stefan U. schrieb:
>> 2k Ohm Pull-Ups ist auffälig wenig, bist du sicher, daß dein Chip genug
>> Strom liefern kann? Ich würde das mal analog mit einem Oszilloskop
>> prüfen.
>
> Bei 2k schaut das Signal nicht so schlecht aus ... werde aber auf 4k7
> aufstocken.

Holla, mal langsam.

In der I2C-Spec steht, dass ein Fast-Mode Device (ein solches ist der 
genannte Portexpander!) 12mA sinken können muss, denn soviel darf an 
Pullupstrom verwendet werden.
Nach Adam Riese ist das bei 5V ein 416Ohm-Widerstand. Und das sagt mir, 
2k sind kein Problem für den Portexpander!

Nein, die 2k sind ein vernünftiger Wert für 400kHz.
Weder ist der Strom besonders hoch (es sind nur 2,5mA bei 5V), noch wird 
irgenwas warm.

Der MPC23009 stirtbt erst bei 25mA (siehe S29 Datenblatt). Da bist du um 
Faktor 10 drunter...

Literatur:
http://www.ti.com/lit/an/slva689/slva689.pdf
http://esd.cs.ucr.edu/webres/i2c20.pdf

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Bei 400kHz sieht es etwas Haiflossig aus, ist aber auch mit 10k i.O.

von GPIO (Gast)


Lesenswert?

Markus M. schrieb:
> Zu 1: Am Ausgang hängt eine LED. Kathode am GPIO, dann Vorwiderstand
> dann GND.

Da ist so ziemlich alles falsch, was bei 2 Bauteilen eben möglich ist.
Der GPIO besitzt einen Open Drain Ausgang (Datenblatt S.1), d.h. er kann 
grundsätzlich nur nach Gnd schalten. Wie soll die LED jemals Strom 
bekommen, wenn das andere Ende ebenfalls (über den Widerstand) an Gnd 
hängt.
So wie du es beschreibst, hängt die Anode über den Widerstand an Gnd. 
Mit der Anode an Gnd und der Kathode an irgendeinem positiveren 
Potential, kann die LED nicht leuchten - egal was du programmierst.

Bei zufälligem Verschaltung von LED/VCC/GND und GPIO gibt es vier 
Möglichkeiten, von denen genau eine funktionert. Du hast mit sicherem 
Griff diejenige Möglichkeit erwischt, bei der es aus zwei Gründen 
nicht funktionieren kann (LED-Polung, Typ der GPIO Ausgangsstufe).

Bevor du dich an I2C-Kommunikation mit so einem Chip wagst, solltest du 
dich erstmal mit den Grundlagen von LEDs und elementarsten digitalen 
Schaltstufen beschäftigen.

von Markus M. (mmax)


Lesenswert?

Ja, das ist schon geklärt. Ich weiß dass ich den falschen IO Expander 
erwischt habe.

Ich hatte ursprünglich den PCF8574 geplant, der hat aber auch Open Drain 
Ausgänge und kann nur gegen GND schalten. Dann bin ich auf den MC23008 
umgestiegen hatte alles getestet und am Steckbrett hat alles wunderbar 
funktioniert. Aufgrund der kleineren Bauform hab ich mich dann für den 
MC23009 entschieden und bin fälschlicherweise davon ausgegangen dass der 
die selbe Ausgangsbeschaltung wie der MC23008 hat. Mein Fehler.

Jetzt werde ich wieder auf den MC23008 im QFN Package umstiegen!

Mir ist nur noch nicht klar ob mein I2C RESET passt. Das werde ich mir 
aber anschauen wenn ich den MC23008 verbaut habe.

Liebe Grüße,
Markus

von Sebastian S. (amateur)


Lesenswert?

Ich kenne den Chip nicht, aber bei allen Bekannten wurde - so Du ihn 
denn brauchst - ein Zieh-Hoch am Interruptausgang benötigt. Meist mit 
dem gleichen Wert wie bei SCL und SDA. Ist halt OC. Eventuell kann man 
auch mit den internen (µP) Zieh-Hochs spielen.

von Hurra (Gast)


Lesenswert?

pegel schrieb:
> Bei 400kHz sieht es etwas Haiflossig aus, ist aber auch mit 10k i.O.

Klar kann das gehen. Deswegen habe ich die Appnote von TI verlinkt. Im 
Endeffekt hängt es mit der Kapazität im Bus zusammen.

Meine Erfahrung ist allerdings:
Umso niederohmiger die Pullups, umso zuverlässiger. Und die 2,5mA von 
den 2k stören nicht wirklich. Ich sehe keinen logischen Grund, diese 
nicht zu verwenden.
Sie verheizen sogar bei 5V lediglich 12,5mW, selbst ein 0402er 
SMD-Widerstand lacht darüber nur.

Und weil I2C notorisch zickig ist, ist jedes bischen Zuverlässigkeit 
hochwillkommen ;-)

von Markus M. (mmax)



Lesenswert?

So, update ... aber noch immer nicht geschafft.

Ich bin jetzt auf den MCP23008 (aus oben erwähnten Gründen) umgestiegen.

Am Steckbrett funktioniert alles soweit, nur in meiner eigenen 
Schaltung, bleibt das ACK nach dem senden der I2C Adresse aus. Anbei 
zwei Oszi Screenshots.

Erstes Bild (mit OK) zeigt die funktionierende Kommunikation. Wobei da 
der MC auch auf meinem eigenen Board sitzt, der MCP23008 am Steckbrett.

Im zweiten Bild (ERROR) sieht man das fehlende ACK. Selber MC in der 
selben Schaltung nur das der MCP auf einer zweiten Platine von mir 
sitzt.

Die PullUps auf SCL, SDA sind in beiden Fällen 10k, wobei ich auch schon 
mit 4,7K probiert hab.

Irgendwie zieht der MCP in meiner Schaltung die Datenleitung für das ACK 
nicht runter.

Hat vielleicht jemand eine Idee, was da nicht passen könnte?

von Forist (Gast)



Lesenswert?

Bildformate sind kein Hexenwerk
Mit verlustfreier komprimierung von PNG verliert man absolut nichts.

von Markus M. (mmax)


Angehängte Dateien:

Lesenswert?

Naja ... wenn man zu blöd zum routen ist, dann kann das nicht 
funktionieren.

Aber jetzt haut alles hin!

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.