Programmierung SPI Kommunikation Befehlsworterstellung

OP #6321615
Ich würde gerne meinen Code zur Diskussion stellen. Es handelt sich um 
die Ansteuerung eines Chips per SPI. Dieser hat ein 24 Bit langen 
Befehl. Die ganzen Bits, die mit const definiert werden, ändern sich 
nicht. Zur besseren Lesbarkeit sind sie aber extra aufgeführt. Dann wird 
das 24 Bit breite Wort in der concat Variable zusammengeführt. Soweit so 
gut, dass sollte der Compiler wegoptimieren können. Allerdings kann ich 
wegen der falschen Anordnung (Endianess) der Bytes in der concat 
variable diese nicht direkt an die SPI Funktion übergeben. Das heißt ich 
muss sie erst umsortieren. Wie macht man das besser?
1
static void Set_Reference_Counter(uint32_t cntr_val_14b){
2
    const uint32_t ctrl_bits = 0b00;
3
    cntr_val_14b &= 0x00003FFF;
4
    const uint32_t anti_backlash_width = 0b00;
5
    const uint32_t test_mode = 0b00;
6
    const uint32_t lock_detect_prec = 0b0;
7

8
    uint32_t concat = (lock_detect_prec<<20) | (test_mode<<18) | (anti_backlash_width<<16) | (cntr_val_14b<<2) | ctrl_bits;
9
    uint8_t data[3];
10
    data[0] = *((uint8_t*) &concat + 2);
11
    data[1] = *((uint8_t*) &concat + 1);
12
    data[2] = *((uint8_t*) &concat + 0);
13

14
    HAL_GPIO_WritePin(SPI3_CS_PLL_CLK_GPIO_Port, SPI3_CS_PLL_CLK_Pin, GPIO_PIN_SET);
15
    HAL_SPI_Transmit(&hspi3, (uint8_t*) &data, 3, 100);
16
    HAL_GPIO_WritePin(SPI3_CS_PLL_CLK_GPIO_Port, SPI3_CS_PLL_CLK_Pin, GPIO_PIN_RESET);
17
}
Persönliche Seite
Anonymous U. schrieb:
> data[0] = *((uint8_t*) &concat + 2);
>     data[1] = *((uint8_t*) &concat + 1);
>     data[2] = *((uint8_t*) &concat + 0);

Das in einen "char"-Typ umcasten und dereferenzieren ist zwar erlaubt, 
aber plattform-abhängig. Ok, der Code ist eh STM32-spezifisch.


Anonymous U. schrieb:
> HAL_SPI_Transmit(&hspi3, (uint8_t*) &data, 3, 100);

Der Cast ist unnötig, du kannst einfach "data" schreiben.

Zur Frage: Das ist ein Fall für Serialisierung. Mit meiner 
µSer-Bibliothek kann man solche Fälle vereinfachen. Zuerst definiert man 
sich ein struct mit den entsprechenden Einträgen und deren Längen in 
Bits:
1
#include <uSer/uSer.hh>
2

3
struct Command1 {
4
    USER_STRUCT (Command1, uSer::AttrNone)
5
    
6
    USER_MEM(std::uint8_t, ctrl_bits, uSer::Width<2>)
7
    USER_MEM(std::uint16_t, cntr_val_14b, uSer::Width<14>)
8
    USER_MEM(std::uint8_t, anti_backlash_width, uSer::Width<2>)
9
    USER_MEM(std::uint8_t, test_mode, uSer::Width<2>)
10
    USER_MEM(std::uint8_t, lock_detect_prec, uSer::Width<4>)
11

12
    USER_ENUM_MEM (ctrl_bits, cntr_val_14b, anti_backlash_width, test_mode, lock_detect_prec)
13
};

Dann schreibt man die gewünschten Werte direkt hinein:
1
static void Set_Reference_Counter (uint32_t cntr_val_14b){
2
    Command1 cmd;
3

4
    cmd.ctrl_bits = 0b00;
5
    cmd.cntr_val_14b = cntr_val_14b;
6
    cmd.anti_backlash_width = 0b00;
7
    cmd.test_mode = 0b00;
8
    cmd.lock_detect_prec = 0b0;

Dann lässt man sie in einen Integer zusammenpacken. Die Berechnung der 
Shifts geschieht dabei automatisch, sodass man nicht selbst rechnen 
muss:
1
    uint32_t concat [1];
2
    uSer::serialize (concat, cmd);

Zum Schluss wandelt man diesen Integer in ein Byte-Array um und gibt 
dabei die "Big Endian" Reihenfolge an, sodass die Bytes umgekehrt 
abgelegt werden:
1
    uint8_t data [3];
2
    uSer::serialize<uSer::Width<24>, uSer::ByteOrder::BE> (data, concat);
3
}

Das "data" Array kann dann wie zuvor ausgegeben werden. Das ganze ist 
dann 100% portabel und funktioniert auf jeder Prozessor-Architektur.

Die Bibliothek: https://github.com/Erlkoenig90/uSer
Angehängte Dateien:
Gast
Maxim B. schrieb:
> Warum benutzt du dann uint32_t? In GCC gibt es auch __uint24

Das bringt bei Cortex-M nichts, weil der 32bit-int am Effizientesten 
verarbeiten kann. Da der Wert ohnehin temporär ist, spielt der 
Speicherverbrauch auch keine Rolle.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.