Forum: Mikrocontroller und Digitale Elektronik SPI Kommunikation mit STM32 und PST360G2


von Karlo (karlvonkiefer)


Angehängte Dateien:

Lesenswert?

Guten Tag zusammen,

das ist mein erster Beitrag und hoffe alle Regeln zu beachten.

Zu meinem Problem: ich bin neu in der STM Umgebung sowie der 
Programmierung.
Ich möchte nun einen Sensor (PST360G2-1S) mit dem STM32-L432KC auslesen.
Leider stoße ich an Probleme, die ich mir leider nicht erklären kann.

Im Anhang findet Ihr meinen Code sowie das Datenblatt zur Kommunikation 
des Sensors.

Eingestellt habe ich in der Cube folgendes:
- SPI Mode: Full-Duplex Master
- Hardware NSS Signal Disable
- Frame Format: Motorola
- Data Size: 8 Bits
- Prescaler: 2
- CPOL: Low
- CPHA: 1 Edge

Die ausgelesenen Werte seinen nicht zu stimmen.
Könnt Ihr mir dabei helfen dem Problem auf den Grund zu gehen?

Liebe Grüße

von Mi N. (msx)


Lesenswert?

Karlo schrieb:
> Die ausgelesenen Werte seinen nicht zu stimmen.

Ich kann da nichts Falsches dran sehen.

> Könnt Ihr mir dabei helfen dem Problem auf den Grund zu gehen?

Nimm ein Oszilloskope und sieh Dir die Signale an.

Ohne Oszilloskope definiere Dir ein paar Portpins passend für synchrone 
Übertragung und lass die Pins per Software 'wackeln'. Das kann ganz 
langsam passieren und mit LEDs kontrolliert werden.
Zu Cube kann ich nichts sagen, das ist mir zu kompliziert.

von Rolf (rolf22)


Lesenswert?

uint8_t data[10];

(data[2] << 8) ist ein uint8_t, der immer null ist. Oder?

: Bearbeitet durch User
von Karlo (karlvonkiefer)


Lesenswert?

Rolf schrieb:
> uint8_t data[10];
>
> (data[2] << 8) ist ein uint8_t, der immer null ist. Oder?

Wieso ist das immer null?

von Adam P. (adamap)


Lesenswert?

The DATA16 could be a valid angle, or an error condition. The two 
meanings are distinguished by the LSB.

Wäre vllt. nicht schlecht erstmal die unteren 2 Bits zu prüfen ob ein 
Fehler vorliegt.
1
if ((data[2] & 0x03) == 0x01)
2
{
3
    // alles OK
4
}
5
6
if ((data[2] & 0x03) == 0x02)
7
{
8
    // Error
9
}

Und was float betrifft, schreib es lieber so:
Nicht das er deine first14 Variable nicht als float betrachtet.
1
float value = (float)first14 / 16384.0f;
2
float angle = (value - 0.1f) / (0.9f - 0.1f) * 360.0f;

: Bearbeitet durch User
von Rolf (rolf22)


Lesenswert?

Karlo schrieb:

> Wieso ist das immer null?

Jede Operation liefert einen Wert eines bestimmten Typs.
xxx << n liefert einen Wert des Typs, den xxx hat.
Welchen Typ sollte man denn sonst nehmen?

Beispiel:
uint8_t xyz = 3;

In Bits geschrieben ist der Wert der Variablen 00000011.
Der Ausdruck (xyz << 7) hat den Typ uint_8 und den Wert 10000000. Ein 
Bit ist im Nirvana verschwunden.
Bei (xyz << 8) ist der Wert also immer 00000000.
Selbst wenn man nach dem Verschieben castet, ändert das nichts: Erst 
wird der Wert (= 00000000) ermittelt, dann wird der Cast ausgeführt:
(uint16_t) (xyz << 8) ist also 0000000000000000

Man muss also den Cast vor dem Verschieben ausführen, um einen 
16-Bit-Wert zu bekommen: ((((uint16_t)yxz)) << 8), das ergibt den 
gewünschten Wert 0000001100000000.
Ohne überflüssige Klammern (uint16_t)yxz << 8

: Bearbeitet durch User
von Adam P. (adamap)


Lesenswert?

Das ist ein 32bit Controller, sprich er führt die Operation in einem 
32bit Register durch. Da verschwindet gar nix.
Das funktioniert so seit Jahren.

von Rolf (rolf22)


Lesenswert?

Adam P. schrieb:
> Das ist ein 32bit Controller, sprich er führt die Operation in
> einem 32bit Register durch. Da verschwindet gar nix.

Das ist eine Frage der C-Semantik. Eine uint8_t-Variable hat nun mal aus 
Programmierersicht genau 8 Bit, und der Compiler muss entsprechend 
übersetzen.

von Adam P. (adamap)


Lesenswert?

Rolf schrieb:
> Das ist eine Frage der C-Semantik. Eine uint8_t-Variable hat nun mal aus
> Programmierersicht genau 8 Bit, und der Compiler muss entsprechend
> übersetzen.

Ja gebe dir ja Recht,
um es universell zu halt würde ich es wohl auch erst casten.
Sollte so aber auch funktionieren.

von Mi N. (msx)


Lesenswert?

Adam P. schrieb:
> Das funktioniert so seit Jahren.

Seit Jahren funktioniert hier auch, daß Leute aufschlagen, nur Fragen 
stellen, keine Details angeben und erwarten, ihre Probleme anhand 
zugeworfener Häppchen gelöst zu bekommen.
Es werden keine Zwischenwerte (Inhalt von data[]) angegeben, nur ein 
printf()-Wert erwähnt, der angeblich falsch sein soll, und dann 
irgendwann gemotzt, daß ihm nicht geholfen wird.

: Bearbeitet durch User
von Adam P. (adamap)


Lesenswert?

Mi N. schrieb:
> Seit Jahren funktioniert hier auch...

Muss ich dir leider Recht geben.

von Rahul D. (rahul)


Lesenswert?

Quellcode als txt-Datei? Ganz mein Humor.
Als könnten Foren (bösartigen) C-Quelltext compilieren und ausführen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf schrieb:
> Jede Operation liefert einen Wert eines bestimmten Typs.
> xxx << n liefert einen Wert des Typs, den xxx hat.

Das ist falsch.

Gegenbeispiel:
1
#include <stdio.h>
2
#include <stdint.h>
3
4
int main (void)
5
{
6
    uint8_t a = 1;
7
    uint8_t b = 8;
8
    uint16_t c;
9
10
    c = (a << 8) | b;
11
12
    printf ("%d\n", c);
13
}
1
cc a.c && ./a.out
2
264
Stichwort ist hier: Integer Promotion.

von Rolf (rolf22)


Lesenswert?

Frank M. schrieb:
> Stichwort ist hier: Integer Promotion.

Ok, da hast du Recht. Aber ich habe auch Recht. ;-)

Die Integer Promotion funktioniert –  entgegen der Aussage von Adam P. – 
nicht bis zu beliebig großen Datentypen. "Kleine" Typen werden nur bis 
zur Größe eines 'int' aufgeblasen:

https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion
if T is char8_t, (since C++20)char16_t, char32_t or (since 
C++11)wchar_t, val can be converted according to the rules specified in 
item (3);
otherwise, if the integer conversion rank of T is lower than the rank of 
int:
val can be converted to a prvalue of type int if int can represent all 
the values of T;
otherwise, val can be converted to a prvalue of type unsigned int.

Wenn der Prozessor größere Register hat, als es einem 'int' entspricht, 
dann verschwinden beim Links-Shift die weiteren Bits im Nirvana. Ggf. 
muss der Compiler eben einen Befehl zum Löschen einfügen:

https://en.cppreference.com/w/cpp/language/operator_arithmetic

The value of a << b is the unique value congruent to a * 2b
 modulo 2N
 where N is the number of bits in the return type (that is, bitwise left 
shift is performed and the bits that get shifted out of the destination 
type are discarded).

von Adam P. (adamap)


Lesenswert?

Rolf schrieb:
> Die Integer Promotion funktioniert –  entgegen der Aussage von Adam P. –
> nicht bis zu beliebig großen Datentypen. "Kleine" Typen werden nur bis
> zur Größe eines 'int' aufgeblasen:

Was anderes habe ich nie behauptet!
Kein Mensch redet hier von 64 oder 128bit variablen.

Wie dem auch sei, du hast Recht.
Katastrophe.

von Rolf (rolf22)


Lesenswert?

Adam P. schrieb:
>> Die Integer Promotion funktioniert –  entgegen der Aussage von Adam P. –
>> nicht bis zu beliebig großen Datentypen. "Kleine" Typen werden nur bis
>> zur Größe eines 'int' aufgeblasen:
>
> Was anderes habe ich nie behauptet!

Du hast gesagt, es würde bis auf die Registergröße von 32 Bit 
aufgeblasen. Ich glaube aber nicht, dass 'int' in diesem Fall 32 Bit 
hat, es wird 16 Bit haben. Oder?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf schrieb:
> Ich glaube aber nicht, dass 'int' in diesem Fall 32 Bit hat

Auf einem STM32 ist int auf jeden Fall 32 Bit.

von Nebo (Gast)


Lesenswert?

Rolf schrieb:
> Ok, da hast du Recht. Aber ich habe auch Recht. ;-)

Du bist genau der Diplomat, den die von Kriegen verletzte Welt braucht.

Respekt - also übernimm die Verantwortung und engagier Dich.

Genau hier und jetzt auf diesem Planeten, wo wir und unsere Kinder 
leben.

von Adam P. (adamap)


Lesenswert?

Rolf schrieb:
> Du hast gesagt, es würde bis auf die Registergröße von 32 Bit
> aufgeblasen. Ich glaube aber nicht, dass 'int' in diesem Fall 32 Bit
> hat, es wird 16 Bit haben. Oder?

Cortex-M4F

Läuft so seit Jahren:
1
static inline uint16_t u8u16(uint8_t *src)
2
{
3
  return ((src[1] << 8) | (src[0]));
4
}
5
6
static inline uint32_t u8u32(uint8_t *src)
7
{
8
  return ((src[3] << 24) | (src[2] << 16) | (src[1] << 8) | (src[0]));
9
}

von Karlo (karlvonkiefer)


Lesenswert?

Ich danke allen soweit für die Hilfe!
Ich werde mich heute wieder dem Programmieren widmen. Falls es 
Neuigkeiten gibt, melde ich mich.

von Mi N. (msx)


Lesenswert?

Karlo schrieb:
> Falls es
> Neuigkeiten gibt, melde ich mich.

Besser nicht.
Morgen ist Freitag und da schreitet ein neuer Gladiator in die Arena ;-)

von Karlo (karlvonkiefer)


Angehängte Dateien:

Lesenswert?

Hey zusammen und an die, die das in der Zukunft lesen werden.

Die Probleme, welche ich hatte, sind behoben und ich bekomme die 
richtigen Winkel auf dem STM32 L4 raus.

Einstellungen für STMCube:
- SPI Mode: Full-Duplex Master
- Hardware NSS Signal Disable
- Frame Format: Motorola
- Data Size: 8 Bits
- Prescaler: 256 (Das ist eine Notwendige Änderung)
- CPOL: Low
- CPHA: 2 Edge (Das ist eine Notwendige Änderung)


Ich hoffe das hilft jemandem in der Zukunft auch!

Ein Tipp von mir als Anfänger für weitere Anfänger: beschäftigt euch mit 
dem Datenblatt ausreichend, um wirklilch jeden einzelnen Schritt zu 
verstehen. Dann ist es leichter Fehler zu finden. Außerdem versteht die 
Commands, die Ihr benutzt und wie diese aufgebaut sind.

Also dann, danke an jede/n, der/die mir geholfen hat!

von Adam P. (adamap)


Lesenswert?

Karlo schrieb:
> Ein Tipp von mir als Anfänger für weitere Anfänger: beschäftigt euch mit
> dem Datenblatt ausreichend, ...

...und hängt Source Code als *.c oder *.cpp Datei an und nicht als *.txt

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.