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?
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?
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.
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?
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.
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.
>> 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?
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.
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?
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
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; |
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.
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.