Forum: Mikrocontroller und Digitale Elektronik 32-Bit SPI Daten empfangen


von DrGonzo (Gast)


Lesenswert?

Hallo Leute,

ich versuche gerade 32-Bit SPI Daten von einem MAX31855 in eine 32-Bit 
uint Variable zu schreiben. Aber egal welche Methode ich ausprobiere, 
der Compiler scheint da immer irgendwie dazwischen zu murksen. Im Moment 
benutze ich AVR-Studio 4 mit der avr-gcc-toolchain.

Hier mal ein paar Beispiele, was ich so ausprobiert habe:
1
buffer |= 0xFF000000 & (uint32_t)(SPI_recvByte() << 24);
2
buffer |= 0x00FF0000 & (uint32_t)(SPI_recvByte() << 16);
3
buffer |= 0x0000FF00 & (uint32_t)(SPI_recvByte() << 8);
4
buffer |= 0x000000FF & (uint32_t)(SPI_recvByte());
1
for(index = 0; index < 4; index++)
2
{
3
    buffer |= (uint32_t)(SPI_recvByte() << (8 * (3 - index)));
4
}
1
for(index = 3; index >= 0; index--)
2
{
3
    buffer |= (uint32_t)(SPI_recvByte() << (8 * index));
4
}

von holger (Gast)


Lesenswert?

Dein cast ist an der falschen Stelle:

buffer |= 0xFF000000 & ((uint32_t)SPI_recvByte() << 24);

oder

buffer |= 0xFF000000 & (SPI_recvByte() << 24UL);

von DrGonzo (Gast)


Lesenswert?

Irgendwie habe ich auch das Gefühl, der Compiler optimiert mir da was 
weg.

von holger (Gast)


Lesenswert?

Nachtrag:

buffer sollte auch mal definiert gesetzt werden.
Mit dem ersten Byte z.B.

Und die Maskiererei kannst du dir auch sparen.

buffer = (uint32_t)SPI_recvByte() << 24;
buffer |= (uint32_t)SPI_recvByte() << 16;

usw.

Und schon sieht das alles viel einfacher aus

von DrGonzo (Gast)


Lesenswert?

Ja, das mag sein. Ich habe es angepasst, aber besser ist es nicht 
geworden.
Es wäre schön wenn die zweite oder dritte Codeschnipsel laufen würde.

Es ist so, das der Sensor (MAX31855) 32-Bit an Daten über den SPI 
sendet. Diese lese ich ein. Da der SPI-Eingangsbuffer des Atmega (nur) 
8-Bit aufnehmen kann, mache ich das halt vier mal hintereinander.

von DrGonzo (Gast)


Lesenswert?

holger schrieb:
> Nachtrag:
>
> buffer sollte auch mal definiert gesetzt werden.
> Mit dem ersten Byte z.B.
>
Ja, mache ich. Im Moment ist buffer auch global, um den ganzen Schmarn 
debuggen zu können.

von Ingo (Gast)


Lesenswert?

Also ich würde den Buffer erstmal per Hand füllen um zu gucken ob der 
Fehler vom SPI kommt oder beim Zusammensetzen passiert.

von DrGonzo (Gast)


Lesenswert?

Ja, habe ich auch schon gemacht. Das funktioniert soweit.
Was mich wundert, wenn ich das ganze debugge, werden effektiv nur die 
beiden Zeilen umgesetzt:

buffer |= (SPI_recvByte() << 8UL);
buffer |= (SPI_recvByte());

Bzw. bewirken diese das sich etwas in buffer ändert.

von DrGonzo (Gast)


Lesenswert?

Wie als ob der beim linksschieben größer als 16 nicht klarkommt

von holger (Gast)


Lesenswert?

>Also ich würde den Buffer erstmal per Hand füllen um zu gucken ob der
>Fehler vom SPI kommt oder beim Zusammensetzen passiert.

Oder besser gesagt: Ich würde mir die Bytes die
SPI_recvByte() liefert mal per UART ansehen.

Das zusammensetzen klappt hiermit schon:

buffer = (uint32_t)SPI_recvByte() << 24;
buffer |= (uint32_t)SPI_recvByte() << 16;
buffer |= (uint16_t)SPI_recvByte() << 8;
buffer |= SPI_recvByte();

Das hab ich schon tausend mal so gemacht.

von DrGonzo (Gast)


Lesenswert?

Also hab das jetzt mal mit USART getestet, das scheint alles zu 
funktionieren.

von holger (Gast)


Lesenswert?

>Also hab das jetzt mal mit USART getestet, das scheint alles zu
>funktionieren.

Dann geht es jetzt? Oder ist dein buffer ein uint16_t?

von DrGonzo (Gast)


Lesenswert?

Ne, es funktioniert nücht. Ich meinte damit nur das die Sachen die über 
SPI eingelesen korrekt auf dem USART ausgegeben werden. Also somit die 
SPI Routine funktioniert.

von DrGonzo (Gast)


Lesenswert?

Hier mal die gesamte Funktion:
1
...
2
// Global
3
volatile uint32_t buffer = 0;
4
...
1
float SPI_getTemp(void)
2
{
3
  float temp = 0.0;
4
  //int8_t index = 0;
5
  uint8_t index = 0;
6
  uint8_t byte[4];
7
  //volatile uint32_t buffer = 0;
8
  char bla_buffer[12];
9
10
  buffer = 0;
11
12
  ATOMIC_BLOCK(ATOMIC_FORCEON)
13
  {
14
    SPI_PORT &= ~(1 << SPI_SS); // select slave  
15
    _delay_ms(1);
16
17
    //for(index = 3; index >= 0; index--)
18
    for(index = 0; index < 4; index++)
19
    {
20
      byte[index] = SPI_recvByte();
21
      USART_Send(itoa(byte[index], bla_buffer, 10)); 
22
      USART_Send("|");
23
24
      //buffer |= (uint32_t)(test << (8 * index));
25
      buffer |= (uint32_t)(byte[index] << (8 * (3 - index)));
26
    }
27
    USART_Send(">");
28
  
29
    /*  
30
    buffer = (uint32_t)(SPI_recvByte() << 24);
31
    buffer |= (uint32_t)(SPI_recvByte() << 16);
32
    buffer |= (uint32_t)(SPI_recvByte() << 8);
33
    buffer |= (uint32_t)(SPI_recvByte());
34
    */
35
    
36
37
    SPI_PORT |= (1 << SPI_SS); // deselect slave
38
  }
39
40
  buffer = buffer >> 18;
41
42
  if(buffer & 0x2000) // check sign bit
43
  {
44
    temp = (float)(2048.0 - (buffer & 0x1FFF) * 0.25);
45
  }
46
47
  else
48
  {
49
    temp = (float)(buffer * 0.25);  
50
  }
51
52
  return(temp);
53
}

von holger (Gast)


Lesenswert?

>Hier mal die gesamte Funktion:

Ja, immer schön beratungsresistent bleiben.

      buffer |= (uint32_t)(byte[index] << (8 * (3 - index)));

Schmeiß den Müll in die Tonne.

von DrGonzo (Gast)


Lesenswert?

Es scheint immer noch daran zu liegen, dass Werte die größer als 16-Bit 
sind, verschluckt werden.

Format:
byte[0] | byte[1] | byte[2] | byte[3] |> buffer > temp

Daten per USART rausgeschickt.
0|196|21|176|>5552> 0.00

Also byte[0..3] ergibt nicht buffer.

von DrGonzo (Gast)


Lesenswert?

holger schrieb:
>>Hier mal die gesamte Funktion:
>
> Ja, immer schön beratungsresistent bleiben.
>
>       buffer |= (uint32_t)(byte[index] << (8 * (3 - index)));
>
> Schmeiß den Müll in die Tonne.

Btw. das von dir angeratene Vorgehen fluppt auch nicht:
1
    byte[0] = SPI_recvByte();
2
    buffer = (uint32_t)(byte[0] << 24);
3
    USART_Send(itoa(byte[0], bla_buffer, 10)); 
4
    USART_Send("|");
5
6
    byte[1] = SPI_recvByte();
7
    buffer |= (uint32_t)(byte[1] << 16);
8
    USART_Send(itoa(byte[1], bla_buffer, 10)); 
9
    USART_Send("|");
10
11
    byte[2] = SPI_recvByte();
12
    buffer |= (uint32_t)(byte[2] << 8);
13
    USART_Send(itoa(byte[2], bla_buffer, 10)); 
14
    USART_Send("|");
15
16
    byte[3] = SPI_recvByte();
17
    buffer |= (uint32_t)(byte[3]);
18
    USART_Send(itoa(byte[3], bla_buffer, 10)); 
19
    USART_Send("|");  
20
    
21
    USART_Send(">");
22
    USART_Send(itoa(buffer, bla_buffer, 10)); 
23
    USART_Send(">");

Ergibt:

0|208|21|144|>5520> 0.00

von holger (Gast)


Lesenswert?

> 0|196|21|176|>5552> 0.00

Das ist sicher nicht 5552. In HEX vieleicht.

Da schmeisst du 18 Bits von 32 weg

  buffer = buffer >> 18;

Was wohl diese Frage beantwortet:

>dass Werte die größer als 16-Bit
>sind, verschluckt werden.

Ausserdem scheint der Wert ja noch signed zu sein

>  if(buffer & 0x2000) // check sign bit

Da ist schieben schon mal eine ganz schlechte Idee.

>Btw. das von dir angeratene Vorgehen fluppt auch nicht:
>
>    byte[0] = SPI_recvByte();
>    buffer = (uint32_t)(byte[0] << 24);

Natürlich nicht wenn du so einen Müll produzierst.

So geht das

   buffer = ((uint32_t)byte[0] << 24);

Ich mach mich jetzt lieber mal vom Acker.

von amateur (Gast)


Lesenswert?

@DrGonzo

Wenn ich bei solch EINFACHEN Problemen nicht weiten komme, extrahiere 
ich die paar Zeilen, lege ein neues leeres Projekt an und füttere die 
Sequenz mit explizit definierten Daten.
Dann sehe ich was ich mache oder was der böse Compiler verbricht.

for (unit8_t i=0;i<3;i++) {
  //      ...00000000      | 0b????????
  Buffer = ( Buffer << 8 ) | Receive ();
}

oder so

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.