PORTB=0b00000100;//TODO SS have to be set to high, otherwise MSTR in SPCR won't be set
7
8
//XXX just debugoutput
9
itoa(DDR_SPI,text,2);
10
uartPutString("\nDDR_SPI: ");
11
uartPutString(text);
12
13
14
//Init with or without interrupt
15
if(spiInt==SPI_INTERRUPT_DISABLE)
16
{
17
//enable SPI, set as master, set clockrate
18
SPCR=(1<<SPE)|(1<<MSTR)|clockRate;
19
uartPutString("\nSPI ENABLED WITHOUT INTERRUPT!\n");
20
21
//XXX just debugoutput
22
itoa(SPCR,text,2);
23
uartPutString("\nSPCR: ");
24
uartPutString(text);
25
}
26
elseif(spiInt==SPI_INTERRUPT_ENABLE)
27
{
28
//enable SPI, set as master, set clockrate, enable interrupts
29
SPCR=(1<<SPE)|(1<<MSTR)|clockRate|(1<<SPIE);
30
//enable global interrupts
31
sei();
32
uartPutString("\nSPI ENABLED WITH INTERRUPT!\n");
33
}
34
else
35
{
36
return1;
37
}
38
39
return0;
40
41
}
SS liegt auf PB2 und wird ausserhalb als Output gesetzt.
Nun habe ich das Problem, dass ich SS auf High setzen muss damit ich das
MSTR-Bit in SPCR setzen kann. Wenn ich ich das nicht mache, also die
Zeile
1
PORTB=0b00000100;
auskommentiere, kann ich alle Bits in SPCR setzen ausser das MSTR-Bit.
Da ich eine ganze Weile gebraucht habe um diesen Fehler zu finden und
SPI für mich "Neuland" ist, habe ich mich sowohl mit dem Datenblatt als
auch einige andere Quellen zu SPI auseinander gesetzt und nach dem was
ich darüber gelesen habe müsste es doch unerheblich sein ob ich den Pin
auf High setze oder nicht, da er ja als Output gesetzt ist.
Ich habe wohl irgendwo einen Denkfehler :/
Kann sich jemand von euch das Verhalten erklären und mir vll. auf die
Sprünge helfen?
Danke schonmal...
Tom
Tom V. schrieb:> Nun habe ich das Problem, dass ich SS auf High setzen muss damit ich das> MSTR-Bit in SPCR setzen kann. Wenn ich ich das nicht mache, also die> ZeilePORTB = 0b00000100; auskommentiere, kann ich alle Bits in SPCR> setzen ausser das MSTR-Bit.
Das ist Quatsch. Zeig dein ganzes Programm.
mfg.
>SS liegt auf PB2 und wird ausserhalb als Output gesetzt.>Nun habe ich das Problem, dass ich SS auf High setzen muss damit ich das>MSTR-Bit in SPCR setzen kann.
Dann hast du PB2 nicht auf Ausgang gesetzt.
>Wenn ich ich das nicht mache, also die>Zeile>>PORTB = 0b00000100;>> auskommentiere, kann ich alle Bits in SPCR setzen ausser das MSTR-Bit.
Ausgänge setzt man in DDRB.
holger schrieb:> Ausgänge setzt man in DDRB.
Über das Data-Direktion-Register wird eigentlich nur ein PullUP auf VCC
geschaltet. Dass sollte man immer machen wenn der Ausgang vom µC
versorgen will. Der Widerstand hat 100KOhm.
(Technisch gesehen ist es sogar eine Stromquelle mit maximal 50mA)
Bei Selectleitungen (eigentlich bei allen Ausgängen wenn das Projekt
fertig ist) empfehlt es sich zusätzlich einen externen Widersand zu
benutzen, damit die Leitung immer Hi-Level hat, auch dann wenn der µC
sich gerade Resettet (z. B. wenn du ihn gerade neu Programmierst).
Beim Reset sind alle Pins des µC Hochohmig und haben daher kein
definierten Pegel. Ein SPI-Slave könnte in der Zeit denken seine
Selectleitung sei Aktiv und würde so eine ISP-Programmierung stören.
Tom V. schrieb:> Nun habe ich das Problem, dass ich SS auf High setzen muss damit ich das> MSTR-Bit in SPCR setzen kann. Wenn ich ich das nicht mache, also die> ZeilePORTB = 0b00000100; auskommentiere, kann ich alle Bits in SPCR> setzen ausser das MSTR-Bit.Thomas Eckmann schrieb:> Das ist Quatsch.
Nein ist es nicht!
Aus dem Datenblatt:
Bit 4 – MSTR: Master/Slave Select
This bit selects Master SPI mode when written to one, and Slave SPI mode
when written logic zero. If SS is configured as an input and is driven
low while MSTR is set, MSTR will be cleared, and SPIF in SPSR will
become set. The user will then have to set MSTR to re-enable SPI Master
mode.
Christian K. schrieb:> Über das Data-Direktion-Register wird eigentlich nur ein PullUP auf VCC> geschaltet. Dass sollte man immer machen wenn der Ausgang vom µC> versorgen will. Der Widerstand hat 100KOhm.
Aber nur eigentlich. Und auch nur bei dir. Für welchen Controller gilt
das?
Christian K. schrieb:> Nein ist es nicht!
Sicher ist es das und das Ausrufezeichen hättest du dir sparen können.
Aber ohne den gesamten Code kommt man hier, wie immer, nicht weiter. Der
Fehler liegt äusserst selten in dem Teil, den der Fragesteller für
einzig relevant hält.
Tom V. schrieb:> SS liegt auf PB2 und wird ausserhalb als Output gesetzt.
Es ist vollkommen klar, dass da der Fehler zu suchen ist.
Aber bislang kann man nicht mehr sagen, als dass in Zeile 42 ein
Semikolon fehlt.
mfg.
Thomas Eckmann schrieb:> Tom V. schrieb:>> SS liegt auf PB2 und wird ausserhalb als Output gesetzt.>> Es ist vollkommen klar, dass da der Fehler zu suchen ist.
Eben.
Und weil es bei SPI im Masterbetrieb meist sowieso nicht sinnvoll ist,
denn SS Pin für etwas anderes zu verwenden, sollte die entsprechende
Verschaltung auf Ausgang hier
ist in derartigen Init-Funktionen auch immer problematisch. Denn ab
sofort können dann Interrupts bereits feuern, egal ob der Rest der
Initialisierung (anderer Komponenten) bereits fertig ist oder nicht.
Es gibt nur einen wirklich sinnvollen Platz für das initiale sei(). Und
der ist hier ...
1
intmain()
2
{
3
Initialisierungendurchführen
4
5
// jetzt ist alles fertig eingestellt. Ab jetzt gilts. Die
6
// Hauptschleife geht gleich los, alles ist 'ready to work'
7
8
sei();// <--- daher 'Feuer frei'
9
10
while(1)
11
{
12
HauptschleifeinderdasProgrammseineArbeitereledigt
13
}
14
}
... unmittelbar als letzte Aktion vor der Hauptschleife.
Es kann maximal sein, dass die sei()/cli() Steuerung in der
Hauptschleife als Folge von irgendwelchen Aktionen passiert.
Aber mitten in den Initialisierungen ist ein sei() ein 'ask for
trouble'. Das geht 20 mal gut, weil es zwischen den benutzten
Systemkomponenten keine Interrupt-Abhängigkeiten gibt, aber das 21.te
mal sucht man sich einen Wolf, weil es dann eben doch ein Programm ist,
bei dem die Reihenfolge der Initialisierungen kritisch ist und dann
plötzlich ein Interrupt zu früh kommt, noch ehe die anderen Komponenten
fertig initialisiert sind.
Thomas Eckmann schrieb:> Christian K. schrieb:>> Über das Data-Direktion-Register wird eigentlich nur ein PullUP auf VCC>> geschaltet. Dass sollte man immer machen wenn der Ausgang vom µC>> versorgen will. Der Widerstand hat 100KOhm.>> Aber nur eigentlich. Und auch nur bei dir. Für welchen Controller gilt> das?
Ok, es sind zwei Sachen, der Port-Output wird freigeschalten und es wird
ein PullUP geschaltet (falls interne PullUps im MCUCR nicht deaktiviert
sind).
Thomas Eckmann schrieb:> Christian K. schrieb:>> Nein ist es nicht!>> Sicher ist es das und das Ausrufezeichen hättest du dir sparen können.
Doch,
Tom V. hat sich über ein Verhalten des µC gewundert das du mit "Das ist
Quatsch" betitelt hast. Dieses Verhalten ist aber im Datenblatt
expliziert beschrieben.
Thomas Eckmann schrieb:> Aber ohne den gesamten Code kommt man hier, wie immer, nicht weiter. Der> Fehler liegt äusserst selten in dem Teil, den der Fragesteller für> einzig relevant hält.
Das stimmt, der Fehler wird vermutlich sein das der nSS-Pin nicht vor
der Initialisierung des SPI auf Output gesetzt wurde.
Hallo
danke erstmal für die Hinweise, insbesondere an Karl Heinz, es macht
natürlich Sinn SS in der Initfunktion mit als Ausgang zu setzen und auch
deine Anmerkung mit dem sei() nach allen Inits werde ich so umsetzen.
Jetzt kommts:
Plötzlich funktioniert es mit dem Codestand von gestern :/
Was ich heut Morgen tat:
Ich hatte lediglich das sei() aus der Initfunktion geschmissen und den
SS Pin mit in der Init gesetzt, wie von Karl Heinz empfohlen:
//PORTB = 0b00000100; //TODO SS muss HIGH gesetzt werden, sonst wird MSTR in SPCR nicht gesetzt
Plötzlich lief es.
Da aber das sei() für mein Problem hier keine direkte Rolle spielte und
ich den SS Pin ja vorher auch schon in der main() auf High gesetzt habe
wunderte ich mich das es funktionierte und bin noch einmal auf meinen
ursprünglichen Code zurück. Und plötzlich funktioniert das ganze. Wobei
mich das jetzt nicht gerade glücklich macht, da dieser Fehler(?) ja
wieder auftreten könnte.(Ich mag es nicht wenn Fehler von selbst
verschwinden)
So hier nochmal was in der ursprünglichen main() abläuft bevor der
spiMasterInit() aufgerufen wird:
Also funktioniert das ganze.
Gestern sah das mit dem selben Codestand anders aus:
Glücklicherweise hatte ich die Konsole von Gestern noch auf und da hatte
ich folgende Ausgabe mit der auskommentierten Zeile:
1
//PORTB = 0b00000100; [...]
1
DDR_SPI: 101110
2
SPI ENABLED WITHOUT INTERRUPT!
3
4
SPCR: 1000000
5
Init finished!
Auch da sieht man ja das SS(PB2) schon als Ausgang gesetzt war, ich aber
das MSTR-Bit gestern nicht setzen konnte.
Ich werde das ganze weiter beobachten und mich gegebenenfalls nochmal
hier melden. Falls jemand eine Erklärung hat immer her damit. Danke
nochmal für eure Hilfe.
Ach und falls jemand interesse verspürt auf den ganzen Code zu schauen
ich habe den Stand von Gestern bei github hochgeladen:
https://github.com/tom-vi/gugl/tree/spi
Ich bin noch recht frisch was die uC-Programmierung angeht und versuch
mich da gerade rein zu fuchsen. Für Tips und Tricks bin ich immer sehr
dankbar :)
Christian K. schrieb:> Ok, es sind zwei Sachen, der Port-Output wird freigeschalten und es wird> ein PullUP geschaltet (falls interne PullUps im MCUCR nicht deaktiviert> sind).
Ist dir klar, was du hier für einen Stuss schreibst? Wahrscheinlich
nicht.
Im DDR-Register werden keine Pullups geschaltet.
Pullups werden im PORT geschaltet, wenn der Pin Eingang ist. Wird der
Pin auf Ausgang geschaltet, wird er 'hart' an Vcc oder GND geschaltet.
Je nach Ausgabe im PORT-Register.
mfg.
Nicht ganz,
zugegeben hatte da was durcheinander gebracht.
PulluUps gibt es schon, und zwar wenn DDRx.y auf 0 ist, PORTx.y auf 1
und MCUCR.PUD auf 0 (Standard).
Wenn DDRx.y auf 1 gesetzt wird, also auf Output, wird der PullUp
weggeschaltet, stattdessen übernimmt ein Ausgangstreiber der dann je
nach PORTx.y das Signal auf GND zieht oder über eine Stromquelle auf Hi.
Christian K. schrieb:> PulluUps gibt es schon, und zwar wenn DDRx.y auf 0 ist, PORTx.y auf 1> und MCUCR.PUD auf 0 (Standard).>> Wenn DDRx.y auf 1 gesetzt wird, also auf Output, wird der PullUp> weggeschaltet, stattdessen übernimmt ein Ausgangstreiber der dann je> nach PORTx.y das Signal auf GND zieht oder über eine Stromquelle auf Hi.
Danke, dass du mir jetzt erklärst, was ich dir vorher geschrieben habe:
Thomas Eckmann schrieb:> Pullups werden im PORT geschaltet, wenn der Pin Eingang ist. Wird der> Pin auf Ausgang geschaltet, wird er 'hart' an Vcc oder GND geschaltet.> Je nach Ausgabe im PORT-Register.
mfg.