Ich bin auf ein seltsames Problem gestoßen: Ich möchte, dass diese
beiden Geräte per I2C kommunizieren:
- Raspberry Pi Zero als Master, 2 GPIOs bit-banged
- ATmega328P (3.3V) als Slave mit Hardware-I2C
Sonst hängt niemand am Bus (abgesehen vom LA). Ich habe externe
2,4-kOhm-Widerstände nach +3.3V als Pull-ups und die internen Pull-ups
sind auf beiden Seiten ausgeschaltet.
*Das Problem: Der AVR weigert sich sporadisch, an ihn adressierte SLA+W
zu ACKen.* Der Fehler tritt häufig (normalerweise nach weniger als 5
Kommunikationsversuchen), aber nicht deterministisch reproduzierbar auf.
Mein erster Gedanke war natürlich, dass ich in der selbstgeschriebenen
Master-Implementierung Fehler habe, aber das was mir der LA ausspuckt
(siehe Bild) sieht m.E. ok aus.
Auf der Slave-Seite habe ich die Standard-Implementierung (AVR simuliert
ein Register-File) genommen. Das Problem ist, dass die ganze
AVR-Firmware mehrere Tausend Zeilen lang ist, weil der AVR noch eine
Menge anderer Dinge zu tun hat (Timer-Interrupts, GPIO-Zeugs, PCINTs
etc.). Bevor ich jetzt viele Stunden investiere um ein Minimalbeispiel
zu finden, würde ich deshalb gerne ein paar allgemeinere Fragen stellen:
1.) Unter welchen Umständen kann die I2C-Hardware des AVR eine an sie
gerichtete SLA+W-Adressierung NACKen? Ausgehend von Tabelle 22-4 und
22-5 in der AVR-Spec habe ich zu Beginn des Hauptprogramms und in der
ISR mit wenigen Ausnahmen* immer TWEA gesetzt. Habe ich einen
Logikfehler in meinem Programm (s.u.)?
*) Die Ausnahmen betreffen lediglich die Statuscodes 0x80, 0xa8 und
0xb8. Nichts davon sollte ein SLA+W beeinflussen, richtig?
2.) Angenommen der AVR ist gerade beschäftigt, z.B. mit anderen
Interrupts oder im Idle-Sleep. Wird dann evtl. ein NACK erzeugt (bzw.
ein ACK versäumt)? Nach meiner Lesart der Spec sollte in so einem Fall
die I2C-Hardware des AVR den SCL-Pin low halten bis die Software Zeit
hat sich zu kümmern, stimmt das?
3.) In der TWI-ISR (s.u.) habe ich verschiedenen Fälle in eigenen Worten
so kommentiert wie ich die Spec interpretiere. Sind da irgendwelche
Verständnisfehler drin?
4.) Ist das was der Master von sich gibt (siehe Bild) korrekt? Die
bitgebangte Implementierung ist nicht besonders schnell, aber das sollte
doch eigentlich kein Problem sein, oder? Das einzige was m.E. nicht
100%ig der I2C-Spec entspricht, ist die etwas zu lange t_HD;DAT (data
hold time, also die Zeit zwischen "Master zieht SCL nach einer
Bitübertragung auf low" und "Master lässt SDA los"). Kann es daran
liegen?
Hier ein kleiner Ausschnitt der AVR-Software. Das simulierte
Register-File geht von 0 bis AVR_REG_MAX und i2cWriteRegister bzw.
i2cReadRegister sind anderswo definierte Funktionen, die die Daten
entgegennehmen bzw. liefern.
1
// currently selected register (0xff for none)
2
uint8_tregSel=0xff;
3
4
intmain()
5
{
6
...
7
PRR&=~(1<<PRTWI);
8
TWAR=(AVR_I2C_ADDRESS<<1)// set address
9
|(0<<0);// don't respond to general call
10
TWCR=(1<<TWEA)// acknowledge address
11
|(1<<TWEN)// enable TWI
12
|(1<<TWIE);// enable TWI interrupts
13
...
14
sei();
15
...
16
while(1){...}
17
}
18
19
ISR(TWI_vect)
20
{
21
uint8_ttwcrBase=(1<<TWINT)|(1<<TWEN)|(1<<TWIE);
22
23
if((TWSR&0xf8)==0x60)
24
{
25
// SLA+W has been received, expecting register address
26
// which we will ACK.
27
regSel=0xff;
28
TWCR=twcrBase|(1<<TWEA);
29
}
30
elseif(regSel==0xff&&(TWSR&0xf8)==0x80)
31
{
32
// The register address byte has been received (and ACKed)
33
regSel=TWDR;
34
// Note that we've already acked the transmission of this
35
// register address byte. If the register address is invalid,
36
// we will NACK the next received byte which contains the
37
// actual data that the master wants to write there.
38
if(regSel<=AVR_REG_MAX)// check if register is valid
39
TWCR=twcrBase|(1<<TWEA);// next written byte will be ACKed
40
else
41
TWCR=twcrBase;// next written byte will be NACKed
42
}
43
elseif(regSel!=0xff&&(TWSR&0xf8)==0x80)
44
{
45
// write received data to register (and perform operations)
46
i2cWriteRegister(regSel,TWDR);
47
regSel++;
48
// Check if another byte would fit into the register file and
49
// have the next received byte be ACKed (or NACKed if not).
50
if(regSel<=AVR_REG_MAX)
51
TWCR=twcrBase|(1<<TWEA);
52
else
53
TWCR=twcrBase;
54
}
55
elseif((TWSR&0xf8)==0x88)
56
{
57
// data has been received and NACKed
58
// switch to non-addressed slave mode, wait for new addressing
59
TWCR=twcrBase|(1<<TWEA);
60
}
61
elseif((TWSR&0xf8)==0xa0)
62
{
63
// stop or restart condition occurred while still being addressed
64
// switch to non-addressed slave mode, wait for new addressing
65
TWCR=twcrBase|(1<<TWEA);
66
}
67
elseif((TWSR&0xf8)==0xa8||(TWSR&0xf8)==0xb8)
68
{
69
// SLA+R has been received and ACKed or
70
// data has been sent and the master has requested more by ACKing
71
72
// if no register has been addressed, start reading at 0x00
73
if(regSel==0xff)
74
regSel=0x00;
75
TWDR=i2cReadRegister(regSel);
76
regSel++;
77
if(regSel<=AVR_REG_MAX)// are there more bytes we could send after this?
78
TWCR=twcrBase|(1<<TWEA);// yes: if the master continues reading, we'll get another 0xb8
79
else
80
TWCR=twcrBase;// no: if the master continues reading, we'll get a 0xc8 and the TWI hardware will only return '1' bits
81
}
82
elseif((TWSR&0xf8)==0xc0)
83
{
84
// data has been transmitted to the master who has
85
// NACKed it, indicating that he wants no more data
86
87
// switch to non-addressed slave mode, wait for new addressing
88
regSel++;
89
TWCR=twcrBase|(1<<TWEA);
90
}
91
elseif((TWSR&0xf8)==0xc8)
92
{
93
// master has tried another read even though we're past the end of the register file
94
// switch to non-addressed slave mode, wait for new addressing
Bert 4. schrieb:> Bitübertragung auf low" und "Master lässt SDA los"). Kann es daran> liegen?
Hmmm.
Das, was ich lese und das, was dein LA als ACK dekodiert, reimt sich
irgendwie nicht, oder ?
Womit wir wieder beim Problem mit I2C_Adresen gelandet sind - obwohl
das wahrscheinlich nicht die Ursache ist - Adresse ist 0x94 schreibend,
da nur die oberen 7 bits dekodiert werden, kann es auch 0x4A sein
- aber wie gesagt, wahrscheinlich nicht die Ursache.
Und wer hat die Werte dann überhaupt eingetragen ( Adress, ACK) ?
Sorry, ich vergaß: AVR_I2C_ADDRESS ist per #define auf 0x4a gesetzt.
(Steht in einem gesonderten Header-File, das sowohl vom AVR- als auch
vom RPi-Programm eingebunden wird, daher hab ich vergessen, das in den
Sourcecode mit reinzukopieren.)
Was meinst du mit dem ACK, das mein LA dekodiert? Vielleicht hab ich
Tomaten auf den Augen, aber ich sehe da nichts Verkehrtes. Während des
neunten Pulses auf SCK hält der AVR SDA low (beim ersten, erfolgreichen
SLA+W) bzw. tut es nicht (beim zweiten, fehlgeschlagenen SLA+W). Was
übersehe ich da?
Edit: Um meine Frage vielleicht etwas klarer auszudrücken - bei den drei
korrekten ACKs zieht der AVR die die SDA-Leitung low noch bevor der RPi
sie losgelassen hat (er hält sie noch low vom zuletzt gesendeten
Null-Bit, gibt sie aber rechtzeitig frei bevor er den neunten SCK-Puls
schickt). Ich wüsste aber nicht wie ich das zuverlässig verhindern
sollte, denn Echtzeitkontrolle habe ich auf dem RPi nicht (bin auf
Raspbian im Userspace). Andererseits wüsste ich aber auch nicht wieso es
ein Problem darstellen sollte wenn sich da was überlappt. Der AVR wird
doch wohl kaum prüfen ob SDA frei ist, bevor er ihn low zieht, oder?
Bert 4. schrieb:> Was meinst du mit dem ACK, das mein LA dekodiert? Vielleicht hab ich> Tomaten auf den Augen, aber ich sehe da nichts Verkehrtes. Während des
Sorry, wahrscheinlich habe ich Tomaten auf den Augen.
> ein ACK versäumt)? Nach meiner Lesart der Spec sollte in so einem Fall> die I2C-Hardware des AVR den SCL-Pin low halten bis die Software Zeit> hat sich zu kümmern, stimmt das?
Wenn erstmal (beim Slaven) TWINT gestezt wird, wird SCL solange auf
LOW gehalten bis TWINT zurückgesetzt wird. Das ist bei dir nicht
der Fall, also wird TWINT (wahrscheinlich) gar nicht gesetzt und die
ISR wird nicht angesprungen.
Was du versuchen kannst:
Jedes empfangene Byte ausgeben.
Jeder Eintritt in die ISR wird ausgegeben (aufsteigend, mit TWSR).
Bei jedem Eintritt in die ISR wird (als TEST, natürlich) SCL für
eine bestimmte Zeit auf LOW gehalten, mit LA kontrollieren.
Vorausgesetzt, die andere Seite unterstützt clockstretching.
Und vor allem, SCL beim Testen so weit wie nur möglich runtersetzen.
EDIT:
Da anscheinend die Adresse gar nicht erst erkannt wird, vielleicht
könntest du es mal mit einer anderen Adresse versuchen oder General
Call erlauben und dann ständig damit versuchen ?
Gute Idee, danke! Ich habe jetzt zu Beginn des ISR einen Befehl
eingefügt, der (TWSR & 0xf8) auf den UART gibt. Ergebnis (siehe Bild):
Ich bekomme ein 0xa0 (Stop Condition der vorherigen Transaktion), aber
kein 0x60 (SLA+W). Du hast also recht, ich bekomme keinen Interrupt für
das SLA+W. Bloß warum?
Mein SCL-Takt liegt dank der ineffizienten Bit-Banging-Implementierung
des Masters bei ca. 3 kHz; ich denke das ist nicht zu schnell.
Es ist natürlich naheliegend, dass das Problem irgendwie von der
vorangegangenen Transaktion herrührt, denn es tritt nur auf, wenn direkt
vorher eine Schreiboperation* durchgeführt wurde. Wenn ich Master-seitig
eine sehr lange Pause zwischen den einzelnen Registerzugriffen einfüge,
verschwindet der Fehler. Aber das ist nicht praktikabel und sollte doch
auch nicht nötig sein, schließlich halte ich die spezifizierte t_BUF
(bus free time) ein.
*) Ob es auch nach Leseoperationen auftritt, kann ich ich gerade nicht
sagen. Bisher waren es nur Schreiboperationen, aber der Fehler ist wie
gesagt sporadisch.
Deinen Vorschlag mit dem Clock Stretching habe ich noch nicht getestet
(kommt noch). Was genau würde mir das sagen?
Edit: Bei allen anderen Transaktionen (die, bei denen das ACK kommt)
kommen die Daten an. Das sehe ich an den Aktionen, die der AVR auf
seinen übrigen GPIOs tätigt.
Dein Vorschlag, mit General Call anstatt mit der normalen Adresse zu
arbeiten, ist ein bisschen aufwändig umzusetzen. Dazu müsste ich beim
Master den ganzen Code aufdröseln und bei der Adresse zwischen Read und
Write unterscheiden, denn der AVR macht (sinnvollerweise) kein Slave
Transmitter bei General Calls. Ich weiß auch gar nicht, ob die Abfolge
"SLA+W mit GC -> Repeated Start -> SLA+R mit normaler Adresse" überhaupt
legal ist.
Bert 4. schrieb:> Mein SCL-Takt liegt dank der ineffizienten Bit-Banging-Implementierung> des Masters bei ca. 3 kHz; ich denke das ist nicht zu schnell.
Nöö, wenn es noch bisschen langsamer wäre, könntest du mitschreiben...
> Deinen Vorschlag mit dem Clock Stretching habe ich noch nicht getestet> (kommt noch). Was genau würde mir das sagen?
Nicht viel, aber wenn der Master das auch unterstützt, kannst du mit
Vollgas am Bus fahren und der Slave bremst in Kurven, wenn nötig ;)
> Transmitter bei General Calls. Ich weiß auch gar nicht, ob die Abfolge> "SLA+W mit GC -> Repeated Start -> SLA+R mit normaler Adresse" überhaupt> legal ist.
Da bin ich mir auch nicht sicher, aber es geht nur um darum, ob die
Adresse als solche immer erkannt wird.
Also mit "SLA+W(GC) -> Pause -> STOP" auf ACK testen.
Unabhängig davon würde ich auch nur "SLA+W(Adr) -> Pause -> STOP" im
loop laufen lassen, um zu sehen, ob es so ohne Probleme funktioniert
und die Adresse immer mit ACK bestätigt wird.
Der Master unterstützt Clock Stretching, das war einer der Gründe warum
ich den bit-bange. Aber es hilft halt nichts, den Takt noch weiter zu
senken, denn das Problem wird dadurch nur schwerer reproduzierbar. Wenn
ich eine Sekunde Pause zwischen zwei Registerzugriffe setze, bekomme ich
innerhalb vertretbarer Testzeiträume gar keine Fehler mehr.
Das mit dem General Call habe ich getestet, es ändert leider überhaupt
nichts: Nach dem 0x80 (das jetzt natürlich ein 0x90 ist) kommt ein 0xa0
für die Stop Condition und dann nichts mehr.
Irgendwelche Ideen? Ich bin leider zusehends am Ende mit meinem Latein.
Was mir noch auffällt (siehe das Bild in meinem Post von 15:54): Der ISR
für die Stop Condition (0xa0) kommt relativ spät, jedenfalls im
Vergleich zu den anderen ISR-Aufrufen (0x60, 0x80 etc.), die praktisch
sofort erscheinen. Kann natürlich am UART liegen, aber angenommen, das
0xa0 kommt tatsächlich mit Verspätung, würde das erklären, warum das
folgende SLA+W übersehen wird? In dem Fall kann der AVR schließlich
nicht den Takt verlangsamen, indem er SCL runter zieht.
Mich stört in den Diagrammen ein wenig, dass sich darin mitunter
scheinbar gleichzeitig SCL und SDA ändern. Nun sind die allerdings nicht
so weit aufgelöst, dass man daraus wirklich was entnehmen könnte. Das
wär aber mal ein Punkt, wo du genauer reinsehen könntest.
Bert 4. schrieb:> Was mir noch auffällt (siehe das Bild in meinem Post von 15:54): Der ISR> für die Stop Condition (0xa0) kommt relativ spät, jedenfalls im> Vergleich zu den anderen ISR-Aufrufen (0x60, 0x80 etc.), die praktisch> sofort erscheinen.
Man kann auch einfach in der ISR am Anfang/Ende mit einem PortBit
wackeln.
Quasi ein "in ISR"-Signal. Es sind ja noch ein paar Kanäle an
10€-LA-Pulseview frei.
Damit mache ich normalerweise "Timing-Debugging". Allerdings sollte man
dann mit annähernd F_CPU abtasten, um das ISR-Timing gut zu sehen.
Ich stand auch mal vor der Frage, wie ich einen AVR an einen RPi
anflanschen soll. Und entschied mich für die serielle Schnittstelle
statt I2C, da der RPi als I2C-Master in Hardware ausscheidet.
Das war dann freilich ein wenig ums Eck, weil ich der Seriellen ein
Packet Framing verpassen musste.
Da hast du recht. Leider ist mein LA ein Billigst-Teil, das den Namen
kaum verdient und mit Ach und Krach 8 MHz schafft. Was besseres habe ich
leider nicht.
Allerdings bin ich vorsichtig optimistisch, dass diese
Gleichzeitigkeiten ok sind. Sie treten nämlich immer nur dann auf, wenn
der Slave etwas mit SDA macht in Reaktion auf eine SCL-Änderung des
Masters.
Wenn ich mir mein letztes Bild im Detail anschaue, gibt es drei Stellen,
an denen SCL und SDA "gleichzeitig" Flanken haben:
1. Stelle: Der Master zieht nach dem Übertragen des 8. Bits (eine 1) SCL
auf low. Der Slave (AVR) zieht dann sofort SDA auf low, in Vorbereitung
auf den kommenden ACK-Takt.
2. und 3. Stelle: Der Master zieht SCL nach dem ACK-Takt wieder auf low.
Daraufhin lässt der Slave SDA sofort los.
Bert 4. schrieb:> Irgendwelche Ideen? Ich bin leider zusehends am Ende mit meinem Latein.
Als eine Möglichkeit:
Master sendet "SLA+W(Adr)" als Ping.
Sollte ACK empfangen werden, geht es normal weiter.
Falls nicht, wird solange "STOP -> START -> SLA+W(Adr)" gesendet,
bis ein ACK erfolgt.
EDIT:
Das passierte mir einmal auch, nur kann ich mich nicht mehr erinnern,
was das für ein IC war - scheint also nicht unüblich zu sein.
Bert 4. schrieb:> Wenn ich mir mein letztes Bild im Detail anschaue, gibt es drei Stellen,> an denen SCL und SDA "gleichzeitig" Flanken haben:> 1. Stelle: Der Master zieht nach dem Übertragen des 8. Bits (eine 1) SCL> auf low. Der Slave (AVR) zieht dann sofort SDA auf low, in Vorbereitung> auf den kommenden ACK-Takt.> 2. und 3. Stelle: Der Master zieht SCL nach dem ACK-Takt wieder auf low.> Daraufhin lässt der Slave SDA sofort los.
Ich sehe da absolut kein Problem. Zeigt nur, dass der Slave voll da
ist und entsprechend reagiert. Vielleicht wäre es interessant wenn
der Master damit ein Problem hätte, was aber nicht der Fall ist.
Sorry, ich hänge gerade zwei, drei Posts hinterher, weil ich nebenher
noch teste.
Die Idee am Pin zu wackeln hatte ich auch nachdem ich das mit dem UART
geschrieben hatte. Das habe ich jetzt gemacht und es scheint dass der
Stop-Condition-Interrupt doch nicht verspätet kommt. Tatsächlich wird
mir das Pin-Wackeln zu Beginn der ISR sogar schon 1,8us vor der Stop
Condition angezeigt. Entweder habe ich Zeitreisen erfunden oder der
Schrott-LA baut in dem Bereich ein bisschen Mist.
Den UART würde ich gerne für andere Sachen offen lassen. Im Moment dient
er zum Debugging und später vielleicht für was anderes. Außerdem bin ich
mir nicht sicher, ob man dem RPi beibringen kann, dass er den UART beim
Start nicht fürs Terminal benutzt. SPI wäre noch eine Möglichkeit, aber
ich würde ungern die Pins dafür verschwenden. Der letzte Ausweg wäre
dann, I2C auch auf der Slave-Seite zu bit-bangen, aber das würde ich mir
wirklich gerne ersparen. Und zu guter letzt geht's ja auch ums Lernen.
Ich würde schon gerne wissen, warum sowas passiert. Entweder der
Hardware-Slave-I2C des AVR hat einen Fehler (sehr unwahrscheinlich) oder
ich mache einen fundamentalen Denkfehler und den hätte ich dann doch
gerne behoben.
Bert 4. schrieb:> Außerdem bin ich> mir nicht sicher, ob man dem RPi beibringen kann, dass er den UART beim> Start nicht fürs Terminal benutzt.
/boot/cmdline.txt:
console=ttyAMA0,115200 rauswerfen
/etc/inittab:
Zeile mit ttyAMA0 mit # auskommentieren
> SPI wäre noch eine Möglichkeit,AVR als SPI-Slave macht keinen Spass.
Bert 4. schrieb:> Entweder der> Hardware-Slave-I2C des AVR hat einen Fehler (sehr unwahrscheinlich)
Genau, das wäre längst schon jemandem aufgefallen.
> oder> ich mache einen fundamentalen Denkfehler
Ich vermute: nein. Ich würde die Ursache eher beim Master vermuten,
genauer: dessen angeblichen Support für Clock-Stretching mal
hinterfragen. Allein davon, dass man bit-banged, ist das ja noch lange
nicht gewährleistet. Entsprechender Code ist schwieriger korrekt zu
implementieren, als man im ersten Moment vermuten würde, jedenfalls im
Userspace eines Nicht-Echtzeit-Systems...
A. K. schrieb:> /boot/cmdline.txt:> console=ttyAMA0,115200 rauswerfen> /etc/inittab:> Zeile mit ttyAMA0 mit # auskommentieren
Danke! Behalte ich mal im Hinterkopf, könnte eines Tages noch nützlich
sein.
> AVR als SPI-Slave macht keinen Spass.
Mist. AVR als Irgendwas-Slave scheint keinen Spaß zu machen.
Jobst M. schrieb:> Beispielschnipsel in ASM, der im Polling funktioniert.
Danke. Das Problem ist, dass der AVR noch viele andere Dinge zu tun hat
(auf pin changes und timer reagieren, mit anderen Geräten kommunizieren
etc.). Ohne Interrupts fürchte ich, dass ich noch viel mehr Ärger
bekomme. Und nach der Diskussion mit Marc glaube ich, wenn ich den
Interrupt nicht bekomme und SCL nicht low gehalten wird, dass dann auch
TWI nicht gesetzt sein wird.
c-hater schrieb:> Bert 4. schrieb:>> oder>> ich mache einen fundamentalen Denkfehler>> Ich vermute: nein. Ich würde die Ursache eher beim Master vermuten,> genauer: dessen angeblichen Support für Clock-Stretching mal> hinterfragen. Allein davon, dass man bit-banged, ist das ja noch lange> nicht gewährleistet. Entsprechender Code ist schwieriger korrekt zu> implementieren, als man im ersten Moment vermuten würde, jedenfalls im> Userspace eines Nicht-Echtzeit-Systems...
Ich kann meinen Master-Code gerne posten (müsste ihn aber vorher noch
etwas aufräumen). Mein Eindruck war, dass ein (Single-)Master recht
einfach zu implementieren ist, weil der Master den Takt bestimmen kann.
(Wie ich einen Slave ohne Echtzeitkontrolle schreiben sollte, wüsste ich
dagegen nicht.) Wenn ich die Spec richtig lese (korrigiert mich hier
bitte ggfs.!), ist das einzige Timing, das der Master einhalten muss,
t_VD;DAT (data valid time) und t_VD;ACK (data valid acknowledge time).
Das hatte ich ja bereits oben angesprochen und bisher hat darin niemand
ein großes Problem gesehen.
Bert 4. schrieb:> Ohne Interrupts fürchte ich, dass ich noch viel mehr Ärger> bekomme. Und nach der Diskussion mit Marc glaube ich, wenn ich den> Interrupt nicht bekomme und SCL nicht low gehalten wird, dass dann auch> TWI nicht gesetzt sein wird.
Die Funktion ist mit IRQ die selbe. Alle zeitkritischen Dinge werden von
der Hardware erledigt.
Wenn also andere IRQs nicht länger als ein Byte dauern, sollte es keine
Probleme geben.
Gruß
Jobst
Jetzt muss ich doch nochmal auf meine zweite Frage im Eingangspost
zurückkommen. Inwieweit können andere Interrupts das TWI beeinflussen?
Ich habe probeweise alle anderen Interrupts abgedreht und konnte den
Fehler nicht mehr reproduzieren. Ob er ganz verschwunden oder nur so
selten geworden ist, dass ich ihn beim Testen nicht mehr treffe, ist
schwer zu sagen.
Dann habe ich schrittweise die Interrupts wieder angestellt und versucht
das Problem einzugrenzen. Der Übergang zwischen Fehler und kein Fehler
scheint hier zu sein: Wenn ich in ISR(TIMER0_COMPA_vect) zu viele
Befehle ausführe, kriege ich das Problem mit den verpassten SLA+Ws.
Genauer gesagt bedeutet "zu viele Befehle" Folgendes:
ISR(TIMER0_COMPA_vect) {millis++;} funktioniert.
ISR(TIMER0_COMPA_vect) {millis++; millis %= 86400000UL;} führt zum
SLA+W-Problem.
Dabei ist millis ein (volatile) uint32_t und TIMER0_COMPA_vect tickt mit
1kHz. Hier die Initialisierung (F_CPU=8000000):
1
PRR&=~(1<<PRTIM0);
2
OCR0A=125;
3
TCCR0A=(0b00<<COM0A0)// OC0A disconnected
4
|(0b00<<COM0B0)// OC0B disconnected
5
|(0b10<<WGM00);// CTC mode, reset on OCR0A
6
TCCR0B=(0b0<<WGM02)
7
|(0b011<<CS00);// 8 MHz / 64 / 125 = 1 kHz
8
TIMSK0|=(1<<OCIE0A);// interrupt when reaching OCR0A
Mir ist klar, dass man in ISRs nicht zu viel machen sollte und ich weiß
nicht genau wie viele Takte diese beiden 32-Bit-Operationen haben, aber
so viel können es nicht sein, oder?
Abgesehen davon, warum kann ein anderer Interrupt das TWI durcheinander
bringen? Meinem Verständnis nach (und wie Jobst oben geschrieben hat),
sollten zeitkritische Dinge auf dem I2C-Bus - und dazu gehört doch wohl
das ACKen eines SLA+W - von der Hardware abgehandelt werden, egal was
das Programm gerade macht, oder nicht?
Auch spannend: Timer 1 läuft nebenher auch noch und macht PWM auf einem
Pin, allerdings ohne ISR. Davon lässt sich das TWI (wie erwartet)
überhaupt nicht stören.
Jobst M. schrieb:> Wenn also andere IRQs nicht länger als ein Byte dauern, sollte es keine> Probleme geben.
Selbst wenn, so lange der Master das Clock Stretching des AVRs
akzeptiert, dürfen andere IRQs doch beliebig lang dauern, weil der AVR
SCL low hält bis die TWI-ISR durchgelaufen ist. Oder nicht? Ein Problem
würde ich erst dann sehen, wenn andere Interrupts so häufig feuern, dass
der TWI-Interrupt mit seiner niedrigen Prio gar nicht mehr zum Zug
kommt.
Bert 4. schrieb:> so lange der Master das Clock Stretching des AVRs> akzeptiertBert 4. schrieb:> weil der AVR SCL low hält
Wo steht, dass der das macht?
Bert 4. schrieb:> der TWI-Interrupt mit seiner niedrigen Prio
IRQ-Prioritäten gibt es beim AVR nicht.
Wenn ich IRQs unterbrechbar machen möchte, steht am Anfang der
Serviceroutine SEI
Gruß
Jobst
Jobst M. schrieb:> Wenn ich IRQs unterbrechbar machen möchte, steht am Anfang der> Serviceroutine SEI
Hä?
Meinst du so?
1
ISR(Some_ISR)
2
{
3
sei();
4
5
6
//do something
7
}
Das ist doch völliger quark. sei und cli setzen doch bloß das I Bit im
SREG Register, das schaltet globale Interrupts doch frei oder sperrt.
Das I Bit wird doch nicht gelöscht sobald ne ISR aufgerufen wird?! Oder
täusche ich mich?
Draco schrieb:> Das ist doch völliger quark. sei und cli setzen doch bloß das I Bit im> SREG Register, das schaltet globale Interrupts doch frei oder sperrt.> Das I Bit wird doch nicht gelöscht sobald ne ISR aufgerufen wird?! Oder> täusche ich mich?
Oh... ich korrigiere mich!
1
The I-bit is cleared by
2
hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts.
Wusste ich nicht. Dachte das I Bit bleibt immer stehen, auch wenn ein
Int ausgelößt wurde.
Marc V. schrieb:> Jobst M. schrieb:>> IRQ-Prioritäten gibt es beim AVR nicht.>> Gibt es sehr wohl.
Allerdings. Grob gesagt, je niedriger die Adresse des Vektors in der ISR
Sprungtabelle ist, desto höher die Priorität. RESET geht also vor alles
andere.
Man kann eine ISR in avrgcc als 'ISR_NOBLOCK' deklarieren, wenn man
weiss, was man da tut. Im Allgemeinen ist I²C aber ein synchroner Bus,
der recht unempfindlich gegenüber anderen ISR ist.
Man darf aber z.B. nicht zulassen, das SDA den Pegel wechselt, wenn SCL
high ist, das interpretiert jeder Slave sofort als Start oder Stop. I²C
ist eben kein fehlerkorrierter oder störunempfindlicher Bus.
Marc V. schrieb:> Jobst M. schrieb:>> Wo steht, dass der das macht?>> Im DaBla.
Bevor ich das geschrieben habe, habe ich dort hinein geschaut, aber
nichts darüber gefunden.
Zeig mir bitte mal die richtige Stelle.
Matthias S. schrieb:> Marc V. schrieb:>> Jobst M. schrieb:>>> IRQ-Prioritäten gibt es beim AVR nicht.>>>> Gibt es sehr wohl.>> Allerdings. Grob gesagt, je niedriger die Adresse des Vektors in der ISR> Sprungtabelle ist, desto höher die Priorität.
Naja. Wenn zwei IRQs gleichzeitig eintreffen, ist das richtig. Aber
Prioritäten im Sinne A darf B unterbrechen, B aber A nicht, so wie beim
8051, hat er nicht.
Gruß
Jobst
>> weil der AVR SCL low hält> Wo steht, dass der das macht?
22.5.5, erster Abschnitt: "As long as the TWINT Flag is set, the SCL
line is held low." Deswegen ist es so wichtig, bei jedem TWI-ISR das
TWINT-Bit zu löschen.
Wenn ich das richtig verstanden habe, funktionieren
Interrupt-Prioritäten so: Interrupts unterbrechen sich nicht, es sei
denn man murkst explizit mit SEI oder ISR_NOBLOCK rum. Treten während
eines ISR weitere Interrupts auf, werden diese gesammelt (wobei
mehrfaches Auftreten desselben Interrupts nur einmal gesammelt wird).
Nach dem reti entscheidet die Prio darüber, welcher der gesammelten
Interrupts zuerst seinen ISR-Aufruf bekommt. Wenn Interrupts hoher
Priorität zu schnell hintereinander auftreten, kann der ISR-Aufruf eines
niedriger priorisierten Interrupts beliebig lange verzögert werden.
Korrekt?
Das erklärt aber m.E. alles nicht, warum mein SLA+W nicht geACKt wird,
schließlich sollte das in Hardware passieren.
Bert 4. schrieb:> Mir ist klar, dass man in ISRs nicht zu viel machen sollte und ich weiß> nicht genau wie viele Takte diese beiden 32-Bit-Operationen haben, aber> so viel können es nicht sein, oder?
Im Prinzip uninteressant, du sollst nicht deine Interrupt Routinen
oder Funktionen der I2C anpassen - also, dies dauert 100us, das geht
noch, aber dies muss raus weil es langer dauert und TWI_ISR wird
möglicherweise übersprungen...
Eine einfache Möglichkeit dies zu umgehen, wäre:
Dies sollte beim Master sowieso implementiert werden und wird
dein Problem wahrscheinlich lösen.
Wie gesagt, es kann sein, dass eine Device auf dem I2C Bus nicht
antworten kann und NACK, bzw, gar keine Bestätigung sendet, was
ja auch ein NACK ist.
Und nicht alle I2C-Devices müssen Clock-Stretching unterstützen.
I2C wird sowieso nicht für zeitkritische Aufgaben genommen, im
Prinzip hast du da auch kein grosses Problem. So, wie von dir
geschildert und von LA angezeigt wird die Adresse nicht als
eigene erkannt, gilt auch für GC.
Timing beim Master wird wahrscheinlich eingehalten, deswegen war
auch der Vorschlag mit GC - da kann man keine bits falsch senden.
Das einzige, was ich mir noch vorstellen kann ist, dass SDA und
SCL unzureichende Widerstände nach VCC haben.
Marc V. schrieb:> Im Prinzip uninteressant, du sollst nicht deine Interrupt Routinen> oder Funktionen der I2C anpassen - also, dies dauert 100us, das geht> noch, aber dies muss raus weil es langer dauert und TWI_ISR wird> möglicherweise übersprungen...
Ja, definitiv auch meine Meinung.
> Eine einfache Möglichkeit dies zu umgehen, wäre:> (...)> Dies sollte beim Master sowieso implementiert werden
Ist es auch. Aber ich würde gerne verstehen was da passiert, aus zwei
Gründen: erstens einfach um etwas zu lernen und zweitens weil es sich um
einen sporadischen Fehler handelt. Wenn ich mit irgendwelchen
Workarounds komme, die auf der Testbank zunächst funktionieren, in
Wirklichkeit aber die Fehlerrate nur senken ohne den Fehler ganz zu
beheben, dann bekomme ich im Betrieb, womöglich nach Monaten, plötzlich
unerklärliche Fehler. Ich wüsste schon gern was da kaputt ist und würde
es idealerweise reparieren. Und wenn das Problem nur workaround-bar aber
nicht lösbar ist, würde ich zumindest in die Doku schreiben wollen, was
denn nun Sache ist.
> Das einzige, was ich mir noch vorstellen kann ist, dass SDA und> SCL unzureichende Widerstände nach VCC haben.
2,4 kOhm nach +3.3V. Ich habe diverse andere Werte probiert, hat keinen
Unterschied gemacht.
Marc V. schrieb:> • Bit 7 – TWINT: TWI Interrupt Flag
??
Die richtige Stelle hat aber Bert schon gezeigt.
Bert 4. schrieb:> 22.5.5, erster Abschnitt:
Gruß
Jobst
Bert 4. schrieb:> Ist es auch. Aber ich würde gerne verstehen was da passiert, aus zwei> Gründen: erstens einfach um etwas zu lernen und zweitens weil es sich um
Mal was anderes:
Ich sehe nirgendwo 0x60 in TWSR als Antwort, diese sollte aber als
erste kommen ?
Mit 0x80 bzw. 0x90 bist du schon adressiert worden, kann aber nach
STOP nicht mehr sein, oder ?
Marc V. schrieb:> Bert 4. schrieb:> Mal was anderes:> Ich sehe nirgendwo 0x60 in TWSR als Antwort, diese sollte aber als> erste kommen ?
Ja, aber irgendwo musste ich schneiden, das Bild ist ja selbst jetzt
noch breiter als die Polizei erlaubt.
0x60 (bzw. 0x70 bei GC) kam, dann ein oder mehrere 0x80 (bzw. 0x90),
dann das 0xa0, dann der Fehler. Auch bei Lesezugriffen kamen die
korrekten Statuscodes.
Bert 4. schrieb:> Ja, aber irgendwo musste ich schneiden, das Bild ist ja selbst jetzt> noch breiter als die Polizei erlaubt.
Probiere mal TWSTO nach 0xA0 zu setzen, könnte helfen.
1
elseif((TWSR&0xf8)==0xa0)
2
{
3
TWCR=twcrBase|(1<<TWEA)|(1<<TWSTO);
4
}
EDIT:
Und vielleicht in der ISR TWSR ganz am Anfang in eine locale
Variable einlesen ?
Reg zugriff ist bestimmt schneller, da TWSR auf Adresse 0xBC ist.
Marc V. schrieb:> Probiere mal TWSTO nach 0xA0 zu setzen, könnte helfen.> Und vielleicht in der ISR TWSR ganz am Anfang in eine locale> Variable einlesen ?
Ändert beides nichts. Außer natürlich, dass Leseoperationen (SLA+W ->
Registeradresse schreiben -> Repeated Start -> SLA+R -> Registerinhalt
lesen) nicht mehr funktionieren.
Bert 4. schrieb:> Ändert beides nichts. Außer natürlich, dass Leseoperationen (SLA+W ->
Das mit local war ja auch nur, um schneller zu sein. Am Anfang
1
locVar=TWSR&0xf8;
sollte nur die if Abfrage schneller machen.
Und jetzt bin ich mit meinem Latein auch am Ende, so etwas darf
ganz einfach nicht passieren, wenn doch, ist die AVR Hardware nicht
in Ordnung...
Bert 4. schrieb:> Danke einstweilen für den Input! Vielleicht hat sonst noch jemand eine> Idee?
a) Mit einer anderen MEGA probieren.
b) Mit Oszi I2C-Bus beobachten.
Bert 4. schrieb:> Ich kann meinen Master-Code gerne posten (müsste ihn aber vorher noch> etwas aufräumen).
Das wäre sicher sinnvoll.
> Mein Eindruck war, dass ein (Single-)Master recht> einfach zu implementieren ist, weil der Master den Takt bestimmen kann.
Nein, das kann er eben nicht, jedenfalls nicht in vollem Umfang.
Genau darin besteht doch Clock-Stretching im Kern: dass der Slave in den
Takt des Masters eingreifen, diesen also sozusagen anhalten kann. Der
Master muss sich diesbezüglich kooperativ verhalten und in dieser
Situation auch wirklich anhalten, sonst jibbet effektiv kein
Clock-Stretching uuuund bumm...
Marc V. schrieb:> a) Mit einer anderen MEGA probieren.
Kann ich später mal machen. Aber ehrlich gesagt habe ich da nicht viel
Hoffnung. Es kann sogar sein, dass ich da zwischenzeitlich schon mal
einen anderen AVR drin hatte, ich hab die nicht nummeriert oder so.
> b) Mit Oszi I2C-Bus beobachten.
Hab ich leider nicht.
c-hater schrieb:> Bert 4. schrieb:>>> Ich kann meinen Master-Code gerne posten (müsste ihn aber vorher noch>> etwas aufräumen).>> Das wäre sicher sinnvoll.
Wie gesagt, ich muss erst den Code ein bisschen aufräumen und die Teile
rauswerfen, die nicht für den RPi sind.
>> Mein Eindruck war, dass ein (Single-)Master recht>> einfach zu implementieren ist, weil der Master den Takt bestimmen kann.>> Nein, das kann er eben nicht, jedenfalls nicht in vollem Umfang.>> Genau darin besteht doch Clock-Stretching im Kern (...)
Ja, sicher, aber das macht die Sache ja nur langsamer. Wenn ich
innerhalb von gewissen Zeiten auf etwas reagieren müsste, hätte ich ein
Problem ohne Echtzeitkontrolle. Clock Streching heißt ja nur, dass der
Master etwas länger nichts tun braucht. Dann geht er halt wieder
schlafen, wendet sich anderen Tasks zu oder eiert schlimmstenfalls in
einer Warteschleife herum. No biggie.
Bert 4. schrieb:>> Genau darin besteht doch Clock-Stretching im Kern (...)> Ja, sicher, aber das macht die Sache ja nur langsamer.
Natürlich, genau das ist ja der Sinn der Sache.
> Wenn ich> innerhalb von gewissen Zeiten auf etwas reagieren müsste, hätte ich ein> Problem ohne Echtzeitkontrolle. Clock Streching heißt ja nur, dass der> Master etwas länger nichts tun braucht.
Genau so ist das auch.
Der Master muss halt nur im richtigen Moment fragen, ob er fortsetzen
darf und nicht z.B. zu früh, zu einem Zeitpunkt, zu dem er das noch
garnicht erfahren kann.
Ich bin nahezu sicher, dass du da einen fetten Bug eingebaut hast.
Vielleicht gibt er sich ja bereits beim "Aufräumen des Codes" zu
erkennen...
c-hater schrieb:> Der Master muss halt nur im richtigen Moment fragen, ob er fortsetzen> darf und nicht z.B. zu früh, zu einem Zeitpunkt, zu dem er das noch> garnicht erfahren kann.
Ich verstehe nicht ganz was du damit meinst. Was genau kann der Master
(nicht) erfahren?
> Ich bin nahezu sicher, dass du da einen fetten Bug eingebaut hast.> Vielleicht gibt er sich ja bereits beim "Aufräumen des Codes" zu> erkennen...
Würde mich freuen, den zu finden. Ich bin gespannt. Siehe Anhang.
Bert 4. schrieb:> Ich verstehe nicht ganz was du damit meinst. Was genau kann der Master> (nicht) erfahren?
Dass der Slave gesagt hat: Stop this shit for now. Was denn sonst?
Das kann man z.B. nicht erfahren, bevor es der Slave überhaupt gesagt
hat. Das ist aber vermutlich eher nicht das Problem, eher das:
Das kann man aber auch nicht erfahren, bevor der eigene Eingang auf den
eigenen Ausgang reagiert haben kann. Ja, das kann auch schonmal länger
dauern, als der Code braucht, um den Ausgang zu setzen und danach den
Eingang abzufragen. Sowas hat man selbst beim vergleichsweise
schweinelangsamen AVR8, selbst da muss man immer mindestens einen Takt
warten...
> Würde mich freuen, den zu finden. Ich bin gespannt. Siehe Anhang.
Heute nicht mehr. Morgen schau' ich mir das mal an.
Bert 4. schrieb:> Danke einstweilen für den Input! Vielleicht hat sonst noch jemand eine> Idee?
0xA0 wird noch erkannt, probiere nach Empfang von 0xA0 die anderen
Interrupts eine Zeit lang zu sperren (ausser TWI, natürlich).
Sollte das helfen, kannst du weitergehen und andere Interrupts einen
nach dem anderen freigeben, um zu sehen wo es genau happert.
Bert 4. schrieb:> Würde mich freuen, den zu finden. Ich bin gespannt. Siehe Anhang.
Viel einfacher wäre es, eine andere MEGA anstatt RPi zu nehmen und
es damit probieren. Sollte es klappen, beim RPi weitersuchen, sollte
es nicht klappen, liegt der Fehler beim Slave.
c-hater schrieb:> Bert 4. schrieb:>>> Ich verstehe nicht ganz was du damit meinst. Was genau kann der Master>> (nicht) erfahren?>> Dass der Slave gesagt hat: Stop this shit for now. Was denn sonst?
Ok, aber wenn ich meinen LA-Bildern trauen darf, ist das nicht das
Problem, oder?
> Das kann man aber auch nicht erfahren, bevor der eigene Eingang auf den> eigenen Ausgang reagiert haben kann. Ja, das kann auch schonmal länger> dauern, als der Code braucht, um den Ausgang zu setzen und danach den> Eingang abzufragen. Sowas hat man selbst beim vergleichsweise> schweinelangsamen AVR8, selbst da muss man immer mindestens einen Takt> warten...
Dazu weißt ich zu wenig über den RPi (und über wiringPi). Um welche
Zeitintervalle geht's da? Meine Schalterei auf den GPIOs bewegt sich ja
im Bereich von dutzenden bis hunderten us.
Marc V. schrieb:> Viel einfacher wäre es, eine andere MEGA anstatt RPi zu nehmen und> es damit probieren.
Kann sein, dass ich sowas letztlich machen muss, aber bevor ich Hardware
umstöpsle, würde ich gerne erst die anderen Fehlerursachen ausschließen.
c-hater schrieb:> Das kann man aber auch nicht erfahren, bevor der eigene Eingang auf den> eigenen Ausgang reagiert haben kann. Ja, das kann auch schonmal länger> dauern, als der Code braucht, um den Ausgang zu setzen und danach den> Eingang abzufragen.
Der Ablauf von clock stretching ist:
release SCL
wait until SCL=1
denn der Slave zeigt das an, indem er SCL auf 0 hält. Genau das findet
sich im gezeigten Code in Form von I2CMSW_WAIT_FOR_SCL wieder.
> Sowas hat man selbst beim vergleichsweise> schweinelangsamen AVR8, selbst da muss man immer mindestens einen Takt> warten...
Wäre bei diesem Ablauf kein Problem.
Ist es aber schon deshalb nicht, weil der RPi die GPIO m.W. über
Systemaufrufe steuert, d.h. da geht für jede Aktion einige Zeit ins
Land.
A. K. schrieb:> Der Ablauf von clock stretching ist:> release SCL> wait until SCL=1> denn der Slave zeigt das an, indem er SCL auf 0 hält. Genau das findet> sich im gezeigten Code in Form von I2CMSW_WAIT_FOR_SCL wieder.
Nein, das stimmt schlicht nicht. In I2CMSW_WAIT_FOR_SCL macht der
gezeigte Teil der Implementierung ausschließlich das, was in deinem
Pseudocode der Zeile
> wait until SCL=1
entspricht (zusätzlich bloss noch das Timeout-Gedöns für die
stall-Erkennung). Der zeitliche Bezug zur gewollten, aber möglicherweise
durch den Client zu verzögernden LH-Flanke geht daraus absolut nicht
hervor. Und schon garnicht der Bezug zu der davor liegenden HL-Flanke.
Da der eigentliche Code überhaupt nicht gepostet wurde, kann ich nur
raten, was da passiert. Aber ein educated guess dürfte sein, dass zur
Steuerung der Abstände dieser Flanken letztlich das Macro
I2CMSW_WAIT_NS
zum Einsatz kommt. Und dessen Implementierung durch den TO scheint mir
doch einigermassen schräg zu sein. Mal abgesehen davon, dass es sowieso
maximal nur mit µs-Genauigkeit funktionieren kann (es wird aber
wenigstens aufgerundet), ist die Funktionsfähigkeit der Sache daran
gekoppelt, das das letztlich benutzte delayMicroseconds() immer wie
erwartet funktioniert. Und darauf würde ich nicht wetten wollen. Schon
ganz allgemein nicht und noch viel weniger unter den Bedingungen eines
User-Tasks in einem Nicht-Echtzeitsystem.
c-hater schrieb:> raten, was da passiert. Aber ein educated guess dürfte sein, dass zur> Steuerung der Abstände dieser Flanken letztlich das Macro
Und mein educated guess ist, dass ihr am falschen Ende sucht.
Nicht beim MASTER liegt das Problem, sondern beim Slaven.
GCA hat auch nicht funktionert obwohl das lauter Nullen sind.
Es wird eher sein, dass da nach dem (richtig erkanntem) STOP irgendwo
beim Slave in TWCR die Adresserkennung ausgeschaltet wird und die
ISR deswegen gar nicht angesprungen wird.
Wie und wo so etwas passieren kann ist die eigentliche Frage.
c-hater schrieb:> Da der eigentliche Code überhaupt nicht gepostet wurde
Was fehlt denn?
> (...) das Macro> I2CMSW_WAIT_NS> zum Einsatz kommt. Und dessen Implementierung durch den TO scheint mir> doch einigermassen schräg zu sein.
Die "Schrägheit" kommt daher, dass diese Library generisch gehalten ist.
Ich habe sie auf den unterschiedlichsten Plattformen verwendet und muss
jeweils nur die I2CMSW_*-Makros anpassen. Nanosekunden scheinen mir da
die einzig richtige Wahl, denn das ist schließlich was in der I2C-Spec
steht.
> (...) ist die Funktionsfähigkeit der Sache daran> gekoppelt, das das letztlich benutzte delayMicroseconds() immer wie> erwartet funktioniert.
Nun, mit der og. Ausnahme ist die einzige Erwartung an die Funktion,
dass sie mindestens das übergebene Zeitintervall wartet.
delayMicroseconds ist eine WiringPi-Funktion
(http://git.drogon.net/?p=wiringPi;a=blob;f=wiringPi/wiringPi.c;h=dfd5de484297b293f6c95978c7eba95b4d53628e;hb=HEAD#l1951)
und wenn ich mir deren Source anschaue, sehe ich nichts, was da
schiefgehen könnte. Ich lasse mich aber gerne korrigieren. Unter welchen
Umständen erwartest du Probleme?
Aber selbst wenn wir einfach mal annehmen, dass die Funktion ihre
Aufgabe nicht immer erfüllt - in meinen konkreten Beispielen tut sie das
doch, oder nicht? Jedenfalls sind alle Timings, die ich mit dem LA
nachgemessen habe absolut im Rahmen der Spec.
Habt ihr diesen Fehler eigentlich jemals finden können?
Ich hab hier grade 2 mega168, einer sendet als master, wird dann slave,
bekommt eine antwort vom anderen master -
-> und schickt sporadisch kein ACK auf SLA+W, obwohl TWEA gesetzt,
TWINT in ISR zurückgesetzt wird etc..
Fun fact: gleiche software auf anderem controller (328P) in anderer
hardware funktioniert..
dunno.. schrieb:> Habt ihr diesen Fehler eigentlich jemals finden können?
Vermutlich hat ihn der TO damals(tm) finden können, sonst hätte er wohl
weitere Hilferufe gesendet...
> Ich hab hier grade 2 mega168, einer sendet als master, wird dann slave,> bekommt eine antwort vom anderen master ->> -> und schickt sporadisch kein ACK auf SLA+W, obwohl TWEA gesetzt,> TWINT in ISR zurückgesetzt wird etc..
Finde den Fehler in deiner Software. Das System (also die
TWI-Funktionalität in allen derzeit käuflichen Mega) funktioniert "as
expected". Da kannst du einen drauf lassen. Sonst hätten wir (und viel
bedeutendere Abnehmer) die Hardwarebasis längst zum Teufel geschickt,
was unweigerlich dazu geführt hätte, dass MC die entweder erst garnicht
mitgekauft oder unverzüglich eingestellt hätte. Haben sie aber nicht...
> Fun fact: gleiche software auf anderem controller (328P) in anderer> hardware funktioniert..
Schöner Ansatz, um nach dem Fehler in der (offensichtlich ziemlich
beschissenen) Software zu suchen, also in deinem Werk. Aber klar: mit an
Sicherheit grenzender Wahrscheinlichkeit ist es eben nicht tatsächlich
dein Werk, sondern zusammengeklauter, unverstandener Code...
Tja, wohl ein typischer Fall ein C&P-Droiden. Billich einzukaufender
Menschenmüll, aber schon mittelfristig teuer, weil weitgehend nutzlos...
Um den thread nicht dumm sterben zu lassen:
Scheinbar gibt es ein problem, wenn zum zeitpunkt des sla+w das twie im
twcr abgeschaltet wird..
Das passiert bei mir, um aus einem anderen thread her den status des i2c
zu holen und ggfs daten zu kopieren.
Der avr verschluckt scheinbar dabei das adressbyte, sendet kein nack,
hält aber dann scl dauerlow, ohne das per interrupt mitzuteilen.
Das ganze funktioniert problemlos, wenn ich nicht den twi interrupt,
sondern alle interrupts per sreg sperre.
Und ja, beim zugriff auf twcr maskiere ich twint, und twen ist gesetzt.