Forum: Mikrocontroller und Digitale Elektronik I2C zwischen 2 PIC18 hängt gelegentlich


von Dominik H. (dominik_ulm)


Lesenswert?

Hallo Leute,

kurz zu mir, mein Name ist Dominik, ich bin hier neu angemeldet und 
studiere Medizintechnik.
Ich habe ein ernsthaftes Problem, mit dem ich mich nun seit Tagen herrum 
schlage. Ich habe einen I2C Bus zwischen zwei PIC18F25K22 eingerichtet. 
Übertragen werden sollen immer nur zwei Datenbyte, ein Aulesen des Slave 
ist erstmal nicht vorgesehen.

Ich habe einen PIC als Master, der Sollwerte für DC-Motoren vorgibt und 
einen PIC als Slave, auf dem der geschlossene Regelkreis des DC-Motors 
verwirklicht ist.

Ich habe hierfür ein paar Zeilen geschrieben, das funktioniert soweit 
und über Stunden hinweg ohne Probleme. Allerdings nur in meinem 
Test-Projekt. Sobald ich den Code in die eigentlichen Projekte, meine 
Hauptsteuerung und meine Motorregelung einbinde, wars das:
Nun habe ich folgendes Problem - der Bus "hängt" sich auf, manchmal 
sofort, manchmal nach ein paar Paketen, manchmal erst nach tausenden. 
Und zwar immer zwischen Adresse und erstem Datenbyte. Der Slave hängt 
dann in der ersten "while(DataRdyI2C1==0);" während der Master (auf dem 
Oszi gut sichtbar) ins Datendauerfeuer geht.

Das Problem lässt sich im Debug-Mode NICHT reproduzieren. Das hat mich 
auch auf folgende Idee gebracht; der einzige Unterschied zwischen Debug 
und Betrieb ist ja die Zeit, die ich zum klicken brauche - also ein 
delay zwsichen Adresse und Byte eingebaut und schon wurde es "besser". 
Ich brauche aber echt eine Pause von mehreren ms um die Aufhänger 
auszumerzen. Das kann ich mir aus Performancegründen aber leider nicht 
erlauben. Ich habe es schon mit clockstretching versucht, entweder es 
tut trotzdem nicht, oder ich bin zu blöd es richtig einzustellen :( Des 
weiteren schalte ich meine Interrupts aus, dass mir da nichts dazwischen 
kommen kann.

Anbei mal noch die Routinen:

Master:
void sende_daten(void) {
    INTCONbits.PEIE=0;
    INTCONbits.GIE=0;
    StartI2C();
    IdleI2C1();
    do {
        statusI2C = WriteI2C1(zf);
    }    while (statusI2C != 0);
    while (SSP1CON2bits.ACKSTAT == 1);
    Delay100TCYx(12);
    do {
        statusI2C = WriteI2C1(Bewegung[0]);
    }    while (statusI2C != 0);
    while (SSP1CON2bits.ACKSTAT == 1);

    do {
        statusI2C = WriteI2C1(Bewegung[1]);
    }    while (statusI2C != 0);
    while (SSP1CON2bits.ACKSTAT == 1);
    StopI2C1();
    INTCONbits.PEIE=1;
    INTCONbits.GIE=1;
}

mit den Einstellungen/Startbedigungen:
SSP1CON1bits.SSPM = 0b1000;
SSP1CON1bits.SSPEN = 1;
statusI2C=0;
OpenI2C1(MASTER,SLEW_OFF);
SSP1CON2bits.ACKSTAT = 0;


Und der Slave:
  if (DataRdyI2C1() == 1) {
            SSP1CON1bits.CKP = 0;
            PIE1bits.ADIE = 0;
            temp = SSP1BUF;

            if (temp == SSP1ADD) {
                SSP1CON1bits.CKP = 1;
                while (DataRdyI2C1() == 0);
                Bewegung[0] = SSP1BUF;
                while (DataRdyI2C1() == 0);
                Bewegung[1] = SSP1BUF;
                PIE1bits.ADIE = 1;
                }
mit den Einstellungen/Startbedigungen:
SSP1CON1bits.SSPEN=1;
SSP1CON1bits.SSPM=0b0110;
SSP1ADD=0xA2;
SSP1CON2bits.SEN=1;
OpenI2C1(SLAVE_7, SLEW_OFF);

Ich komm echt nich drauf, vlt. hab ich irgendwas übersehn, oder nich 
kapiert, k.A. ich seh vor lauter Bäumen den Wald nicht mehr und würde 
mich über jede Hilfe freuen!
Danke fürs Durchlesen und Mitdenken im vorraus!

Grüße aus Ulm,
Dominik

EDIT: Was man noch dazu sagen muss (k.A. ob's ne Rolle spielt) der Slave 
arbeitet seinen Code mit einer festen Frequenz von 1kHz ab.

von Michael .. (bigneal)


Lesenswert?

also wenn ich lese, das es eine Motorsteuerung ist und der I2C-Bus sich 
nur in der richtigen Schaltung aufhängt, fällt mein Verdacht sofort auf 
Stöhrungen auf dem Bus.

Schau dir die Daten und Clock-Leitung mit dem KO an.
Oder versuch mal die Übertragungsrate zu senken und/oder die pull-up 
Widerstände kleiner zu machen (die unterste Grenze ist 5V -> 1.7k, 3.3V 
-> 1.2k)

von Ingo S. (schicki)


Lesenswert?

So ich abe auch kurz ein paar Fragen:

1. Wie lange ist deine Verbindung?
Bei langen Verbindungen ist der I²C nicht ganz optimal. Das sollten die 
Leitungen auf jeden Fall sauber entsört sein. Her hat NXP eine ganze 
Reihe an Bus Repeatern usw..

2. Wie schnell ist Deine Geschwindigkeit
100 oder 400 KHZ? Ich habe auch mal einen Triber für eine Segmentanzeige 
über I²C geschrieben. Bei viel Traffik ist der Bus ggf. auch mit 400 KHZ 
zu langsam. Es kommt ganz drauf an, was Du sonst noch im Programm 
machst.

3. Wie hoch ist Deine Versorgungsspannung? Dieser PIC hat einen weiten 
Bereich auf den ersten Blick.

• 2.3V to 5.5V Operation – PIC18FXXK22 devices
• 1.8V to 3.6V Operation – PIC18LFXXK22 devices


3. Nimm Dir die Ratschäge von Michael zu Herzen, so gehe ich auch immer 
vor.

4. Wenn das alles nichts hilft kann ich Dir einmal ein paar Beispiele 
von Standard I²C-Slaves zukommen lassen.

http://www.schwabenplan.com/allgemeines.htm

Wenn was ist einfach schreiben

Ingo

von Bananen Joe (Gast)


Lesenswert?

Die While-Schleifen sind dein Problem!
Es ist besser, zyklisch if-Abfragen zu verwenden, Flags zusetzen 
(Statemachine) und Timeouts einzubauen, damit deine Controller eben 
nicht hängen bleiben und auch mal eine Übertragung ignorieren kann bzw. 
eine erneute Anfrage möglich ist.

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.