I2C Slave mit dem Attiny 841

Gast #5876610
Lesenswert?

Hallo
versuche seit ein paar Stunden den Attiny 841 als I2C Slave in Betrieb 
zu nehmen. Als Master verwende ich einen Atmega 128. Das Programm auf 
dem Atmega läuft mit anderen Slaves ohne Probleme. Leider scheint es im 
Netz zu diesem Thema nicht viel zu geben. Es wird in der App 311 vom 
Hersteller zwar beschrieben wie es geht, geht aber leider nicht. Auch 
die Seiten von Jtronic funktionieren nicht. Es gibt auch eine Abhandlung 
zur Verwndung von 2 Atmmegas bzw. Attiny, geht aber auch nicht. Bin 
jetzt ziemlich ratlos. Programmiere mit C und AVR 7. Die I2C 
schnittstelle scheint etwas anders zu sein als die übrigen.
Der Vorgänger zum Attiny 841 soll docj der Attiny 84 sein. Stimmen die 
wenigsten überein?
Hat jemand ein Beispiel dazu?
Der Attiny funktioniert sonst ohne Probleme, kann Ein und Ausgänge 
schalten.
LG Klaus
Gast #5876679
Lesenswert?

Klaus schrieb:

> Die I2C
> schnittstelle scheint etwas anders zu sein als die übrigen.

Die ist sogar ziemlich anders. Im Besonderen kann sie z.B. 
ausschließlich Slave.

> Der Vorgänger zum Attiny 841 soll doch der Attiny 84 sein. Stimmen die
> wenigsten überein?

Nein, absolut nicht. Der Tiny84 hat nämlich überhaupt keine dedizierte 
I2C-Hardware, sondern, wie die meisten Tinys, nur das USI, was es aber 
wiederum beim 841 nicht gibt.
Gast #5876688
Lesenswert?

Ich hätte da auch eine Frage. Gibt es irgendwo ausserhalb der bekannten 
NXP Dokus  I2C Zustandsmaschinen Dokus die eine formelle Implementierung 
diverser I2C Funktionalität erlaubt?

Die NXP Bus Spezifikation ist ja sehr nützlich, aber eine formale 
Zustandsmaschine Spezifikation diverser Modelle (I2C Busmaster, I2C 
Slave) um das Protokol ohne Verletzungen unter allen Umständen zu 
gewährleisten zu können wäre natürlich angenehm zur Verfügung zu haben. 
Ich denke da Dokumentation im Stil ähnlich wie z.B IEEE-488 wo die 
minimale vorgeschriebene Bus Device genau vorgeschrieben ist und man 
einen Unterschied zwischen Bus Protokoll Compliance und (optionale) 
Device Funktionen macht.

Sicher, es ist nicht schwer einen I2C Busmaster zu schreiben der 
praktisch funktioniert aber eine komplette Implementation die 
Fehlersituationen formell korrekt behandelt ist ein anderes Kapitel.

Bitte kein RTFM. Ich habe bis jetzt noch keine Dokus die in der 
Formalität und Komplettheit vergleichsweise an die IEEE-488 Bus 
Spezifikation herankommt gefunden. Man ist da meist diesbezüglich 
scheinbar auf sich selber gestellt.

Ferner wäre eine formelle Testsuite auch sehr nützlich, kommerzielle I2C 
Devices oder eigene Entwicklungen zu testen um irgendwelche Bugs 
bloszulegen. Es wäre ja peinlich wenn eine Eigenentwicklung dann später 
unerwartet z.B durch einen Bug den Bus blockiert...

Z.B. muß ich anhand der NXP Unterlagen annehmen, daß der ACK/NACK 
Datenzustand innerhalb der vorherigen Clock Timing stabil sein muß. Bei 
uC FW Implementierung ohne HW könnte das möglicherweise ins Auge gehen 
wenn man keine I2C HW im uC verwenden würde.

Abgesehen davon wäre das noch wichtiger bei Eigenentwicklung mittels uC 
oder FGPA/CPLD um festzustellen, daß das eigene Design alles Notwendige 
adequate erfüllt. Bis jetzt mußte ich noch kein eigenes I2C Device 
selber entwickeln.

Es gibt viele I2C Beispiele, Bibliotheken, Application Notes aller Art. 
Aber ohne viel Zeit mit sorgfältiger Eigenanalyse hinzustecken, hat man 
keine Gewissheit ob alle diese Implementationen die NXP Vorgaben 
wirklich erfüllen.

Also, gibt es formelle Bus Spezifizierungs Dokus die über die von NXP 
hinaus gehen und man Unterlagen ähnlich der IEEE-488 hätte auf die man 
bauen könnte? Wie würdet ihr das Problem ohne solche Dokus angehen um 
einigermaßen sichergehen zu können, daß man alle vorgesehenen 
Ausnahms-Fälle richtig behandelt?
Gast #5876708
Lesenswert?

USI habe ich mit verschiedenen Typen gemacht. Verwende dazu die Datein 
von Jtronic. Da aber USI auf dem Ati 841 nicht läuft, gibt es nicht 
viele Möglichkeiten. Selber etwas zu machen traue ich mir nicht zu.
Der Hersteller gibt zwar als Beispiel die App 311 an, doch leider geht 
die auch nicht bzw. recht kompliziert.
Habe auch die angegeben Stellen auf dem Bild angeschaut. Github hat auch 
kaum was dazu oder für den Arduino. Suche aber was für normales C. Das 
ganze scheint nicht so einfach zu sein.
Gast #5876724
Lesenswert?

Klaus schrieb:

> Das
> ganze scheint nicht so einfach zu sein.

Doch, ist es. Die Hardware des 841 stellt genau die zusätzliche 
Unterstützung bereit, die man beim USI so schmerzlich vermisst und 
relativ aufwendig in Software implementieren muss.

Es ist also deutlich einfacher, einen "normalen" I2C-Slave mit der 
Hardware des 841 umzusetzen als mit dem USI. Die darüber hinaus 
gebotenen Möglichkeiten der Hardware (mehrere Slave-Adressen, 
promiscuous mode) muss man ja nicht nutzen.
#5876726
Lesenswert?

Klaus schrieb:
> Das ganze scheint nicht so einfach zu sein.

Häh? Das TWI_Modul vom 841 ist doch relativ komfortabel, macht fast 
alles selber.

Der Anhang ist eine Quick&Dirty-Lösung um ein 16x2-LCD per TWI 
anzusprechen. In TWI_Init werden die notwendigen Interrupts angeschaltet 
und Slave-Adresse gesetzt, anschliessend wird nur noch die ISR 
ausgewertet wenn was über den Bus kommt. Und das geht sehr einfach indem 
man das Statusregister TWSSRA ausliest und schaut was da reinkam: wars 
ein Addressmatch, oder Stop, oder Daten? Dementsprechend wird gehandelt. 
In der Main wird dann das Display beschrieben falls das Flag gesetzt 
ist.
Ist etwas rudimentär, nur auf eingehende Daten ausgelegt und ohne 
jedwede Fehlerbehandlung. Musst es dir halt umstricken wie es für dich 
passt.

Ich hab mit dem 841 nicht soviel gemacht, ist auch schon etwas länger 
her; aber das TWI war eigentlich problemlos WIMRE.
Angehängte Dateien:
Gast #5876731
Lesenswert?

Klaus schrieb:
> USI habe ich mit verschiedenen Typen gemacht. Verwende dazu die Datein
> von Jtronic.

Also nicht gemacht, sondern ^C ^V.

Klaus schrieb:
> Suche aber was für normales C. Das
> ganze scheint nicht so einfach zu sein.

I2C gehört zu den einfachsten Protokollen, die ich kenne. Man braucht 
auch keine formale Zustandsmaschinen Spezifikation, dazu sind es einfach 
zuwenig Zustände. Wer es einmal verstanden hat, implementiert es aus dem 
Kopf.

MfG Klaus
Gast #5876737
Lesenswert?

Danke für die Info und das Beispiel. Werde es ausprobieren. Wenn I2C Bus 
so einfach, warum haben viele Probleme damit? Mit den andren ICs habe 
ich keine Probleme, bloss der 841 zickt ganz schön rum. egal, adnke an 
alle
#5876750
Lesenswert?

Für die Faulen: Wizard von CodeVision, gibts auch als Demo. Keine Ahnung 
ob die TWI unterstützt. Damit hatte ich das in 2min am laufen, war 
allerdings der Tiny441, sollte aber bis auf den Speicher identisch sein.

Nein, das ersetzt nicht das Verstehen, ist aber sehr schön, dass man 
erst mal was lauffähiges hat und das dann Schritt für Schritt durchgehen 
kann.
Angehängte Dateien:
Gast #5876871
Lesenswert?

Klaus schrieb:
> Danke für die Info und das Beispiel. Werde es ausprobieren. Wenn
> I2C Bus
> so einfach, warum haben viele Probleme damit? Mit den andren ICs habe
> ich keine Probleme, bloss der 841 zickt ganz schön rum. egal, adnke an
> alle

Ich habe mir mal die App note 311 zu Gemüte geführt. Von wegen State 
machine ist nicht nötig weil man das alles im Kopf halten kann. Der 
Grund warum das so einfach sein soll besteht ja darin, daß der 
Hersteller diesen Teil in HW gelöst hat um SW Latenzen und komplizierten 
Code zu vermeiden. Die Frage wie dieser Teil gelöst ist, lohnt sich 
näher betrachtet zu werden. Daß der TWI Sklaven Code im Beispiel so 
einfach ist, ist kein Wunder und ist eigentlich ein bischen Schummeln:-)

In meinem vorherigen Beitrag wollte ich die Frage aufwerfen wie man das 
bei anderen uC ohne solche TWI Unterstützung machen könnte. In diesen 
Fall würde eine formale Doku dieser Implementierung schon nützlich sein 
weil die TWI HW ein schwarzer Block ist und sein Eigenleben hat was 
Bustransaktionen betrifft.

Bis jetzt konnte ich herstellerseitig noch nie eine formale 
Dokumentation bezüglich der TWI Implementierung in ausreichenden Detail 
finden. Es werden ja nur die Schnitstelleregister und teilweises 
Verhalten dokumentiert, aber nicht die interne Logik im einzelnen. Die 
gleiche Notwendigkeit besteht ja wenn man einen TWI Sklaven mittels CPLD 
oder FPGA verwirklichen möchte. Da muß man ja auch die State Machine 
Logik und HW Verhalten genauestens definieren können. Es ist ja schön, 
daß die Hersteller einem mit TWI halb entgegen konmen. Die andere Hälfte 
wäre auch nützlich dokumentiert zu haben. Wenn man natürlich nur 
einfachst TWI Sklave verwirklichen möchte, reicht das Erhältliche.

Es gibt in Quartus übrigens ein CPLD Beispiel. Aber ein uC ist oft auch 
keine schlechte Lösung und viel billiger.

Hat sich denn noch keiner von Euch über den "schwarzen Block" viel 
Gedanken gemacht?
Gast #5876905
Lesenswert?

Ich will jetzt nicht den Versuch machen, das ganze I2C Protokoll hier 
aufzuschlüsseln. Aber ein paar Hinweise zum Prinzip: der Transfer eines 
Bits ist ein Handshake auf der Clockleitung. Der Master zieht Clock auf 
low, mindestens so lange, wie als Bitzeit/2 verabredet ist ( 5 us bei 
100kHz). Bei einem Write legt er die Daten auf SDA. Der Slave erkennt 
die fallende Flanke der Clock und zieht seinerseits SCL auf low. Dann 
liest er die Daten vom Master bzw. legt seine Daten auf SDA und lässt 
SCL wieder los. Ist SCL wieder oben, wartet der Master wieder eine halbe 
Bitzeit und alles beginnt von vorne. Meist sind die Slaves so schnell, 
daß sie SCL losgelassen haben, bevor der Master es tut. Jetzt gilt es 
noch Start, Stop und Bus Idle zu erkennen.

MfG Klaus
Gast #5877018
Lesenswert?

Da wird es wohl Zeit etwas grundlegendes mit dem I2C Bus und dem Attina 
841 zu machen. Von der Grösse her ist er ja bestens geeignet kleine 
Platinen mit verschiedenen Elementen aufzubauen und mit dem Bus zu 
verbinden. Hatte so was ähnliches als Start UP für einen PIC gesehen.
#5877034
Lesenswert?

Ich habe hier:

https://www.avrfreaks.net/comment/2694441

Code für Series 1 gepostet. Nach Überfliegen des Datenblatts scheint 
mir, dass die Slave Engines für Series 1 und ATtiny841 ziemlich ähnlich, 
aber nicht ganz identisch sind. Mit Copy & Paste wird es nicht gehen, 
aber ich vermute, es sind nur wenige Anpassungen notwendig.

Der Slave ist Interrupt-basiert und emuliert ein Registerfile, ähnlich 
einem EEPROM. Für Series 1 waren wegen eines (von Microchip inzwischen 
bestätigten) Bugs an einer Stelle ein paar Klimmzüge notwendig, bei 841 
mag das anders sein. Der Versuch, das Thema hier im 
Microcontroller-Forum ernsthaft zu diskutieren, ist seinerzeit leider in 
einem Schwall von unqualifizierten Hass-Postings geendet.

Vielleicht nützt es ja was.
Gast #5877099
Lesenswert?

Klaus schrieb:

> Bei anderen Beispielen mit Code wird I2C Master oder TWIslave mit c und
> verwendet. Das hast du nicht drin. Geht das auch diese Datein?

Wenn du wenigstens auch nur einmal kurz in's DB geschaut hättest, dann 
wüsstest du, dass die I2C-Hardware des 841 ausschließlich Slave sein 
kann...
Gast #5877133
Lesenswert?

Ich habe in das Datenblatt geschaut und gesehen das es nur Slave 
erlaubt. Bin gerade dabei die Register anzuschauen und die einzelnen 
Funktionen durchzugehen und hoffentlich auch zu verstehen

c-hater schrieb:
>> Bei anderen Beispielen mit Code wird I2C Master oder TWIslave mit c und
>> verwendet. Das hast du nicht drin. Geht das auch diese Datein?

Mit diesem I2C Master meine ich eine Datei von Peter und nicht den 
Betrieb als Master
#5877169
Lesenswert?

Klaus schrieb:
> Bei anderen Beispielen mit Code wird I2C Master oder TWIslave mit c und
> verwendet. Das hast du nicht drin. Geht das auch diese Datein?

Du brauchst da keine weiteren Treiber oder sonst was; die Hardware 
erledigt das alles. Wie ich bereits schrieb, du initialisierst das 
Interface und schaust dann in der ISR im Statusregister nach was vom 
Master kam. Da ist keine Magie dabei.


> Bin gerade dabei die Register anzuschauen und die einzelnen
> Funktionen durchzugehen

Ein sehr guter Ansatz...
Gast #5877227
Lesenswert?

Klaus schrieb:

> Danke für den Code. Habe mal reingeschaut. Nach dem ersten Eindruck sind
> die unterschiedlichen Codes relativ gleich auch stückweise nur.

Mehr gibt es einfach nicht zu schreiben, weil halt die Hardware fast 
alles selber erledigt.

Du bist so dramatisch unfähig, dass du dich mit Wertungen einfach mal 
stark zurückhalten solltest. Statt dessen solltest du dich auf deinen 
faulen Arsch setzen und versuchen, zu begreifen, was du da für lau 
geliefert bekommen hast...
#5877245
Lesenswert?

Klaus schrieb:
> Danke für den Code. Habe mal reingeschaut. Nach dem ersten Eindruck sind
> die unterschiedlichen Codes relativ gleich auch stückweise nur.

Bei mir ist beides drin: Slave Read und Slave Write, und bei Slave Write 
auch noch jener Teil, der I2C Frames trennt. So arg viel mehr gibts bei 
I2C nicht. Das war auch nicht als fertige Lösung für dich gemeint, 
sondern ...

Klaus schrieb:
> Hat jemand ein Beispiel dazu?
#5877257
Lesenswert?

Aber du hast recht, das Error-Handling aus main() fehlte:
1
                ATOMIC_BLOCK(ATOMIC_FORCEON) {
2
                        if ((TWSSRA & 1<<TWBE) && (i2c_state == I2C_Idle)) {
3
                                // bus error set, and safe to transmit error message
4
                                TWSSRA = 1<<TWBE; // reset bus error
5
                                xmit_string(PSTR("BUS ERROR"), 0);
6
                        }
7
                }
Und im Watchdog-Interrupt gibts eins auf die Nuss, wenn I2C zu lange 
aktiv ist, weil dann der WDT nicht zurückgesetzt wird:
1
        if (i2c_state == I2C_Idle) {
2
                WDTCSR |= 1<<WDIE; // re-enable the watch dog interrupt
3
                wdt_reset();
4
        }
Gast #5882056
Lesenswert?

Hallo
lese diesen Beitrg schon einige Zeit mit. Habe auch so meine Probleme 
mit dem Attiny 841. Der ist halt anders als die anderen Attiny. Mir geht 
es eigentlich um das das ADC und die übertragung mit I2C. Habe schon 
einiges dazu programmiert. Leider klappt die übertgaung nicht so wie sie 
soll. Im Master habe ich eine Abfrage drin die die Adresse des Slave 
überprüft ob sie vorhanden ist. Dies Abfrage funktioniert sehr gut und 
der Slave wird als vorhanden angezeigt.Habe für mich auch Angaben zu den 
Registern dazu geschrieben. Nur leider kommt beim Master nichts an.
Mein Code:
1
void I2C_init(void)
2
  {
3
  TWSA = I2C_SLAVE_ADDRESS;          // TWI Adressregister
4
  TWSD = 0xFF;                // Datenregister
5
  TWSCRA = (1<<TWEN)|(1<<TWSHE)|(1<<TWASIE)|(1<<TWSIE)|(1<<TWDIE);      
6
  // Register A, TWEN-Schnittstelle Aktivieren, TWSHE-Haltezeit aktivieren, TWASIE-Adressenunterbrechung aktivieren, 
7
  // TWSIE-Stop Unterbrechung aktivieren, TWDIE-Datenunterbrechung aktivieren 
8
    TWSCRB = (1<<TWAA)|(1<<TWCMD1)|(0<<TWCMD0);  // Register B, TWI Bestätigungsaktion, TWI Befehl
9
  sei();      // Interrups einschalten
10
  }
1
ISR( TWI_SLAVE_vect )
2
  {
3
    uint8_t status = TWSSRA & 0xC0;      // Register A
4
  if (status & I2C_DATA_INTERRUPT)
5
  // Daten wurden vom Master empfangen oder werden angefordert
6
    {
7
      if (TWSSRA & (1 << TWDIR))          // Master fordert Daten vom Slave an
8
      {
9
      if(tx_buf_index >= sizeof(tx_buf))
10
        {
11
        tx_buf_index=0;
12
        }
13
      TWSD = tx_buf[tx_buf_index];
14
      tx_buf_index++;
15
      TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
16
      }
17
    else       // Master sendet Daten zum Slave
18
      {
19
      TWSCRB |= (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
20
      command = TWSD;
21
      }
22
    }
23
  else if (status & I2C_ADDRESS_STOP_MATCH)
24
    {
25
    if (TWSSRA & I2C_BUS_COLLISION)
26
      {
27
      TWSCRB = (uint8_t) (1<<TWCMD1);
28
      }
29
    else
30
      {
31
      if (TWSSRA & (1<<TWAS))
32
        {
33
        // ACK
34
        TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
35
        }
36
      else
37
        {
38
        // Stop Condition
39
        TWSCRB = (uint8_t) (1<<TWCMD1);
40
        }
41
      }
42
    }
43
  }
1
int main(void)
2
  {
3
    //ADC_init();
4
  I2C_init();
5
  while(1)
6
    {
7
    if(command != 0x00)
8
    {
9
      switch(command)
10
      {
11
        case 0x01:
12
        // Test Daten
13
        tx_buf[0] = 0x01;
14
        tx_buf[1] = 0x02;
15
        tx_buf[2] = 0x03;
16
        tx_buf[3] = 0x04;
17
        tx_buf_index = 0;
18
        break;
19
      }
20
      command = 0x00;
21
    }

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren