Forum: Mikrocontroller und Digitale Elektronik "I2C-Stopp" wird nicht ausgeführt (HW-TWI, AVR)


von Der T. (Gast)


Angehängte Dateien:

Lesenswert?

Nachdem nur sporadisch Daten in das externe EEPROM (24C04) übernommen 
werden, habe ich mich auf die Fehlersuche gemacht.

Ausgangslage:
- Standard-Routinen für Hardware-TWI (Mega128)
- Bisher galten die Routinen als "fehlerfrei"
- Am Bus befinden sich ein 24C04 und zwei LM75 (Temp-Sens)
- Fehler: Sporadisch werden die in das EEP zu schreibenden Daten nicht 
übernommen
- Die Kommunikations-Routinen melden dabei keinen Fehler

Ich habe das Szenario soweit eingrenzen können, dass direkt nach einem 
fehlerhaften Schreibzyklus eine Abfrage eines LM75 erfolgt. Obwohl im 
Code die Anweisung "TWIM_Stop()" steht, wird diese nicht ausgeführt. Es 
folgt ohne ein I2C-Stopp direkt ein Re-Start für den LM75. Dadurch wird 
die EEP-interne Schreibroutine anscheinend nicht angestossen und die 
Daten sind weg.. :-(
(Ich habe davon einen Screenshot gemacht und die Zustände eingezeichnet)

Die TWIM-Stop() - Routine lautet wie folgt:
1
void TWIM_Stop (void)
2
{
3
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
4
  while (TWCR & (1<<TWINT));
5
}

Warum gibt die Hardware diese Stop-Anweisung nicht aus?
Setze ich nach der Stop-Anweisung noch ein Delay von 20us, so läuft das 
ganze. Das kann doch aber nicht die Lösung sein..?!? :-(

von Der T. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe nun als Workaround 80(!!) NOP's in die Stop-Funktion eingefügt, 
um eine Verzögerung von ~7,2us (bei 11,0592MHz) zu erreichen.
=> siehe Screenshot!

Warum die TWI-Hardware jedoch nicht sofort reagiert, ist mir immer noch 
ein Rätsel.. :-(
(Auch in den Errata-Sheet's finde ich nichts passendes.)

Code:
1
void TWIM_Stop (void)
2
{
3
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
4
  while (TWCR & (1<<TWINT));
5
6
  NOP(); NOP(); NOP(); NOP(); NOP();
7
  NOP(); NOP(); NOP(); NOP(); NOP();
8
  NOP(); NOP(); NOP(); NOP(); NOP();
9
  NOP(); NOP(); NOP(); NOP(); NOP();
10
  NOP(); NOP(); NOP(); NOP(); NOP();
11
  NOP(); NOP(); NOP(); NOP(); NOP();
12
  NOP(); NOP(); NOP(); NOP(); NOP();
13
  NOP(); NOP(); NOP(); NOP(); NOP();
14
  NOP(); NOP(); NOP(); NOP(); NOP();
15
  NOP(); NOP(); NOP(); NOP(); NOP();
16
  NOP(); NOP(); NOP(); NOP(); NOP();
17
  NOP(); NOP(); NOP(); NOP(); NOP();
18
  NOP(); NOP(); NOP(); NOP(); NOP();
19
  NOP(); NOP(); NOP(); NOP(); NOP();
20
  NOP(); NOP(); NOP(); NOP(); NOP();
21
  NOP(); NOP(); NOP(); NOP(); NOP();
22
}

von Klaus (Gast)


Lesenswert?

Möglicherweise hilft auch ein einziger Nop vor dem while()

MfG Klaus

von Jackfritt (Gast)


Lesenswert?

Pull up falsch?

von Bernhard R. (barnyhh)


Lesenswert?

Der Techniker schrieb:
> Ich habe das Szenario soweit eingrenzen können, dass direkt nach einem
> fehlerhaften Schreibzyklus eine Abfrage eines LM75 erfolgt. Obwohl im
> Code die Anweisung "TWIM_Stop()" steht, wird diese nicht ausgeführt. Es
> folgt ohne ein I2C-Stopp direkt ein Re-Start für den LM75. Dadurch wird
> die EEP-interne Schreibroutine anscheinend nicht angestossen und die
> Daten sind weg.. :-(
> (Ich habe davon einen Screenshot gemacht und die Zustände eingezeichnet)
>
> Die TWIM-Stop() - Routine lautet wie folgt:void TWIM_Stop (void)
> {
>   TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
>   while (TWCR & (1<<TWINT));
> }
>
> Warum gibt die Hardware diese Stop-Anweisung nicht aus?
> Setze ich nach der Stop-Anweisung noch ein Delay von 20us, so läuft das
> ganze. Das kann doch aber nicht die Lösung sein..?!? :-(

Eine Fragen:
Wie wird die LM75-Kommunikation angestoßen?

Meine Glaskugel sagt:
- LM75 wird per Interrupt angestoßen.
- Ohne die NOPs kommt der LM75-IRPT ab und zu zufällig direkt vor der 
STOP-Routine des 24C04.

Abhilfe:
Atomare I2C-Zugriffe bis incl. STOP-Command.

Das ist aber alles Spekulation und ohne Source-Code nicht überprüfbar.

Bernhard

von Stefan++ (Gast)


Lesenswert?

Hallo,

vielleicht änderst du deine Routine

Der Techniker schrieb:
> Die TWIM-Stop() - Routine lautet wie folgt:void TWIM_Stop (void)
> {
>   TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
>   while (TWCR & (1<<TWINT));
> }

so ab

void TWIM_Stop (void)
{
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
}

von Der T. (Gast)


Lesenswert?

Klaus schrieb:
> Möglicherweise hilft auch ein einziger Nop vor dem while()
>
> MfG Klaus

Schon getestet -> leider nein.. :-(

von Der T. (Gast)


Lesenswert?

Jackfritt schrieb:
> Pull up falsch?

2x 3k3  - Ansonsten keine weiteren Bauteile am Bus.

von Der T. (Gast)


Lesenswert?

> Meine Glaskugel sagt:
> - LM75 wird per Interrupt angestoßen.
> - Ohne die NOPs kommt der LM75-IRPT ab und zu zufällig direkt vor der
> STOP-Routine des 24C04.

Leider nein. Momentan sind nur ein Timer-IRQ (zum setzen von 
Event-Flags) und die IRQ's für die UART aktiv. TWI läuft ausschließlich 
über Polling (while-Schleife). :-/

von Klaus (Gast)


Lesenswert?

Der Techniker schrieb:
> Schon getestet -> leider nein.. :-(

Ich vermute aber, es ist was ähnliches. Deine while() Schleife 
terminiert zu früh, dein Code überläuft den I2C Controler. Sehe gerade 
Stefan denkt auch in die Richtung

MfG Klaus

von Der T. (Gast)


Lesenswert?

Stefan++ schrieb:
> Hallo,
>
> vielleicht änderst du deine Routine
> so ab
>
> void TWIM_Stop (void)
> {
>   TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
>   while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
> }

Gerade probiert: Dann bleibt die CPU dort hängen und der WDT greift nach 
1s. :-(

von Der T. (Gast)


Lesenswert?

Klaus schrieb:
> Der Techniker schrieb:
>> Schon getestet -> leider nein.. :-(
>
> Ich vermute aber, es ist was ähnliches. Deine while() Schleife
> terminiert zu früh, dein Code überläuft den I2C Controler. Sehe gerade
> Stefan denkt auch in die Richtung
>
> MfG Klaus

Da stimme ich euch ja 100%ig zu, nur irgendwie habe ich dann Tomaten auf 
den Augen..?!?
Wenn ich es nicht selber sehen würde, würde ich es nicht glauben.. ;-b

von Der T. (Gast)


Lesenswert?

Wieder etwas schlauer:
"Assuming that the status code is as expected, the application must 
write a specific value to TWCR, instructing the TWI hardware to transmit 
a STOP condition. Which value to write is described later on. However, 
it is important that the TWINT bit is set in the value written. Writing 
a one to TWINT clears the flag. The TWI will not start any operation as 
long as the TWINT bit in TWCR is set. Immediately after the application 
has cleared TWINT, the TWI will initiate transmission of the STOP 
condition. Note that TWINT is NOT set after a STOP condition has been 
sent."

D.h. zum Initiieren des TWI-Stops muss man das Stopp-Bit zusammen mit 
dem TWI-IRQ-Flag (und dem TWI-Enable) setzten. Erst NACHDEM (!) die 
Hardware das IRQ-Flag gelöscht hat, wird die Stopp-Prozedur gestartet..

Jetzt stellt sich mir nur die Frage, wie bekomme ich mit wann das 'Stop' 
gesendet wurde. Das Stop-Flag wird nämlich zusammen mit dem IRQ-Flag 
zurückgesetzt..? :-(

von Der T. (Gast)


Lesenswert?

Ich mache es nun so, weil mir ein Delay nicht gefällt und ich keine 
bessere Lösung finde:

Header:
1
#define SCL_LINE  (PIND & (1<<PD0))
2
#define SDA_LINE  (PIND & (1<<PD1))

STOP/Warte-Routine:
1
void TWIM_Stop (void)
2
{
3
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
4
  while (TWCR & (1<<TWINT));
5
}
6
7
void TWIM_Ready (void)
8
{
9
  while (!(SCL_LINE && SDA_LINE));
10
}

An den Programmstellen, an denen ein Stopp zwingend gefordert ist, rufe 
ich nun die Funktion TWIM_Ready() nach dem TWIM_Stop() auf um zu 
warten.. (~5us)

Oder weiß noch jemand eine elegantere Lösung?

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

was macht den TWSR bevor und während der Ausgabe von STOP?
Wird der Status 0xF8 evl. erst nach der Ausgabe von STOP erreicht?

Sascha

von Jackfritt (Gast)


Lesenswert?

Mach mal 2k als pullup rein.
Ich habe hier auch einen I2C Slave der zeitweise
Nicht mag wenn die pullups zu hoch sind.
Dann "hängt" der bus.

von Steffen H. (avrsteffen)


Lesenswert?

HAllo Techniker

Das Problem kenn ich :-) siehe meinen Beitrag:
Beitrag "Re: [ASM] Hardware TWI-MASTER Interrupt basierend für Mega AVR"

Ich hab es damals so gelöst:
Ich habe einen wait to PIN CHANGE INTERRUPT auf die SDA-Leitung 
eingefügt, wenn in der Interrupt Aktion "twi_stop" in das TWCR 
eingetragen wurde.
1
.equ    TWI_PORT  = PORTC
2
.equ    TWI_SCL   = 0
3
.equ    TWI_SDA   = 1

Hier die Aufgabe im Interrupt das STOP zu senden:
1
twi_process_stop:
2
  ldi   r16, twi_stop_cmd
3
  lds   r17, (PCMSK2)
4
  sbr   r17, (1<<TWI_SDA)
5
  sts   (PCMSK2), r17         ; Pin Change Interrupt enabled
6
TWI_int_end:
7
  sts   (TWCR), r16
Da es ja kein Interrupt mehr gibt wenn der Prozessor den TWI-STOP 
ausgeführt hat und deine Leitungen für SDA und SCL im korrekten timing 
wieder auf Hi-Z stehen, muss man da mit einem anderen Pin den SDA 
überwachen und eben durch die lo-hi-Flanke des SDA einen Interrupt 
auslösen können.

Ist der PIN Change Interrupt erst mal ausgelöst musst du ihn wieder 
abschalten.
1
PIN_CHANGE_INT2:
2
  in    COPY_SREG, SREG      ; CPU-Status sichern
3
  push  r16
4
  lds   r16, (PCMSK2)
5
  cbr   r16, (1<<TWI_SDA)
6
  sts   (PCMSK2), r16       ; Pin Change Interrupt disabled
7
  lds   r16, (TWI_STATE)    
8
  cbr   r16, (1<<TWI_busy)  ; lösche busy Flag TWI FLAG Register
9
  sbr   r16, (1<<TWI_ready) ; setze ready Flag TWI FLAG Register
10
  sts   (TWI_STATE), r16
11
  pop   r16
12
  out   SREG, COPY_SREG
13
  reti

Da hat man dann zwar noch eine Leitung mehr, aber leider sah ich auch 
keine andere Möglichkeit wenn man nicht warten will. Und außerdem weißt 
du ja nicht genau wie lange man warten muss. Da kann ja immernoch irgend 
ein anderer Interrupt das ganze verlängern.

Gruß Steffen

von Stefan++ (Gast)


Lesenswert?

Hallo,

nachdem
>  while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
nichts hilft (geht eigentlich immer) sehe ich jetzt nur noch zwei 
Möglichkeiten:

1. Du rufst dein TWIM_Stop bereits vor Ende der gerade laufenden
   TWI-Aktion auf (TWINT ist noch nicht gesetzt) oder

2. deine Hardware hat wircklich zu weiche Pull-Ups
   (hab schon gesehen dass deswegen Aktionen nicht zu Ende kommen)


Übrigens:
Die while-Schleife
>  while (TWCR & (1<<TWINT));
nach einem vorhergehenden Reset von TWINT (!!!) durch
>  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
macht keinen Sinn da TWINT ja immer 0
Das kannst du auch gleich weglassen !

von Steffen H. (avrsteffen)


Lesenswert?

Steffen H. schrieb:
> Da hat man dann zwar noch eine Leitung mehr, aber leider sah ich auch
> keine andere Möglichkeit wenn man nicht warten will.
Muss mein eigenen Blödsinn korrigieren! Man braucht keine zusätzliche 
Leitung. Man nimmt einfach den PIN Change Interrupt - Pin des SDA-Pins 
dazu :-)

Steffen

von Klaus (Gast)


Lesenswert?

Der Techniker schrieb:
> Oder weiß noch jemand eine elegantere Lösung?

Nach einem Stop sollte der Bus Idle sein. Kann man irgendwie testen, ob 
der Bus Idle ist?

MfG Klaus

von Steffen H. (avrsteffen)


Lesenswert?

Stefan++ schrieb:
> nachdem
>>  while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
> nichts hilft (geht eigentlich immer) sehe ich jetzt nur noch zwei
> Möglichkeiten:
>
> 1. Du rufst dein TWIM_Stop bereits vor Ende der gerade laufenden
>    TWI-Aktion auf (TWINT ist noch nicht gesetzt) oder
>
> 2. deine Hardware hat wircklich zu weiche Pull-Ups
>    (hab schon gesehen dass deswegen Aktionen nicht zu Ende kommen)

Also auf TWSTO im TWSR zu warten bringt schonmal gar nichts. Denn da 
musst du dein TWSTO-Bit setzen um einen STOP ausführen zu lassen.

Wenn du Zustände des HW-TWI abfragen willst, dann musst du schon das 
TWI-Statusregister befragen. Und das ist TWSR. Allerdings gibt es da 
keinen Status für "TWI STOP ausgeführt".

Steffen

von Stefan++ (Gast)


Lesenswert?

@ Steffen
Datenblatt nicht gelesen was !!!

von Steffen H. (avrsteffen)


Lesenswert?

Stefan++ schrieb:
> Datenblatt nicht gelesen was !!!
Ich schon :-) Und du?
Lass euch bitte nicht täuschen von dem *TWINT*-Flag. Das ist wirklich im 
TWCR Register enthalten und signalisiert, dass eine TWI Aktion 
ausgeführt wurde. Allerdings weißt du erst über das Statusregister 
TWSR was passiert ist.

Nichts für Ungut
Steffen

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Bitte schön ;-)

von Stefan++ (Gast)


Lesenswert?

Hallo,

also heutzutage kann doch jeder lesen oder?

siehe Datenblatt:
• Bit 4 – TWSTO: TWI STOP Condition Bit
Writing the TWSTO bit to one in Master mode will generate a STOP 
condition on the 2-wire
Serial Bus. When the STOP condition is executed on the bus, the TWSTO 
bit is cleared automatically.

und
• Bit 7 – TWINT: TWI Interrupt Flag
This bit is set by hardware when the TWI has finished its current job 
and expects application software response.
....
Flag must be cleared by software by writing a logic one to it. Note that 
this flag is not automatically cleared by hardware when executing the 
interrupt routine. Also note that clearing this flag starts the 
operation of the TWI, so all accesses to the TWI Address Register 
(TWAR), TWI Status
Register (TWSR), and TWI Data Register (TWDR) must be complete before 
clearing this flag.

von Der T. (Gast)


Lesenswert?

Stefan++ schrieb:
> 1. Du rufst dein TWIM_Stop bereits vor Ende der gerade laufenden
>    TWI-Aktion auf (TWINT ist noch nicht gesetzt) oder

Jein - eigentlich nicht.. ;-)
Einzige Ausnahme: Wenn etwas auf dem Bus schief geht. An diese 
Möglichkeit habe ich jedoch auch schon gedacht und vor jedem TWIM_Stop() 
der Fehlerroutinen eine UART-Ausgabe mit einem eindeutigen Buchstaben 
eingefügt.
So kann/konnte ich über das Logfile sehen, welche Unterroutinen der 
Reihe nach aufgerufen worden. (=> keine Einzige Fehlerroutine, da alles 
korrekt abläuft..)

> 2. deine Hardware hat wircklich zu weiche Pull-Ups
>    (hab schon gesehen dass deswegen Aktionen nicht zu Ende kommen)

Habe ich auch gerade mit 1k8 getestet - keine Veränderung.. :-(
(außer der Verlustleistung :-b)

von Stefan++ (Gast)


Lesenswert?

Hallo,

ich bin noch immer darüber verwundert dass die Warteschleife
>  while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
bei dir nicht funktioniert

Ich verwende sie in all meinen Programmen und sie geht immer!
Überigens haben die LPC214x das gleiche TWI-Modul. Modul, Register, Bits 
etc. heissen nur anders und sind auch etwas anders anzusprechen aber 
funktionieren gleich. Die "State-Machine" ist absolut die gleiche.

Blöde Frage:
TWCR ist schon volatile (???), unter Umständen optimiert der Compiler 
die ständig neue Abfrage weg und dein WDT schlägt zu.
Bitte überprüf das mal, auch im List-file, was der Compiler da macht.

Ansonsten kann man aus der Ferne ohne genaue Code-Einsicht nicht mehr 
sagen.

Gruss Stefan++

von Steffen H. (avrsteffen)


Lesenswert?

Stefan++ schrieb:
> Blöde Frage:
> TWCR ist schon volatile (???), unter Umständen optimiert der Compiler
> die ständig neue Abfrage weg
Wirklich blöde Frage. TWCR ist ein Hardwareregister. Wie/Was soll da 
volatile gemacht werden? Das ist doch keine Variable..

@ Techniker
Versuch mal bitte diesen Code Schnipsel.
1
void TWIM_Stop (void)
2
{
3
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
4
  while ((SCL_LINE && SDA_LINE));
5
}


Gruß Steffen

von Karlheinz (Gast)


Lesenswert?

Was hast du gegen Stefan

was hinter einem Bezeichner wie TWCR steckt weiss der Compiler erst wenn 
es ihm einer sagt.

Das gleiche gilt für deine SCL_LINE und SDA_LINE. Die kennt der Compiler 
auch erst nach einer entsprechenden Deklaration. Wo ist die?

Karlheinz

von Klaus (Gast)


Lesenswert?

Steffen H. schrieb:
> Wirklich blöde Frage. TWCR ist ein Hardwareregister. Wie/Was soll da
> volatile gemacht werden? Das ist doch keine Variable..

Doch, es ist eine Variable an einer festen Adresse. Und es ist der 
klassische Fall für volatile, ihr Wert kann und wird sich außerhalb des 
aktuellen Software Kontext ändern. Zwar nicht durch einen anderen 
Software Kontext aber durch die Hardware.

MfG Klaus

von Klaus (Gast)


Lesenswert?

Der Techniker schrieb:
> Habe ich auch gerade mit 1k8 getestet - keine Veränderung.. :-(
> (außer der Verlustleistung :-b)

Da bellst du auch den falschen Baum an. Auf dem Scope-Bild ist ganz klar 
zu sehen, daß auch mit den alten Werten als Pullups die Signale in 
Ordnung sind.

MfG Klaus

von Der T. (Gast)


Lesenswert?

Steffen H. schrieb:
> Versuch mal bitte diesen Code Schnipsel.
>
1
> void TWIM_Stop (void)
2
> {
3
>   TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
4
>   while ((SCL_LINE && SDA_LINE));
5
> }
6
>
>

Warum soll ich endlos warten, wenn SCL und SDA high sind?

Dann überspringe ich doch den "Fehler" und sollte es doch einmal passen, 
bleibt das Programm hängen..?!?

Oder übersehe ich da etwas?

von Der T. (Gast)


Lesenswert?

Klaus schrieb:
> Da bellst du auch den falschen Baum an. Auf dem Scope-Bild ist ganz klar
> zu sehen, daß auch mit den alten Werten als Pullups die Signale in
> Ordnung sind.

Das dachte ich mir auch - aber ich bin ja für Anregungen jederzeit 
offen.. ;-)

von Der T. (Gast)


Lesenswert?

Stefan++ schrieb:
> ich bin noch immer darüber verwundert dass die Warteschleife
>>  while (TWCR & (1<<TWSTO));     // warte bis STOP ausgeführt
> bei dir nicht funktioniert
>
> Ich verwende sie in all meinen Programmen und sie geht immer!

Nicht nur du - aber wie gesagt, das Flag zeitgleich mit dem INT-Flag 
zurückgesetzt und das Stopp ist zu dem Zeitpunkt noch nicht ausgegeben 
(erst ~5us später).

Zum verifizieren habe ich jetzt noch ein neues Projekt angelegt, bei dem 
es nur den 24C04 und einen LM75 gibt. Gleiches verhalten, wenn direkt 
nach dem Schreiben der LM75 angesprochen wird. Baue ich zwischen den 
beiden Zugriffen (EEP und LM75) ein Delay von 10us ein läuft es. Dadurch 
schließe ich "Scheinfehler" durch die restliche Software aus - obwohl 
diese mangels IRQ's sowieso nicht existieren können. Für diesen Test 
habe ich sogar einen nagelneuen Mega128 verwendet - man weiß ja nie.. 
;-)

Kann es sein, dass du bei deiner Anwendung evtl. nicht direkt 
nacheinander den Bus belegst und dadurch den Fehler nicht bemerkst?

von Rolf (rolf22)


Lesenswert?

Karlheinz schrieb:

> Die kennt der Compiler auch erst nach einer entsprechenden Deklaration.
> Wo ist die?

Gäbe es keine, dann würde der Compiler gar nicht übersetzen. 
Offensichtlich HAT er aber übersetzt. ;-)
(Es geht ja hier nicht um eine Sprache für Web-Skripts wie etwa 
JavaScript, Python usw., wo der Typ erst zur Laufzeit in manchmal 
unerwarteter Weise "erraten" wird).

Benutzt man ein vernünftiges Entwicklungssystem (Arduino, AVR Studio, 
PlatformIO, ...) dann enthält das eine oder mehrere Dateien mit 
sämtlichen für die jeweilige Hardware benötigten Deklarationen und zeigt 
die auch an ("IntelliSense"). Einschließlich "const" oder "volatile", wo 
sinnvoll.

von Pat A. (patamat)


Lesenswert?

Rolf schrieb:
> vernünftiges Entwicklungssystem

Was gab es vor 11 Jahren so an "vernünftigem"?

von Harald K. (kirnbichler)


Lesenswert?

Rolf schrieb:
> Gäbe es keine, dann würde der Compiler gar nicht übersetzen.
> Offensichtlich HAT er aber übersetzt. ;-)

Meinst Du, daß das nach ganzen ELF JAHREN noch irgendwen interessiert?

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.