Forum: Mikrocontroller und Digitale Elektronik Daten über I2C von AtTiny85 als Slave auslesen / TinyWireS Lib


von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Hallo zusammen,

das Jahr des Mad Max 2021 geht langsam zu Ende und bald fahren wir in 
die Donnerkuppel ein; zumindest Einige...

.. und ich bekomme den I2C Slave nicht hin.
Ich suchte nach einer extrem kostengünstigen Alternative einen I2C Slave 
zu bauen. Auf der Suche nach einem Bauteil blieb ich beim AtTiny85 und 
der TinyWireS Lib hängen. Soweit so gut.

Die Wire.h Lib vom Arduino funktioniert mit dem AtTiny85 nicht. Aus dem 
Grund verwendete ich die TinyWireS Lib. Von dieser Lib existieren einige 
Versionen. Es gibt die Version die arbeiten mit Events/Interrupt Handler 
und welche die arbeiten ohne diesen Mechanismus im Hauptprogram. Also 
OnRequest/ OnResponse usw. meine ich damit. Ich habe wohl die 
ursprüngliche Version erwischt die ohne Interrupt im Hauptprogramm 
arbeitet.
1
#include <TinyWireS.h>
2
#include <usiTwiSlave.h>
3
#define I2C_SLAVE_ADDR  0x44            // i2c slave address (38)
4
#define LED1_PIN         4              // ATtiny Pin 3
5
#define LED2_PIN         1              // ATtiny Pin 6
6
7
void setup(){
8
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
9
  pinMode(LED2_PIN,OUTPUT);             // for verification
10
  Blink(LED1_PIN, 4);                    // show it's alive
11
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode  
12
}
13
14
void loop() {   
15
byte byteRcvd = 0;
16
  while (TinyWireS.available()){        // got I2C input!
17
    byteRcvd = TinyWireS.receive();     // get the byte from master
18
    // master must wait for this to finish before calling Wire.requestFrom
19
    byteRcvd += 1;                     // add 10 to what's received
20
    //Blink(LED1_PIN, sendBack); 
21
    byteRcvd = 0x42;
22
    TinyWireS.send(byteRcvd);           // send it back to master
23
  }
24
}
25
void Blink(byte led, byte times){ // poor man's display
26
  for (byte i=0; i< times; i++){
27
    digitalWrite(led,HIGH);
28
    delay (250);
29
    digitalWrite(led,LOW);
30
    delay (250);
31
  }
32
}

Das Senden zum Slave funktioniert soweit. Alledings muss ich beim 
Response vom Slave zum Master immer 0x00 zurückgeben! Das sieht aus wenn 
der Wert wie ein Rückgabecode behandelt würde.

Ich bin den Code unter der Arduino "IDE" über die TinyWireS  bis zur 
usiTwiSlave Library gefolgt. (TinyWireS.send(byteRcvd);)

In der usiTwiSlave werden die Daten in der ISR gesendet:
1
ISR( USI_OVERFLOW_VECTOR )
2
{
3
4
  switch ( overflowState )
5
  {
6
7
    // Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK,
8
    // else reset USI
9
    case USI_SLAVE_CHECK_ADDRESS:
10
      if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) )
11
      {
12
          if ( USIDR & 0x01 )
13
        {
14
          overflowState = USI_SLAVE_SEND_DATA;
15
        }
16
        else
17
        {
18
          overflowState = USI_SLAVE_REQUEST_DATA;
19
        } // end if
20
    TxLock();
21
        SET_USI_TO_SEND_ACK( );
22
    TxUnLock();
23
      }
24
      else
25
      {
26
        SET_USI_TO_TWI_START_CONDITION_MODE( );
27
      }
28
      break;
29
30
    // Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK,
31
    // else reset USI
32
    case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
33
      if ( USIDR )
34
      {
35
        // if NACK, the master does not want more data
36
        SET_USI_TO_TWI_START_CONDITION_MODE( );
37
        return;
38
      }
39
      // from here we just drop straight into USI_SLAVE_SEND_DATA if the
40
      // master sent an ACK
41
42
    // copy data from buffer to USIDR and set USI to shift byte
43
    // next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
44
    case USI_SLAVE_SEND_DATA:
45
      // Get data from Buffer
46
      if ( txHead != txTail )
47
      {
48
        txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
49
    TxLock();  
50
    //txBuf[txTail] = 0;
51
      //USIDR = txBuf[ txTail ]; //txBuffer;
52
    USIDR = 0x00; // <<<=================hier
53
    //USI_SET_SDA_OUTPUT();
54
    //DDR_USI |=  (1 << PORT_USI_SDA);
55
    //PORT_USI |= (1 << PORT_USI_SDA);    
56
    TxUnLock();
57
      }
58
      else
59
      {
60
        // the buffer is empty
61
        SET_USI_TO_TWI_START_CONDITION_MODE( );
62
        return;
63
      } // end if
64
      overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
65
      SET_USI_TO_SEND_DATA( );
66
    //UsiBlink(4, 25);
67
      break;
68
69
    // set USI to sample reply from master
70
    // next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
71
    case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
72
      overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
73
    TxLock();
74
      SET_USI_TO_READ_ACK( );
75
    TxUnLock();
76
      break;
77
78
    // Master read data mode: set USI to sample data from master, next
79
    // USI_SLAVE_GET_DATA_AND_SEND_ACK
80
    case USI_SLAVE_REQUEST_DATA:
81
      overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
82
      SET_USI_TO_READ_DATA( );
83
      break;
84
85
    // copy data from USIDR and send ACK
86
    // next USI_SLAVE_REQUEST_DATA
87
    case USI_SLAVE_GET_DATA_AND_SEND_ACK:
88
      // put data into buffer
89
      // Not necessary, but prevents warnings
90
      rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
91
      rxBuf[ rxHead ] = USIDR;
92
      // next USI_SLAVE_REQUEST_DATA
93
      overflowState = USI_SLAVE_REQUEST_DATA;
94
      SET_USI_TO_SEND_ACK( );
95
      break;
96
97
  } // end switch
98
99
} // end ISR( USI_OVERFLOW_VECTOR )

Vor "<<<=================hier" (case USI_SLAVE_SEND_DATA:) steht die 
Stelle wo das Register gesetzt wird. An der Stelle muß die Lib falsch 
sein.

Es gibt wohl laut Datenblatt eine Möglichkeit mit der man an der Stelle 
Adresswerte auf Register übergeben kann; - aber das funktioniert 
logischerweise mit uint_8 nicht.

Jetzt die Frage:
Was habe ich da nicht verstanden?

: Bearbeitet durch User
von Hans (Gast)


Lesenswert?

Hat der Attiny85 einen I2C Slave bzw. nutzbar dafür?

von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Schreiben geht, aber lesen geht nicht bei Rückgabewerten ungleich 0.

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Schreiben macht nur bei Ausgaben und Steuerungen Sinn. Das Lesen (von 
Nullwerten) sieht bei mir wie auf dem Bild aus. Wobei das Terminal am 
Ende scheinbar nicht antwortet...

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Hans schrieb:
> Hat der Attiny85 einen I2C Slave bzw. nutzbar dafür?

Ja, die TinyWireS Lib! Die Lib für den Master wäre die TinyWireM Lib!

von Oliver S. (oliverso)


Lesenswert?

Hans schrieb:
> Hat der Attiny85 einen I2C Slave bzw. nutzbar dafür?

Eigentlich hat der gar kein I2C. Der hat eine USI, mit der man so etwas 
ähnlich hinbasteln kann.

Andreas V. schrieb:
> Es gibt wohl laut Datenblatt eine Möglichkeit mit der man an der Stelle
> Adresswerte auf Register übergeben kann; - aber das funktioniert
> logischerweise mit uint_8 nicht.

Nun ja, diese Aussage ist irgendwie … gewagt, und zeigt ein gewisses 
Unverständnis über die Funktion der USI und I2C an sich.
Es wird dir nichts anderes übrig bleiben, als das Datenblatt zu 
verstehen, und dann die fragwürdige Libs aus dem Netz auf Fehler hin zu 
überprüfen.

Wenn’s ohne Arduino auch geht, würde ich mir das hier anschauen:
http://www.jtronics.de/avr-tutorial/avr-library-i2c-twi-slave-usi/

Oliver

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Nachtrag:

Andreas V. schrieb:
> //txBuf[txTail] = 0;
>       //USIDR = txBuf[ txTail ]; //txBuffer;
>     USIDR = 0x00; // <<<=================hier
>     //USI_SET_SDA_OUTPUT();
>     //DDR_USI |=  (1 << PORT_USI_SDA);
>     //PORT_USI |= (1 << PORT_USI_SDA);

Stammen die USIDR-Zeile und die Auskommentierungen von dir?
Wenn ja, warum?
Was passiert, wenn du den Original-Code laufen lässt?
Du hast deine zu sendenden Daten auch vor der eigentlichen 
I2C-Kommuniaktion in den txBuf-Buffer geschrieben, unter benutzung der 
dafür vorgesehenen Funktionen, die die Indizies richtig setzen, oder?

Oliver

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Oliver S. schrieb:
> Stammen die USIDR-Zeile und die Auskommentierungen von dir?
Die direkte Zuweisung ist von mir. Der Rest nicht.

> Wenn ja, warum?
Mit dem originalen Code lief der Client in Fehler!

> Was passiert, wenn du den Original-Code laufen lässt?
Fehler!
> Du hast deine zu sendenden Daten auch vor der eigentlichen
> I2C-Kommuniaktion in den txBuf-Buffer geschrieben, unter benutzung der
> dafür vorgesehenen Funktionen, die die Indizies richtig setzen, oder?
Geht so nicht. Es kann aber sein daß man dafür ein spezielles Terminal 
braucht!

von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb:
>> Wenn ja, warum?
> Mit dem originalen Code lief der Client in Fehler!

Geht das etwas genauer?
Wie sieht dann das Diagramm aus?

Oliver

von Oliver S. (oliverso)


Lesenswert?

Nachtrag:

Andreas V. schrieb:
> 1314void loop() {
> 15byte byteRcvd = 0;
> 16  while (TinyWireS.available()){        // got I2C input!
> 17    byteRcvd = TinyWireS.receive();     // get the byte from master
> 18    // master must wait for this to finish before calling
> Wire.requestFrom
> 19    byteRcvd += 1;                     // add 10 to what's received
> 20    //Blink(LED1_PIN, sendBack);
> 21    byteRcvd = 0x42;
> 22    TinyWireS.send(byteRcvd);           // send it back to master
> 23  }
> 24}

Hast du gelesen und verstanden, was das Programm tut?

Oliver

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

> Hast du gelesen und verstanden, was das Programm tut?
>
> Oliver

Wenn man das immer so genau wüßte!

Ich gehe mal davon aus ein normaler Master hält sich nicht an den 
Kommentar:
>> 18    // master must wait for this to finish before calling

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb im Beitrag #6898896
> Wenn man das immer so genau wüßte!

Das solltest du aber. Das, was da in loop steht, definiert, was der 
Slave macht. Das solltest du schon wissen, und der Master auch.

Oliver

von Heinrich (Gast)


Lesenswert?

Hast du dir mal den Attiny 841 angesehen?

von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Ich bin jetzt von den Tiefen in die tiefsten Tiefen der Library 
abgetaucht. Ehrlich gesagt wundere ich mich in letzter Zeit immer mehr. 
Die Aussage daß der ATTiny nur mit 8MHz läuft gab mir zu denken!!! Was 
mir auffiel waren Acks die zu früh geschickt wurden und kollidierten.

Die Stelle beim Senden zum Master wo die Bits verschoben werden konnten 
auch nicht funktionieren. An der Stelle kam immer 0x00 oder 0xFF zurück.
1
#define SET_USI_TO_SEND_DATA( ) \
2
{ \
3
  /* set SDA as output */ \
4
  DDR_USI |=  ( 1 << PORT_USI_SDA ); \  
5
  /* clear all interrupt flags, except Start Cond */ \
6
  USISR    =  \
7
       ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
8
       ( 1 << USIDC)| \
9
       /* set USI to shift out 8 bits */ \
10
       ( 1 << USICNT0 ); \
11
}

"( 0 << USICNT0 );"  setzte ich auf "( 1 << USICNT0 );" was mir 
logischer erschien. Und schon kann ich auch Werte schicken.
Jetzt kann man auch Werte unterschiedlich von 0x00 und 0xff senden.

Grundsätzlich kann der Code mit speziellen ATTiny's funktionieren. 
Allerdings scheint mein ATTiny85 aus der Rolle zu fallen, weil sich die 
technischen Werte geringfügig unterscheiden.

Was mir auffiel war daß man versucht Daten unsynchronisiert in einen 
Puffer(Array) zu schreiben und dann zu senden. Dadurch entstehen 
Synchronisierubngsfehler und der Slave crasht.

Ich habe angefangen die Library zu synchronisieren. Ich nutze momentan 
nur das erste Arrayelement im Puffer. Und schon fallen viele Fehler weg.

ALLERDINGS IST DAS NICHT DAS GELBE VOM EI, WEIL ICH KEINE SEMAPHOREN FÜR 
DIE ARDUINO IDE GEFUNDEN HABE!!!

Die meisten Übertragungen laufen jetzt wie im Bild!

FYI: Ich habe zwei Bytes zum Master gesendet! 0x34 und 0x08.

Die Rückgabe auf dem Terminal sieht dann wie folgt aus:
> I2C Read, Address = 44, Read 2 bytes, Delay = 0
OK
< 34 08

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Andreas V. schrieb:

> Grundsätzlich kann der Code mit speziellen ATTiny's funktionieren.
> Allerdings scheint mein ATTiny85 aus der Rolle zu fallen, weil sich die
> technischen Werte geringfügig unterscheiden.

Unsinn. Ein USI ist wie das andere. Die einzige Ausnahme von dieser 
Regel ist die Verfügbarkeit eines in Leserichtung gebufferten 
Datenregisters, das gibt's nicht für jedes USI.
Aber so lange der Code dieses sowieso nicht benutzt, sollte er (so er 
denn korrekt ist) auf jedem USI laufen, ganz egal welcher Tiny den nun 
enthält. Und im Bezug auf einen Tiny85 sogar dann, wenn der Code dieses 
Bufferregister benutzt, denn der hat den!

Das Problem ist möglicherweise das Timing. Dieser Slave funktioniert nur 
dann zuverlässig, wenn der I2C-Master Clock-Stretching beherrscht. Nur 
bei hohem Systemtakt des Slaves und cleverer Benutzung könnte er u.U. 
auch ohne diese Vorraussetzung funktionieren.

Das Problem könnte also z.B. der Master sein. Laß mich raten: Raspi?

> ALLERDINGS IST DAS NICHT DAS GELBE VOM EI, WEIL ICH KEINE SEMAPHOREN FÜR
> DIE ARDUINO IDE GEFUNDEN HABE!!!

Kann es auch nicht geben. Es gibt beim Arduino kein preemptives 
Multitasking, sondern nur Main und Interrupts. Interrupts sind 
(zumindest auf den Arduino-AVR8) systemweit blockierend und können 
deshalb nicht warten, weil sie unweigerlich bis in alle Ewigkeit warten 
würden. Damit sind alle in MT-Systemen üblichen Sync-Mechanismen 
praktisch nicht sinnvoll umsetzbar. Das einzige, was geht, sind 
"critical sections", hier typisch ausgedrückt durch atomic blocks im 
Kontext von Main, denn die ISRs sind von Natur aus "critical sections". 
In Main kann man halt solche Blocks verwenden, wenn man verhindern muss, 
dass irgendwelche ISRs reingrätschen. Letztlich wird aber einfach die 
Notwendigkeit zum Warten dadurch verhindert, dass der Code, der 
eventuell warten müsste, erst garnicht zur Ausführung gelangt.

Oder anders ausgedrückt: du hast rein garnix von der Programmierung 
außerhalb einer MT-OS-Umgebung verstanden, nix von der Funktionsweise 
eines AVR8 und dem USI und außerdem nichts von der Logik von 
I2C-Transfers und benutzt deshalb diesen Slave vollkommen falsch 
und/oder an einem ungeeigneten Master...

Sprich: bevor du anfängst, an dem Code rumzufrickeln, solltest du 
erstmal all diese Wissenslücken schließen.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

@c-hater:
Danke! Du hast das was ich schrieb bzw. meinte auf andere Weise 
ausgedrückt. Der Hinweis mit den "critical sections" war echt hilfreich. 
Danach werde ich suchen! Ich kenne den Arduino Compiler nicht so gut. 
Ich verwende die Arduino IDE auch nur weil ich ein "billiges" und weit 
verbreitetes Bauteil als Alternative verwenden wollte.

Die Lib ist so wie sie ist. Allerdings möchte ich die TinyWireS Lib so 
nicht verwenden. Das ist mir zu unsicher. Die Read Error Meldungen beim 
Terminal kommen nicht umsonst. Auch der Absturz des Slave kommt davon!

Mit den Interrupts hast Du natürlich vollkommen Recht!

Ich greife mit dem MCP2221 auf i2c zu!

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb:
> Ich verwende die Arduino IDE auch nur weil ich ein "billiges" und weit
> verbreitetes Bauteil als Alternative verwenden wollte.

Es zwingt dich überhaupt niemand, die Arduino-IDE und deren libs zu 
benutzen. Der Harware ist es völlig egal, womit du die programmierst.

Oliver

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Andreas V. schrieb:
> Der Hinweis mit den "critical sections" war echt hilfreich.
> Danach werde ich suchen! Ich kenne den Arduino Compiler nicht so gut.
Das hat nichts mit Arduino zu tun.

util/atomic.h
Wird beim Compiler, dem AVR gcc, mitgeliefert.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Merkwürdig an der Sache mit dem Synch ist:

rxBuf ist so definiert:
1
volatile uint8_t rxBuf[ TWI_RX_BUFFER_SIZE ];

Außerhalb des ISR wird so zugegriffen (in usiTwiReceiveByte):
1
uint8_t returnValue =  rxBuf[ rxTail ];

innerhalb des ISR wird :
1
rxBuf[ rxHead ] = USIDR;
bzw. ich habe es mal hardcodiert um das Register auszuschließen ->
1
rxBuf[ rxHead ] = 123;

Dadurch daß die Variable "volatile" definiert ist hätte ich jetzt 
erwartet daß der Compiler den Variablezugriff für mich regelt. Das hat 
wohl der Autor auch so gedacht. Allerdings crasht es bei mir an den 
Stellen.

Gibt es da eine Compilereinstellung?

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Heinrich schrieb:
> Hast du dir mal den Attiny 841 angesehen?

Der Mikrocontroller ist nicht schlecht. Er zeichnet sich durch sehr 
niedrigen Stromverbarauch aus! Eventuell kann ich die Slave-Lib dafür 
auch verwenden!

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Hallo zusammen,

ich habe jetzt viele Fehler in der Slave-Lib eliminiert. Nur Eines kann 
ich mir nicht erklären.

Warum bekomme ich einen Schreibfehler wenn ich dem Datenregister einen 
Wert ungleich 0 zuweise?
1
ISR( USI_OVERFLOW_VECTOR )
2
{
3
4
  switch ( overflowState )
5
  {
6
     ....
7
     case USI_SLAVE_SEND_DATA:
8
      // Get data from Buffer      
9
    if ( txBufCounter > 0 )      
10
    {
11
    volatile uint8_t tmpData = TxBufferRemoveByte();     
12
    
13
    USIDR = 0x02; //tmpData; <== hier knallt es egal was ich mache ausser bei Wert 0 
14
    //_delay_us(T4_TWI*200);
15
    overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;  SET_USI_TO_SEND_DATA( );
16
    }
17
      ...   
18
      break;
19
   ....
20
   }
21
}

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb:
> Dadurch daß die Variable "volatile" definiert ist hätte ich jetzt
> erwartet daß der Compiler den Variablezugriff für mich regelt. Das hat
> wohl der Autor auch so gedacht. Allerdings crasht es bei mir an den
> Stellen.

Andreas V. schrieb:
> Warum bekomme ich einen Schreibfehler wenn ich dem Datenregister einen
> Wert ungleich 0 zuweise?
> …
> 13    USIDR = 0x02; //tmpData; <== hier knallt es egal was ich mache
> ausser bei Wert 0

Der Prozessor knallt nicht (oder wenn, dann nur mit viel Rauch), der 
crasht auch nicht, und bringt auch keine Schreibfehler.

Die Problembeschreibungen sind Murks.

Wie soll man dir da helfen?

Oliver

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Ich weiß ja auch nicht wie ich es noch genauer beschreiben soll. Der 
Prozesser kommt nach der Zeile in einen instabilen Zustand bzw. geht 
ganz außer Betrieb. ...
1
USIDR = 0x02;

Nach meinem Verständnis dürte daß nicht passieren, außer der Master 
zieht den Pin nach unten und es gibt einen Schluß....

von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb:
> Der
> Prozesser kommt nach der Zeile in einen instabilen Zustand bzw. geht
> ganz außer Betrieb. ...1USIDR = 0x02;

Beides ist mit an Sicherheit grenzender Wahrscheinlichkeit nicht der 
Fall.

Wie diagnostizierst du das denn?

Oliver

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Der Slave antwortet dann nicht mehr. Wenn ich die Zeile auskommentiere 
bekomme ich im Terminal zwar immer 0 zurück, aber es antwortet 
wenigstens immer.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

So sieht die Terminalausgabe im Fehlerfall aus:
1
>I2C Write, Address = 44, Data: EE Delay = 370
2
OK
3
> I2C Read, Address = 44, Read 1 bytes, Delay = 0
4
Read error. Error code: I2C_READ002 -25

Danach gibt es dann nur noch Timeouts:
1
> I2C Write, Address = 44, Data: EE Delay = 370
2
Timeout. Error code: -18
3
> I2C Read, Address = 44, Read 1 bytes, Delay = 0
4
5
Read error. Transfer was not possible. Error code: -24


So sollte die Ausgabe im Normalfall aussehen:
1
> I2C Write, Address = 44, Data: EE Delay = 370
2
OK
3
> I2C Read, Address = 44, Read 1 bytes, Delay = 0
4
OK
5
< 42

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Andreas V. schrieb:
> Ich greife mit dem MCP2221 auf i2c zu!

Dann sollte der ATtin85 kein Problem sein, da der MCP2221 Clock 
Stretching kann (Datenblatt, S.21), was die Voraussetzung für Slaves mit 
einem MC ist.

Ein I2C-Slave muß auf einem MC grundsätzlich als Interrupt laufen, damit 
der Master nicht ewig warten muß, wenn die Mainloop des Slave mal etwas 
beschäftigt ist.

Zur Qualität der Arduino-Libs kann ich nichts sagen.

von Peter D. (peda)


Lesenswert?

Andreas V. schrieb:
> Was
> mir auffiel waren Acks die zu früh geschickt wurden und kollidierten.

Die ACK/NACK sehen völlig o.k. aus, sie müssen während SCL = 1 stabil 
sein.
Aber der jeweils 8. SCL-Puls ist eindeutig zu kurz.

von Oliver S. (oliverso)


Lesenswert?

Andreas V. schrieb:
> So sieht die Terminalausgabe im Fehlerfall aus:>I2C Write, Address = 44,
> Data: EE Delay = 370
> OK
>> I2C Read, Address = 44, Read 1 bytes, Delay = 0
> Read error. Error code: I2C_READ002 -25

Taj, das sagt ja auch nur: Funzt nicht.

Kannst du mal dein ganze Slave-Projekt hier anhängen?

Oliver

von Peter D. (peda)


Lesenswert?

Peter D. schrieb:
> Aber der jeweils 8. SCL-Puls ist eindeutig zu kurz.

Dem Slave ist nur erlaubt, nach der 1-0 Flanke vom Master den SCL länger 
auf low zu halten. Vielleicht ist der Bitzähler falsch gesetzt, so daß 
es auf der falschen Flanke erfolgt. Ohne den konkreten Code läßt sich 
das nicht feststellen.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Moinsen! Das Hauptprogramm sieht schon mal so aus:
1
#include <TinyWireS.h>
2
#include <usiTwiSlave.h>
3
#define I2C_SLAVE_ADDR  0x44            // i2c slave address (38)
4
#define LED1_PIN         4              // ATtiny Pin 3
5
#define LED2_PIN         1              // ATtiny Pin 6
6
7
void setup(){
8
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
9
  pinMode(LED2_PIN,OUTPUT);             // for verification
10
  Blink(LED1_PIN, 4);                    // show it's alive
11
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode  
12
}
13
14
void loop() {   
15
byte byteRcvd = 0;
16
  while (TinyWireS.available()){           // got I2C input!
17
    byteRcvd = TinyWireS.receive();     // get the byte from master
18
  //   master must wait for this to finish before calling Wire.requestFrom
19
   // byteRcvd += 1;                     // add 10 to what's received
20
    byte sendBack = byteRcvd + 0;
21
    //Blink(LED1_PIN, byteRcvd);     
22
    TinyWireS.send(byteRcvd);           // send it back to master
23
    //for (int x=0; x<9;x++){}
24
    //Blink(LED1_PIN,byteRcvd);                  // show we transmitted
25
 }
26
}
27
28
void Blink(byte led, byte times){ // poor man's display
29
  for (byte i=0; i< times; i++){
30
    digitalWrite(led,HIGH);
31
    delay (222);
32
    digitalWrite(led,LOW);
33
    delay (222);
34
  }
35
}

von m.n. (Gast)


Lesenswert?

Heinrich schrieb:
> Hast du dir mal den Attiny 841 angesehen?

Es ist zwar keine große Hilfe, dem TO einfach einen anderen Controller 
vorzuschlagen, aber in diesem Fall ein guter Rat, dies beim nächsten Mal 
zu berücksichtigen.

Selber hatte ich auch einmal ein TWI auf USI-Basis zum Laufen gebracht, 
aber es war eine blöde Gurkerei. Im hiesigen Fall hat die als einfach 
vermutete Zusammenklickerei von LIBs ja auch nicht den erhofften, 
schnellen Erfolg gebracht.
Wenn ein 8-pol. AVR mit TWI benötigt wird, würde ich die neueren 
Versionen wie ATtiny412 +++ empfehlen. Nicht perfekt aber immerhin 
schnell erledigt.

von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Die Library liegt Im Netz in diversen Formen, teilweise stark 
modifiziert, teilweise nicht compilierbar, vor. Ich wundere mich in 
letzter Zeit nicht mehr...

Der ursprüngliche Ringbuffer konnte volllaufen, deshalb habe ich ihn 
durch unit getesteten Code ersetzt. Jetzt werden alte Daten einfach 
weggeworfen, wenn der Puffer droht vollzulaufen. Was interessiert mich 
der alte Sch...!
Das hat aber erst einmal nichts mit der Übertragung zu tun, weil es auch 
bei hard codiertem festen Wert nicht funzt!

Das Problem wird wahrscheinlich durch die Werte der einzelnen Bits im 
Status-Register verursacht.

Im Anhang die deprecated Lib die momentan noch ziemlicher Murks ist...

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Peter D. schrieb:
> Zur Qualität der Arduino-Libs kann ich nichts sagen.

Das ist keine Arduino Lib.
Das ist irgendwas anderes.
Das implementiert noch nicht mal das Interface einer Arduino Wire/I2C 
Lib

Von Arduino gab es nie, irgendeine I2C Implementierung für Tinys
(soweit mir bekannt)

Aus meiner Sicht ist die einzige Gemeinsamkeit mit Arduino, dass es vom 
AVR gcc kompiliert wird, und sich als Lib in die IDE integrieren lässt.

von Oliver S. (oliverso)


Lesenswert?

Oliver S. schrieb:
> Wenn’s ohne Arduino auch geht, würde ich mir das hier anschauen:
> http://www.jtronics.de/avr-tutorial/avr-library-i2c-twi-slave-usi/

Das wäre immer noch einen Versuch wert.

Oliver

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Oliver S. schrieb:
> Oliver S. schrieb:
>> Wenn’s ohne Arduino auch geht, würde ich mir das hier anschauen:
>> http://www.jtronics.de/avr-tutorial/avr-library-i2c-twi-slave-usi/
>
> Das wäre immer noch einen Versuch wert.

Kommt Ihr da drauf? Ich bekomme die Seite vom Virenscanner gesperrt! 
Auch wenn ich bestätige. Ich müßte eine Ausnahme einfügen oder den 
Virenscanner abschalten...

von Gerhard Z. (germel)


Lesenswert?

Andreas V. schrieb:
> Kommt Ihr da drauf?

Ja, ohne Umstände, allerdings mit Linux!

von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Danke auch an alle. Die Library unterscheidet sich nicht stark von 
meiner umgestellten Lib. Ich habe nur den Puffer überlaufsicher gemacht. 
Die originale Library funktionierte bei mir allerdings beim Read (vom 
Master aus gesehen) nicht zuverlässig bzw nur mit 00 oder FF. Das Timing 
funktioniert mit der ungeänderten Lib nur wenn ich den ATTiny85 mit 8 
MHz laufen lasse und writes sende. Bei anderen Zahlen mit Read fällt der 
ATTiny 85 I2C Slave auf die Nase. Ich änderte die Baudrate nach unten 
und nach oben. Es wurde immer nur die Adresse und das Ack vom Read 
geschickt.

Inzwischen sendet der ATTiny85 auch ganze Antworten ungleich 00 und FF 
bei Frequenzen 1 MHz, 8 MHz und 16 MHz.zurück. Die 16 MHz scheinen 
jedoch stabiler zu laufen.

Die Wahrscheinlichkeit bei (Hex-)Zahlen wie 1,3,6,7,8,9 ist sehr hoch 
dass sie korrekt übertragen werden. Hex-Zahlen wie 2, EA oder 0A werden 
mit fast 100%iger Sicherheit nicht übertragen. Da scheint der Master 
(MCP2221) vorher hineinzukätschen und ein Stop-Bit zu senden.

Das sieht dann wie im Anhang aus! Wie kann man das verhindern? So ein 
Problem hatte ich mit dem MCP2221 noch nicht!

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Angehängte Dateien:

Lesenswert?

Hier noch mal das Ende der Bitfolge bei einer anderemn Messung mit 2A 
vom Slave zum Master.

Noch ein Nachtrag: Mit 400000 bps läuft die Übertagung stabiler!

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Hallo Leute,

es hat sich mal wieder erledigt, weil ich an der total falschen Stelle 
suchte! Ich war anfangs von falscher Programmierung bzw. Timing 
Problemen ausgegangen. Auch falsche Initialisierung zog ich in Betracht. 
Aber das war jetzt der Hammer.

Ich habe vor ca. einem Jahr Sensoren ausgetestet. Die machten mit 4,7K 
und 10K Pullups Schwierigkeiten. Aus dem Grund verwendete ich im 
Testboard damals 2,2K Pullups. Ich hatte nur vergessen die Pullups 
wieder durch 10K's auszutauschen. Alledings hätte mir das auch nichts 
gebracht. Das versuchte ich heute nämlich auch ohne Erfolg! Als ich dann 
aber 4,7K Pullups verwendete funktioniert alles einwandfrei.

Ich weiß daß man Pullups bei I2C grundsätzlich mit 4,7K bemessen sollte. 
Das steht im Standard. Allerdings verwenden moderne Architekturen wegen 
dem Stromverbrauch oft 10K Pullups.

Mea Culpa; aber daß durch "falsche"  Pullup's der ganze AtTiny85 crasht 
finde ich doch sehr schrottig!!!

Die Slave-Lib kann ich also jetzt auch verwenden. Der Puffer kann bei 
mir jedenfalls nicht volllaufen! Im Gegensatz zur originalen Lib habe 
ich das eleiminiert!

Die Aussage daß die Library nur mit 8 MHz läuft ist schlichtweg falsch! 
Mit 1 MHz oder 16 MHz läuft sie auch. Allerdings erhöht sich bei höheren 
Taktfrequenzen im Prozesser, wie ich das gerade gemerkt habe, die 
Stabilität des Bauteils. Also besser mit 16 MHz programmieren. 1 MHz ist 
jedenfalls grenzertig wegen den elektrischen Eigenschaften die im 
Datenblatt angegeben sind.

von Stefan F. (Gast)


Lesenswert?

Andreas V. schrieb:
> Ich weiß daß man Pullups bei I2C grundsätzlich mit 4,7K bemessen sollte.

Nö, wer sagt dass? Halte dich doch eher an den Empfehlungen in der I²C 
Spezifikation. 
https://www.nxp.com/docs/en/user-guide/UM10204.pdf#page=50

Dort wird maximal 3 mA empfohlen (bzw. 20 mA für den exotischen "fast 
mode plus").

Mit den im Arduino Umfeld üblichen 10 kΩ hatte ich auch schön öfters 
Probleme. Ich verwende 2,2 kΩ bei 3,3 V.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Stefan ⛄ F. schrieb:
> Mit den im Arduino Umfeld üblichen 10 kΩ hatte ich auch schön öfters
> Probleme. Ich verwende 2,2 kΩ bei 3,3 V.

Und genau mit 2,2K bringt es den AtTiny zum Absturz! Ich habe mehrere 
AtTiny85 IC's ausprobiert! Ich konnte es nicht glauben!

: Bearbeitet durch User
von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Mit 3V finktioniert es! Ich hatte die AtTiny Power im 5V Pin des Arduino 
Power-Pin stecken! Wobei der AtTiny ja eine Betriebsspannung bis 5V 
verträgt. Allerdings waren dann die Pullup's Out of Spec!

von Peter D. (peda)


Lesenswert?

Andreas V. schrieb:
> Und genau mit 2,2K bringt es den AtTiny zum Absturz!

Erzähl mal Genaueres über den Testaufbau. Was sind da alles für I2C-ICs 
dran, wie lang sind die Leitungen.

Z.B. ein COG-LCD ist sehr hochohmig, das kann keine 3mA treiben.

Der ATtiny85 hat allerdings auch kein normgerechtes I2C, die 
vorgeschriebenen Filter fehlen:
"The USI two-wire mode is compliant to the Inter IC (TWI) bus protocol, 
but without slew rate limiting on outputs and without input noise 
filtering."
Ein Widerstand 100R in Reihe zu SDA/SCL ist daher zu empfehlen.

Aber auch viele andere Atmel AVRs und 8051 patzen leider beim 
I2C-Standard, d.h. halten ihn nicht ein. Alle, die ich probiert habe, 
sind nicht Multimaster fähig (z.B. ATmega8, AT89C51ID2).

Auch der Nachbau des Philips P89C668, der Tekmos TK89C668, kann kein 
Multimaster. Ob der überhaupt I2C kann, habe ich nicht geprüft, er 
stürzt schon beim Init ab.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nö, wer sagt dass? Halte dich doch eher an den Empfehlungen in der I²C
> Spezifikation.
> https://www.nxp.com/docs/en/user-guide/UM10204.pdf#page=50

Hallo Stefan! Danke für die Info! Das ist aber ein Empfehlung von 
Philipps. AtTiny ist Microchip bzw. Atmel. Mit 2K bzw. 2,5 mA bzw. 5V 
habe ich mir einen AtTiny gekillt. Es kann natürlich sein daß er vorher 
schon einen Schaden hatte. Aber auch der zweite AtTiny macht bei den 
Werten Mucken.

Es kann natürlich sein das mein Händler (aus der Bucht) mir da 
minderwertige Ware verkauft hat. Es war halt sehr günstig! Das 
Datenregister hat jedenfalls auf Bit 0 nur noch den Wert 1. Laut 
Datenblatt entnahm ich 10 mA Sink bei 5V. Irgendwie triftet da Theorie 
und Praxis auseinander!

Siehe Seite 162 / Punkt 5:
https://cdn-reichelt.de/documents/datenblatt/A300/ATTINY25-ATTINY45-ATTINY85_DATASHEET.pdf#page=162

Ich bestellte mir noch einmal AtTiny's. Mal sehen ob die der 
Spezifikation gerecht werden...

von m.n. (Gast)


Lesenswert?

Andreas V. schrieb:
> Es kann natürlich sein das mein Händler (aus der Bucht) mir da
> minderwertige Ware verkauft hat.

Sag doch nicht soetwas! Es gibt eben Bauteile, die bei gewissen 
Funktionen patzen und die man am besten meidet. Deine Widerstandsauswahl 
finde ich auch äußerst grenzwertig. Meist wird damit eine andere "Macke" 
kaschiert.

Bei mir laufen IIC-EEPROMs allein mit den Pullups eines STM32 mit 100 
kHz. Es geht eben, wenn man weiß, was man macht, und sich zur Sicherheit 
die Signale auch mal ansieht.

von Stefan F. (Gast)


Lesenswert?

Peter D. schrieb:
> Z.B. ein COG-LCD ist sehr hochohmig, das kann keine 3mA treiben.

Dann ist es aber nicht zur I²C Spezifikation konform, denn die fordert 
mindestens 3 mA.

von Stefan F. (Gast)


Lesenswert?

Andreas V. schrieb:
> Mit 2K bzw. 2,5 mA bzw. 5V habe ich mir einen AtTiny gekillt.

Das kann nicht sein. Die Ausgänge sind mehr als 10x so hoch belastbar. 
Da muss etwas anderes schief gelaufen sein.

> Siehe Seite 162 / Punkt 5

Das sind die Angaben zur Stromaufnahme des gesamten Mikrocontrollers 
ohne externe Beschaltung. Die Limits stehen im Kapitel 21.1 "Absolute 
maximum ratings"

> DC Current per I/O Pin 40.0 mA

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

So oder so! Es haut alles nicht hin.

Dummerweise habe ich mir die Signale nur mit dem Logic Analyzer 
angeschaut, weil ich an einen Programmmierfehler meinerseits dachte.

Zur Beschaltung gibt es nicht viel zu sagen:

PC <=> USB-I2C-Bridge <=> AtTiny

Bridge: MCP2221
Attiny: AtTiny85
Pullup-Widerstände 2K (funzt nicht bei 5V), 10K funzt überhaupt 
nicht,4,7K funzt bei 5V und 3,3V

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

So, Leute gestern habe ich mir auf dem Oszi die Signale angeschaut. Die 
Signale sehen aus wie man das bei einem so billigen Bauteil erwartet. 
Sie sind ein bisschen abgerundet, aber akzeptabel.

Was mich dabei ein bisschen gewundert hat:

Szenario 1:
Ich kann den AtTiny85-12c-Slave über einen Rotary Encoder in 5-er 
Schritten (von 0-100) einstellen. Ungerade Werte werden über die 
USB-i2c-Bridge zu 100% richtig an den PC übertragen. Sende ich aber 
gerade Werte wie 10, 20, 30, ... dann bekomme ich in 2% bis 3% der Fälle 
falsche Werte angezeigt. Und zwar genau immer eins zuviel; - also: 11, 
21, 31, ...

Das ist bei 3V immer der Fall egal wie ich die Baudrate verändere. 
Pullups: 10K

Szenario 2:
Aufbau wie bei Szenario 1, - nur mit anderer(SOP) USB-i2c-Bridge. Die 
Fehlerquote verringert sich auf 0%. Pullups: 10K

Szenario 3:
Aufbau wie bei Szenario 1, - mit dritter(SOP) USB-i2c-Bridge. Die 
Fehlerquote ist bei 1,5 %. Pullups: 10K

Szenario 4:
Aufbau wie bei Szenario 1, - mit vierter USB-i2c-Bridge.
Die Fehlerquote ist bei 0,06 %. Pullups: 10K

Szenario 5:
Aufbau wie bei Szenario 1, - mit fünfter(SOP) USB-i2c-Bridge. Die 
Fehlerquote ist bei 0,07 %. Pullups: 10K

Szenario 6:
Aufbau wie bei Szenario 1, - mit selbstgebauter (DIP) USB-i2c-Bridge.
Fehlerquote ist bei 0 %. Pullups: 2K

*alle USB-i2c Bridges basieren auf dem MCP2221

FAZIT:
Was mir dabei immer wieder zu denken gibt. Viele "professionelle" Geräte 
verlassen sich darauf daß immer alles korrekt übertragen wird. Sei es 
Datenübertragung über Ethernet oder RS232. Da kenne ich einige Geräte 
die ihre Daten nicht mit CRC's übertragen und abprüfen. Gut Ethernet hat 
gewisse Prüfmechanismen, aber die CRC32 geht nur über die Header.

In der Praxis habe ich allerdings erlebt dass Auswuchtmaschinen aus 
unerkärlichen Gründen in das Futter fahren oder medizinische Geräte auf 
einmal unerklärlich irgendwelche Dinge machen die sie nicht tun sollen. 
Hinterher kann man den Schaden nicht nachvollziehen. Immer wenn das der 
Fall ist wurden keine CRC32 Prüfsummen gebildet bzw. überprüft.

Gut, das sind keine Bauteile die man mit denen in der Industrie oder MIL 
vergleichen kann, aber das zeigt mal wieder eindrucksvoll daß man sich 
auf Hardware NIE verlassen darf. Allerdings hätte ich nicht geglaubt 
dass die Werte sich je nach Bridge-Adapter so unterscheiden würden.

Also: Immer CRC32 bilden und prüfen und Sequenznummern schaden auch 
nicht....

: Bearbeitet durch User
von beo bachta (Gast)


Lesenswert?

Andreas V. schrieb:
> Gut, das sind keine Bauteile die man mit denen in der Industrie oder MIL
> vergleichen kann, aber das zeigt mal wieder eindrucksvoll daß man sich
> auf Hardware NIE verlassen darf.

Stell dir vor, in deinem PC wird bei der Übertragung von Daten
vom Prozessor ins RAM oder vom RAM in den Prozessor sich darauf
verlassen dass das fehlerfrei funktioniert. Und das viele
tausende oder millionen Male pro Sekunde.

Das zeigt mal wieder eindrucksvoll daß man sich auf Hardware
NIE verlassen darf.

von Andreas V. (Firma: IGL) (andreas_va)


Lesenswert?

beo bachta schrieb:
> Stell dir vor, in deinem PC wird bei der Übertragung von Daten
> vom Prozessor ins RAM oder vom RAM in den Prozessor sich darauf
> verlassen dass das fehlerfrei funktioniert. Und das viele
> tausende oder millionen Male pro Sekunde.

Ich kann mich noch an billigen Speicher erinnern der hatte kein ECC und 
nur Paritätsprüfung!....

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.