-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: TWI kommunikation, Slave läuft nicht

  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388

    TWI kommunikation, Slave läuft nicht

    Anzeige

    Guten Tag,

    Ich bin zur Zeit dabei einen Atmega644(Master) mit einem Atmega8 (Slave) kommunizieren zu lassen.
    Der Mastercode funktioniert soweit(glaube ich), auch die verbindung mit dem Slave funktioniert(Interupt wird aufgerufen).

    Dort möchte ich einen bestimmten Wert den ich vom Master erhalte in einer Variable speichern.
    Nur leider passiert nichts.
    Ausschnitte aus meinem Slavecode:
    Code:
    unsigned volatile char adresse, daten;
    
    void twi_slave(void)
    {
    TWAR = 0x40;
    TWRC = (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
    TWSR = 0;
    };
    
    ISR(TWI_vect)
    {
    daten = TWDR;
    TWRC |= (1<<TWINT);
    TWRC = (1<<TWEA) | (1<<TWEN) | (1<<TWSTO);
    if (TWSR &0b11111000 == 0x80)
    {
    if (daten == 0x04)
    {PORTB |= (1<<PORTB1);}
    else
    {PORTB &= ~(1<<PORTB1);}
    }
    TWRC |= 0b1000000;
    };
    
    int main(void)
    {
    sei();
    twi_slave();
    DDRB |= (1<<PORTB1);
    PORTB &= ~(PORTB1);
    
    while(1)
    {}
    }
    Und mein Mastercode(Alles etwas unübersichtlich, und Beta):
    Code:
    #include <avr/io.h>         // I/O Port definitions 
    #include <avr/interrupt.h>   // Interrupt macros 
    
    #define F_CPU 16000000UL	//CPU Tackt
    
    unsigned volatile char daten, error;
    uint8_t adresse;
    
    void twi_init(void);
    int twi_senden(uint8_t adresse, char daten);
    
    
    int main(void) 
    {
    
    	twi_init();
    	adresse = 0x40;
    	daten = 0x04;
    	
    	while(1)
    	{
    		twi_senden(adresse, daten);
    		
    	};
    
    }
    
    void twi_init(void)
    {
    	DDRC &= !((1<<DD0) | (DD1));
    	PORTC = (1<<DD0) | (1<<DD1);
    	TWSR = 0x00;		//Prescaler 
    	TWBR = 12;		//TWI 400khz
    };
    
    int twi_senden(uint8_t adresse, char daten)
    {
    	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);		//TWI aktivieren und Start condition auslösen
    	while(!(TWCR & (1<<TWINT))); 	//Warten auf Start condition
    	if((TWSR & 0xF8) != 0x08) return 0;
    	
    	TWDR = adresse & (0xFE);		//Adresse mit Schreibbit(xxxxxxx0) in Register
    	TWCR = (1<<TWINT) | (1<<TWEN);	//senden
    	if((TWSR & 0xF8) != 0x18) return 0;
    	
    	while(!(TWCR & (1<<TWINT)));	//warten auf ACK oder NACK
    	
    	TWDR = daten;					//Byte in Datenregister laden
    	TWCR = (1<<TWINT) | (1<<TWEN);	//senden
    	while (!(TWCR & (1<<TWINT)));	//warten auf ACK oder NACK
    	if ((TWSR & 0xF8) != 0x28) return 0;
    	
    	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);	//STOP Conditions auslösen
    	return 1;	
    };

    Ivh versuche folgendes zu lösen
    Ich habe 3 Variablen die ich durch den Master im Slave mit bestimmten Werten setzten möchte.
    Mit TWI wird ja immer ein Byte gesendet soweit ich das verstanden habe.
    Ich möchte aber einen wert von 1000-2000 (also 10Bit) übertragen.
    Desweitern muss ich ja entscheiden welche Variable im Slave angepasst wird.


    Hat jemand eine Idee wie man das lösen könnte?

    Ich denke das auswählen der Variable läst sich mit switch lösen.
    Sprich ich gebe jeder Variable eine Nummer und übermittle diese um zu bestimmen welche Variable gesetzt werden soll.
    Nur wie übermittle ich den eigentlichen Wert, so das er auch in die richtige Variable geschrieben wird. Mit der zusätzlichen Schwierigkeit das der Wert grösser als 8Bit ist.

    Ich bin für jede Hilfe sehr dankbar

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    31
    Beiträge
    4.255
    Schau dir erstmal die defines für die Statuscodes in der avr-libc (<util/twi.h>)
    an.
    if (TWSR &0b11111000 == 0x80)
    versteht keiner.
    if (TW_STATUS == TW_SR_DATA_ACK)
    ist da schon deutlich besser lesbar.

    Lass dir mal in der ISR den aktuellen Statuscode ausgeben. Dazu solltest du beim Master ne gewisse Wartezeit zwischen zwei Übertragungen einfügen.

  3. #3
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Ursprünglich hatte ich meinen Code mit der AVR-lib erstellt.
    Da dies aber nicht ging habe ich aus "verzweiflung" fragmente von anderen Codes übernommen. Deshalb ist der Code so verbastelt.

    Ein konkreter Fehler fählt dir so nicht auf?

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    31
    Beiträge
    4.255
    Hast du jetzt mal ne Version mit den Codes? Dann lässt sich das viel schneller prüfen... und deine Fehlerbeschreibung ist auch noch relativ nichtssagend...

  5. #5
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    So, die Masterdatei
    Code:
    #include <avr/io.h>         // I/O Port definitions 
    #include <avr/interrupt.h>   // Interrupt macros 
    #include <util/twi.h>
    
    #define F_CPU 16000000UL	//CPU Tackt
    
    unsigned volatile char daten, error;
    uint8_t adresse;
    
    void twi_init(void);
    int twi_senden(uint8_t adresse, char daten);
    
    
    int main(void) 
    {
    
    	twi_init();
    	adresse = 0x40;
    	daten = 0x04;
    	
    	while(1)
    	{
    		twi_senden(adresse, daten);
    		
    	};
    
    }
    
    void twi_init(void)
    {
    	DDRC &= !((1<<DD0) | (DD1));
    	PORTC = (1<<DD0) | (1<<DD1);
    	TWSR = 0x00;		//Prescaler 
    	TWBR = 12;		//TWI 400khz
    };
    
    int twi_senden(uint8_t adresse, char daten)
    {
    	uint8_t twst;
    	
    	while(1)
    	{
    	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);		//TWI aktivieren und Start condition auslösen
    	while(!(TWCR & (1<<TWINT))); 	//Warten auf Start condition
    	twst = TW_STATUS & 0xF8;
    	//if((TWSR & 0xF8) != 0x08);
    	if ((twst != TW_START) && (twst != TW_REP_START))continue;
    	
    	TWDR = adresse & (0xFE);		//Adresse mit Schreibbit(xxxxxxx0) in Register
    	TWCR = (1<<TWINT) | (1<<TWEN);	//senden
    	//if((TWSR & 0xF8) != 0x18);
    	while(!(TWCR & (1<<TWINT)));	//warten auf ACK oder NACK
    	twst = TW_STATUS & 0xF8;
    	if ((twst == TW_MT_SLA_NACK) || (twst == TW_MR_DATA_NACK))
    	{
    		TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    		while(TWCR & (1<<TWSTO));
    		continue;
    	}
    	
    	TWDR = daten;					//Byte in Datenregister laden
    	TWCR = (1<<TWINT) | (1<<TWEN);	//senden
    	while (!(TWCR & (1<<TWINT)));	//warten auf ACK oder NACK
    	//if ((TWSR & 0xF8) != 0x28);
    	
    	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);	//STOP Conditions auslösen
    	return 1;	
    	}
    };

    Und hier die Slavedatei:
    Code:
    #include <avr/io.h>         // I/O Port definitions 
    #include <avr/interrupt.h>   // Interrupt macros 
    #include <util/twi.h>
    #define F_CPU 16000000UL	//CPU Tackt
    #define timer 236
    
    unsigned volatile char adresse, daten;
    
    void twi_slave(void)
    {
    	TWAR = 0x40;
    	TWCR &= ~(1<<TWSTA) | (1<<TWSTO);
    	TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWIE); 	//ack, TWI enable, Interupt
    	TWSR = 0;
    };
    
    
    ISR(TWI_vect)
    {
    
    switch(TW_STATUS)
    {
    case TW_SR_SLA_ACK:
    //Wen ich hier den PORT1 Highschalte klappts.
    TWCR = (1<<TWEN) | (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWWC);
    break;
    case TW_SR_DATA_ACK:
    //Hier klappts leider nicht mehr, heisst das abfragen dieses Status schlägt fehl
    PORTB |= (1<<PORTB1);
    break;
    }
    	
    	/*daten = TWDR;
    	TWCR |= (1<<TWINT);
    	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    	if (TW_STATUS == TW_SR_SLA_ACK)
    	{
    	daten = TWDR;
    	//if (daten == 0x04)
    	{PORTB |= (1<<PORTB1);}
    	else
    	{PORTB &= ~(1<<PORTB1);}	
    	}*/
    	TWCR |= 0b10000000;
    };
    int main(void) 
    {
    
    	sei(); 										//Globale Interupts zulassen
    		twi_slave();
    
    	DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3);			//B... AUSGANG
    	PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));		//B.. Low
    
    	while(1)
    	{
    
    
    	}
    
    }
    So, ich habe den Status stück für Stück abgefragt. Und bei TW_STATUS_DATA_ACK
    kriege ich keine Rückmeldung.
    Also das heisst für mich das Ansprechen des Slaves funktioniert(TW_STATUS_SLA_ACK) und im weiteren Ablauf ist ein Fehler.
    Nur habe ich keine Ahnung wo, noch nicht einmal ob Master oder Slave. Aber ich tendiere auf Master aufgrund der scheiternden Status abfrage im Slave.

    Ich habe noch kein warten für das senden drin.
    Würdest du das über delay machen oder einen Timer laufen lassen?

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    31
    Beiträge
    4.255
    Du hast dich beim Master ja anscheinend größtenteils bei P. Fleury bedient. Warum übernimmst du seine lib nicht komplett? Es reicht, wenn du den Slave als offene Baustelle hast...

  7. #7
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Es läuft, ich habe vergessen am Schluss TWCR_NACK aufzurufen.

    Jetzt versuche ich folgendes zu lösen.
    Ich habe 3 Variablen die ich durch den Master im Slave mit bestimmten Werten setzten möchte.
    Mit TWI wird ja immer ein Byte gesendet soweit ich das verstanden habe.
    Ich möchte aber einen wert von 1000-2000 (also 10Bit) übertragen.
    Desweitern muss ich ja entscheiden welche Variable im Slave angepasst wird.


    Hat jemand eine Idee wie man das lösen könnte?

    Ich denke das auswählen der Variable läst sich mit switch lösen.
    Sprich ich gebe jeder Variable eine Nummer und übermittle diese um zu bestimmen welche Variable gesetzt werden soll.
    Nur wie übermittle ich den eigentlichen Wert, so das er auch in die richtige Variable geschrieben wird. Mit der zusätzlichen Schwierigkeit das der Wert grösser als 8Bit ist.

    Ich bin für jede Hilfe sehr dankbar

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    31
    Beiträge
    4.255
    Schau mal ins Wiki, da findest du meinen Code für nen Slave:
    http://www.rn-wissen.de/index.php/TWI_Slave_mit_avr-gcc
    Ich hab mich dabei an fertigen I2C-Speicherbausteinen orientiert. Das erste Byte einer Übertragung wählt die Speicherstelle im Slave aus, und dann kann man beliebig viele Daten hintereinander schreiben, die dann fortlaufend abgelegt werden.

  9. #9
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Wen ich den Code richtig verstehe muss ich erst die Position im Buffer übermittel. Z.B. eine 1 um die erste Postition im Buffer zu bestimmen.

    Anschliessend kann ich den Wert übermitteln für Position 1 des Buffers.
    Der nächste Wert kommt dann in Position 2.... usw.

    Ist das so Richtig?

    Was mach ich wen ich nicht(Oder nicht immer) alle Positionen des Buffers brauche?
    einfach einen Wert in die letzte Position schreiben?

    Übrigens ein sehr schön dokumentierter Wiki Eintrag von dir,
    er hat mir schon viel geholfen.

  10. #10
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    31
    Beiträge
    4.255
    Wenn du nicht alle Positionen brauchst, hörst du einfach mit der Übertragung auf. Beim nächsten Mal musst du dann aber wieder erst die Startposition senden.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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