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.
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)
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.