Forum: Mikrocontroller und Digitale Elektronik Programmierung SPI Kommunikation Befehlsworterstellung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Anonymous U. (gastt)


Bewertung
0 lesenswert
nicht lesenswert
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?
static void Set_Reference_Counter(uint32_t cntr_val_14b){
    const uint32_t ctrl_bits = 0b00;
    cntr_val_14b &= 0x00003FFF;
    const uint32_t anti_backlash_width = 0b00;
    const uint32_t test_mode = 0b00;
    const uint32_t lock_detect_prec = 0b0;

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

    HAL_GPIO_WritePin(SPI3_CS_PLL_CLK_GPIO_Port, SPI3_CS_PLL_CLK_Pin, GPIO_PIN_SET);
    HAL_SPI_Transmit(&hspi3, (uint8_t*) &data, 3, 100);
    HAL_GPIO_WritePin(SPI3_CS_PLL_CLK_GPIO_Port, SPI3_CS_PLL_CLK_Pin, GPIO_PIN_RESET);
}

von Jim M. (turboj)


Bewertung
0 lesenswert
nicht lesenswert
Mach die Bitschieberei für concat gleich als 3 einzelne Bytes.

von Anonymous U. (gastt)


Bewertung
0 lesenswert
nicht lesenswert
Habe ich überlegt. Allerdings kann ich halt bei der 32 Bit Variable den 
Shiftamount direkt aus dem Datenblatt rauslesen. Wenn ich es einzeln 
mach, dann muss ich wieder selber rumrechnen.

von Niklas G. (erlkoenig) Benutzerseite


Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
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:
#include <uSer/uSer.hh>

struct Command1 {
    USER_STRUCT (Command1, uSer::AttrNone)
    
    USER_MEM(std::uint8_t, ctrl_bits, uSer::Width<2>)
    USER_MEM(std::uint16_t, cntr_val_14b, uSer::Width<14>)
    USER_MEM(std::uint8_t, anti_backlash_width, uSer::Width<2>)
    USER_MEM(std::uint8_t, test_mode, uSer::Width<2>)
    USER_MEM(std::uint8_t, lock_detect_prec, uSer::Width<4>)

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

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

    cmd.ctrl_bits = 0b00;
    cmd.cntr_val_14b = cntr_val_14b;
    cmd.anti_backlash_width = 0b00;
    cmd.test_mode = 0b00;
    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:
    uint32_t concat [1];
    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:
    uint8_t data [3];
    uSer::serialize<uSer::Width<24>, uSer::ByteOrder::BE> (data, concat);
}

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

von Anonymous U. (gastt)


Bewertung
0 lesenswert
nicht lesenswert
Oh, Danke :-) Sowas ist auf jeden Fall schön beim Programmieren. 
Allerdings wird hier der Compiler nicht viel optimieren können?

von Niklas G. (erlkoenig) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Anonymous U. schrieb:
> Allerdings wird hier der Compiler nicht viel optimieren können?

Doch, das wird praktisch völlig wegoptimiert. Da sollte im Endeffekt das 
gleiche rauskommen wie bei dem originalen Code. Das kann man ggf. im 
generierten Assembler-Code überprüfen. Siehe auch:
https://erlkoenig90.github.io/uSer-doc/html/tutorial.html#Minimize

von Anonymous U. (gastt)


Bewertung
0 lesenswert
nicht lesenswert
Haha, des wollt ich hören. Dann muss ich selber nicht im Code 
nachfielseln :-D Ne, Spaß beiseite, vielen Dank des werd ich mal 
ausprobiern.

von Maxim B. (max182)


Bewertung
0 lesenswert
nicht lesenswert
Anonymous U. schrieb:
> Dieser hat ein 24 Bit langen
> Befehl.

Warum benutzt du dann uint32_t? In GCC gibt es auch __uint24

von Niklas Gürtler (Gast)


Bewertung
1 lesenswert
nicht lesenswert
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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.