Forum: Mikrocontroller und Digitale Elektronik SPI Anfang Oszi


von Peter M. (allforone)


Lesenswert?

Hallo Leute,
Ich versuche mich im Moment mit der SPI Schnittstelle anzufreunden.

Ich bin ein absoluter Beginner. Absolut ist in dem Fall noch milde 
ausgedrückt.

Das Board ist ein DEMO9S08AW60 von freescale. Es soll als Master später 
fungieren.

   SPI1BR = 0x35;
   SPI1C1 = 0b10100000;
   SPI1C2 = 0x00;


Nach diesen Einstellungen müsste doch eigentlich ein Takt über die SCK 
Leitung gehen. Jetzt habe ich das Oszi angeschlossen, doch ich sehe nur 
ein stark schwankende Kurve.

Was ist hier falsch?

von Eumel (Gast)


Lesenswert?

Jan R. schrieb:
> doch ich sehe nur
> ein stark schwankende Kurve.

Welchen Takt hast du eingestellt? Wie schnell ist dein Oszi?

von Peter M. (allforone)


Lesenswert?

Laut den Teiler Tabellen sollten es 80KHz sein, die ich eingestellt 
habe.
Am Oszi wird neben der Kurve eine Zahl angezeigt. Die ist bis bis 2,5KHz 
aber schwankt viel zu stark. Jetzt kommen nur noch angezeigte Werte und 
keine Kurve mehr...

Vom Gedankengang her ist es aber richtig, dass ich etwas messen müsste 
können?

von Hans (Gast)


Lesenswert?

50hz schwankende kurve??? ggf pins nicht richtig konfiguriert (falls das 
bei dem controller geht)?

73

von M. D. (wpmd)


Lesenswert?

Kannst du vielleicht mal ein Bild von den Oszi-Einstellungen hier 
reinstellen? Dann könnte man bewerten ob es evtl. daran liegt dass du 
nichts siehst.

Achso, ein paar mehr Infos zum Oszi wären auch nicht schlecht...

von Der (Gast)


Lesenswert?

Masse Pins des Oszis an Masse Pins des Boards angeschlossen?

von Matrose (Gast)


Lesenswert?

Leicht schwankende Kurven sollte man als Bild hier einstellen.

von Peter M. (allforone)


Lesenswert?

Es geht keine Ahnung wieso....

Habe das hier:

   SPI1C1 = 0b10100000;
   SPI1C2 = 0x00;

in das hier geändert:

   SPI1C1 = 0x50;
   SPI1C2 = 0x00;

eigentlich dachte ich, dass die Bits im Control Register richtig gesetzt 
waren. Plötzlich keine schwankende Kurve mehr und schöne passende 
Zahlen.

Nun mal eine allgemeine Verständnisangelegenheit zu SPI.

Man unterscheidet bei der Kommunikation via SPI Schnittstelle zwischen 
einem Master und mehreren möglichen Slaves. Diese können dann 
verschieden angeordnet sein (Daisy-Chain oder sternförmig).
Um eine Verbindung bzw. Kommunikation zu ermöglichen, muss zuerst der 
Master konfiguriert werden. Dazu werden in den Controlregistern die 
passenden Bits gesetzt, als auch der Taktteiler angegeben.

SPI1BR = 0x35;
SPI1C1 = 0x50;
SPI1C2 = 0x00;

Nun muss der Slave konfiguriert werden. Dazu müssen im Control Register 
wieder die passenden Bits gesetzt werden. Das Master-Bit darf nicht 
gesetzt werden.

Wenn es jetzt zur Kommunikation bzw. Datenaustausch kommt, muss beachtet 
werden, dass dieser immer synchron stattfindet, d.h. es werden IMMER 
gleichzeitig Daten gesendet und Empfangen. Außerdem muss beachtet 
werden, dass die nötigen Statusflags richtig sind und es nicht zu einem 
Überlauf eines Buffers (transmission oder read) kommt.

void SendData (unsigned char data)
{
   do{
      spi_status = SPI1S;
   }
   while( (spi_status) == 0);
   SPI1D = data;

}

Wo befinden sich die Daten, die vom Slave dann zum Master gesendet 
wurden.
Auch im Data register? Oder in einem Buffer?

Könnt ihr einfach mal drauf schauen, ob ich es richtig verstanden habe?

Vielen Dank!

von M. D. (wpmd)


Lesenswert?

Jan R. schrieb:
> Habe das hier:
>
>    SPI1C1 = 0b10100000;
>    SPI1C2 = 0x00;
>
> in das hier geändert:
>
>    SPI1C1 = 0x50;
>    SPI1C2 = 0x00;

0b10100000 = 0xa0 != 0x50 = 0b01010000

von Peter M. (allforone)


Lesenswert?

Ah dann habe ich mich da mit einer 0 vertan gehabt. Sehr gut, ich schaue 
mir gleich nochmal die einzelnen Bits in dem Control Register an, 
welches dann falsch war.

von Thomas E. (thomase)


Lesenswert?

Jan R. schrieb:
> Ah dann habe ich mich da mit einer 0 vertan gehabt. Sehr gut, ich schaue
> mir gleich nochmal die einzelnen Bits in dem Control Register an,
> welches dann falsch war.
Deswegen schreibt man das auch nicht so: 0b0010000.
Weil bei 0b000100000 niemand auf einen Blick sieht ob es 7, 8 oder 9 Bit 
sind. Hexadezimale Schreibweise ist zwar eindeutig lesbar, aber welche 
Bits da gesetzt werden, ist auch nicht sofort erkennbar und bei der 
Umrechnung sehr fehleranfällig. Ganz zu schweigen von den Witzbolden, 
die das dezimal schreiben.

Deswegen benutzt man die Schreibweise mit den Bitnamen:
SPCR |= (1 << SPE) | (1 << MSTR);

Das ist jetzt AVR. Aber zu deinem Compiler werden wohl auch Header 
gehören, die das unterstützen.

Sollte das nicht so sein, kannst du dir sowas selber schreiben. Ist 
natürlich eine Mordsarbeit. Aber die Open-Source-Leute machen sich die 
Arbeit ja auch für die Allgemeinheit.

Als kleine Verbesserung könntest du aber zumindest mit
1
#define Bit7 7
2
#define Bit6 6
3
...
4
#define Bit0 0
etwas mehr Übersicht erlangen.

Dann musst du nur im Datenblatt gucken, an welcher Position im Register 
das betreffende Bit steht:
Statt SPI1C1 = 0x50;
schreibst du dann
SPI1C1 = (1 << Bit6) | (1 << Bit4);

Kannst natürlich auch "SPI1C1 = (1 << 6) | (1 << 4);" schreiben. Das 
kommt aufs gleiche raus. Aber das mit Bitx zu schreiben, finde ich immer 
noch übersichtlicher. Du hast ja selbst gesehen, daß man sich mit wegen 
einem verschobenen Bit dumm und dämlich suchen kann.

Und keine Angst, da wird im Controller nichts geschoben und verodert. 
Das rechnet der Compiler vorher aus.

mfg.

von Peter M. (allforone)


Lesenswert?

Vielen Dank für die Antwort bezgl. der besseren Schreibweise.
Werde ich gleich mal schauen, ob freescale etwas bereitstellt.
Könnte noch jemand zu meinem Text bzgl. SPI Stellung nehmen, inwiefern 
ich es verstanden habe?
Wäre super nett!

Muss es hier so heißen:
SPI1C1 = (1 << Bit6) | (1 << Bit4);

oder so:

SPI1C1 |= (1 << Bit6) | (1 << Bit4);

Ich würde sagen Letzteres, da die Oder-Verknüpfung angewendet werden 
muss.

von Thomas E. (thomase)


Lesenswert?

Jan R. schrieb:
> Vielen Dank für die Antwort bezgl. der besseren Schreibweise.
> Werde ich gleich mal schauen, ob freescale etwas bereitstellt.
> Könnte noch jemand zu meinem Text bzgl. SPI Stellung nehmen, inwiefern
> ich es verstanden habe?
> Wäre super nett!
Ohne deinen Controller zu kennen. Aber Motorola bzw. Freescale kochen 
auch nur mit Wasser.
Bei allen mir bekannten SPIs ist so, daß es 1 Datenregister gibt. Das 
sind tatsächlich natürlich zwei, aber vom Zugriff her ist es eins.
Beim Master schreibt man Daten rein und die SPI-"Mechanik" schiebt diese 
Bit für Bit raus. Zur gleichen Zeit sorgt der Takt dafür, daß das, was 
im Datenregister(Senden) des Slave steht, Bit für Bit ausgelesen wird 
und im Datenregister(Empfangen) des Master landet.

> Muss es hier so heißen:
> SPI1C1 = (1 << Bit6) | (1 << Bit4);
>
> oder so:
>
> SPI1C1 |= (1 << Bit6) | (1 << Bit4);
>
> Ich würde sagen Letzteres, da die Oder-Verknüpfung angewendet werden
> muss.

Nach Reset sollte das Register 0 sein. Damit würde die zweite Version 
das Register richtig beschreiben. Mit der ersten Version stellst du 
allerdings sicher, daß in jedem Falle genau das drinsteht, was du haben 
willst. Egal an welcher Stelle im Programm du das machst oder welcher 
Müll da evtl. vorher drinstand.
Bei der Initialisierung des Registers benutzt man die erste, will man in 
einem gesetzten Register etwas ändern, nimmt man die zweite Version.

mfg.

von Peter M. (allforone)


Lesenswert?

Ok gut vielen Dank.
Mein Controller ist der MC9S08AW60 von freescale.
Ich denke so in der Art hatte ich es auch verstanden.
Komliziert wird es dann nur, wenn interruptgesteuert,d.h. immer wenn der 
transmission buffer leer ist, dass dann automatisch ein Interrupt 
ausgelöst wird und so der nächste Datensatz geschickt wird.

Hier bei einem Beispiel:

      do {
      spi_status = SPI1S;
   }
   while( (spi_status&0x20) == 0);
   SPI1D = 0x3C;

Wieso wurde noch geprüft, ob 0x20 auch gleich 0 ist?
Im forum hier habe ich es schon mal gesehen, kann es mir nur nicht 
erklären?
Ist das eventuell eine controllerspezifische Geschichte?

von Thomas E. (thomase)


Lesenswert?

Jan R. schrieb:

> Hier bei einem Beispiel:
>
>       do {
>       spi_status = SPI1S;
>    }
>    while( (spi_status&0x20) == 0);
>    SPI1D = 0x3C;
>
> Wieso wurde noch geprüft, ob 0x20 auch gleich 0 ist?
> Im forum hier habe ich es schon mal gesehen, kann es mir nur nicht
> erklären?
> Ist das eventuell eine controllerspezifische Geschichte?

0x20 kann niemals 0 sein. Das ist mathematischer Unsinn.
Hier "while( (spi_status&0x20) == 0);" wird mit der UND-Verknüpfung ein 
Bit ausmaskiert. Da kommt auch wieder die Schreibweise ins Spiel:

while((spi_status & (1 << Bit5)) == 0);

Allerdings macht man man das nicht so aufwendig:
>       do {
>       spi_status = SPI1S;
>    }
>    while( (spi_status&0x20) == 0);

while (!(SPI1S & (1 << Bit5));

tut das gleiche und jeder sieht auf einen Blick, daß hier gewartet wird, 
solange Bit5 des SPI1S-Registers 0 ist.
Bit5 wird am Anfang der Übertragung auf 0 gesetzt und am Ende wieder auf 
1. Mit der Abfrage und dem damit verbundenen Warten verhindert man, daß 
das Datenbyte währenddessen überschrieben wird.

mfg.

von Peter M. (allforone)


Lesenswert?

Sehr gut vielen Dank! Im Nachhinein erscheint es ganz logisch.

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.