Forum: Mikrocontroller und Digitale Elektronik AVR TWI/I2C: 0xff wird empfangen


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hi zusammen,

ich hab hier eigenartiges Phänomen, und find den Fehler nicht:

zwei ATmega328P kommunizieren per i2c miteinander, einer Master einer 
Slave, Master frägt alle 10 msec und Slave antwortet mit einem int32_t, 
also vier Byte.

Das ganze funktioniert soweit wunderbar, aber von Zeit zu zeit empfange 
ich -1 also 0xffffffff.

Das problem liegt definitiv am Empfänger = Master, ich hab testweise die 
i2c-Routine des Slaves so modifiziert dass TWDR beim Daten senden hart 
auf 0x66 gesetzt wird. Ich empfange dann auch 0x66666666, aber ab und an 
wieder 0xffffffff. Ursache kann eigentlich nur sein, dass TWDR eben 0xff 
enthält. Eigenartigerweise schaut der Transfer sonst ganz normal aus, es 
kommen vier Bytes, kein Fehler, nächster Transfer ist dann idR auch 
wieder in Ordnung.

Der i2c-Receiver ist interrupt-basierend, und die empfangenden Werte 
werden auch ausschließlich in den Stati "Data byte has been received; 
ACK has been returned" (erste bytes) und "Data byte has been received; 
NOT ACK has been returned" (letztes Byte) verarbeitet.

Gibts da noch irgendein Flag das mir einen Fehler mitteilen möchte? 
Vielleicht ein Timeout? Aber dann hätt ich doch im TWI-Status-Register 
nciht absolut plausible werte stehen?

Es kann doch auch nciht sein dass irgendwas mir die SDA auf low zieht, 
dann würde ja schon die ganze Slave-Adressierung usw. nicht 
funktionieren...

Hat bitte bitte jemand eine idee was da faul sein könnte?

von Klaus 2. (klaus2m5)


Lesenswert?

Wie kommst Du darauf, dass es definitiv am Master liegt? 0xff ist 
typisch für einen Slave, der SDA nicht ansteuert. Bekommst Du nach der 
Read Adresse immer ein ACK vom Slave?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Klaus 2m5 schrieb:
> Wie kommst Du darauf, dass es definitiv am Master liegt?

"definitiv" ist natürlich relativ :-)

> 0xff ist typisch für einen Slave, der SDA nicht ansteuert. Bekommst Du
> nach der Read Adresse immer ein ACK vom Slave?

Ja, sonst würde mir die TWI-State Machine ja gar nicht erst in den 
lese-Teil springen.

von Tim (Gast)


Lesenswert?

Code?
Hast du eine I2C monitor? Oszi?
Vielleicht sendet der Slave ja auch nicht?
Mal auf beiden Seiten einen Zähler eingebaut und
geprüft ob die gleichmäßig hoch laufen?
Fehlerbehandlung und Zähler eingebaut?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Tim schrieb:
> Code?
Bitte gerne.

> Hast du eine I2C monitor? Oszi?
I2C-Monitor nicht, Billigst-Oszi schon, aber kein Speicher-oszi. Da 
geschätzte 99% der Übertragungen problemlos funktionieren, wirds mit 
meinem oszi schwierig...

> Vielleicht sendet der Slave ja auch nicht?
Dann würde er auch kein ACK auf das SLA+R senden?

> Mal auf beiden Seiten einen Zähler eingebaut und
> geprüft ob die gleichmäßig hoch laufen?
Wie meinst du das?


Code des Slave-Transmitters/Receivers:
1
/* $Id: i2c_slave.c 371 2013-04-12 16:17:31Z michi $
2
 * $URL: https://svn.trisoft.at/AVR/StepCtrl/i2c_slave.c $
3
 *
4
 * simple I2C slave
5
 *
6
 * Copyright (C) 2013 Michael Reinelt <michael@reinelt.co.at>
7
 *
8
 */
9
10
11
#include <stdint.h>
12
#include <avr/interrupt.h>
13
#include <util/twi.h>
14
15
#include "i2c_slave.h"
16
17
18
#define I2C_PORT PORTC
19
#define I2C_DDR DDRC
20
#define I2C_SDA _BV(4)
21
#define I2C_SCL _BV(5)
22
#define I2C_FREQ 100000L  // 100 kHz
23
24
#define I2C_PACKETSIZE 64  // maximum receive bytes
25
26
static volatile uint8_t I2C_RxBuffer[I2C_PACKETSIZE];
27
static volatile uint8_t I2C_RxIndex;
28
static volatile uint8_t I2C_TxBuffer[I2C_PACKETSIZE];
29
static volatile uint8_t I2C_TxIndex;
30
static volatile uint8_t I2C_TxLength;
31
static volatile uint8_t I2C_busy;
32
static volatile uint8_t I2C_error;
33
34
35
// hack to report current stepper position
36
extern uint32_t Stepper_position;
37
38
39
void i2c_start(const uint8_t address)
40
{
41
    I2C_DDR &= ~(I2C_SCL | I2C_SDA);  // set pins to input
42
    I2C_PORT &= ~(I2C_SCL | I2C_SDA);  // no internal pullups on slave
43
44
    // init transceiver
45
    I2C_RxIndex = 0;
46
    I2C_busy = 0;
47
    I2C_error = 0;
48
49
    // enable I2C  
50
    TWSR &= ~(TWPS0 | TWPS1);  // prescaler
51
    TWBR = ((F_CPU / I2C_FREQ) - 16) / 2;  // bit rate
52
    TWAR = address << 1;  // set I2C address
53
    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // fully enable TWI
54
}
55
56
57
uint8_t i2c_busy(void)
58
{
59
    return I2C_busy;
60
}
61
62
63
uint8_t i2c_get(uint8_t * data, uint8_t len)
64
{
65
    if (I2C_busy) {
66
  // Transceiver currently busy
67
  return 0;
68
    }
69
70
    if (I2C_error) {
71
  // recover from error
72
  I2C_error = 0;
73
  I2C_RxIndex = 0;
74
    }
75
    // maybe we have less data than expected
76
    if (len > I2C_RxIndex)
77
  len = I2C_RxIndex;
78
79
    // copy data to caller buffer
80
    for (uint8_t i = 0; i < len; i++) {
81
  data[i] = I2C_RxBuffer[i];
82
    }
83
    I2C_RxIndex = 0;
84
85
    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // fully (re-)enable TWI
86
87
    return len;      // number of bytes received
88
}
89
90
// I2C ISR
91
ISR(TWI_vect)
92
{
93
    // code based on tables 21.4..6 from ATmega328 data sheet
94
95
    switch (TW_STATUS) {
96
97
    case 0x00:      // Bus error due to an illegal START or STOP condition
98
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
99
  I2C_busy = 0;    // transmission aborted
100
  I2C_error = 1;    // set error flag
101
  break;
102
103
    case 0x60:      // own SLA+W has been received; ACK has been returned
104
    case 0x68:      // own SLA+W has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
105
    case 0x70:      // general call address has been received; ACK has been returned
106
    case 0x78:      // general call address has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
107
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // send ACK
108
  I2C_RxIndex = 0;  // reset packet index
109
  I2C_busy = 1;    // transmission started
110
  break;
111
112
    case 0x80:      // previously addressed with own SLA+W; data has been received; ACK has been returned
113
    case 0x88:      // previously addressed with own SLA+W; data has been received; NAK has been returned
114
    case 0x90:      // previously addressed with general call; data has been received; ACK has been returned
115
    case 0x98:      // previously addressed with general call; data has been received; NAK has been returned
116
  if (I2C_RxIndex < I2C_PACKETSIZE) {
117
      I2C_RxBuffer[I2C_RxIndex++] = TWDR;  // store received data
118
  }
119
  if (I2C_RxIndex < I2C_PACKETSIZE) {
120
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // send ACK
121
  } else {
122
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // last byte, send NAK
123
  }
124
  break;
125
126
    case 0xA8:      // own SLA+R has been received; ACK has been returned
127
    case 0xB0:      // own SLA+R has been received; ACK has been returned; Arbitration lost in SLA+R/W as Master
128
  *(uint32_t *) I2C_TxBuffer = Stepper_position;  // hack to report current stepper position
129
  I2C_TxLength = 4;  // we have 4 bytes
130
  I2C_TxIndex = 0;  // reset packet index
131
  I2C_busy = 1;    // transmission started
132
    case 0xB8:      // data byte in TWDR has been transmitted; ACK has been received
133
  if (I2C_TxIndex < I2C_TxLength) {
134
      TWDR = I2C_TxBuffer[I2C_TxIndex++];  // transmit next byte
135
  } else {
136
      TWDR = 0;    // we have nothing more...
137
  }
138
  if (I2C_TxIndex < I2C_TxLength) {
139
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // send ACK
140
  } else {
141
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // last byte: send NAK
142
  }
143
  break;
144
145
    case 0xA0:      // a STOP condition or repeated START condition has been received while still addressed as Slave
146
    case 0xC0:      // data byte in TWDR has been transmitted; NAK has been received
147
    case 0xC8:      // last data byte in TWDR has been transmitted (TWEA = 0); ACK has been received
148
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // re-enable twi
149
  I2C_busy = 0;    // transmission ended
150
  break;
151
152
    case 0xF8:      // no relevant state information available; TWINT = 0
153
    default:      // all other states
154
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
155
  I2C_busy = 0;    // transmission aborted
156
  I2C_error = 1;    // something strange happened
157
  break;
158
    }
159
}

Code des Masters:
1
/* $Id: i2c_master.c 254 2013-02-18 05:04:27Z michi $
2
 * $URL: https://svn.trisoft.at/AVR/RoboCtrl/i2c_master.c $
3
 *
4
 * simple I2C master
5
 *
6
 * Copyright (C) 2013 Michael Reinelt <michael@reinelt.co.at>
7
 *
8
 */
9
10
#include <stdint.h>
11
#include <avr/interrupt.h>
12
#include <util/twi.h>
13
#include <util/delay.h>
14
15
#include "i2c_master.h"
16
17
18
#define I2C_PORT PORTC
19
#define I2C_DDR DDRC
20
#define I2C_SDA _BV(4)
21
#define I2C_SCL _BV(5)
22
#define I2C_FREQ 100000L  // 100 kHz
23
24
static volatile uint8_t I2C_slarw;
25
static volatile uint8_t *I2C_Packet;
26
static volatile uint8_t I2C_PacketSize;
27
static volatile uint8_t I2C_PacketIndex;
28
static volatile uint8_t I2C_busy;
29
static volatile uint8_t I2C_status;
30
static volatile uint8_t I2C_error;
31
32
33
void i2c_init(void)
34
{
35
36
    I2C_DDR &= ~(I2C_SCL | I2C_SDA);  // set pins to input
37
    I2C_PORT |= (I2C_SCL | I2C_SDA);  // enable pullups
38
39
    // init transceiver
40
    I2C_PacketSize = 0;
41
    I2C_PacketIndex = 0;
42
    I2C_busy = 0;
43
    I2C_status = 0;
44
    I2C_error = 0;
45
46
    // enable I2C  
47
    TWSR &= ~(TWPS0 | TWPS1);  // prescaler
48
    TWBR = ((F_CPU / I2C_FREQ) - 16) / 2;  // bit rate
49
    TWDR = 0xFF;    // Default content = SDA released.
50
    TWCR = _BV(TWEN);    // enable TWI to standby state
51
}
52
53
54
uint8_t i2c_busy(void)
55
{
56
    return I2C_busy;
57
}
58
59
60
static uint8_t i2c_start(uint8_t slarw, uint8_t * data, uint8_t len)
61
{
62
    while (I2C_busy);    // wait until i2c is idle
63
    I2C_slarw = slarw;    // slave address + R/W bit
64
    I2C_Packet = data;    // set buffer pointer
65
    I2C_PacketSize = len;  // expected number of bytes
66
    I2C_PacketIndex = 0;  // reset buffer index
67
    I2C_busy = 1;    // Transmission in progress
68
    I2C_status = 0;    // reset TWI status
69
    I2C_error = 0;    // reset error flag
70
    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWSTA);  // enable TWI and send START
71
    while (I2C_busy);    // wait until i2c is idle
72
    return I2C_error;
73
}
74
75
76
uint8_t i2c_get(uint8_t address, uint8_t * data, uint8_t len)
77
{
78
    for (uint16_t i = 10000; i > 0; i--) {
79
  uint8_t ret = i2c_start((address << 1) + 1, data, len);
80
  if (ret == 0 || I2C_status != 0x48)
81
      return ret;
82
  // slave may be busy, retry
83
  _delay_us(10);
84
    }
85
    return 1;
86
}
87
88
89
uint8_t i2c_put(uint8_t address, uint8_t * data, uint8_t len)
90
{
91
    for (uint16_t i = 10000; i > 0; i--) {
92
  uint8_t ret = i2c_start((address << 1) + 0, data, len);
93
  if (ret == 0 || I2C_status != 0x20)
94
      return ret;
95
  // slave may be busy, retry
96
  _delay_us(10);
97
    }
98
    return 1;
99
}
100
101
102
// I2C ISR
103
ISR(TWI_vect)
104
{
105
    // code based on tables 22.2..6 from ATmega328 data sheet
106
107
    switch (TW_STATUS) {
108
109
    case 0x08:      // A START condition has been transmitted
110
    case 0x10:      // A repeated START condition has been transmitted
111
  TWDR = I2C_slarw;  // send slave address + R/W
112
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // send byte
113
  break;
114
115
    case 0x18:      // SLA+W has been transmitted; ACK has been received
116
    case 0x28:      // Data byte has been transmitted; ACK has been received
117
  if (I2C_PacketIndex < I2C_PacketSize) {
118
      TWDR = I2C_Packet[I2C_PacketIndex++];
119
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // send byte
120
  } else {
121
      TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);  // send STOP after last byte
122
      I2C_busy = 0;  // Transmission finished
123
  }
124
  break;
125
126
    case 0x38:      // Arbitration lost
127
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWSTA);  // Initiate a (RE)START condition
128
  break;
129
130
    case 0x40:      // SLA+R has been transmitted; ACK has been received
131
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // Send ACK after reception
132
  break;
133
134
    case 0x50:      // Data byte has been received; ACK has been returned
135
  if (I2C_PacketIndex < I2C_PacketSize) {
136
      I2C_Packet[I2C_PacketIndex++] = TWDR;  // store received data
137
  }
138
  if (I2C_PacketIndex < I2C_PacketSize) {
139
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // Send ACK after reception
140
  } else {
141
      TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);  // Send NAK after reception of last byte
142
  }
143
  break;
144
145
    case 0x58:      // Data byte has been received; NOT ACK has been returned
146
  if (I2C_PacketIndex < I2C_PacketSize) {
147
      I2C_Packet[I2C_PacketIndex++] = TWDR;  // store received data
148
  }
149
  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);  // Send STOP
150
  I2C_busy = 0;    // Transmission finished
151
  break;
152
153
    case 0x20:      // SLA+W has been transmitted; NOT ACK has been received
154
    case 0x30:      // Data byte has been transmitted; NOT ACK has been received
155
    case 0x48:      // SLA+R has been transmitted; NOT ACK has been received
156
    case 0xF8:      // No relevant state information available; TWINT = “0”
157
    case 0x00:      // Bus error due to an illegal START or STOP condition
158
    default:
159
  I2C_busy = 0;    // transmission aborted
160
  I2C_status = TW_STATUS;  // keep TWI status
161
  I2C_error = 1;    // set error flag
162
  TWCR = _BV(TWEN);  // Reset TWI
163
  break;
164
    }
165
}

Der Slave sendet bei Anfrage den int32_t Stepper_position.

Der Master fragt 100mal in der Sekunde per i2c_get(0x66, &int32_var, 
sizeof(int32_var) ab.

von Klaus 2. (klaus2m5)


Lesenswert?

Ich würde mir an Deiner Stelle einen Trace bauen: Die letzten 20 
Statuscodes in einem Array speichern und wenn Du 0xffffffff 
zurückbekommst ausgeben.

von Tim (Gast)


Lesenswert?

>> Hast du eine I2C monitor? Oszi?
>I2C-Monitor nicht, Billigst-Oszi schon, aber kein Speicher-oszi.
Hier im Forum sind ein parr I2C Monitore beschrieben.
Definitiv eine Anschaffung wert.

>> Vielleicht sendet der Slave ja auch nicht?
>Dann würde er auch kein ACK auf das SLA+R senden?
Nun wenn du alles ausschließt muss die Übertragung ja auch
immer zu 100% funktionieren....

>> Mal auf beiden Seiten einen Zähler eingebaut und
>> geprüft ob die gleichmäßig hoch laufen?
>Wie meinst du das?
Nun, nach erfolgreichem Abschluss der Übertragung auf
beiden Seiten einen Zähler erhöhen. Dann weisst du
wenigstens ob die Routinen der Ansicht sind das alles OK ist.
Fehlerzähler sind natürlich Pflicht.

Ich habe mir den Code durchgelesen aber keinen offensichtlichen
Fehler finden können.
Ich gehe mal davon aus das du den return wert von i2c_get auswertest.
Externen Pullups hat du dran?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

bin leider erst jetzt dazu gekommen, mir das genauer anzuschauen.

ja, externe Pullups (je 4k7 am Master und am Slave) sind dran.

Ich hab mal die idee aufgegriffen, mir die letzten 32 TWI-Stati am 
Master receiver zu merken, und im Fall dass ich 0xff empfange, 
auszugeben.

Das Ergebnis hilft nciht wirklich weiter:

0x58 // Data byte has been received; NOT ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x40 // SLA+R has been transmitted; ACK has been received
0x08 // A START condition has been transmitted
0x58 // Data byte has been received; NOT ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x40 // SLA+R has been transmitted; ACK has been received
0x08 // A START condition has been transmitted
0x58 // Data byte has been received; NOT ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x50 // Data byte has been received; ACK has been returned
0x40 // SLA+R has been transmitted; ACK has been received
0x08 // A START condition has been transmitted

Die hex-Werte sind Echtdaten, die "Übersetzungen" hab ich händisch 
hinzugefügt.

Die Tabelle ist "umgedreht", neuester Eintrag ist oben.

Die letzte Übertragung liefert 4x 0xff, die anderen "normale" Werte. Die 
Übertragungen schauen aber alle gleich aus, keine Fehler, keine 
Ausreisser im Status, und entsprechen genau meinen Erwartungen bzw. auch 
der Auflistung aus dem ATmega-Datenblatt:

1. master Receiver sendet ein "START" um den Bus zu kriegen
2. Master Receiver sendet SLA+R und adressiert damit den Slave
3. Slave antwortet mit ACK
4. Slave schickt der reihe nach die Daten, master antwortet mit ACK bzw. 
mit NAK beim letzten Byte

Als nächstes werd ich halt versuchen sowas ähnliches am Slave zu 
implementieren, wird nur etwas lästiger weil ich dort keinen UART habe 
um die Debug-Daten auszugeben.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

So, ich bin einen Schritt weiter: Das problem tritt immer dann auf, wenn 
am Slave der Status 0xf8 " no relevant state information available; 
TWINT = 0" auftritt.

ich weiss leider nicht wirklich, was dieser Status bedeutet, wann und 
warum er auftritt, und wie ich am besten darauf reagieren soll. Aus dem 
Datenblatt werd ich nciht wirklich schlau...

Kann mir da jemand weiterhelfen?

von Harald M. (mare_crisium)


Lesenswert?

Michael,
wenn ich mich nicht täusche, müsste der Master nach dem Empfang des 
abschliessenden NAK vom Sklaven ein STOP-Signal senden!? Ohne das STOP 
erscheint dem Sklaven das nächste START als "repeated Start-Signal".

Ciao,
mare_crisium

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Harald M. schrieb:
> wenn ich mich nicht täusche, müsste der Master nach dem Empfang des
> abschliessenden NAK vom Sklaven ein STOP-Signal senden!? Ohne das STOP
> erscheint dem Sklaven das nächste START als "repeated Start-Signal".

Tut er doch:
1
    case 0x58:      // Data byte has been received; NOT ACK has been returned
2
  if (I2C_PacketIndex < I2C_PacketSize) {
3
      I2C_Packet[I2C_PacketIndex++] = TWDR;  // store received data
4
  }
5
  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);  // Send STOP
6
  I2C_busy = 0;    // Transmission finished
7
  break;

von Klaus 2. (klaus2m5)


Lesenswert?

0xf8 sollte nie einen Interrupt erzeugen (TWINT=0)! Trotzdem scheint der 
Slave die Interrupt Routine zu durchlaufen. Hast Du vielleicht einen 
Interrupt enabled, der vor dem TWI Vektor liegt, aber keinen Vektor 
definiert?

0xf8 ist wohl eher nur ein Status, der ohne Interrupts zum Tragen kommt, 
wenn das Program periodisch TWSR abfragt. Auf jeden Fall ist es kein 
Fehlerstatus und die ISR sollte einfach nichts tun, also nicht
1
    case 0xF8:      // no relevant state information available; TWINT = 0
2
    default:      // all other states
3
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
4
  I2C_busy = 0;    // transmission aborted
5
  I2C_error = 1;    // something strange happened
6
  break;
sondern
1
    case 0xF8:      // no relevant state information available; TWINT = 0
2
  break;
3
    default:      // all other states
4
  TWCR = _BV(TWSTO) | _BV(TWINT);  // return to a well-defined unaddressed slave mode and release SCL and SDA
5
  I2C_busy = 0;    // transmission aborted
6
  I2C_error = 1;    // something strange happened
7
  break;

Harald M. schrieb:
> wenn ich mich nicht täusche, müsste der Master nach dem Empfang des
> abschliessenden NAK vom Sklaven ein STOP-Signal senden!? Ohne das STOP
> erscheint dem Sklaven das nächste START als "repeated Start-Signal".

Für den Slave besteht zwischen STOP...START und repeated START kein 
Unterschied. STOP wird nur in einer Multimaster Umgebung gebraucht, um 
dem anderen Master(s) mitzuteilen, dass der Bus jetzt wieder frei ist.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Klaus 2m5 schrieb:
> 0xf8 sollte nie einen Interrupt erzeugen (TWINT=0)! Trotzdem scheint der
> Slave die Interrupt Routine zu durchlaufen. Hast Du vielleicht einen
> Interrupt enabled, der vor dem TWI Vektor liegt, aber keinen Vektor
> definiert?

Nein, kein falscher/fehlender Vektor.

Offensichtlich ist das schon ein Interrupt, aber ein irgendwie 
spezieller. Auch die Application Notes avr311 und avr315 bzw. der 
Beispielcode dort ist sich nciht ganz sicher wie damit umzugehen ist :-)

> 0xf8 ist wohl eher nur ein Status, der ohne Interrupts zum Tragen kommt,
> wenn das Program periodisch TWSR abfragt. Auf jeden Fall ist es kein
> Fehlerstatus und die ISR sollte einfach nichts tun
Danke, da hast du natürlich recht! Hat mein problem aber nicht gelöst...

Aber ich bin guter Hoffnng den Fehler schlussendlich gefunden zu haben: 
der Slave ruft in der MainLoop periodisch i2c_get() auf, um auf 
Kommandos des masters zu reagieren. Und dabei wird am TWCR 
herumgespielt, was so nicht sein darf.

Ich muss das jetzt überdenken, halte euch aber am laufenden!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Yep, das wars. Ich bin ein Trottel :-)


in der i2c_get() vom Slave wurde generell und immer folgende zeile 
ausgeführt:
1
   TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);  // fully (re-)enable TWI

und das hat natürlich eine gerade laufende Transaktion gehörig 
durcheinandergebracht.

Die zeile ist so schon korrekt, gehört aber nur ausgeführt wenn ein 
Fehler aufgetreten ist (also im "if I2C_error" zweig)


Danke euch allen!

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.