Unaligned Access beim Raspberry Pi

Ich habe eine kleine Microcontrollerschaltung mit einem STM32, welche Daten über UART an einen Raspberry PI überträgt. Die Daten sind in einem kleinen Protokoll verpackt, welches auf TLV (Tag Length Value) beruht und über CRC gesichert ist. Darüber werden sowohl char (1 byte) als auch integer und float übertragen (4 Bytes). Dabei wird ein Integer oder Float aus 4 Byte (INT1-4) gebildet. Es sieht dann so aus:

| Tag | Length | Byte   | CRC
| Tag | Length | Byte   | Byte   | Byte   | Byte | CRC
| Tag | Length | INT1   | INT2   | INT3   | INT4 | CRC 
| Tag | Length | FLOAT1 | FLOAT2 | FLOAT3 | FLOAT4 | CRC

Entwickelt habe ich es allerdings am PC in C++. Dort klappt die Wandlung des Streams zurück in ein INT/Float über einen Cast:

char *data;
...
reinterpret_cast<float>(data)
reinterpret_cast<float>(data + 4)

Am PC stellt der Cast kein Problem dar, auch wenn die Adresse nicht ein vielfaches von 4 ist (alignment). Am Raspberry PI allerdings kann der ARM Prozessor den Zugriff nur auf aligned Adressen machen und nicht auf Addressen die ungerade sind (0 = OK / 1,2,3 NOK). Ein X86 Prozessor schafft dies allerdings ist er dabei ein wenig langsamer, was aber kein Problem in diesem Kontext darstellt. Der ARM bricht mit Segmentation Fault ab, da er einen Busfehler feststellt (übrigens genau wie der STM32).

Um das handhaben zu können und das allgemeine Protoll nicht ändern zu müssen, kann man sich mit folgendem Konstrukt behelfen:

float ptr2float(char *ptr)
{
  union p2f
  {
    unsigned char c[4];
     float f;
  } tmp;

  tmp.c[0] = ptr[0];
  tmp.c[1] = ptr[1];
  tmp.c[2] = ptr[2];
  tmp.c[3] = ptr[3];

  return tmp.f;
}

Damit ist der Code portabel und funktioniert auch auf anderen Architekturen. Einen abgewandelten Code verwende ich auch auf dem Embedded Board mit einem STM32. Dabei kann man gleich auch die Konvertierung von little zu big endian machen oder umgekehrt. Ein strcpy oder memmove wäre auch möglich, allerdings ist  der Code meist länger, da man gewisse Dinge abfangen muss und auch das strcopy intern das Alignment beachten muss, was mehr Laufzeit kostet (hierzu sei der GCC Code von strcpy und strncpy empfohlen).

Leave a comment

Your comment