Forum: Mikrocontroller und Digitale Elektronik mehrere Bytes via SPI vom Slave


von S. L. (goldencue)


Lesenswert?

Hallo zusammen.

System:

ATMEGA8 ( dient als SPI-Master )
ATMEGA8 ( dient als SPI-Master-Dummy )
AVR Studio 4.18

den ganzen Leitungskram kann ich mir hier sparen, da die SPI ansich 
funktioniert.

zum Code des Masters:
1
void spi_init(void)
2
{
3
4
SPI_DDR |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS);
5
SPI_DDR &= ~(1<<SPI_MISO);                    
6
SPI_PORT |= (1<<SPI_SS)|(1<<SPI_MISO);;
7
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPHA);
8
9
}
10
11
while(1){
12
13
spi_receive_3bword();
14
15
}
16
17
void spi_receive_3bword(){
18
19
spi_received_3bword[0] = 0;
20
spi_received_3bword[1] = 0;
21
spi_received_3bword[2] = 0;
22
      
23
      
24
  
25
SPDR = SPI_DUMMY;
26
SPI_PORT &= ~(1<<SPI_SS);          
27
while(!(SPSR & (1<<SPIF)));
28
spi_received_3bword[2] = SPDR;
29
30
SPDR = SPI_DUMMY;
31
while(!(SPSR & (1<<SPIF)));
32
spi_received_3bword[0] = SPDR;
33
      
34
SPDR = SPI_DUMMY;
35
while(!(SPSR & (1<<SPIF)));
36
spi_received_3bword[1] = SPDR;
37
      
38
SPI_PORT |= (1<<SPI_SS);
39
      
40
}

zum Code des Slaves:
1
void SPI_Init(void)
2
{
3
4
SPI_DDR = (1<<SPI_MISO);
5
SPCR |= (1<<SPE)|(1<<CPHA)|(1<<SPIE);
6
7
}
8
9
SIGNAL (SIG_SPI) {
10
11
  volatile u8 receive_dummy = 0;
12
13
  SPDR = 0b00000001;
14
  while(!(SPSR & (1<<SPIF)));
15
  receive_dummy = SPDR;
16
  SPDR = 0b00001000;
17
  while(!(SPSR & (1<<SPIF)));
18
  receive_dummy = SPDR;
19
  SPDR = 0b10000000;
20
  while(!(SPSR & (1<<SPIF))); 
21
22
}

zum Problem:

Mit den oben gezeigten Routinen bekomme ich eine Verbindung; kann senden 
und empfangen. Nun möchte ich vom Slave ( was später mal ein 
EKG-Messchip ADS1298 sein wird ) mehrere Byte empfangen bekommen ohne 
zwischenzeitlich SS auf high zu ziehen, da der ADS1298 24bitconfig + ( 8 
x 24bit Messdaten ) durchgängig an den µC sendet. Die Kommunikation wird 
vom Master eingeleitet und nur dann sollen Daten vom Slave bekommen 
werden. Nun verstehe ich zum einen nicht, wie oben beschriebener Code 
funktionieren kann, obwohl die Atmega nur 8bit Puffer haben und die Bits 
ja aber durchgängig ( also bei jeder Taktflanke ) gesendet/empfangen 
werden sollen.
Da die Datenpakete der Messkanäle 24bit=3Byte groß sind, möchte ich 
zunächst natürlich das Übertragen von 3Byte umsetzen. Das tut es auch. 
Nur wie man sehen kann überträgt der Slave nicht das erste Byte zuerst, 
sondern das dritte. Darauf folgen dann das erste Byte und dann das 
mittlere. Ich muss zugeben...bin verwirrt. Jetzt hab ich zum Test die 
Arrayelemente angepasst um alle Bytes da zu haben, wo sie sein sollten. 
Aber das ist doch Gullorx. Das kann ja nicht der richtige Weg sein und 
bei Datenmengen >3Byte klappt das dann sowieso nicht mehr.

Ich bitte um Hilfe, da ich nicht zu einer funktionierenden Kommunikation 
komme. Wo ist nur mein Denkfehler?

Habt vielen Dank für eure Mühe!

von Marc2100 (Gast)


Lesenswert?

Hi,
Du solltest dir das Beispiel im Datenblatt nochmal anschauen,  dort ist 
es eigentlich sehr schön beschrieben.
Du wartest zum beispiel beim slave im Interrupt darauf, daß er fertig 
wird, das solltest du nicht dort machen.
Besser ist es wie im Datenblatt beschrieben, dich per Interrupt 
"benachrichtigen" zu lassen, und dort auch schon das neue Databyte ins 
spi Register zu legen. Danach ist der Interrupt im slave auch schon fast 
fertig, du kannst zum Schluss noch das empfangene Byte auslesen, aber 
das brauchst du ja erstmal im slave nicht.

von Amateur (Gast)


Lesenswert?

Schau Dir mal die Beispiele zu EEPROMs oder RAMs an.
Die Adressen sind immer >8 Bit und im Blockmodus werden auch mehr als 1 
Byte gelesen oder geschrieben.
Beide Seiten müssen diesen Modus aber auch unterstützen.

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


Lesenswert?

Marc2100 schrieb:
> Du wartest zum beispiel beim slave im Interrupt darauf, daß er fertig
> wird, das solltest du nicht dort machen.

 Woran siehst du den, dass es eine ISR ist ?

Matthias T. schrieb:
> Nur wie man sehen kann überträgt der Slave nicht das erste Byte zuerst,
> sondern das dritte. Darauf folgen dann das erste Byte und dann das
> mittlere. Ich muss zugeben...bin verwirrt. Jetzt hab ich zum Test die

 Was spricht dagegen, Bytes so zu übertragen, wie die auch definiert
 sind ?
 Beides sind deine MEGAs, du kannst die Reihenfolge festlegen, oder ?

von Jim M. (turboj)


Lesenswert?

Matthias T. schrieb:
> obwohl die Atmega nur 8bit Puffer haben und die Bits
> ja aber durchgängig ( also bei jeder Taktflanke ) gesendet/empfangen
> werden sollen.

Dem SPI Slave ist es egal, wenn der Master zwischen den Bits mal kurz 
eine Pause hinlegt - solange CS sich nicht ändert. Mit dem Schreiben auf 
SPDR werden jeweils 8 Clock Pulse gesendet.

Matthias T. schrieb:
> Nur wie man sehen kann überträgt der Slave nicht das erste Byte zuerst,
> sondern das dritte. Darauf folgen dann das erste Byte und dann das
> mittlere.

Das ist hier irgendein kranker Beispielcode. Im ADS1298 Handbuch steht 
genau drin, wie die Bits kommen müssen - und zwar im normalen Big Endian 
Format.

Matthias T. schrieb:
> Da die Datenpakete der Messkanäle 24bit=3Byte groß sind, möchte ich
> zunächst natürlich das Übertragen von 3Byte umsetzen.

Nein, Du möchtest eine Funktion bauen, die Dir die 27 oder 28 (RDATA 
Kommando) Byte auf einmal vom ADS abholt und in ein Array packt.

von Kaj (Gast)


Lesenswert?

Marc Vesely schrieb:
> Marc2100 schrieb:
>> Du wartest zum beispiel beim slave im Interrupt darauf, daß er fertig
>> wird, das solltest du nicht dort machen.
>
>  Woran siehst du den, dass es eine ISR ist ?
Matthias T. schrieb:
> SIGNAL (SIG_SPI)

Ganz neben bei: SIGNAL ist gefühlt seit 20 Jahre veraltet...

von Marc2100 (Gast)


Lesenswert?

SIGNAL (SIG_SPI), sieht für mich wie ein Interrupt Aufruf aus.

von S. L. (goldencue)


Lesenswert?

danke erstmal für eure Antworten und das ist schon einiges, nach dem ich 
nachlesen und testen kann. Ich hatte nur jetzt schon drei Tage gelesen 
und...naja...nichts gefunden mit mehreren Bytes...oder ich war zu doof 
dazu. egal.

Soweit ich weiss kann ich mit dem Flag DORD die Übertragungsrichtung des 
einzelnen Bytes festlegen. Im Code sende ich jedoch

1: 0b10000000
2: 0b00001000
3: 0b00000001

( als Test! ) und so soll es danach im spi_received_3bword-Array auch 
drin stehn und nicht verwürfelt

von S. L. (goldencue)


Lesenswert?

Jim Meba schrieb:
> Nein, Du möchtest eine Funktion bauen, die Dir die 27 oder 28 (RDATA
> Kommando) Byte auf einmal vom ADS abholt und in ein Array packt.

Nein. Ich möchte gleich jeden Messkanal ( 3Byte ) separat in einem 
Array...zwecks Mittelwert/Prüfsumme/CRC-Berechnung

von S. L. (goldencue)


Lesenswert?

Marc2100 schrieb:
> SIGNAL (SIG_SPI), sieht für mich wie ein Interrupt Aufruf aus.

ja das ist veraltet. In dem Fall ist das allerdings unwichtig, da es 
funktioniert und ich keinen Unterschied zur neueren ISR kenne.

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


Lesenswert?

Matthias T. schrieb:
> ( als Test! ) und so soll es danach im spi_received_3bword-Array auch
> drin stehn und nicht verwürfelt

 LOL.
 Reihenfolge beim einschreiben ändern ?

: Bearbeitet durch User
von S. L. (goldencue)


Lesenswert?

Marc Vesely schrieb:
> Reihenfolge beim einschreiben ändern ?

wäre das die "profimethode"? kann ich mir schwer vorstellen. Zumal die 
Daten später vom ADS1289 unveränderbar sind bis sie im Master mC landen

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


Lesenswert?

Matthias T. schrieb:
> wäre das die "profimethode"? kann ich mir schwer vorstellen. Zumal die
> Daten später vom ADS1289 unveränderbar sind bis sie im Master mC landen

 Du sendest 0x80, 0x08, 0x01, schreibst aber 0x01, 0x80, 0x08 in dein
 Array.
 Warum ?
 Ist das die "profimethode" ?

 Kann ich mir aber auch schwer vorstellen.

von S. L. (goldencue)


Lesenswert?

Marc2100 schrieb:
> Du wartest zum beispiel beim slave im Interrupt darauf, daß er fertig
> wird, das solltest du nicht dort machen.

mir ist das bekannt und in regulärem Code würde ich eine ISR auch nur so 
kurz es geht beanspruchen. In dem Fall hier ist es so, dass ich alle 1S 
vom Master eine Kommunikation aufbaue und damit die ISR des Slaves mehr 
als genug Zeit hat, die ISR abzuarbeiten, ohne dass ein anderer 
Interrupt oder dieser stört.

von S. L. (goldencue)


Lesenswert?

Marc Vesely schrieb:
> Du sendest 0x80, 0x08, 0x01, schreibst aber 0x01, 0x80, 0x08 in dein
>  Array.

sry war mein Fehler.
ich sende:

1: 0x01
2: 0x08
3: 0x80

wenn ich jetzt das Array im Master so anlegen würde, dass es mit 
0...beginnt, würden die Elemente quasi:

..[0]: 0x80
..[1]: 0x01
..[2]: 0x08

beeinhalten. Es soll aber nach der gesendeten Reihenfolge ins Array 
geschrieben werden.

Also da muss was an der Übertragung falsch sein, da die Bytes ansich 
richtig übermittelt werden.

Warum sendet der Slave nicht einfach 1,2,3 in Abfolge sondern 3,1,2. Das 
ist mir noch schleierhaft.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Matthias T. schrieb:
> Warum sendet der Slave nicht einfach 1,2,3 in Abfolge sondern 3,1,2. Das
> ist mir noch schleierhaft.

 0x01, 0x08, 0x80 werden gesendet.
 0x01 ist erstes Byte der gesendet (und empfangen) wird.
 0x08 ist zweites Byte der gesendet (und empfangen) wird.
 0x80 ist drittes Byte der gesendet (und empfangen) wird.

 Warum schreibst du diese Bytes nicht einfach so, wie die empfangen
 werden, in deinen Array ?

von c-hater (Gast)


Lesenswert?

Matthias T. schrieb:

> Nun verstehe ich zum einen nicht, wie oben beschriebener Code
> funktionieren kann, obwohl die Atmega nur 8bit Puffer haben und die Bits
> ja aber durchgängig ( also bei jeder Taktflanke ) gesendet/empfangen
> werden sollen.

Was genau verstehst du daran nicht? Für die SPI-Logik an sich spielt der 
Zustand der SS-Leitung so gut wie keine Rolle, mal abgesehen von der 
Tatsache, daß  SS auf High die Anschlüsse des Slave in den High-Z-Status 
bringt und ein Pegelwechsel an SS von High auf Low die SPI-Logik 
zurücksetzt.

Der Trick ist einfach, daß der Zustand nach dem Rücksetzen der Logik 
exakt derselbe Zustand ist, den sie auch dann hat, wenn eben gerade das 
achte Bit einer Transaktion übertragen wurde. Es spielt also für die 
Übertragung an sich absolut keine Geige, ob zwischen den Bytes SS 
toggelt oder nicht.

Das muß aber nicht so sein. Es gibt (viele) Geräte, die das Signalspiel 
an SS zur Wortsynchronisation benutzen. Für solche Geräte ist es 
natürlich dann nicht egal, wenn SS zwischen den Bytes auf Low geht, die 
würden dann immer nur das "erste" Byte senden, weil eben der "not 
selected"-Status den Bytezähler zurücksetzt.

Dieses Verhalten kann man natürlich auch mit einem AVR nachbauen, wenn 
man das möchte.

> Da die Datenpakete der Messkanäle 24bit=3Byte groß sind, möchte ich
> zunächst natürlich das Übertragen von 3Byte umsetzen. Das tut es auch.
> Nur wie man sehen kann überträgt der Slave nicht das erste Byte zuerst,
> sondern das dritte. Darauf folgen dann das erste Byte und dann das
> mittlere.

Nun, ich habe das DB des Teils nicht gelesen. Entweder ist das sozusagen 
die "natürliche" Reihenfolge in der die Daten geliefert werden, oder es 
gibt einen Mechanismus zur Wortsynchronisation, den du nicht korrekt 
implementiert hast (weil du das DB ebenfalls nicht gelesen hast). Die 
Wortsynchronisation muß übrigens nicht zwingend über das Signalspiel an 
SS erfolgen, sie kann auch über die vom Master gesendeten Daten 
erfolgen.

Welche Variante dein Teil verwendet, steht in seinem Datenblatt. Am 
besten, du liest es einfach mal und programmierst dann deinen Master so, 
daß er es korrekt so umsetzt, wie es der Slave braucht.

von Marc2100 (Gast)


Lesenswert?

Was mir noch auffällt, wann löst der Interrupt eigentlich das erste mal 
aus, im slave?
So wie ich das sehe, ja erst nachdem du den ersten Transfer vom  Master 
initiiert hast. Dann wartest du in der Isr auf die nächste drei 
Übertragungen, während der Master die erste falsche, da im slave nicht 
festgelegten, Daten ins Array schreibt, sodass du ab da, immer eine 
falsche Reihe folge hast.

von S. L. (goldencue)


Lesenswert?

Marc Vesely schrieb:
> Warum schreibst du diese Bytes nicht einfach so, wie die empfangen
>  werden, in deinen Array ?

so würde ich es erwarten und auch gern so machen. Nur steht im Array 
nach Empfang:

Element 1 ([0]) hat 0x80
Element 2 ([1]) hat 0x01
Element 3 ([2]) hat 0x08

das ist aber nicht was ich gesendet hab :(

Wie das Array im Master jetzt von der SPI gefüllt wird stünden die Werte 
an richtiger Stelle. Aber das wäre halt scheisse. Ich möchte

Byte 1 -> Element 1
Byte 2 -> Element 2
Byte 3 -> Element 3

Wenn ich das so anlege, steht aber danach im Array:

Element 1 hat Byte 3
Element 2 hat Byte 1
Element 3 hat Byte 2

Das soll nicht!!!

von Stefan E. (sternst)


Lesenswert?

Matthias T. schrieb:
> Warum sendet der Slave nicht einfach 1,2,3 in Abfolge sondern 3,1,2. Das
> ist mir noch schleierhaft.

Die ISR im Slave startet nach einer Übertragung, also ist das erste 
Byte, dass der Master empfängt, Müll.
Der Master startet die Übertragung des zweiten Bytes direkt nach dem 
ersten. Das ist zu wenig Zeit für den Slave, um in der ISR überhaupt zu 
dem Punkt zu kommen, wo das erste echte Byte ins Datenregister 
geschrieben wird. Also ist auch das zweite von Master empfangene Byte 
Müll.
Das dritte empfangene Byte ist dann erste echte Datenbyte.

Zu allem Überfluss startest du die Übertragung auch noch, bevor du das 
SS-Signal setzt.

von S. L. (goldencue)


Lesenswert?

Stefan Ernst schrieb:
> Zu allem Überfluss startest du die Übertragung auch noch, bevor du das
> SS-Signal setzt.

das war ein Test und wundert mich ehrlich gesagt ja auch. Nur - erst SS 
auf low zu ziehen und dann das SPDR zu "befüllen" führte zu keinem 
besseren Ergebnis - leider.

von S. L. (goldencue)


Lesenswert?

ich werde all eure Vorschläge jetzt mal durchackern und dabei auf die 
Lösung hoffen. Ich weiss es liegt an mir und meinem Verständnis und 
deshalb wird "begreifen" des Kommunikationsablaufes hier das 
Schlüsselwort sein ;)

ich teste/ lerne und berichte natürlich sobald ich mehr weiss


vielen vielen Dank euch erstmal!!!

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Marc Vesely schrieb:
>> Warum schreibst du diese Bytes nicht einfach so, wie die empfangen
>>  werden, in deinen Array ?
>
> so würde ich es erwarten und auch gern so machen. Nur steht im Array
> nach Empfang:
>
> Element 1 ([0]) hat 0x80
> Element 2 ([1]) hat 0x01
> Element 3 ([2]) hat 0x08
>
> das ist aber nicht was ich gesendet hab :(

Dein Code im Master
1
SPDR = SPI_DUMMY;
2
SPI_PORT &= ~(1<<SPI_SS);          
3
while(!(SPSR & (1<<SPIF)));
4
spi_received_3bword[2] = SPDR;
5
6
SPDR = SPI_DUMMY;
7
while(!(SPSR & (1<<SPIF)));
8
spi_received_3bword[0] = SPDR;
9
      
10
SPDR = SPI_DUMMY;
11
while(!(SPSR & (1<<SPIF)));
12
spi_received_3bword[1] = SPDR;

reduziert auf das wichtige
1
...
2
   spi_received_3bword[2] = SPDR;
3
...
4
   spi_received_3bword[0] = SPDR;
5
...
6
   spi_received_3bword[1] = SPDR;

Vergleich die Indizies.
Genau hier verwürfelst du die Daten.

Beim SPI dreht sich da gar nichts um. In der Reihenfolge, in der 
gesendet wird, in der Reihenfolge wird auch empfangen.
Es liegt an dir, bzw. an deinem Code die Reihenfolge festzulegen. Schick 
sie im Slave genau in der Reihenfolge weg, in der du sie gespeichert 
haben willst und speichere sie im Master mit aufsteigenden Indizes im 
Array. Das ist wirklich keine Hexerei. Je mehr du da künstelst, um so 
eher baust du dir da Fehler ein.
1
  SPI_PORT &= ~(1<<SPI_SS);          
2
  for( i = 0; i < 3; i++ ) {
3
    SPDR = SPI_DUMMY;
4
    while(!(SPSR & (1<<SPIF)));
5
    spi_received_3bword[i] = SPDR;
6
  }
es wird auf 3 Bytes vom Slave gewartet und genau in der Reihenfolge, in 
der die Bytes eintrudeln, werden sie im Array abgelegt.

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Karl Heinz schrieb:
> Vergleich die Indizies.
> Genau hier verwürfelst du die Daten.

Und noch einer. ;-)

Matthias T. schrieb:
> Jetzt hab ich zum Test die
> Arrayelemente angepasst um alle Bytes da zu haben, wo sie sein sollten.
> Aber das ist doch Gullorx.

Seine Frage lautet also eigentlich:
"Warum muss ich die Daten so verwürfelt ins Array Schreiben, damit der 
Inhalt dann dem entspricht, was ich bei normaler Reihenfolge erwarten 
würde?"

Und die Antwort steht (denke ich) in meinem Post.

von S. L. (goldencue)


Angehängte Dateien:

Lesenswert?

Jetzt sende ich zum Anfang der Kommunikation ein Dummy-Byte, um am Slave 
die ISR auszulösen, und ich habe am Master zwischen jedem Bytesenden 
etwas Zeit gelassen. Jetzt kommen die Bytes auch da an im Array, wo sie 
hin sollen.
Einmal je Sekunde iniziiert der Master nun diese Kommunikation.

Jetzt jedoch verschieben sich die Werte jeweils um ein Element. Also:

1e Kommunikation:

0x01 -> ..[0]
0x08 -> ..[1]
0x80 -> ..[2]

2e Kommunikation:

0x08 -> ..[0]
0x80 -> ..[1]
0x01 -> ..[2]

3e Kommunikation:

0x80 -> ..[0]
0x01 -> ..[1]
0x08 -> ..[2]

u.s.w.

Im Anhang hab ich mal den Ablauf, wie ich ihn möchte

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Matthias T. schrieb:
> Jetzt sende ich zum Anfang der Kommunikation ein Dummy-Byte

Und was genau ist für dich jetzt "Anfang der Kommunikation"?

Wenn das innerhalb der Hauptschleife passiert, wundert mich das 
beobachtete Verhalten nicht.
Ansonsten: Code zeigen.


Edit:
Dir ist schon klar, dass die Änderungen, die du jetzt am Master 
vornimmst, nur wegen deines speziellen Fake-Slaves nötig sind, oder?
> Nun möchte ich vom Slave ( was später mal ein
> EKG-Messchip ADS1298 sein wird )
Da sieht die Sache dann wieder anders aus.

: Bearbeitet durch User
von S. L. (goldencue)


Lesenswert?

Stefan Ernst schrieb:
> Wenn das innerhalb der Hauptschleife passiert, wundert mich das
> beobachtete Verhalten nicht.

Die Hauptschleife führt momentan zur Fehlersuche nur einmal die Sekunde 
die SPI-Funktion aus.

von S. L. (goldencue)


Lesenswert?

Stefan Ernst schrieb:
> Dir ist schon klar, dass die Änderungen, die du jetzt am Master
> vornimmst, nur wegen deines speziellen Fake-Slaves nötig sind, oder?

Ja. Es geht im Moment nur um die rudimentäre Funktionsweise. Der ADS1298 
benötigt dann andere Einstellungen zur Kommunikation. Aber ich muss 
Schritt für Schritt sicherstellen, dass jede Funktion perfekt läuft. Ich 
habe schon USART mit 9830400Hz, die Umrechnung und einen Sheduler 
umgesetzt. Ist im Mom aber alles ausgeblendet.

von Peter D. (peda)


Lesenswert?

Matthias T. schrieb:
> SPDR = SPI_DUMMY;
> SPI_PORT &= ~(1<<SPI_SS);

/SS muß natürlich auf 0 gesetzt werden, bevor man sendet.

Matthias T. schrieb:
> SIGNAL (SIG_SPI) {
>
>   volatile u8 receive_dummy = 0;
>
>   SPDR = 0b00000001;

Du schreibst also erst, nachdem ein Byte gesendet wurde.
Das geht so nicht.
Du mußt einen externen Interrupt auf die fallende Flanke von /SS 
auslösen und dann sofort das 1. Byte laden.

Der AVR ist allerdings ein mangelhafter Slave, da er keinen Sendepuffer 
hat. Daher muß der Master vor jedem Dummy-Senden etwas warten, z.B. 
10µs.

von S. L. (goldencue)


Lesenswert?

Peter Dannegger schrieb:
> Der AVR ist allerdings ein mangelhafter Slave, da er keinen Sendepuffer
> hat. Daher muß der Master vor jedem Dummy-Senden etwas warten, z.B.
> 10µs.

genau das hab ich jetzt getan.

der Code sieht im Moment so aus

Master:
1
while(1){
2
3
  if (tmp_cnt == 0)
4
  {
5
    spi_receive_3bword();
6
  }
7
8
  _delay_ms(1000);
9
10
  tmp_cnt = 0;
11
  
12
  }
13
14
unsigned char SPI_Receive( unsigned char in )
15
{
16
  SPDR = in;
17
18
  /* Wait for reception complete */
19
  while(!(SPSR & (1<<SPIF)));
20
21
  /* Return data register */
22
  return SPDR;
23
}
24
25
////////////////////////////SPI COMMUNICATION////////////////////////
26
27
void spi_receive_3bword()
28
{
29
  
30
  spi_received_3bword[0] = 0x00;
31
  spi_received_3bword[1] = 0x00;
32
  spi_received_3bword[2] = 0x00;
33
      
34
      
35
  SPDR = 0x00;
36
      
37
  SPI_PORT &= ~(1<<SPI_SS);
38
  SPI_Receive( SPI_DUMMY );
39
  _delay_us(10);
40
  spi_received_3bword[0] = SPI_Receive( SPI_DUMMY );
41
  _delay_us(10);
42
  spi_received_3bword[1] = SPI_Receive( SPI_DUMMY );
43
  _delay_us(10);
44
  spi_received_3bword[2] = SPI_Receive( SPI_DUMMY );
45
  SPI_PORT |= (1<<SPI_SS);
46
  if ( spi_received_3bword[0] > 0) tmp_cnt++;
47
48
}

Slave:
1
SIGNAL (SIG_SPI) {
2
3
  SPDR = 0b00000001;
4
  while(!(SPSR & (1<<SPIF)));
5
  SPDR = 0b00001000;
6
  while(!(SPSR & (1<<SPIF)));
7
  SPDR = 0b10000000;
8
  while(!(SPSR & (1<<SPIF)));
9
}

Aus mir unersichtlichen Gründen bestehen weiterhin folgende Ergebnisse:

1e Kommunikation:

0x01 -> ..[0]
0x08 -> ..[1]
0x80 -> ..[2]

2e Kommunikation:

0x08 -> ..[0]
0x80 -> ..[1]
0x01 -> ..[2]

3e Kommunikation:

0x80 -> ..[0]
0x01 -> ..[1]
0x08 -> ..[2]

u.s.w.

ich verstehe nicht wo dieses Schieben stattfindet???

: Bearbeitet durch User
von S. L. (goldencue)


Lesenswert?

Zwischendurch...HABT GROSSEN DANK FÜR EURE MÜHE UND ZEIT!!!

von Stefan E. (sternst)


Lesenswert?

Matthias T. schrieb:
> der Code sieht im Moment so aus

Also doch, das Senden des Dummy-Bytes steht innerhalb der Hauptschleife. 
Wenn du laufend ein Byte "vernichtest", statt wirklich nur das 
allererste, dann fehlt dir natürlich auch laufend ein Byte.

von S. L. (goldencue)


Lesenswert?

Stefan Ernst schrieb:
> Also doch, das Senden des Dummy-Bytes steht innerhalb der Hauptschleife.

wo?

von Stefan E. (sternst)


Lesenswert?

Matthias T. schrieb:
> wo?

Ernsthaft?

1
void spi_receive_3bword()
2
{
3
  
4
  spi_received_3bword[0] = 0x00;
5
  spi_received_3bword[1] = 0x00;
6
  spi_received_3bword[2] = 0x00;
7
      
8
      
9
  SPDR = 0x00;
10
      
11
  SPI_PORT &= ~(1<<SPI_SS);
12
  SPI_Receive( SPI_DUMMY );   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
13
  _delay_us(10);
14
  spi_received_3bword[0] = SPI_Receive( SPI_DUMMY );
15
  _delay_us(10);
16
  spi_received_3bword[1] = SPI_Receive( SPI_DUMMY );
17
  _delay_us(10);
18
  spi_received_3bword[2] = SPI_Receive( SPI_DUMMY );
19
  SPI_PORT |= (1<<SPI_SS);
20
  if ( spi_received_3bword[0] > 0) tmp_cnt++;
21
22
}

von S. L. (goldencue)


Angehängte Dateien:

Lesenswert?

Matthias T. schrieb:
>> Also doch, das Senden des Dummy-Bytes steht innerhalb der Hauptschleife.

Aber wo soll es denn sonst stehen? Jetzt bin ich gänzlich verwirrt.

Und warum genau geht mir da je ein Byte verloren? Ich sende pro 
transmission 4x das Dummy. Bitte schau nochmal auf den Ablaufplan im 
Anhang. Wo liegt nun der Unterschied zum Code?

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Matthias T. schrieb:
> SPDR = 0x00;
>
>   SPI_PORT &= ~(1<<SPI_SS);

Ist doch immer noch falsch rum.

So:
1
  SPI_PORT &= ~(1<<SPI_SS); // slave enable
2
  _delay_us( 10 );          // wait a little
3
  SPDR = 0x00;              // generate 8 clock cycle
4
  // ...

von Stefan E. (sternst)


Lesenswert?

Matthias T. schrieb:
> Aber wo soll es denn sonst stehen? Jetzt bin ich gänzlich verwirrt.

Eine Tatsache, die dir offensichtlich nicht klar ist, und dir vielleicht 
ein Licht aufgehen lässt:
Bei deinem Slave-Code ist das Interrupt-Flag am Ende der ISR gesetzt, so 
dass die ISR nach ihrem Ende gleich wieder aufgerufen wird.

von S. L. (goldencue)


Lesenswert?

Peter Dannegger schrieb:
> Ist doch immer noch falsch rum

ups...das sollte nicht sein und war auch Teil des "Fehlverhaltens".

von S. L. (goldencue)


Lesenswert?

So und und nun mal die Lösung. Jetzt funktioniert alles, auch wenn ich 
die Kommunikation jetzt natürlich noch anpassen muss.

Der "Fehler" lag auf der Slaveseite. Nach dem letzten Byte einer Abfrage 
des Masters muss ich das Slave-SPI noch mit 0x00 "leeren". Jetzt steht 
der Inhalt bei neuer Anfrage wieder auf null und alles läuft wie 
erwartet.


Ich danke nochmals sehr für eure Bemühungen !!!

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.