Forum: Mikrocontroller und Digitale Elektronik Alignment des ARM7


von Nils (Gast)


Lesenswert?

Hallo zusammen,

ich bin gerade bei meiner Bachelor Arbeit und muss eine bestehende 
Software auf einem Keil Board zum laufen bringen (fürs erste). 
Funktioniert auch alles bisher ganz gut. Das Board ist ein MCB2140 
(LPC2148) von Keil und Bestandteil des hitex StarterKits.

Jetzt ist es so, dass ich in dem Programm ( C ) auf dem Controller von 
einer Funktion ein Struct zurückbekommen sollte. Bekomm ich aber nicht, 
sondern nur den ersten Teil dieses structs. Das aber nur so nebenbei.

Mein Chef meinte, das alles liegt am alignement des Prozessors. Habe 
mich jetzt auch ein wenig eingelsen, was alignement angeht und weiss 
jetzt schonmal was das ist :)

Jetzt muss ich rausfinden wie das alignment auf dem Stack ist und mit 
dem vergleichen, für den dieses Programm urspürnglich geschrieben wurde. 
Weiss vielleicht jemand wie das bei dem ARM7 Prozessor ist?

Grüße
Nils

von antworter (Gast)


Lesenswert?

Bitte mehr Infos:

Welcher Compiler, welche Optimierung (-O), relevante 
Quelltextausschnitte, Testläufe

von Nils (Gast)


Lesenswert?

Sorry, leider bin ich ganz neu im C Geschäfft, aber ich versuche mal so 
viel ich weiss zu beantworten. Da fällt mir aber gerade auf, dass ich 
nur den Compiler kenne: arm-hitex-elf-gcc.

Vielleicht würde es mir schon helfen, wenn jemand weiss, wie das 
alignment des LPC2148 ist, dann kann ich weiter googlen.

von Nils (Gast)


Lesenswert?

OK jetzt hab ich was:

typedef struct
{
  UInt  uiLength;    /* Current length of flex string */
  Char  charData[8]; /* Content of string */
} FlexString8;

typedef struct
{
  FlexString8  Name;
  FlexString4  Version;
} DeviceIdent_Struct;

USInt usiOffset1 = offsetof ( DeviceIdent_Struct, Version ); // 0x0C
USInt usiOffset2 = offsetof ( FlexString8, charData ); // 0x02
USInt usiOffset3 = sizeof(FlexString8); // 0x0C
USInt usiOffset4 = sizeof(UInt); // 0x02
USInt usiOffset5 = sizeof(Char); // 0x01
USInt usiOffset6 = sizeof(Char[8]); // 0x08

Nur weiss ich jetzt zb.B. leider nicht, wie die sizeOf( FlexString) 
zustande kommt. Eigentlich müsste die doch 10 sein und nicht 12. Liegt 
das am Alignment des Controllers?

Unter welchen Umständen schmeisst der mir noch 2 "Füllbytes" in die 
Länge mit rein?

Grü0e Nils

von let (Gast)


Lesenswert?

Der Compiler macht da wohl ein Word-Alignment. In dem Fall ist die
Lücke zwischen uiLength und charData.

Versuche es doch mal damit:

typedef struct
{
  UInt  uiLength;    /* Current length of flex string */
  Char  charData[8]; /* Content of string */
} __attribute__((packed)) FlexString8;

Wobei ich nicht weiß inwieweit der Arm7 das unterstützt.
Der Zugriff auf Daten im Speicher ist bei manchen Prozessoren
schneller wenn diese (Daten) an Wortgrenzen ausgerichtet sind.

 - Michael

von gerhard (Gast)


Lesenswert?

hallo nils,
ja der arm benötigt ein alignment, abhängig von der größe der variable 
auf die er zugreifen soll.
16 bit variable (im arm jargon "half word") müssen auf durch 2 teilbare 
adressen beginnen.
32 bit variable (im arm jargon "word") müssen auf durch 4 teilbare 
adressen beginnen.
dies weiss der compiler natürlich und füllt deine struktuiren 
entsprechend auf. kritisch istr bei manchen compilern aber der sizeof 
operatir da dieser ev. die füll-bytes nicht berücksichtigt.
ich würde dir empfehlen das auffüllen selbst zu machen und die 
strukturen entsprechend zu definieren.

gruss
gerhard

von Nils (Gast)


Lesenswert?

Schonmal vielen Dank,

das _attribute_ ((packed)) hat leider nicht geholfen, die Länge meines 
FlexStrings ist immer noch 12.

#pragma pack(1)

hab ich auch versuch, ging auch nicht.

Aber wo packt der denn seine Füllbytes bei dem FlexString rein?

Wenn

USInt usiOffset2 = offsetof ( FlexString8, charData );

gleich 2 ist, dann müsste er sie doch hinter die charData einbauen oder?



von let (Gast)


Lesenswert?

Stümmt, darauf habe ich nicht geachtet. Das 'packed' bringt
dann so oder so nichts.
Vom Padding am Ende einer Struktur habe ich noch nie gehört.

Ich habe seit zwei Tagen ein 2148 Board. Der UART geht inzwischen,
sodaß ich das mal mit meiner GCC Version (4.1.1) probieren kann.

Geht aber erst heute Abend.

 - Michael

von Martin Thomas (Gast)


Lesenswert?

Möglicherweise hilft das packed-attribute schon - aber nur teilweise. 
Wenn recht erinnert, wird vom gnu C-Compiler dann auch das 
character-array "unmittelbar" hinter dem Längen-Integer angeordnet aber 
am Ende wieder auf "grade" Wordadresse aufgefüllt. #pragma pack dürfte 
das Gleiche auslösen (ich habe pragmas bei gcc noch nie genutzt). In der 
"untersten Ebene" für Flexstring würde attribute packed dann hilfreich 
sein, aber eine Ebene drüber bei DeviceIdent nicht mehr. Das Ganze 
entspricht ja den bisherigen Erkenntnissen. Lässt sich aber auch gut 
testen, in dem man einen uint8_t* auf die Startadresse eines Objekts der 
Struktur zeigen lässt ("casten") und dann Byte für Byte ausgibt 
"cout(*p++)" (oder per Debugger anschaut), dann Elemente ändern und 
wieder Bytestream anschauen. Der tatsächliche Offset wird dann gut 
erkennbar.

Aber diese Art der Zugriffs auf Elemente ist nicht wirklich gut, 
insbesondere wenn aligments zur Optimierung des Speicherzugriffs im 
Spiel sind. Man läd sich - wie schon gemerkt - neue Sorgen auf. Besser 
wäre es Code zu schreiben, der die einzelnen Elemente eines Objekts aus 
der Struktur in ein Bytearray schreibt, bzw. aus einem Bytearray den 
Inhalt für die Elemente ausliest (Serializer/Deserializer). Vielleicht 
etwas langsamer aber dafür problemloser.

von Dirk D. (dirkd)


Lesenswert?

Bist Du eigentlich sicher, daß UInt 2 Bytes groß ist? Ein unsigned int 
sollte auf einem ARM eigentlich 32 Bit groß sein.

Was genau ist UInt bei dir?

Um einigermaßen portabel zu sein könnte man auch die Typen

uint8_t, uint16_t und uint32_t aus

stdint.h verwenden.


Zum Thema Attribute
http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Type-Attributes.html#Type-Attributes

von Frank G. (pancho)


Lesenswert?

Zumal es idR weder aus Speicherverbrauchs- noch aus Performance-Sicht 
dienlich ist, auf einem ARM Integers mit weniger als 32 bit zu 
verwenden.
Alternative: Das Uint an das Ende der Struktur, falls es wirklich nur 
zwei Bytes hat.

von let (Gast)


Lesenswert?

So, ich habe mal den GNUARM Compiler v4.1.1 angeworfen:

typedef struct {
  char a;         // 1 Byte
  int  b;         // 4 Bytes
  short c;        // 2 Bytes
  char str[8];  // 8 Bytes
} testObj;

Ergebnis:

sizeof(testObj) = 20
offsetof(a)     = 0
offsetof(b)     = 4
offsetof(c)     = 8
offsetof(str)   = 10

Und:

typedef struct {
  char a;         // 1 Byte
  int  b;         // 4 Bytes
  short c;        // 2 Bytes
  char str[8];  // 8 Bytes
} __attribute__((packed)) testObj;

mit dem Ergebnis:

sizeof(testObj) = 15
offsetof(a)     = 0
offsetof(b)     = 1
offsetof(c)     = 5
offsetof(str)   = 7

Der ARM7 ist also offenbar nicht auf ein Alignment angewiesen, auch
wenn es schneller sein mag.
Wo die zwei Bytes am Ende der "von Nils'schen" Struktur herkommen
kann ich mir nicht erklären.

Da 'UInt' anscheinend nur zwei Bytes groß ist, handelt es sich bei der
Struktur wohl um eine Schnittstelle für Daten die von Außen angeliefert
werden. Stimmts ? ;)

 - Michael

von A.K. (Gast)


Lesenswert?

Der ARM7 ist sehr wohl auf Alignment angewiesen. Ein 32bit-Load mit A0:1 
!=0 wird zwar nicht auf die Nase fallen, aber auch nicht das tun, was 
man davon vielleicht erwartet.

Nur erzeugt der Compiler in solchen Fällen Code, der auch ohne Alignment 
auskommt. Bei Bitfields geht es ja auch.

von let (Gast)


Lesenswert?

^ Ich dachte mir schon das meine Aussage etwas voreilig war und habe
mir mal die .lst-Datei angesehen. Der Compiler schiebt die Daten in
der Tat passend zurecht.

Der GCC beeindruckt mich immer wieder. Ich mußte die Codeoptimierung
abschalten damit auch tatsächlich auf 'obj' zugegriffen wird.
Sonst hat der Compiler für rprintf() einfach die Konstanten eingesetzt:
1
typedef struct {
2
  char a;
3
  char b;
4
  char c;
5
  short size;
6
} __attribute__((packed)) stype;
7
8
    obj.a = 1;
9
    obj.b = 2;
10
    obj.c = 3;
11
    obj.size = sizeof(stype);
12
    
13
    rprintf("a=%u, b=%u, c=%u, size=%u\n", obj.a, obj.b, obj.c, obj.size);

 - Michael

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.