Forum: Mikrocontroller und Digitale Elektronik SPI Geräte stören sich gegenseitig. ILI9341 regiert auf ENC28J60 Befehle. Was tun


von Jan H. (jan_h865)


Lesenswert?

Hallo Community,

Ich habe zurzeit ein kleines Problem. Und zwar habe ich seit länger Zeit 
ein kleinen Webserver auf dem ATMega644 mit dem ENC28J60 laufen.
Der ENC28J60 wird über das SPI Interface angesteuert. Nun wollte ich 
mein Projekt gerne weiter ausbauen mit einen TFT Display, um Information 
über den Server dort anzuzeigen.

Das Display ist ein 240x320 2.2 Zoll QVGA SPI Display mit dem ILI9341 
Treiber.

Dieses Display habe ich dann auch mit dem SPI Bus verbunden anstatt denn 
SS Pin(Nutzt der ENC) habe ich ihm Pin 2 gegeben.

Wenn ich nun an das Display ein Text schreibe. Wird dieser Text auch 
nach dem Einschalten angezeigt. Jedoch wenn ich dann meinen Webserver im 
Internet aufrufe dann wird mir die Webseite, im Browser dargestellt, und 
zudem wird das TFT Display weiß.

Wenn ich aber nach dem Init des Display die CS Leitung vom TFT Display 
abziehe, und dann Webseite öffne bleibt der Text auf dem Display stehen. 
Also müssen sich die beiden Geräte gegenseitig stören, oder?

Da beide die SPI Kommunikation nutzten. Habe ich eine Klasse 
erstellt(SPI.c/h) um dort das SPI zu Initialisieren.

SPI.c:
1
#include "processor.h" //Enthält F_CPU und BAUD
2
#include "SPI.h" //Dort sind die Macros festlegt: SPI_CONTROL_DDR=DDRB; SPI_CONTROL_PORT=PORTB; MOSI=PORTB5; MISO=PORTB6; SCK=PORTB7; SS=PORTB4
3
4
void init_SPI_Interface(void) {
5
  SPI_CONTROL_DDR |= (1<<SPI_CONTROL_MOSI) | (1<<SPI_CONTROL_SCK) | (1<<SPI_CONTROL_SS); // MOSI, SCK, SS output
6
  SPI_CONTROL_DDR &= ~(1<<SPI_CONTROL_MISO); // MISO input
7
8
  SPI_CONTROL_PORT &= ~(1<<SPI_CONTROL_MOSI); // MOSI Low
9
  SPI_CONTROL_PORT &= ~(1<<SPI_CONTROL_SCK); // SCK Low
10
  SPI_CONTROL_PORT |= (1<<SPI_CONTROL_SS); //SS High
11
12
  SPCR = (1<<SPE) | (1<<MSTR);
13
  SPSR |= (1<<SPI2X);
14
15
}

Der ENC28J60 nutzt als CS Pin: Port B 4
Das TFT Display nutzt als CS Pin: Port B 2

Was könnte da das Problem sein. Denn nachdem senden des Textes wird die 
CS Leitung vom TFT Display wieder auf HIGH gelegt. Und dürfte somit 
nicht auf Daten die an denn ENC28J60 gesendet werden reagieren, oder?

Lg Jan.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Alloziert Du die Resource SPI so, dass Dir kein Interrupt 
dazwischenfunkt?

SPI ETH wird wohl im Interrupt gebraucht. Wartet der Interrupt dann, bis 
eine Display SPI Zugriff fertig ist? Behandelt er den Display CS 
richtig?

Nur mal so zum nachdenken.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Jan H. schrieb:
> oder?
Richtig,  dafür ist der Slaveselect da. Wird er tatsächlich auf high 
gelegt? Hast du das gemessen?

von Jan H. (jan_h865)


Lesenswert?

Lothar M. schrieb:
> Richtig,  dafür ist der Slaveselect da. Wird er tatsächlich auf high
> gelegt? Hast du das gemessen?

Messen wird denk ich schwer, da ich an der CS leitung ein 10K Pullup 
Widerstand habe.

So werden die Codes beim TFT gesendet:
1
void ili9341_writecommand8(uint8_t com)//command write
2
{
3
  controlport &=~((1<<dc)|(1<<cs));//dc and cs both low to send command
4
  _delay_us(5);//little delay
5
  ili9341_spi_send(com);
6
  controlport |=(1<<cs);//pull high cs
7
}
8
9
10
void ili9341_writedata8(uint8_t data)//data write
11
{
12
  controlport |=(1<<dc);//st dc high for data
13
  _delay_us(1);//delay
14
  controlport &=~(1<<cs);//set cs low for operation
15
  ili9341_spi_send(data);
16
  controlport |=(1<<cs);
17
}

Und beim ENC auch über all CSACTIVE; dann SPI und dann CSPASSIV;
1
// set CS to 0 = active
2
#define CSACTIVE ENC28J60_CONTROL_PORT&=~(1<<ENC28J60_CONTROL_CS)
3
// set CS to 1 = passive
4
#define CSPASSIVE ENC28J60_CONTROL_PORT|=(1<<ENC28J60_CONTROL_CS)

Der ENC hat auch ein 10K Pullup Widerstand an der CS leitung

Lg Jan.

von GHD (Gast)


Lesenswert?

Jan H. schrieb:
> Lothar M. schrieb:
>> Richtig,  dafür ist der Slaveselect da. Wird er tatsächlich auf high
>> gelegt? Hast du das gemessen?
>
> Messen wird denk ich schwer, da ich an der CS leitung ein 10K Pullup
> Widerstand habe.

Ja und? Pegel ist Pegel egal ob Pullup oder nicht. Den SPI Teilnehmer 
interessiert das nicht.

Was soll der Pullup überhaupt? Dein Ausgangspin für das CS ist jeweils 
eine Push Pull Stufe. Was soll der Pullup? Unnötig den CS Ausgangspin 
belasten? Oder hast du Angst, dass im Reset während der CS Ausgangspin 
floatend ist irgendwas passiert?

von Jan H. (jan_h865)


Lesenswert?

GHD schrieb:
> Ja und? Pegel ist Pegel egal ob Pullup oder nicht. Den SPI Teilnehmer
> interessiert das nicht.
>
> Was soll der Pullup überhaupt? Dein Ausgangspin für das CS ist jeweils
> eine Push Pull Stufe. Was soll der Pullup? Unnötig den CS Ausgangspin
> belasten? Oder hast du Angst, dass im Reset während der CS Ausgangspin
> floatend ist irgendwas passiert?

Habe mir mal die CS Leitung mit meinen Oszi angeschaut. Wenn ich nur 
denn Text setzte habe ich nach dem Init genau 5 CS Low. Für set_cursor, 
set_rotation, set_textSize, set_TextColor, clearScreen. Danach nur noch 
HIGH 3,3 Volt. Beim ENC28J60 genau so. Also auch HIGH wenn nix passiert 
und LOW beim Empfänger habe getestet in dem ich die Webseite aufgerufen 
habe und aufs Oszi geschaut habe.

Kann es vllt. passieren das eine Anfrage an denn ENC28J60 geht dieser 
denn CS auf Low schreibt und gleichzeitig im TFT Display noch was 
gemacht wird? So das das TFT auch gleichzeitig low ist?

Lg Jan.

von (prx) A. K. (prx)


Lesenswert?

Jan H. schrieb:
>   controlport &=~((1<<dc)|(1<<cs));//dc and cs both low to send command

Um beim AVR 2 Bits auf einmal zu setzen/löschen, ohne einem Interrupt 
eine Lücke zu öffnen, kann man nicht die PORTx Register verwenden. So 
wie hier besteht die Möglichkeit, dass ein Interrupt, der den gleichen 
Port bedient, zwischenrein funkt. Alternative: einzelbitweise bei Ports, 
die bitadressierbar sind, oder die Toggle-Funktion von PINx verwenden.

https://www.mikrocontroller.net/articles/Interrupt#Atomarer_Datenzugriff

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

GHD schrieb:
> Was soll der Pullup überhaupt?

Bei den meisten AVRs sitzt SPI auf den gleichen Pins wie ISP. Pullups an 
allen SS stellt sicher, dass ISP und die Slaves nicht kollidieren. 
Manche Slaves haben den aber schon drin.

: Bearbeitet durch User
von Rudolph (Gast)


Lesenswert?

Lothar M. schrieb:
> Richtig,  dafür ist der Slaveselect da.

Als Chip-Select Ausgang ist der SlaveSelect-Eingang eben nicht da.
Aber da man den Pin sowieso auf Ausgang setzen muss wenn man SPI benutzt 
und nicht die SlaveSelect Funktionalität haben will, drängt sich die 
Verwendung als Chip-Select quasi auf, ja. :-)

Die Informationen sind auf jeden Fall noch zu dünn.
Weder ist die Hardware ausreichend beschrieben, noch die Software.
Ich tippe da auf einen Software-Fehler.

Aber das könnte auch ein falsch angeschlossener Pegel-Wandler sein, das 
war so der einzige Fehler den ich bisher auf dem SPI hatte mit mehreren 
Slaves.

Versuch mal, das Programm auf ein Minimum zu reduzieren.

von Jan H. (jan_h865)


Angehängte Dateien:

Lesenswert?

Rudolph schrieb:
> Versuch mal, das Programm auf ein Minimum zu reduzieren.

Ich habe habe mal alles unnötige aus mein Programm entfernt. So das nur 
noch die Klassen drin sind wo mit SPI gearbeitet wird. Dieses sind 
ili9341.c/h, enc28j60.c/h, main.c, SPI.c/h und processor.h. Andere 
Sachen wie ADC, USART, DS18B20 TFT Grafik IP ARP habe ich raus gelassen.

Mal so ne Andere Frage. Was wäre wenn man bevor man ein CS Aktiv macht 
ein Status setzt(w. encSPI=1) und dann beim display spi vorher abfragt:
1
if(encSPI == 1) {
2
   while(encSPI != 0) {
3
     //Wait for encSPI equals 0 
4
     if(encSPI == 0) break;
5
  }
6
  tftSPI = 1; //Not Ready to use ENC SPI
7
  TFT_CS == LOW //Enable TFT CS
8
  Command ... //Write Command
9
  TFT_CS == HIGH //Disable TFT CS
10
  tftSPI = 0; //Ready to use ENC SPI
11
}else{
12
  tftSPI = 1; //Not Ready to use ENC SPI
13
  TFT_CS == LOW //Enable TFT CS
14
  Command ... //Write Command
15
  TFT_CS == HIGH //Disable TFT CS
16
  tftSPI = 0; //Ready to use ENC SPI
17
}
und halt umgekernt. Dann müsste es doch auch gehen. Bin mir nur nicht so 
sicher bei dem while()

lg jan.

von Rudolph (Gast)


Lesenswert?

Nur kurz drüber geschaut, weder das Display noch der ENC28J werden im 
Interrupt bedient, oder etwa doch?

So können die sich doch regulär gar nicht in die Quere kommen und die 
Status-Variablen sind überflüssig.
Mit Interrupts wäre das while() auf jeden Fall tödlich, wenn gerade auf 
dem SPI gesendet wird und der IRQ aufgerufen wird der auch senden 
soll...

Und das manipuliert immer noch am Display rum?
Also es gibt einen Unterschied zwischen dem geposteten Code und
einer Version die iniEthernet() und ethernet_arp_request() 
auskommentiert hat?

Wie sieht denn die Hardware dazu aus?

von Arduinoquäler (Gast)


Lesenswert?

Rudolph schrieb:
> Nur kurz drüber geschaut, weder das Display noch der ENC28J werden im
> Interrupt bedient, oder etwa doch?

Eigentlich müsste man mit einem Oszilloskop per Zufallstreffer
sehen dass beide Chip Selects irgendwann gleichzeitig aktiv
sind.

Jan H. schrieb:
> Da beide die SPI Kommunikation nutzten. Habe ich eine Klasse
> erstellt(SPI.c/h)

1
void init_SPI_Interface(void)
ist aber nicht Member irgendeiner Klasse. Insofern verstehe
ich das mit der Klasse nicht .....

von Jan H. (jan_h865)


Angehängte Dateien:

Lesenswert?

Rudolph schrieb:
> Interrupt bedient, oder etwa doch?

Nein. Im Interrupt(habe ich entfernt in diesen Code) wird nur die 
Temperatur eines LM35 ausgelesen und die Temperaturen des DS18B20.

Rudolph schrieb:
> Und das manipuliert immer noch am Display rum?

Also falls du damit meinst wo das Display immer noch rum spinnt. Janein. 
Also wenn ich die ganze Zeit mit ein Delay(nicht _delay_ms() Methode 
sondern mit Timer2 Overflow gereget) 100 ms ein Punkt auf dem Display 
löse und setzte. Und dann die Webseite aufrufe, dann bleibt das Display 
stehen und reagiert nicht mehr. ENC reagiert ebenfalls nicht mehr.
Wenn ich aber was auf Display schreibe und dann die Webseite aufrufe 
bleibt der Punkt auf dem Display stehen. Es seiden man kommt an die +5V 
oder GND Kabel.

Rudolph schrieb:
> Wie sieht denn die Hardware dazu aus?

Ich habe mal ein Schaltplan erstellt von meiner Hardware. Das ist 
wirklich nur der Controller und der Reset die Spannungversorgung ist 
dort nicht mit drin.

Arduinoquäler schrieb:
> ist aber nicht Member irgendeiner Klasse. Insofern verstehe
> ich das mit der Klasse nicht .....

Klar, ich hätte das mit dem SPI Interface auch in der main.c Klasse 
machen können jedoch finde ich es so übersichtlicher.

Lg Jan.

: Bearbeitet durch User
von Arduinoquäler (Gast)


Lesenswert?

Jan H. schrieb:
> Klar, ich hätte das mit dem SPI Interface auch in der main.c Klasse
> machen können jedoch finde ich es so übersichtlicher.

Deine Erwiderung lässt mich daran zweifeln ob du weisst was
eine Klasse im Sinne von C-Programmierung ist.

von Rudolph (Gast)


Lesenswert?

Die Leitungen gehen sicher nicht direkt ohne andere Teile dazwischen auf 
den ILI9341 von dem Display und den ENC28J60, da zumindest der ENC28J60 
ja für 3,3V ist.
Wenn ich das richtig interpretiere geht auch der ILI9341 nur bis 3,3V.

Und wenn Du den Schaltplan erst erstellen musstest, ist das Teil auf dem 
Steckbrett aufgebaut?

von Arduinoquäler (Gast)


Lesenswert?

Jan H. schrieb:
> Ich habe mal ein Schaltplan erstellt von meiner Hardware. Das ist
> wirklich nur der Controller und der Reset die Spannungversorgung ist
> dort nicht mit drin.

Der ENC28J60 braucht vergleichsweise (zum Controller) viel Strom
und könnte bei schwachen oder fehlenden Abblock-Massnahmen auf
der Versorgung die anderen Schaltungsteile stören.

von Jan H. (jan_h865)


Lesenswert?

Rudolph schrieb:
> ja für 3,3V ist.
> Wenn ich das richtig interpretiere geht auch der ILI9341 nur bis 3,3V.

Ja das ist richtig. Die CS, MOSI, SCK DC, RESET Leitung gehen auf denn 
CD4050 Converter der mit 3,3 Volt betrieben wird. Dadurch kommen nur 3.3 
Volt auf denn Steuerleitungen an.

Rudolph schrieb:
> Und wenn Du den Schaltplan erst erstellen musstest, ist das Teil auf dem
> Steckbrett aufgebaut?

Also der ENC28J60 ist mit einer Ethernet Buchse auf einer 
Lochrasterplatine aufgelötet. Mit einen Pin Header(Vcc, Gnd, Sck, miso, 
mosi, cs, adc(lm35)).

Und das TFT Display habe ich auf eine Platine gemacht. Diese passt genau 
auf denn Arduino UNO. Ist also ein "Arduino Shield". Dort drauf ist ein 
3,3 Regler. 2 CD4050 Converter 1 für TFT ILI9341 und einer für denn SD 
Karten Slot.

Arduinoquäler schrieb:
> Der ENC28J60 braucht vergleichsweise (zum Controller) viel Strom
> und könnte bei schwachen oder fehlenden Abblock-Massnahmen auf
> der Versorgung die anderen Schaltungsteile stören.

Die Spannungversorgung wäre eigentlich mit ein 7805 gemacht. Jedoch 
Powerere ich das ganze mit mein Labornetzteil. Das auf 5V eingestellt 
ist. Die Schaltung zieht 245 mA. Ohne ENC und TFT nur 40 mA.

Lg Jan.

von nur mal am rande (Gast)


Lesenswert?

Arduinoquäler schrieb:

> Deine Erwiderung lässt mich daran zweifeln ob du weisst was
> eine Klasse im Sinne von C-Programmierung ist.


Es gibt keine Klassen im Sinne von C-Programmierung.

von Arduinoquäler (Gast)


Lesenswert?

Jan H. schrieb:
> Die Spannungversorgung wäre eigentlich mit ein 7805 gemacht. Jedoch
> Powerere ich das ganze mit mein Labornetzteil. Das auf 5V eingestellt
> ist. Die Schaltung zieht 245 mA. Ohne ENC und TFT nur 40 mA.

Du hast es wieder nicht verstanden (wie bei der Klasssen-
Programmierung).
Ein Labornetzteil garantiert noch keine zuverlässige Abblockung.

Ausserdem ist auch der Aufbau entscheidend für die korrekte
Funktion. Aus den bisherigen Verlauf entnehme ich dass du uns
deinen Aufbau nicht zeigen willst.

von Arduinoquäler (Gast)


Lesenswert?

nur mal am rande schrieb:
> Es gibt keine Klassen im Sinne von C-Programmierung.

Aber Klassen in Sinne von Programmieren in der Schule, gell?

von Rudolph R. (rudolph)


Lesenswert?

Jan H. schrieb:
> Ja das ist richtig. Die CS, MOSI, SCK DC, RESET Leitung gehen auf denn
> CD4050 Converter der mit 3,3 Volt betrieben wird. Dadurch kommen nur 3.3
> Volt auf denn Steuerleitungen an.
>
> Und das TFT Display habe ich auf eine Platine gemacht. Diese passt genau
> auf denn Arduino UNO. Ist also ein "Arduino Shield". Dort drauf ist ein
> 3,3 Regler. 2 CD4050 Converter 1 für TFT ILI9341

Und wie ist das genau verdrahtet? Wirklich?

> und einer für denn SD Karten Slot.

Ah sieh an, noch ein SPI-Teilnehmer.
Wenn der fest verdrahtet ist gehört der auch in den Schaltplan, auch 
wenn CS per Pullup auf VCC hängt und keine Karte im Slot ist.

von Jan H. (jan_h865)


Angehängte Dateien:

Lesenswert?

Rudolph R. schrieb:
> Und wie ist das genau verdrahtet? Wirklich?

Ich habe dafür auch noch mal ein Schaltplan angefertigt. Ich verwende 
anstatt des AMS1117 3.3V Regler ein kleinen DC-DC Step Down Regler(max 1 
A) wo die Spannung auf 3,35 Volt eingestellt ist.

Hinter/Vor denn Pin Header steht die Bezeichnung was der Pin bedeutet 
die Zahl in der Klammer dahinter steht für die Zahl am Pin Header bsp: 
SCK(2) mit 2 ist dann gemeint beim Pin Header wo die Zahl 2 steht.

Rudolph R. schrieb:
> Ah sieh an, noch ein SPI-Teilnehmer.

Naja. Also die MISO ist gar nicht am Controller angeschlossen. Und CS 
auch nicht.

Rudolph R. schrieb:
> Wenn der fest verdrahtet ist gehört der auch in den Schaltplan, auch
> wenn CS per Pullup auf VCC hängt und keine Karte im Slot ist.

Sorry. vergessen.

Also nochmal was andere ich habe auf mein TFT Display eine Lade 
Animation gebastelt. Dort sind acht Punkte die weiß sind. Jede 100 
ms(über overflow) macht er denn nächsten Punkt schwarz und denn 
vorherigen weiß. So habe ich eine kleine Lade Animation. Das heißt ja 
auch das alle 100 ms die CS Leitung low gelegt wird.
Wenn ich nun die Webseite aufrufe dann bleibt das TFT stehen. Komisch 
ist jedoch auch, das die Animation bereits läuft bevor überhaupt der 
ENC28J60 Initialisiert ist, und während der ENC28J60 über das SPI 
Initialisiert(Mac Adresse / Server) werden SPI Befehle ausgeführt. Und 
das TFT bleibt nicht stehen erst wenn die ethernet_arp_request() 
Funktion anschlägt bleibt es stehen.

Lg Jan.

: Bearbeitet durch User
von felix (Gast)


Lesenswert?

Ich tipp auf einen falsch angeschlossenen Pegelwandler, so dass CS high 
nichts bewirkt, aber habe nur flüchtig drüber gelesen... Das SD 
cardmodule von catalex hat diesen Fehler und hat mich erst mal ein paar 
Stunden gekostet.

von Jan H. (jan_h865)


Lesenswert?

Hallo Leute,
Nach vielen Debuggen mit dem Display und denn ENC28J60, habe ich nun das 
Problem gefunden.
Und zwar was das ganze kein Problem der Hardware oder am SPI Bus.
Sondern das Problem lag im Code. Ich habe meine Lade Animation die ich 
vorher fürs Display programmiert habe auf dem Display gezeigt. Und habe 
nach und nach denn Code von der HTTP Webseite entfernt bis ich denn 
Fehler gefunden habe:

Folgender Code:
1
plen=fill_tcp_data_p(buf, plen, PSTR("Temperatur Sensor Außen: <font color='red'>Can't find Temp Sensor</font>!<br/>"));

Das Problem ist das <font color='red'>. Wenn ich dieses aus dem Code 
entferne dann läuft das Display normal weiter und auch der ENC läuft 
ohne Probleme weiter. Das Display läuft auch weiter wenn ich die Seite 
aufrufe.

Kann mir jemand vielleicht erklären warum das grade mit dem <font 
color='red>zu Problemen führen kann? Kann mir es selber nicht erklären.

Lg Jan.

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,


pauschal könnte man vermuten, daß irgendein Speicher verbotenerweise 
beschrieben wird. Dies fällt anscheinend nur an dieser Stelle auf. 
Vermutlich ist aber sonst ein Fehler dafür verantwortlich: falsche 
Variablendeklaration, Arrayzugriff außerhalb des definierten Bereichs, 
Überlauf... Dazu müßte man schon genauer das Programm untersuchen.

MfG

von Jan H. (jan_h865)


Lesenswert?

Christian S. schrieb:
> daß irgendein Speicher

Hallo,

Es scheint doch nicht an den <font> zu legen sondern. An der Buffersize. 
Diese habe ich auf 900 festgelegt(Standard Wert von der Library). Ich 
habe die einfach mal Spaßeshalber auf 1500(bytes) gesetzt. Und auf 
einmal ging alles wieder ohne Probleme.

Vielleicht wahr der Speicher von 900 Bytes voll. Und das hat zu irgend 
einer Kettenreaktion geführt. Die dann dafür sorgte das der SPI Bus lahm 
gelegt wurde.

Lg Jan.

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.