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


von mr.chip (Gast)


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:
1
struct{
2
  unsigned char read:1;
3
4
  char * outbuffer;
5
  uint8_t outptr;
6
  uint8_t outlen;
7
8
  char * inbuffer;
9
  uint8_t inptr;
10
  uint8_t inlen;
11
}i2c;
12
13
void i2c_init(uint8_t addr){
14
  TWAR = (addr << 1) | 1;
15
  TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
16
}
17
18
void i2c_setinputtarget(char * buffer[], uint8_t len){
19
  i2c.inbuffer = buffer;
20
  i2c.inlen = len;
21
  i2c.inptr = 0;
22
}
23
24
void i2c_setoutputsource(char * buffer[], uint8_t len){
25
  i2c.outbuffer = buffer;
26
  i2c.outlen = len;
27
  i2c.outptr = 0;
28
}
29
30
void i2c_received(){
31
  uint8_t i = 0;
32
  for(i = 0; i < i2c.inlen; i ++)
33
    uart_sendchar(*(i2c.inbuffer + i));
34
}


TWI-ISR:
1
//TWI-Interrupt
2
ISR(TWI_vect){
3
  PORTB = 0b00000000;
4
  uart_sendchar('x');
5
  uint8_t status = TWSR & 0b11111100;
6
  TWCR &= ~((1 << TWSTA) | (1 << TWSTO));
7
  
8
  // Own SLA+W received, ACK returned
9
  if(status == 0x60){
10
    i2c.inptr = 0;
11
    TWCR |= (1 << TWINT) | (1 << TWEA);
12
  }
13
  // Arbitration lost
14
  else if(status == 0x68){
15
16
  }
17
  // General call address received, ACK returned
18
  else if(status == 0x70){
19
20
  }
21
  // Arbitration lost
22
  else if(status == 0x78){
23
24
  }
25
  // Data received, ACK returned
26
  else if(status == 0x80){
27
    uart_sendchar(TWDR);
28
    if(i2c.inptr < i2c.inlen - 1){
29
      *(i2c.inbuffer + i2c.inptr) = TWDR;
30
    i2c.inptr ++;
31
    TWCR |= (1 << TWINT) | (1 << TWEA);
32
  }
33
  else{
34
      *(i2c.inbuffer + i2c.inptr) = TWDR;      
35
    i2c.inptr ++;
36
    TWCR |= (1 << TWINT);
37
    TWCR &= ~(1 << TWEA);
38
  }
39
  }
40
  // Data received, NOT ACK returned
41
  else if(status == 0x88){
42
    *(i2c.inbuffer + i2c.inptr) = TWDR;
43
    TWCR |= (1 << TWINT) | (1 << TWEA);
44
  i2c_received();
45
  }
46
  // General-Call Data received, ACK returned
47
  else if(status == 0x90){
48
49
  }
50
  // General-Call Data received, NOT ACK returned
51
  else if(status == 0x98){
52
53
  }
54
  // STOP or REPEATED START condition received
55
  else if(status == 0xA0){
56
    TWCR |= (1 << TWINT) | (1 << TWEA);
57
  }
58
  // SLA+R received, ACK returned
59
  else if(status == 0xA8){
60
    i2c.outptr = 0;
61
    if(i2c.outptr < i2c.outlen - 1){
62
      TWDR = *(i2c.outbuffer + i2c.outptr);
63
    i2c.outptr ++;
64
    TWCR |= (1 << TWINT) | (1 << TWEA);
65
  }
66
  else{
67
      TWDR = *(i2c.outbuffer + i2c.outptr);
68
      TWCR &= ~(1 << TWEA);
69
    TWCR |= (1 << TWINT);
70
  }
71
  }
72
  // Arbitration lost
73
  else if(status == 0xB0){
74
75
  }
76
  // Data byte transmitted, ACK received
77
  else if(status == 0xB8){
78
    if(i2c.outptr < i2c.outlen - 1){
79
      TWDR = *(i2c.outbuffer + i2c.outptr);
80
    i2c.outptr ++;
81
    TWCR |= (1 << TWINT) | (1 << TWEA);
82
  }
83
  else{
84
      TWDR = *(i2c.outbuffer + i2c.outptr);
85
      TWCR &= ~(1 << TWEA);
86
    TWCR |= (1 << TWINT);
87
  }
88
  }
89
  // Data byte transmitted, NOT ACK received
90
  else if(status == 0xC0){
91
    TWCR |= (1 << TWINT) | (1 << TWEA);
92
  }
93
  // Last data byte transmitted (TWEA = 0), ACK received
94
  else if(status == 0xC8){
95
96
  }
97
}


Hauptprogramm:
1
void main(){
2
3
  DDRB = 0b00000010;
4
5
  PORTB = 0b00000010;
6
7
  uart_init();
8
9
  sei();
10
11
  char inbuffer[16];
12
  char outbuffer[16];
13
14
  uart_sendchar('h');
15
  i2c_init(0);
16
  i2c_setinputtarget(&inbuffer, 16);
17
  i2c_setoutputsource(&outbuffer, 16);
18
19
  uint32_t cnt = 0;
20
21
  while(1){
22
    asm volatile("nop");
23
  if(flags.uart_received){
24
    sensor_capture();
25
    PORTB = (~(PORTB)) & (0b00000010);
26
    flags.uart_received = 0;
27
    }
28
  if(flags.datacapture_ready){
29
      sensor_transmit();
30
    flags.datacapture_ready = 0;
31
  }
32
  }
33
}

von mr.chip (Gast)


Lesenswert?

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

von Jörg X. (Gast)


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

von mr.chip (Gast)


Lesenswert?

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

von mr.chip (Gast)


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.

von mr.chip (Gast)


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?

von mr.chip (Gast)


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...

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
Noch kein Account? Hier anmelden.