- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 7 von 7

Thema: I2C-Kommunikation läuft nicht über längere Zeit (Atmega644PA)

  1. #1

    I2C-Kommunikation läuft nicht über längere Zeit (Atmega644PA)

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo Community!

    Ich bin schon seit längerer Zeit hier im Forum Mitleser und habe bereits einige nützliche Informationen erhalten, auch für mein aktuelles Projekt (einen Quadrocopter zu bauen ). Doch nun stehe ich vor einem Problem, das mich seit Tagen verwirrt.

    Ich habe einen zentralen Controller (Atmega644PA), der den Sensor ausliest (MPU6050), alle Berechnungen durchführt und die Daten für die Geschwindigkeit an die 4 Motorregler (Atmega88A) überträgt.
    Die gesamte Kommunikation zwischen den Bauteilen läuft über I2C (mit der fleury-lib) , jedoch nur etwa 0-30sec, danach funktioniert der I2C-Part nicht mehr. Doch nun ein wenig genauer:

    Was ich bisher getestet habe:
    - Auslesen des Sensors + Berechnung (Winkel, PID (aktuell nur P)) und Ausgabe auf einem LCD Display (es werden die Werte genauso angezeigt wie sie zu einem Motorregler gesendet werden würden) Das funktioniert wunderbar, auch beliebig lange.

    - Kommunikation mit den Reglern (Atmega88A als Slave) und Motorsteuerung. Die Regler (+Software) sind ein Nachbau der Regler von Ulrich Radig. Die Motoren fahren langsam hoch und starten wieder von vorne, das Ganze ebenfalls beliebig lange.

    Hier die main für die Augabe aufm LCD:
    Code:
    while(1){
    	while(a!=1);		// wait until timer1 overflow (sets a=1) -> constant sample rate (500Hz)
    	a=0;
    	
    	get_gyro_data(gyro_data);      //gyro_data -> uint16_t , reads raw data from MPU6050
    	get_acc_data(acc_data);
    		
            //complementary filter + angle calculation in degrees
    	angle_calculation(acc_data,gyro_data,gyro_data_offset,&pitch,&roll);    //gyro_data_offset -> uint16_t, pitch/roll -> float
    
            pid_calculation(0,&pitch,&pid_pitch);     //pid_pitch -> int16_t
            motora+=pid_pitch;    //motora -> uint8_t
    
            i2c_send_data_to_lcd(motora);      //sends data to lcd display
         }
    Und hier für die Motoren:
    Code:
    while(1){
    	while(a!=1);		// wait until timer1 overflow (sets a=1) -> 10Hz
    	a=0;
    	
            motora++;
            motorb++;
    	i2c_start(MOTORA+I2C_WRITE);     //MOTORA: adress of motor A
    	i2c_write(motora);
    	i2c_stop();
            i2c_start(MOTORB+I2C_WRITE);     //MOTORB: adress of motor B
    	i2c_write(motorb);
    	i2c_stop();
    }
    Da beides so sehr gut funktioniert kann ich eigentlich ein Hardware-Fehler ausschließen. Trotzdem hier noch kurz: Pull-ups für I2C sind 4,7k, der MPU6050 ist über einen Pegelwandler, bestehend aus 2 Transistoren (siehe AN10441), angeschlossen. Stromversorgung ist ein 3S Lipo (mit 78S05 für die 5V). Elkos müssten genug 1mF low-esr drauf sein). Wenn ein Schaltplan hilfreich ist, stell ich ihn auch noch rein.

    Tja nur zusammen läuft es nicht wirklich. Wenn ich die berechneten Werte, statt an das Display, an die Regler schicke, dann läuft es maximal 30 Sekunden, dann bricht die Kommunikation zusammen. Innerhalb dieser 30 sec stabilisiert sich aber mein quad 1achsig auf einer Holzkonstruktion (und schwingt dabei, ist aktuell ja nur ein P-Regler). Immerhin etwas

    Bei den Reglern kommt es zu einem i2c-timeout. d.h. es werden keine neuen Werte mehr vom Atmega644PA versendet und die Motoren gehen aus.
    Der Atmega644PA hängt sich aber nicht vollkommen auf. In der ISR für den Timer1 habe ich einen Zähler eingebaut, der eine LED blinken lässt. Gehen die Motoren aus, blinkt diese weiter.
    -> d.h. die while(1) schleife hängt irgendwo nach 30sec fest.
    Dann habe ich eine Variable drin, die überprüft ob sie von der while(1) schleife zurückgesetzt wurde (d.h. die schleife noch aktiv ist), wenn sie in der ISR abgefragt wird.
    Wenn sie nicht zurückgesetzt wurde dann resete ich das TWI und übertrage neue Daten an den Motor (langsames hochfahren), dann läuft er wieder!

    Hier die ISR:
    Code:
    ISR(TIMER1_COMPA_vect){
    	if(b==1){				//d=1 if while(1) in main does nothing -> reset TWI + send new datas to motor 
    		TWCR &= ~((1 << TWSTO) | (1 << TWEN));
    		TWCR |= (1 << TWEN);
    		for(int b=0;b<50;b++){					//shows that I2C works again
    			i2c_start(MOTORC+I2C_WRITE);
    			i2c_write(b);
    			i2c_stop();
    			_delay_ms(100);
    		}
    	}	
    	
    	a=1;   //for while(1)
    	DDRB|=(1<<PB1);
    	if(c==250){
    		PORTB^=(1<<PB1);	//toggle green led (=ISR works)
    		c=0;
    	}
    	c++;
    }
    Der Fehler, wo es nun hängt liegt offenbar in der Funktion i2c_start(), genauer hier:
    Die LED bleibt an, der Controller hängt in dieser Schleife. Anscheinend kommt kein ACK/NACK mehr zurück. Überprüfen kann ich das leider nicht, meine Soundkarte als Oszi ist nicht schnell genug btw die i2c-Frequenz zu senken bringt leider nichts, im Gegensatz selbst TWBR=5; (~760kHz) funktioniert.

    Code:
    unsigned char i2c_start(unsigned char address)
    {
            //....... other code
    	PORTB|=(1<<PB3);		//red led = on
    
    	// wail until transmission completed and ACK/NACK has been received
    	while(!(TWCR & (1<<TWINT)));
    
    	PORTB&=~(1<<PB3);		//red led = off
    	//....... other code
    }

    Eine Lösung wäre in der ISR TWI zu resetten und dann an den Anfang der Schleife zu springen, aber das ist, soweit ich weiß, ein nogo... Ein Watchdog kommt eher nicht in Frage da ich am Anfang vom Programm ja den Gyro-Offset bestimmen muss und zudem noch andere Einstellungen vornehmen muss. Außerdem Suche ich nach einem Weg das Hängenbleiben zu vermeiden. Ständige Resets in einem Quadrocopter sind nicht das wahre

    Klicke auf die Grafik für eine größere Ansicht

Name:	bild1.jpg
Hits:	15
Größe:	68,9 KB
ID:	28775

    motorregler.c PID.c PID.h mpu6050.c MPU6050.h i2cmaster.h main.c twimaster.c

    Vielen Dank im Voraus!

    mfg adrian

  2. #2
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    ... Kommunikation ... läuft über I2C ... nur etwa 0-30sec, danach funktioniert der I2C-Part nicht mehr. Doch nun ein wenig genauer:
    ...
    Code:
    ...
        i2c_start(MOTORA+I2C_WRITE);     //MOTORA: adress of motor A
        i2c_write(motora);
        i2c_stop();
            i2c_start(MOTORB+I2C_WRITE);     //MOTORB: adress of motor B
        i2c_write(motorb);
        i2c_stop();
    }
    Hallo Adrian,

    willkommen im Forum.

    Leider hast Du den I²C-Takt in Deiner Lösung nicht genannt. Aber das ist wohl nicht so wichtig. Ich kenne ähnliche Fehler die ich so lange hatte, bis ich mich mal mit dem I²C-Timing beschäftigt hatte. Der Code, den ich oben blau markiert hatte, scheint mir verdächtig.

    Nach dem Stop braucht das System ne Weile bis per I²C wieder geschrieben -- oder gelesen -- werden kann. Wenn man das sofort angeht KANN es funktionieren, muss aber nicht. Und wenns nicht sofort klappt ,dann kann die Kommunikation hängen bleiben. Daher hatte ich bei i2c_start nach einem i2c_stop -- neee, genaugenommen jetzt immer -- eine Abfrage eingefügt, ob der Bus überhaupt bereit ist. Beispiel hier (klick).
    Code:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Lesen (read back) vom Slave   ... mit der Routine aus fleury´s lib
      i2c_start_wait(SLAVE_MoCo+I2C_WRITE); // set device address and write mode
      i2c_write( laddr );           // write address = laddr, das angepeilte Byte
            i2c_stop();             //
    
      while ((i2c_rep_start(SLAVE_MoCo+I2C_READ))) {}// Slave bereit zum Lesen?
    //i2c_rep_start(SLAVE_MoCo+I2C_READ);   // set device address and read mode
      ipwm12  = i2c_readAck();      // Bytes lesen... ab laddr = 0x33/51
      soll12  = i2c_readAck();      //
      ipwm34  = i2c_readAck();      // 
      soll34  = i2c_readNak();      // letztes Byte lesen, NAK
            i2c_stop();             //
    Das Zauberwort heißt bei mir "while" - und dann wartet der Befehl ab, bis der Bus frei ist. Und schon liefs (bei mir). Nun könnte ich Dir das viele Zeugs in den Herstellerschriften zum TWI/I²C bzw. dessen Timing schreiben - kannst Du in den entsprechenden Schriften nachlesen. Vorschlag: probiers mit "while" - vielleicht klappts und dann kannst Du Dir vielleicht das Lesen sparen. Übrigens könnte man bei erfolglosem Warten noch ne Fehlermeldung einbauen. Wenn man möchte.

    Viel Erfolg.
    Ciao sagt der JoeamBerg

  3. #3
    Ja, die Frequenz habe ich vergessen (würden aber in der datei twimaster.c stehen), sie liegt bei 400kHz. Aber wie gesagt, das Problem tritt frequenzunabhängig auf.

    Leider funktioniert dein Lösungsansatz bei mir nicht. Ich glaube auch zu wissen warum: nach i2c_stop() wird ja trotzdem im Endeffekt i2c_start() (über den Umweg while() und i2c_rep_start() ) direkt aufgerufen und kann deswegen dort hängen. Ich habe es auch mit kurzen delays zwischen jeder i2c-Operation versucht, brachte recht wenig.

    Um mal zu sehen, wo genau das Programm stehen bleibt, habe ich jeweils vor den einzelnen Funktionen eine Led angeschalten, am Ende wieder ausgeschalten. Abwechselnd blieb es bei i2c_start() und i2c_readAck() an.
    D.h. es kann nur in folgender Schleife hängen: while(!(TWCR & (1<<TWINT))); (je nachdem was ihr für eine lib benützt, ich verwende die von fleury)

    Um diese zu verlassen muss TWINT == 1 sein. Deswegen habe ich in der ISR, statt wie oben das TWI zu reseten und die Motoren neu ansteuern einfach TWCR |= (1<<TWINT); eingegeben. Sozusagen die brachiale Lösung dass das Programm weiterläuft. Und es scheint zu funktionieren!

    Was es allerdings genau bewirkt und welche Auswirkungen es genau hat kann ich leider nicht sagen, dazu fehlt mir das Wissen (und die Zeit mich dazu ordentlich einzulesen^^)

    Zwar eigentlich keine schöne Lösung und es packt das Problem nicht an der Wurzel, aber es läuft... Es sei denn ich hatte in der letzten halben Stunde einfach nur Glück und es lief auch so Sobald ich es mal längere Zeit laufen lassen kann melde ich mich wieder!

  4. #4
    Ich hatte wohl doch nur Glück.
    Das setzten von TWCR |= (1<<TWINT); in der ISR bringt ein paar mal etwas und das Programm läuft weiter (eine LED an der Stelle, wo ich TWCR |= (1<<TWINT) setze, schaltet um) aber nur für weitere 10 Sekunden... danach bleibt das Programm wieder stehen...
    SDA und SCL sind beide High! (dauerhaft)

    Da ich mir nun beim besten Willen nicht vorstellen kann, wo das Problem nun liegt werde ich für die Ansteuerung auf PPM o.ä. umsteigen.

    Es ist etwas komisch, da das ansprechen der Regler ja bereits funktioniert, ich kann nacheinander z.B. immer größere Werte übergeben, sodass der Motor hochfährt. Nur zusammen mit dem MPU6050 nicht. Aber ich kann wiederum von diesem Sensor die Werte auf einem LCD-Display ausgeben lassen.

    Es wäre natürlich weiterhin praktisch wenn jemand eine Lösung hätte I2C zu resetten bzw. wenn die ISR ausgeführt wird, die Schleife zu unterbrechen und an anderen bestimmen Stelle weiterzumachen.

    mfg

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    ... wenn jemand eine Lösung hätte I2C zu resetten ...
    Versuch mal die Methode von Klebwax (klick hier). Habs (noch) nicht getestet - derzeit ne andere Baustelle.
    Ciao sagt der JoeamBerg

  6. #6
    Hat leider auch nicht funktioniert Mittlerweile glaube ich, dass der Sensor die ganzen Probleme macht und den Bus blockiert.
    Habe es jetzt so gelöst, dass ich den Sensor mit Hardware-I2C auslese und die 4 Motorregler mit Software-I2C ansteuere (getrennte Leitungen). Funktioniert bestens!

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    08.10.2011
    Beiträge
    51
    Kein Plan ob dass hilfreich ist, aber solange ds TWINT-Bit gesetzt ist kann keine Altion auf den TWI gestartet werden. TWINT wird ja nach jeder Aktion am I2C gesetzt und anschließend gelöscht werden. Vielleicht wird es bei deinem Problem irgendwann nicht gelöscht und haltet somit den TWI auf.

    Bin selbst leider kein Mikrokontroller-Guru, beschäftige mich erst seit einigen Monaten intensiv damit. Wird wohl zu meinem neuen Hobby ^^

    Mfg
    fulltime

Ähnliche Themen

  1. LCD an PCF8574 über I2C - 2*16 läuft / 4*20 LCD nicht?
    Von stfan1409 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 6
    Letzter Beitrag: 15.04.2012, 15:06
  2. Problem: Kommunikation über RN-PC->I2C langsam
    Von hspecht74 im Forum Bauanleitungen, Schaltungen & Software nach RoboterNetz-Standard
    Antworten: 8
    Letzter Beitrag: 08.04.2010, 12:50
  3. Kommunikation Atmega8 <-> Beagleboard über I2C
    Von PcVirus im Forum C - Programmierung (GCC u.a.)
    Antworten: 0
    Letzter Beitrag: 23.03.2010, 13:15
  4. TWI kommunikation, Slave läuft nicht
    Von hosti im Forum C - Programmierung (GCC u.a.)
    Antworten: 13
    Letzter Beitrag: 24.06.2009, 13:23
  5. Temperaturmessung über I2C und LM75 läuft nicht
    Von michaelkoemm im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 16.10.2007, 18:50

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad