Forum: Mikrocontroller und Digitale Elektronik SPI Routine eines dsPIC, der gleichzeitig sendet und emfängt


von Ralf Kowalski (Gast)


Lesenswert?

Hallo zusammen,

ich versuche aktuell das SPI Modul meines dsPIC30F5011 als Master zu 
konfigurieren.
Dabei versuche ich eine Routine zu basteln, die gleichzeitig empfängt 
und sendet.

Als "Empfangsdaten" erwarte ich jeweils immer 1 Byte aus 0en und 1en ;)

Die Routine sieht aktuell folgendermaßen aus:
1
unsigned char sendreadSPI2(unsigned char data)
2
{ 
3
   unsigned char dummy;
4
   dummy = SPI2BUF ; //Auslesen vor dem Senden
5
   
6
   SPI2BUF  = data;
7
8
   while(!IFS1bits.SPI2IF); //Warten bis gesendet=>Auslesen Interrupt Flag
9
10
   while(SPI2STATbits.SPITBF); //Warten bis TransmitBuffer voll
11
   dummy = SPI2BUF ; //reset, damit gesendetes Byte weg ist
12
13
   while(!SPI2STATbits.SPIRBF); //Warten bis Empfangsbuffer voll
14
    
15
   return SPI2BUF;
16
17
}

Irgendwie bleibt meine Schleife aber kontinuierlich in dem 
while(!SPI2STATbits.SPIRBF); hängen. Nun versuche ich auszuschließen, 
dass diese Schleife einen Fehler hat oder ob meine Initialisierung für 
meinen Slave falsch ist.

Sieht jemand einen entscheidenden Denkfehler?

Der Programmablauf wäre grob:

1.) Senden eines Request, dass ich mehrere Register auslesen will.
Also quasi: sendreadSPI2(Befehl);

2.) for- Schleife, welche lang genug für jedes Register ist das ich 
erwarte und dann nach dem Motto:
 Ergebnis1= sendreadSPI2(0x00);

Das 0x00 sende ich, damit ausgelesen wird, aber keine neue Information 
gesendet. Dürfte ja auch so richtig sein oder?

Liebe Grüße
Ralf

von holger (Gast)


Lesenswert?

>   dummy = SPI2BUF ; //reset, damit gesendetes Byte weg ist

Was soll das denn? Mach das weg.

von c-hater (Gast)


Lesenswert?

Ralf Kowalski schrieb:

> ich versuche aktuell das SPI Modul meines dsPIC30F5011 als Master zu
> konfigurieren.
> Dabei versuche ich eine Routine zu basteln, die gleichzeitig empfängt
> und sendet.

Da genau das der absolute Normalfall für SPI ist, sollte das unabhängig 
vom verwendeten µC vollkommen problemlos umzusetzen sein...

Das Problem ist vermutlich nur, dass du sowas von überhaupt keine 
Vorstellung hast, wie SPI funktioniert, dass es die Hunde jammert...

von Wolfgang (Gast)


Lesenswert?

Ralf Kowalski schrieb:
> Dabei versuche ich eine Routine zu basteln, die gleichzeitig empfängt
> und sendet.

Was wäre da so besonders dran. SPI ist immer ein Byteaustausch - auf dem 
einen Ende kommt was aus dem Schieberegister raus und auf dem anderen 
Ende kommt was rein.

von W.S. (Gast)


Lesenswert?

Ralf Kowalski schrieb:
> Die Routine sieht aktuell folgendermaßen aus

Ja.
Ich verstehe dein Anliegen dennoch nicht. Normalerweise vergeudet man 
Rechenzeit nicht, weswegen Trampelschleifen verpönt sind. Man wartet 
deshalb lieber auf das Eintreffen von Bedingungen wie z.B. ein 
Interrupt, der anzeigt, daß jetzt ein neuese Byte/Wort irgendwo 
eingetroffen ist oder daß ein Sendepuffer jetzt ein neues Byte/Wort 
vertragen könnte. Und dann reagiert man per Interrupt-Routine darauf. 
Dazu werden In- und Out-Ströme dezent zwischengepuffert, so daß man eine 
zeitliche Entkopplung hat zwischen dem Strom und seinem eigentlichen 
Algorithmus.

Wo bittesehr sehe ich sowas in deinem Entwurf?

W.S.

von Ralf Kowalski (Gast)


Lesenswert?

c-hater schrieb:
> Das Problem ist vermutlich nur, dass du sowas von überhaupt keine
> Vorstellung hast, wie SPI funktioniert, dass es die Hunde jammert...

Ich taste mich da langsam heran und habe in anderen Foren gelesen, dass 
es nicht unbedingt unüblich ist die Routinen entweder aufzuteilen, daher 
war ich etwas verunsicher, wieso man das ganze aufteilt.



Scheint die Routine denn sonst richtig zu sein? Abgesehen von der 
Anmerkung vonholger?

von Ralf Kowalski (Gast)


Lesenswert?

W.S. schrieb:
> Ich verstehe dein Anliegen dennoch nicht. Normalerweise vergeudet man
> Rechenzeit nicht, weswegen Trampelschleifen verpönt sind. Man wartet
> deshalb lieber auf das Eintreffen von Bedingungen wie z.B. ein
> Interrupt, der anzeigt, daß jetzt ein neuese Byte/Wort irgendwo
> eingetroffen ist oder daß ein Sendepuffer jetzt ein neues Byte/Wort
> vertragen könnte. Und dann reagiert man per Interrupt-Routine darauf.
> Dazu werden In- und Out-Ströme dezent zwischengepuffert, so daß man eine
> zeitliche Entkopplung hat zwischen dem Strom und seinem eigentlichen
> Algorithmus.
>
> Wo bittesehr sehe ich sowas in deinem Entwurf?

Ich verstehe deine Anmerkung. Die Rechenzeit ist bei mir prinzipiell 
aber eher unkritisch. Dazu habe ich nur einen Slave, der mir nur dann 
Daten zurückgibt, wenn ich konkret vorher per Request anfordere. Daher 
würde der Interrupt doch eigentlich auch nur direkt nach dem Senden 
ausgelöst werden und es ergeben sich keine weiteren vorteile abgesehen 
davon, dass er ggf. nicht in der while festhängt. Dieses in der while 
festhängen könnte man allerdings auch noch ohne großen Aufwand 
beseitigen.

von c-hater (Gast)


Lesenswert?

Ralf Kowalski schrieb:

> Ich taste mich da langsam heran und habe in anderen Foren gelesen

Lesen in Foren ist u.U. nützlich, wenn man ein konkretes Problem hat. Es 
kann aber niemals systematisches Lernen ersetzen.

> dass
> es nicht unbedingt unüblich ist die Routinen entweder aufzuteilen, daher
> war ich etwas verunsicher, wieso man das ganze aufteilt.

Es gibt sicher Bussysteme, bei denen es sehr sinnvoll ist, Lesen und 
Schreiben in getrennten Routinen zu behandeln. Nur ist SPI eben kein 
solches Bussystem, sondern das genaue Gegenteil davon. Mit hinreichendem 
Grundlagenwissen über die Funktionsweise ist das jedem sofort klar, der 
auch nur ansatzweise logisch denken kann. Dein Problem ist halt, dass 
dir genau dieses Grundlagenwissen fehlt. Da hilft nur eins: Lernen.

von holger (Gast)


Lesenswert?

So, mal kurz das Datenblatt von so nem dsPic gelesen.
Das ganze kann viel kürzer werden:
1
unsigned char sendreadSPI2(unsigned char data)
2
{ 
3
   SPI2BUF  = data;
4
5
   while(!SPI2STATbits.SPIRBF); //Warten bis Empfangsbuffer voll
6
    
7
   return SPI2BUF;
8
}

Fast genau so einfach wie bei einem AVR;)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

W.S. schrieb:
> Rechenzeit nicht, weswegen Trampelschleifen verpönt sind. Man wartet
> deshalb lieber auf das Eintreffen von Bedingungen wie z.B. ein
> Interrupt, der anzeigt, daß jetzt ein neuese Byte/Wort irgendwo
> eingetroffen ist oder daß ein Sendepuffer jetzt ein neues Byte/Wort
> vertragen könnte. Und dann reagiert man per Interrupt-Routine darauf.

 Aber nicht beim SPI.
 Ein Slave kann keine Kommunikation starten, nur Master.
 Deswegen ist es nix mit Interrupt und Master, es sei denn, Master
 sendet Daten in Paketen, was aber hier nicht der Fall ist.

von Ralf Kowalski (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die Anmerkungen und Hilfestellungen die ich bisher erhalten 
habe

Ich denke ich habe mein eigentliches Problem gefunden.
Mein Slave "verlangt" CPOL=1 und CPHA=1 also folglich:
Eine Clock, die den Idle auf High hat. Darüber hinaus müssen die Daten 
am SDI des Slaves stabil sein, wenn eine steigende Flanke der CLK kommt.

Interpretiere ich die angehängte Grafik richtig:

CKP muss 1 sein => Idle = 1
CKE muss 0 ein => Daten auf steigender Flanke stabi

Daraus folgt der zweite SCKX  Graph ist der entsprechend relevante.

Für SMP finde ich im Reference:
1
SMP: SPI Data Input Sample Phase bit
2
Master mode:
3
1 = Input data sampled at end of data output time
4
0 = Input data sampled at middle of data output time

Nach welcher relevanten Info muss ich dazu im Datenblatt des Slaves 
suchen?
Mir scheint es aus dem Zusammenhang so, als hängt das stark davon ab, 
wie ich CKE setze. Wenn ich eine steigende Flanke abwarte kann ich mit 
der ANtwort folglich erst am Ende rechnen und nicht direkt in der Mitte.

Vielen Dank für jede weitere Hilfe :)

von Marc V. (Firma: Vescomp) (logarithmus)


Angehängte Dateien:

Lesenswert?

Ralf Kowalski schrieb:
> Nach welcher relevanten Info muss ich dazu im Datenblatt des Slaves
> suchen?

 Irgendwo muss auch SPI MODE stehen.

: Bearbeitet durch User
von Gästchen (Gast)


Lesenswert?

Hallo,

bei PIC24 (welche fast identisch mit dspic33 sind) ist das so:

SPI1CON1bits.CKE = xx; //clock edge select
SPI1CON1bits.CKP = XX; //clock polarity select

Steht im SPI-Kapitel des Handbuchs.

Sei dir im Klaren, dass dieses nur eine Zusammenfassung ist. Eine 
detailliertere Beschreibung findest du auf der Produktseite deines PIC.
Dort sind auch Codebeispiele drin, welche das Leben doch sehr 
erleichtern.

Desweiteren gibts das hier:
http://www.microchip.com/doclisting/TechDoc.aspx?type=CodeExamples

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Heiner schrieb im Beitrag #4642295:
> c-hater schrieb:
>> ist das jedem sofort klar, der
>> auch nur ansatzweise logisch denken kann.
>
> Du hast es drauf, Troll!
>
> lg Heiner

 Diesmal hat er Recht, der Troll bist du.

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.