Forum: Mikrocontroller und Digitale Elektronik I2C über Interrupts mitlesen


von T.Gxxxx (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

seit einigen Tage komme ich nun leider nicht mehr weiter und hoffe, dass 
ihr mir helfen könnt.

Ich habe ein PIC18 Experimentierboard, ein PicKit2 und ein MGC3130 Board 
von Microchip.

Mit meinem PIC18 möchte ich gerne die I2C Datenübertragung auf dem 
MGC3130 Board mitlesen. Dafür ist auch extra eine I2C Schnittstelle auf 
dem Board angebracht.

Hierzu habe ich mit zwei Adern von einem Flachbandkabel, keine 10 cm 
lang, das PIC Experimentierboard mit dem MGC3130 Board verbunden.

SCL kommt bei meinem PIC auf den External Interrupt INT0 Pin und SDA 
kommt bei meinem PIC auf den External Interrupt INT1 Eingang.

Der Pic18 verfügt zwar über ein I2C Modul, welches ich jedoch bewusst 
nicht nutzen möchte, da dann das einfache Mitlesen der I2C Verbindung 
wegen der gleichen Slave Adresse, dem R/W Bit und dem ACK Bit nicht so 
einfach möglich ist. (Auf dem MGC3130 Board kommuniziert der 
MGC3130(Slave) mit einem Master).

Deshalb habe ich die beiden Leitungen auf external Interrupteingänge 
gelegt.

Im C - Code passiert bei mir folgendes :

1. INT1  SDA  reagiert auf fallende Flanken
2. Warten auf eine fallende Flanke am SDA Eingang
3. Fallende Flanke am SDA Eingang kommt :   SCL Pin High ?
4. JA SCL ist High -->  Startbedinung.
5. Der INT1 Interrupt wird deaktiviert und INT0 hingegen aktiviert mit 
steigender Flanke.
6. Bei jeder SCL steigenden Flanke wird nun SDA auf HIgh oder Low 
abgefragt und dementsprechend ein Bit in  buffer[20] gesetzt.
7. Nach 20 EInträgen werden alle Interrupts abgeschaltet.

Das Problem ist nun aber, dass ständig falsche Werte in meinem Buffer 
stehen. Die I2C Adresse kommt ja nach der Startbedinung als erstes. Die 
ist 0x42  also  1000010   aber in meinem Buffer steht bei jedem Versuch 
etwas anderes drin ?

Kommt ihr mir bitte weiterhelfen ?
Ich hänge mal meinen C code an und ein Bild, dass ich von meinem Oszi

von San L. (zwillingsfreunde)


Lesenswert?

Gerade zu dem was ich sage nicht ganz sicher, da ich den PIC den du 
verwendest nicht kenne, aber:

Laut deinem Code läuft der PIC mit 20 MHz. Bedeutet, der PIC braucht:
(1 / 20MHz) * 4 = 200ns
um einen Befehl auszuführen, welcher einen Maschinenzyklus braucht.

Laut deinem KO Bild sendet dein I2C mit einer Frequenz con 370KHz 
(Vermute mal, I2C läuft bei dir im Fast Mode, also 400 KHz?)

Heisst, du kriegst alle:
1 / 400KHz = 2,5 us
eine neue Flanke.

2,5 us / 200ns = 12,5

Heisst, du kannst gerade mal 12 Befehle ausführen, bis die nächste 
Flanke eintrifft.

Ich habe sowas wie du hier probierst zwar noch nie gemacht, bin mir auch 
absolut nicht sicher über meine Antwort, aber spontan würde ich sagen: 
Der PIC ist zu langsam und daran scheitert es.

von T.Gxxxx (Gast)


Lesenswert?

Vielen Dank, du hast Recht.
Habe das soeben mit meinem Oszilloskop überprüft.

Alleine einen High/Low Pegel abzufragen und diesen anschließend in einem 
Buffer zu speichern, dauert auf meinem Controller in C fast 10us.

von Somebody123 (Gast)


Lesenswert?

T.Gxxxx schrieb:
> Vielen Dank, du hast Recht.
> Habe das soeben mit meinem Oszilloskop überprüft.
>
> Alleine einen High/Low Pegel abzufragen und diesen anschließend in einem
> Buffer zu speichern, dauert auf meinem Controller in C fast 10us.

Hallo,

dein Problem ist nicht, dass der Controller zu langsam wäre, sondern die 
Interrupt Latency.

Bevor dein Controller in die ISR geht, muss erst einmal der ganze Käse 
aus den Registern weggespeichert werden etc etc. Das dauert. Wie lange 
steht im Datenblatt, aber sicher mal >10 Taktzyklen, eher viel mehr.

Zu schaffen ist das trotzdem: Du wirst es vermutlich hinbekommen, wenn 
du das Startbit als "Trigger" verwendest und dann in die Empfangsroutine 
springst. Den Interrupt muss man dann abschalten.

Wenn du in deiner Empfangsroutine bleibst, schafft der PIC das leicht. 
In der Empfangsroutine darfst du dich aber nicht unterbrechen lassen 
(Interrupts aus).

von San L. (zwillingsfreunde)


Lesenswert?

Somebody123 schrieb:
> Bevor dein Controller in die ISR geht, muss erst einmal der ganze Käse
> aus den Registern weggespeichert werden etc etc. Das dauert. Wie lange
> steht im Datenblatt, aber sicher mal >10 Taktzyklen, eher viel mehr.

Stimmt. Die Speicherung des Workregisters und des Statusregisters 
beanspruchen auch noch einmal ein paar Zyklen für sich, daran habe ich 
garnicht mehr gedacht.

Denke aber auch ohne Interrupt wird das ganze sehr schwierig, da ich 
denke dass meine Berechnung oben korrekt ist. Wird schon relativ schwer 
mit 12 Maschinenzyklen da was anständiges zu schreiben. Denke, in 
Assembler würde man es evt. mit einer guten Lösung noch knapp 
hinkriegen, in C wohl kaum eine Chance, da der Code wirklich auf ein 
Minimum reduziert werden muss..

von Ein (Gast)


Lesenswert?

T.Gxxxx schrieb:
> Mit meinem PIC18 möchte ich gerne die I2C Datenübertragung auf dem
> MGC3130 Board mitlesen.

Und was soll das ganze? Kann man dafür nicht einfach einen fertigen 
I2C-Logger für 10..12€ nehmen, der die Daten auf den PC streamt?

von Max H. (hartl192)


Lesenswert?

Somebody123 schrieb:
> Bevor dein Controller in die ISR geht, muss erst einmal der ganze Käse
> aus den Registern weggespeichert werden etc etc. Das dauert.
Das war mal so (Mid-Range-Core). Bei den PIC18er sieht es anders aus:
> 9.9 Context Saving During Interrupts
> During interrupts, the return PC address is saved on
> the stack. Additionally, the WREG, STATUS and BSR
> registers are saved on the Fast Return Stack.
Siehe: 5.1.3 FAST REGISTER STACK

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.