mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TWI-Slave will nicht hören


Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich habe hier ein ziemliches Problem mit dem TWI eines Mega8:

Ein Mega32 als Master versucht etwas zu senden, doch der Slave (Mega8) 
reagiert nicht im geringsten. Auf dem Master wird der TWI-Interrupt 
erwartungsgemäss ausgelöst (START sent, NOT ACK received). Die 
SCL-Leitung ist zuerst auf High, nach dem Senden dauerhaft auf Low (wie 
zu erwarten, da noch kein STOP gesendet wurde). Auf dem Slave passiert 
rein gar nichts - nicht mal der TWI-Interrupt wird ausgelöst. (Dann 
sollte eine LED angehen und ein Zeichen übers UART gesendet werden - nix 
von dem passiert.

Ich bin langsam ein bisschen am verzweifeln, da ich dem Problem einfach 
nicht auf die Schliche komme. Primäres Ziel ist nun mal, dass der 
TWI-Interrupt auf dem Slave ausgelöst wird.

Achja: Die Schaltung sollte stimmen. (Was für Pullups sollte man am 
besten verwenden? 1.8k Ohm?)

Gruss

Michael


TWI-relevante Codefragmente:
struct{
  unsigned char read:1;

  char * outbuffer;
  uint8_t outptr;
  uint8_t outlen;

  char * inbuffer;
  uint8_t inptr;
  uint8_t inlen;
}i2c;

void i2c_init(uint8_t addr){
  TWAR = (addr << 1) | 1;
  TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
}

void i2c_setinputtarget(char * buffer[], uint8_t len){
  i2c.inbuffer = buffer;
  i2c.inlen = len;
  i2c.inptr = 0;
}

void i2c_setoutputsource(char * buffer[], uint8_t len){
  i2c.outbuffer = buffer;
  i2c.outlen = len;
  i2c.outptr = 0;
}

void i2c_received(){
  uint8_t i = 0;
  for(i = 0; i < i2c.inlen; i ++)
    uart_sendchar(*(i2c.inbuffer + i));
}


TWI-ISR:
//TWI-Interrupt
ISR(TWI_vect){
  PORTB = 0b00000000;
  uart_sendchar('x');
  uint8_t status = TWSR & 0b11111100;
  TWCR &= ~((1 << TWSTA) | (1 << TWSTO));
  
  // Own SLA+W received, ACK returned
  if(status == 0x60){
    i2c.inptr = 0;
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  // Arbitration lost
  else if(status == 0x68){

  }
  // General call address received, ACK returned
  else if(status == 0x70){

  }
  // Arbitration lost
  else if(status == 0x78){

  }
  // Data received, ACK returned
  else if(status == 0x80){
    uart_sendchar(TWDR);
    if(i2c.inptr < i2c.inlen - 1){
      *(i2c.inbuffer + i2c.inptr) = TWDR;
    i2c.inptr ++;
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  else{
      *(i2c.inbuffer + i2c.inptr) = TWDR;      
    i2c.inptr ++;
    TWCR |= (1 << TWINT);
    TWCR &= ~(1 << TWEA);
  }
  }
  // Data received, NOT ACK returned
  else if(status == 0x88){
    *(i2c.inbuffer + i2c.inptr) = TWDR;
    TWCR |= (1 << TWINT) | (1 << TWEA);
  i2c_received();
  }
  // General-Call Data received, ACK returned
  else if(status == 0x90){

  }
  // General-Call Data received, NOT ACK returned
  else if(status == 0x98){

  }
  // STOP or REPEATED START condition received
  else if(status == 0xA0){
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  // SLA+R received, ACK returned
  else if(status == 0xA8){
    i2c.outptr = 0;
    if(i2c.outptr < i2c.outlen - 1){
      TWDR = *(i2c.outbuffer + i2c.outptr);
    i2c.outptr ++;
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  else{
      TWDR = *(i2c.outbuffer + i2c.outptr);
      TWCR &= ~(1 << TWEA);
    TWCR |= (1 << TWINT);
  }
  }
  // Arbitration lost
  else if(status == 0xB0){

  }
  // Data byte transmitted, ACK received
  else if(status == 0xB8){
    if(i2c.outptr < i2c.outlen - 1){
      TWDR = *(i2c.outbuffer + i2c.outptr);
    i2c.outptr ++;
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  else{
      TWDR = *(i2c.outbuffer + i2c.outptr);
      TWCR &= ~(1 << TWEA);
    TWCR |= (1 << TWINT);
  }
  }
  // Data byte transmitted, NOT ACK received
  else if(status == 0xC0){
    TWCR |= (1 << TWINT) | (1 << TWEA);
  }
  // Last data byte transmitted (TWEA = 0), ACK received
  else if(status == 0xC8){

  }
}


Hauptprogramm:
void main(){

  DDRB = 0b00000010;

  PORTB = 0b00000010;

  uart_init();

  sei();

  char inbuffer[16];
  char outbuffer[16];

  uart_sendchar('h');
  i2c_init(0);
  i2c_setinputtarget(&inbuffer, 16);
  i2c_setoutputsource(&outbuffer, 16);

  uint32_t cnt = 0;

  while(1){
    asm volatile("nop");
  if(flags.uart_received){
    sensor_capture();
    PORTB = (~(PORTB)) & (0b00000010);
    flags.uart_received = 0;
    }
  if(flags.datacapture_ready){
      sensor_transmit();
    flags.datacapture_ready = 0;
  }
  }
}

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achja: Ein Nachtrag: Ich versuche in diesem Fall den Slave per 
General-Call zu erreichen, um mögliche Fehler bei der Adressierung 
auszuschliessen.

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das:
> TWCR &= ~((1 << TWSTA) | (1 << TWSTO));
wird doch zu:
TWCR &= 0b11001111;
dadurch eine 1 ins TWINT gesschrieben (bit 7 - ist gesetzt, wenn die 
ISR aufgerufen wird) und so TWINT gelöscht (ist ein Flag!) und sagt der 
TWI Hardware 'weitermachen'.
Die ganze Zeile scheint mir überflüssig.
Schau dir doch mal die Atmel-Appnotes zum TWI an (AVR312 und 315).

hth. Jörg

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm...die Zeile wird aber bisher noch nicht mal ausgeführt :-) (Ich 
komme ja noch nicht mal bis zum Interrupt...)

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bin mittlerweile einen Schritt weiter: Offenbar liegts tatsächlich am 
Master. Ich kann dort nämlich machen was ich will, er meldet immer START 
sent und danach SLA+R sent, NOT ACK received. Stets SLA+R, egal wie ich 
das dazugehörige Bit setze.

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TWDR wird auf dem Master tatsächlich nicht geschrieben und hat immer den 
Inhalt FF. Laut Datenblatt kann TWDR nur geschrieben werden, wenn TWINT 
gesetzt ist - ist es eigentlich auch, da ja sonst der Interrupt nicht 
ausgelöst würde und ich es auch nicht gelöscht habe.

Doch warum frisst mein TWDR keine Daten?

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, das Problem ist gelöst, es lag am Master. Der nämlich verschickte 
eine völlig unnsinnige Adresse, so dass sich der Slave niemals 
angesprochen fühlte. Die Adresse muss beim Master ins TWDR gespeichert 
werden, das wiederum kann nur wenn TWINT gesetzt ist geschrieben werden. 
Nun kam es unglücklicherweise tatsächlich dazu, dass ich TWINT gelöscht 
habe, vor dem Schreiben der Adresse...

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.