mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TWI bei mega644 läuft nicht


Autor: Jannik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

Sitze jetzt schon einige Tage drann zwei mega 644 miteinander 
kommunizieren zu lassen.
Ich möchte zunächst einfach nur 1Byte vom Master zum Slave schicken..
Vll seht ihr schon den ein oder anderen Fehler im Quellcode?!

Master hat diesen Code:
#include "twi_com.h"


int slave = 0b0000111;

void twi_init(void) {
  TWBR = 0x11; //SCL auf 400KHz: 0x11 ; 200KHz: 0x2A ; 100KHz : 0x5C
  TWSR |= (1<<TWPS0) | (1<<TWPS1); //Prescale Bits - Teiler = 1
}

void twi_trans_value (void) {
    
  int value = 0b10101010;  

  TWCR = 0x00;

  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);   //Start Condition senden

  while (!(TWCR & (1<<TWINT)));          //Warten ob erfolgreich
  
  TWDR = (slave<<1) | TW_WRITE; //Slave adresse + Zugriffsart (W) in Datenregister schreiben
  
  TWCR = (1<<TWINT) | (1<<TWEN); //TWDR senden

  while (!(TWCR & (1<<TWINT))); //Warten bis gesendet

  TWDR = value; //Daten in TWDR laden

  TWCR = (1<<TWINT) | (1<<TWEN); //Daten senden

  while (!(TWCR & (1<<TWINT)));  //Warten bis gesendet

  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); //STOP senden


} 

Der slave sieht folgendermaßen aus:

int SLAVEADR = 0b0000111;
void twi_init(void) {

  TWAR = (SLAVEADR<<1)|(1<<TWGCE) ; //Slaveadr.... Global Call Off
  TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWEA) | (1<<TWIE); //Global Interrupt off
}

void twi_get_data(void) {

  while(!(TWCR & (1<<TWINT))); //Warten bis der Slave angesprochen wurde
    
  twi_data = TWDR;
  TWCR |= (1<<TWINT);

}

ISR (TWI_vect) {
  twi_get_data();
}

Die funktionen werden nacheinander aufgerufen.. interrupts sind 
aktiviert.

Wäre super nett wenn hier mal einer rüberschaut.

Gruß
Jannik

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wie sieht denn Deine Hardwareanschaltung aus?

Autor: Jannik (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier der Master und der slave. Verbunden über einen steckverbinder 
(länge ca. 10cm)

Autor: F. Reiling (freiling)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
als erstes kannst du mal versuchen, die I2C-Taktrate herunterzusetzen. 
dann könntest du versuchen, nach jedem Schritt eine LED aufleuchten zu 
lassen um rauszufinden ob dein programm hängt.
z.b. So:
  int value = 0b10101010;  

  TWCR = 0x00;

  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);   //Start Condition senden

  while (!(TWCR & (1<<TWINT)));          //Warten ob erfolgreich

    LED1_an;
  
  TWDR = (slave<<1) | TW_WRITE; //Slave adresse + Zugriffsart (W) in Datenregister schreiben
  
  TWCR = (1<<TWINT) | (1<<TWEN); //TWDR senden

  while (!(TWCR & (1<<TWINT))); //Warten bis gesendet

     LED2_an;


usw.

Autor: Jannik (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe nochmal ein wenig weiter geforscht.. Habe mir noch ein Jtag 
interface organisiert um der Sache auf den Grund zu gehen.
Hier ist der Wurm drinn :)
Jetzt wird der Slave schonmal unter der vergebenen Adresse angesprochen. 
Jedoch bekommt der Slave als Daten vom Master (im TWDR) die Slave 
adresse+Schreibbit ?!
Wie kann man das erklären? Ich bin recht ratlos wie diese 
Adresse+Schreibbit im TWDR des Slaves landet? Eigentlich verschicke ich 
ja ein ganz anderes Byte. Weiß wer weiter? Ich habe es ebenfalls im 
Quellcode kommentiert. Mein Gefühl sagt mir dass irgendwas im Slavecode 
nicht stimmt....

Hier nochmal der Master:
#include "twi_com.h"


int slave = 0b0100111;

void twi_init(void) {
  TWBR = 0x5C; //SCL auf 400KHz: 0x11 ; 200KHz: 0x2A ; 100KHz : 0x5C
  TWSR |= (1<<TWPS0) | (1<<TWPS1); //Prescale Bits - Teiler = 1
}

void twi_trans_value (void) {
    
  int value =127;  

  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);   //Start Condition senden

  while (!(TWCR & (1<<TWINT)));          //Warten ob erfolgreich
  
  TWDR = (slave<<1) | TW_WRITE; //Slave adresse + Zugriffsart (W) in Datenregister schreiben
  
  TWCR = (1<<TWINT) | (1<<TWEN); //TWDR senden

  while (!(TWCR & (1<<TWINT))); //Warten bis gesendet

  TWDR = value; //Daten in TWDR laden

  TWCR = (1<<TWINT) | (1<<TWEN); //Daten senden

  while (!(TWCR & (1<<TWINT)));  //Warten bis gesendet

  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); //STOP senden


}



Und hier der Slave:
#include "Twi_com.h"
#include "mylcd.h"


int twi_data = 0;
int SLAVEADR = 0b0100111;

void twi_init(void) {

  TWAR = (SLAVEADR<<1)|(1<<TWGCE) ; //Slaveadr.... Global Call Off
  TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWEA) | (1<<TWIE); //Global Interrupt off
  lcd_set_cursor(0,LINE0);
  lcd_puts_p(small_font,PSTR("Slave init rdy")); //Kommt
}

void twi_get_data(void) {
  lcd_set_cursor(0,LINE1);
  lcd_puts_p(small_font,PSTR("Wait for rqst")); //Kommt
  
  while(!(TWCR & (1<<TWINT))); //Warten bis der Slave angesprochen wurde
  
  lcd_set_cursor(0,LINE2);
  lcd_puts_p(small_font,PSTR("Try to get data"));  //Kommt
  
  twi_data = TWDR;
  lcd_draw_line(0,LINE5,twi_data/2,LINE5,BLACK);

  if (twi_data == 78) { // Slavadr+Schreibbit als Dezimal. Was macht das im TWDR?! Hilfe!
    lcd_set_cursor(0,LINE3);
    lcd_puts_p(small_font,PSTR("DATA OKAY")); // Kommt
  }

  TWCR |= (1<<TWINT);
  
  lcd_set_cursor(0,LINE4);
  lcd_puts_p(small_font,PSTR("Get Data rdy")); //Kommt
}

ISR (TWI_vect) {

  twi_get_data();
}

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Was ich total vermisse, ist die Abfrage der Statusbits im TWS-Register. 
Da kannst du erkennen woran es hakt.

MfG Spess

Autor: Jannik (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Wieder ein wenig weiter....

Habe mal ein Bild von der Übertragen vom Master aus angehängt. SCL liegt 
bei ca. 1KHz. Daten sehen recht sauber aus. Habe es mal mit Bleistift 
makiert wo die Adresse und das Datenbyte gesendet wird. Hoffe man 
erkennt es einigermaßen. Was ich jetzt sehe ist, dass der Slave kein Ack 
zurückgibt sondern ein NotAck (SDA ist im neunten Bit auf "1" und nicht 
auf "0".

Woran kann das liegen? Die Startkondition sowie Slaveadresse+Write kommt 
ja genau richtig an - das sieht man ja nun auf dem Oszi. Wieso sendet 
der Slave kein Ack?

Hier nochmal die zwei Zeilen aus dem Slave (die ja eigentlich für ein 
Ack nach der Adresse ausreichen sollten, oder etwa nicht?!)
int SLAVEADR = 0b0100111;

void twi_init(void) {

  TWAR = (SLAVEADR<<1)|(1<<TWGCE) ; //Slaveadr.... 
  TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWEA) | (1<<TWIE); //Global Interrupt on
 
}

Müsen die Pins SDA und SCL als Dateneingang oder Ausgang definiert sein? 
Für SCL macht ja Slaveseitig ein Eingang sinn. Nur bei SDA wird ja 
emfangen und gesendet (für Ack/NotAck. Hierzu finde ich nichts im 
Datenblatt. Regelt die TWI Hardware die SCL und SDA Datenrichtungen 
automatisch?

Vielen Dank!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.