32-Bit SPI Daten empfangen

Gast #3105675
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
}
Gast #3105694
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
Gast #3105696
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.
Gast #3105703
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.
Gast #3105709
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.
Gast #3105731
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
}
Gast #3105740
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.
Gast #3105751
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
Gast #3105778
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.
Gast #3105813
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren