PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Probleme mit I2C-Kommunikation mit Interrupt



__lissy__
26.06.2013, 06:47
Hallo zusammen =)

Ich habe bereits eine I2C-Kommunikation mit Polling programmiert, die auch funktioniert. Nun wollte ich das Ganze Interrupt gesteuert machen. Auch hier soll mein Controller (AT MEGA 164 PA) als Master arbeiten. Auf der Leiterplatte befindet sich ebenfallsnoch ein Temperatursensor (Auf Port B Pin 0). Dieser soll der Slave sein, wie auch schon beim Polling-Beispiel.
Der Master sendet also die Start-Condition, daraufhin wird TWINT gesetzt und das Programm springt in die ISR. Dort wird dann die Slave-Adresse mit Schreib- oder Lesebefehl (Adresse = 0x48 mit angehängter 0 oder 1) gesendet um den Slave auszuwählen. Danach springt das Programm auch wieder brav in die ISR, leider aber mit Status-Code 0x20, also einem NACK für die Adresse. Dies habe ich auch mit einem Oszi nachgemessen.

Doch woran liegt das, was mache ich falsch? Im Prinzip ist es das Gleiche wie beim Polling, mit dem Unterschied dass nicht gewartet wird bis TWINT gesetzt wird while (!(TWCR & (1<<TWINT))) sondern dies einen Interrupt auslöst.
25852

schon mal vielen Dank im Voraus

MagicWSmoke
26.06.2013, 10:12
Auch hier soll mein Controller (AT MEGA 164 PA) als Master arbeiten. Auf der Leiterplatte befindet sich ebenfallsnoch ein Temperatursensor (Auf Port B Pin 0). Dieser soll der Slave sein, wie auch schon beim Polling-Beispiel.
SCL befindet sich beim ATM164 auf PortC PC0, SDA auf PC1, auf PortB geht's höchstens mit Soft-I2C. Im Code ist zwar der PortC/DDRC richtig angegeben, kommt halt darauf an, wo der Sensor hängt, falls auf PortB, dann stellt die dazwischenliegende Luft ein zu großes Hindernis dar :D
Das hier macht wenig bis keinen Sinn:

TWI_DDR |= (1 << SDA);
TWI_DDR |= (1 << SCL);
Denn das Einschalten der I2C-Einheit "überfährt" bereits die normale Pinfunktion. Du könntest höchstens die Port-Bits setzen, dann werden die internen Pullups eingeschaltet.
Sind denn externe Pullups dran?
Außerdem ist der Fehlerfall ungünstig im Code gelöst, da I2C in einem solchen Fall nicht abgeschaltet wird und der Interrupt damit weiter auslöst.

__lissy__
26.06.2013, 10:53
Schon mal danke für deine Antwort =)

Also ich hab jetzt mal die code-zeilen TWI_DDR |= (1 << SDA) und TWI_DDR |= (1 << SCL) auskommentiert.

SCL und SDA ist auf PC0 bzw. PC1, der Temperatur-Sensor (TMP112AI) ist direkt daran angeschlossen, also SCL ist verbunden mit Pin 1, SDA ist verbunden mit Pin 6. Pin 4 des Temperatursensors ist auf GND, daher auch die Adresse des Slaves. Allerdings benötigt der Sensor noch eine Stromversorgung, diese ist auf PB0, daher muss ich diese auf low setzen um den Sensor zu versorgen.

Dies müsste auch richtig sein, da es bei der Polling-Variante klappt. Dass der Sensor versort ist habe ich auch nachgemessen.

Externe Pull-Ups sind vorhanden.

Ja, bei dem Fehlerfall, da hab ich noch so gar keine Ahnung was ich da machen soll, evtl beenden oder so?

MagicWSmoke
26.06.2013, 15:43
Also ich hab jetzt mal die code-zeilen TWI_DDR |= (1 << SDA) und TWI_DDR |= (1 << SCL) auskommentiert.
Die hatten im gezeigten Code einfach keinen Effekt, können aber u.U. schädlich sein, sobald die I2C-Unit abgeschalten wird, übernimmt wieder die normale Funktion den Pin und kann je nach Zustand von PORTx auf Low oder High treiben, während man auf dem I2C-Bus nicht aktiv auf High treibt.

Allerdings benötigt der Sensor noch eine Stromversorgung, diese ist auf PB0, daher muss ich diese auf low setzen um den Sensor zu versorgen.
Sehr eigenwillig, den Versorgungs-GND wegzuschalten, aus welchem Grund wird nicht VCC geschalten?

Ja, bei dem Fehlerfall, da hab ich noch so gar keine Ahnung was ich da machen soll, evtl beenden oder so?
Man schaltet den Interrupt ab, Seite 13:
AVR315: Using the TWI module as I2C master (http://www.atmel.com/Images/doc2564.pdf)
Warum ist das Thema auf [Erledigt]? Sieht mir nicht sehr erledigt aus.

__lissy__
27.06.2013, 06:33
Das Thema ist auf [Erledigt], da es mein Ziel war die Kommunikation als Master Interrupt-gesteuert zu programmieren. Dies funktioniert nun, im Anhang habe ich mal meinen jetzigen Code, er ist alles andere als perfekt, aber es war auch nur eine Übung. Falls Bedarf besteht, kann ich das Thema auch wieder auf nicht erledigt stellen.

25878

MagicWSmoke
27.06.2013, 08:09
Dies funktioniert nun, im Anhang habe ich mal meinen jetzigen Code, er ist alles andere als perfekt, aber es war auch nur eine Übung. Falls Bedarf besteht, kann ich das Thema auch wieder auf nicht erledigt stellen.
Zum Zeitpunkt ich das "Erledigt" nachfragte, war nicht erkennbar dass es funktioniert, das war also höchstens für Dich erledigt.
Nun kann ein Forum nicht von abgeschlossenen Beiträgen profitieren, deren Ergebnis nicht bekannt ist.
Betrachte es so, dass die Nennung des Fehlers/Problems sozusagen die "Rückzahlung" an's Forum und dessen Teilnehmer ist, welche geholfen haben.
Oft geschieht das aber nicht, d.h. Du liest Dir einen Thread durch und irgendwann ist Schluss, der TE meint "geht jetzt" und behält sein Geheimwissen für sich.
Das hast Du ja durch Anhängen Deines Codes nicht so gemacht, jetzt könntest Du noch sagen, wo der Fehler lag, dann hat jeder Nachleser, ohne groß die Codes zu vergleichen, einen direkten Erkenntnisgewinn.

__lissy__
27.06.2013, 08:16
Da ich recht viele Sachen ausprobiert habe, bin ich mir nich 100% sicher ob es daran liegt, aber ich vermute, dass es an dem sleep-Befehl liegt. Nach der Initialisierung wird 1 sec gewartet, erst dann beginnt die Kommunikation. Dies muss wohl so sein, da der Temperatursensor (Slave) Zeit benötigt.
Wie gesagt, das ist nur meine Vermutung, da das Programm nicht mehr funktioniert, wenn ich diesen Befehl auskommentiere. Allerdings habe ich davor ja auch schon I2C mit Polling programmiert, welches ja auch funktioniert hat. Bei diesem Programm war allerdings kein warten nötig, obwohl die gleichen Bausteine verwendet wurden.
Ansonsten entspricht das Programm soweit dem Code zu Beginn des Problems, bis auf die Änderungsvorschläge des Forums.

MagicWSmoke
27.06.2013, 08:29
aber ich vermute, dass es an dem sleep-Befehl liegt. Nach der Initialisierung wird 1 sec gewartet, erst dann beginnt die Kommunikation. Dies muss wohl so sein, da der Temperatursensor (Slave) Zeit benötigt.
Du hast bemerkt, dass der angehängte Code (Post #5) keine solche Wartezeit enthält, als womöglich eine alte Version ist?
Es ist wohl ein Prototyp für sleep_ms() im Code drin, das war's dann aber schon.

__lissy__
27.06.2013, 08:37
25879

Dies müsste nun aber wirklich die richtige Version sein