Liebe Leute,
seit drei Tagen suche ich einen Fehler in dem Eigenbau einer
Lüftungssteuerung meiner Werkstatt und bin jetzt an einem Punkt wo mir
die Ideen ausgehen. Anbei der Schaltplan und ein Foto zur Illustration.
Der Fehler zeigt sich daran dass das Anzeigebild auf dem angeschlossenen
ST7735-Display nicht vom Portraitmodus in den Landschaftsmodus rotiert.
Ein Austausch der Ansteuerbibliothek hat nicht geholfen. Ein Wechsel des
Display ebenfalls nicht. Das Problem tritt auch auf wenn das
MCP2515-Modul entfernt wird.
Ich habe die SPI-Kommunikation zwischen uC und ST7735 untersucht. Die
analogen Pegel sehen korrekt aus. Ich habe aber tatsächlich eine
digitale Problemstelle gefunden. Die korrekte Sequenz zur Rotation wäre
CS H->L, SPI 0x28, SPI 0x36, DC L->H, SPI 0x60, DC H->L, SPI 0x29, CS
L->H.
In früheren Versuchen mit teils anderer Reihenfolge der Initialisierung
hat die Rotation zwar funktioniert, es gab dann aber anscheinend an
anderer Stelle in der SPI-Kommunikation Probleme.
Ein rudimentärer Nachbau auf dem Arbeitstisch mit einem Arduino Pro Mini
funktioniert mit derselben Softwareversion tadellos, siehe Bild
t5_garage01_st7735_ok.png. Beim Aufbau in der Werkstatt fehlt aber SPI
0x36 (und die entsprechende Übertragungszeit), siehe Bild
t5_garage01_st7735_pl.png.
Der entsprechende Assemblercode an dieser Stelle lautet (aus
https://github.com/lexus2k/lcdgfx/blob/master/src/v2/lcd/st7735/lcd_st7735.inl,
template <class I> void InterfaceST7735<I>::setRotation(uint8_t
rotation):
Es scheint als ob beim Werkstattaufbau beim Aufruf von transfer(0x36)
SPIF schon gesetzt wäre. Allerdings sollte das Lesen von SPDR beim
vorherigen Aufruf von transfer(0x28) SPIF gelöscht haben.
Ich habe nun zwei Fragen. Erstens: Hat jemand eine Erklärung für dieses
Verhalten. Zweitens: Hat jemand einen Vorschlag wo und wie ich
weitersuchen soll?
LG, Sebastian
PS: PB2 (!SS) ist nach bestem Wissen und Gewissen als Output
konfiguriert, da er als !CS für das MCP2515-Modul benutzt wird.
Wenn der Schaltplan so gezeichnet ist wie der Aufbau, Resetbeschaltung
spendieren, Abblockkondensatoren einlöten und bei größeren
Temperaturschwankungen lieber einen externen Taktgeber verwenden, die
sind in der Regel deutlich präziser.
Sebastian W. schrieb:> PS: PB2 (!SS) ist nach bestem Wissen und Gewissen als Output> konfiguriert, da er als !CS für das MCP2515-Modul benutzt wird.
Der Knackpunkt ist, ist das auch vor dem SPI-Init erfolgt!
Peter D. schrieb:> er Knackpunkt ist, ist das auch vor dem SPI-Init erfolgt!
Das wars! Mille grazie, Peter. YMMD!
Manchmal sieht man den Wald vor lauter Bäumen nicht.
LG, Sebastian
Das ist merkwürdig!
Sebastian W. schrieb:> Ein rudimentärer Nachbau auf dem Arbeitstisch mit einem Arduino Pro Mini> funktioniert mit derselben Softwareversion tadellos, siehe Bild> t5_garage01_st7735_ok.png. Beim Aufbau in der Werkstatt fehlt aber SPI> 0x36 (und die entsprechende Übertragungszeit), siehe Bild> t5_garage01_st7735_pl.png.
War bei dem "Arbeitstischaufbau" das MCP2515-Modul nicht angeschlossen?
Holger L. schrieb:> War bei dem "Arbeitstischaufbau" das MCP2515-Modul nicht angeschlossen?
Nein, auch nicht. Das Problem war, dass ich SPI.begin() vor der
MCP2515-Initialisierung aufgerufen habe, aber nicht auch vor der
ST7735-Initialisierung, und dass die ST7735-Initialisierung vor der
MCP2515-Initialisierung stattfand. PB2 war also während der
ST7735-Initialisierung (obwohl dafür nicht benutzt) als Input
konfiguriert, und der in der Werkstatt schwankende Eingangspegel an der
"Antenne" PB2, also !SS, hat dann sporadisch die SPI-Maschinerie des
Atmega in den Slave-Modus versetzt ...
LG, Sebastian
Sebastian W. schrieb:> Peter D. schrieb:>> er Knackpunkt ist, ist das auch vor dem SPI-Init erfolgt!>> Das wars! Mille grazie, Peter. YMMD!> Manchmal sieht man den Wald vor lauter Bäumen nicht.
Leider zu früh gefreut. Es hat zwar so kurz funktioniert aber jetzt ist
der Fehler trotz der Softwarekorrektur wieder da!
Ich habe in der Prozedur setRotation jetzt ein Portgewackel auf PD4
eingebaut:
Und dann habe ich sowohl das CAN-Modul als auch das Display abgezogen
und die Software laufen lassen ohne dass irgendetwas an den SPI-Ports
angeschlossen ist. Das Ergebnis siehe Bild: Es wird jetzt 0x28 statt
0x36 gesendet!
Was mir auffällt ist das DEBUG L->H geht obwohl das erste Byte 0x28
immer noch gesendet wird ...
LG, Sebastian
Sebastian W. schrieb:> Leider zu früh gefreut. Es hat zwar so kurz funktioniert aber jetzt ist> der Fehler trotz der Softwarekorrektur wieder da!
An diesem Punkt solltest du einmal sorgfältig in dich
gehen und
- einen soliden Aufbau wählen.
- genügend Abblock-Kondensatoren vorsehen (laut Schaltplan
fehlen am AVR alle Kondensatoren!)
- alle fliegenden Leitungen beseitigen da diese beliebig
Störungen auffangen können. Wenn ich "Lüftungssteuerung "
lese dann ist das allein schon ein Grund für Fehlfunktion.
So wie das jetzt aufgebaut ist kann das nicht gutgehen.
SCNR
Sebastian W. schrieb:> Leider zu früh gefreut.
Nachdem ich sehe dass du hier schon fast 10 Jahre angemeldet bist
solltest du eigentlich hier im Forum genügend (Negativ-) Beispiele
an Aufbauten gesehen haben wie man es nicht macht. Dein Aufbau
gehört sicherlich dazu.
OMG schrieb:
Also zunächst mal danke für die Rückmeldung. Allerdings:
OMG schrieb:> - einen soliden Aufbau wählen.
Der Aufbau mit Streifenraster ist sehr solide.
OMG schrieb:> - genügend Abblock-Kondensatoren vorsehen (laut Schaltplan> fehlen am AVR alle Kondensatoren!)
Jetzt nachgerüstet. Wie zu erwarten war (zum Zeitpunkt des Fehlers
benötigte der uC nur Strom für winzigste interne Gateumladungen) keine
Änderung.
OMG schrieb:> - alle fliegenden Leitungen beseitigen da diese beliebig> Störungen auffangen können.
Fliegende Leitungen habe ich keine (Zuleitungen wohl).
OMG schrieb:> Wenn ich "Lüftungssteuerung "> lese dann ist das allein schon ein Grund für Fehlfunktion.> So wie das jetzt aufgebaut ist kann das nicht gutgehen.
Ist halt eine induktive Last.
Mir ist allerdings bei der Beantwortung deines Beitrags aufgefallen, das
das Gate des IRLML6244 keinen Pulldown hat und also während der
Initialisierung floatet, und auch noch einen 12k zu GND nachgerüstet.
Ich habe jetzt alle Leitungen nach außen (ausser der 15V-Zuleitung)
gekappt. Der Fehler tritt immer noch auf!
Weitere Infos folgen ...
LG, Sebastian
Liebe Leute,
ich habe höchstwahrscheinlich die Ursache für mein Problem gefunden.
Sebastian W. schrieb:> Es scheint als ob beim Werkstattaufbau beim Aufruf von transfer(0x36)> SPIF schon gesetzt wäre. Allerdings sollte das Lesen von SPDR beim> vorherigen Aufruf von transfer(0x28) SPIF gelöscht haben.Sebastian W. schrieb:> Was mir auffällt ist das DEBUG L->H geht obwohl das erste Byte 0x28> immer noch gesendet wird ...
Werkstattaufbau und Arbeitstischnachbau unterscheiden sich in einem
wesentlichen Punkt: Während der Arduino Pro Mini auf dem Arbeitstisch
den Arduino-Bootloader enthält ist beim Werkstattaufbau ein
selbstgebauter CAN-Bootloader im Einsatz. Dieser CAN-Bootloader endet
mit dem Senden einer ACK-Nachricht an den CAN-Bootserver. Dabei mache
ich im CAN-Bootloader den Fehler am Ende SPDR nicht mehr zu lesen und
also SPIF gesetzt zu lassen. Und es scheint so zu sein, dass danach SPCR
= SPSR = 0 vor dem Sprung vom Bootloader zur Applikation zwar SPI
deaktiviert, SPIF aber gesetzt bleibt!
Dann startet die Applikation, aktiviert SPI wieder und beginnt das
Display zu initialisieren. SPDR wird geschrieben aber SPIF ist noch
gesetzt. Also endet das anschliessende Warten auf SPIF sofort. Wird dann
SPDR gelesen dann wird SPIF zwar gelöscht, aber man liest das bei einer
vorherigen Übertragung erhaltene Byte. Sobald dann die aktuelle
Übertragung fertig ist wird SPIF wieder gesetzt. Und dieser Zustand kann
dann recht lange anhalten.
Wenn in diesem Zustand dann aber SPDR geschrieben wird während die
frühere Übertragung noch läuft (gegen das es in diesem Zustand ja keine
Absicherung mehr gibt) dann gibt es eine race condition bei der
anscheinend entweder die neue Übertragung verfällt oder das vorherige
Byte erneut gesendet oder auch ein ganz anderes Byte gesendet wird
Ich habe jetzt provisorisch folgenden Code in die Lüftungssoftware
eingebaut und das Problem wird umgangen:
1
#ifdef CANBOOT_WORKAROUND
2
// The following is to work around an issue of the canboot bootloader ...
3
SPI.begin();
4
uint8_tspif=!!(SPSR&_BV(SPIF));
5
if(spif){
6
uint8_tspi=0xFF;
7
if(SPSR&_BV(SPIF))spi=SPDR;
8
TraceVar(spi);
9
spif=!!(SPSR&_BV(SPIF));
10
TraceVar(spif);
11
}
12
SPI.end();
13
#endif
Später werde ich den CAN-Bootloader korrigieren und installieren.
Hoffentlich funktioniert mein Mechanismus, bei dem der CAN-Bootloader
sich selbst überschreibt! Ansonsten müsste ich bei allen Geräten lokal
an die ISP-Stecker und das wäre doch ziemlicher Aufwand ...
LG, Sebastian
> Und es scheint so zu sein
Es scheint nicht nur, es ist so.
> provisorisch folgenden Code
Das nun verstehe ich nicht - weshalb reicht als Notbehelf nicht ein
simples 'wirfmichweg = SPDR;' zu Beginn der Anwendungssoftware?
S. Landolt schrieb:> Das nun verstehe ich nicht - weshalb reicht als Notbehelf nicht ein> simples 'wirfmichweg = SPDR;' zu Beginn der Anwendungssoftware?
Sollte auch reichen. Ich brauche aber die Rückmeldung (über TraceVar auf
TXD0) ob SPIF tatsächlich gesetzt ist um meine spätere Korrektur des
CAN-Bootloaders zu verifizieren. Ausserdem hatte ich die Befürchtung,
wirfmichweg würde wegoptimiert. Die zweite Abfrage von SPIF innerhalb
der if-Anweisung ist aber in der Tat völlig überflüssig ...
LG, Sebastian.
> Befürchtung, wirfmichweg würde wegoptimiert
Okay - in meinem Assembler wird nichts wegoptimiert, und in C gibt es
doch sicher eine Möglichkeit, eine solche Variable festzunageln
(volatile?), oder?
S. Landolt schrieb:>> Befürchtung, wirfmichweg würde wegoptimiert>> Okay - in meinem Assembler wird nichts wegoptimiert, und in C gibt es> doch sicher eine Möglichkeit, eine solche Variable festzunageln> (volatile?), oder?
Das sollte gehen. Allerdings habe ich grad noch mal das Datenblatt
gelesen, und dort steht: "Alternatively, the SPIF bit is cleared by
first reading the SPI Status Register with SPIF set, then accessing the
SPI Data Register (SPDR)". Insofern ist es wohl sicherer, vor dem Lesen
von SPDR auch noch SPSR zu lesen ...
LG, Sebastian
Sebastian W. schrieb:> Ausserdem hatte ich die Befürchtung,> wirfmichweg würde wegoptimiert.
Wird es auch. Macht aber nix, der Lesezugriff auf SPDR wird nicht
wegoptimiert. Ziel erreicht, kein Speicher verschwendet.
"volatile" ist am SPDR schon gesetzt, das reicht.
1
uint8_twirfmichweg=SPDR;
2
SPDR;
3
(void)SPDR;
Kompiliert zu:
1
in r24,0x2e
2
in r24,0x2e
3
in r24,0x2e
Ich bevorzuge die letzte Variante, da ist klar dokumentiert, dass der
gelesene Wert verworfen werden soll.
> reading the SPI Status Register with SPIF set
Das macht doch Ihr Bootloader, oder wartet der nicht auf das Ende der
von ihm angestoßenen Übertragung?
Egal, ist schließlich nur ein Notbehelf.
Sebastian W. schrieb:> Später werde ich den CAN-Bootloader korrigieren und installieren.> Hoffentlich funktioniert mein Mechanismus, bei dem der CAN-Bootloader> sich selbst überschreibt!
Ok, der Bootloader ist korrigiert und installiert, und der
CANBOOT_WORKAROUND ist nicht mehr nötig, SPIF ist beim Einsprung in die
Anwendung jetzt 0.
Im Bootloader waren zwei Fehler. Zum einen wurde beim Senden nach dem
Warten auf SPIF nie SPDR gelesen und so SPIF gelöscht. Das erklärt mir
auch einige vorher unerklärliche Fehler bei der Installation neuer
Anwendungssoftware mit dem Bootloader, weil dadurch genau die oben
beschriebenen Sendefehler auftreten können. Zum anderen habe ich vor dem
Sprung zur Anwendung erst die Ports auf Input ohne Pullup zurückgesetzt
und danach SPI über SPCR abgeschaltet, und dadurch wohl den SPI Slave
Modus aktiviert und so SPIF gesetzt!
In diesem Zusammenhang habe ich auch noch herausgefunden das allein das
Lesen von SPDR nicht ausreicht um SPIF zu löschen; wie im Datenblatt
erwähnt muss zuvor erst noch SPSR gelesen werden.
LG, Sebastian
Es ist good practice in jeder Initfunktion, das Interface zurück zu
setzen. Dazu das Interface disablen und alle Interruptflags durch
1-setzen (beim AVR) zu löschen.