Forum: Mikrocontroller und Digitale Elektronik C: Speicherzugriff


von Master S. (snowman)


Lesenswert?

Hallo

Ich stehe auf dem Schlauch, warum es das eine Mal funktioniert und das 
andere Mal nicht. Ich habe einen PIC32 mit XC32 und ICD3 zum debuggen.

Definiert habe ich folgendes (hintendran, die Adressen während des 
Debuggens)
1
struct {
2
    LightElement Light[NumberOfLightElements];  // Adr. 0xA00003E0
3
    unsigned char Dimming[6];                   // Adr. 0xA0000440
4
    unsigned char WaterChange[6];               // Adr. 0xA0000446
5
    unsigned char DummFill_1[20];               // Adr. 0xA000044C
6
    unsigned char DummFill_2[4*32];             // Adr. 0xA0000460
7
} Settings0;
8
9
unsigned char SpecLightDummy[6];                // Adr. 0xA0000290

Da der PIC32 32bit-Befehle ausführen kann, möchte ich folgendes machen, 
was auch funktioniert (die 6 Dimming-Variablen werden auf die 6 
SpecLightDummy-Variablen kopiert):
1
*(unsigned long *)&SpecLightDummy[0] = *(unsigned long *)&Settings0.Dimming[0];
2
*(unsigned int *)&SpecLightDummy[4] = *(unsigned int *)&Settings0.Dimming[4];

jedoch hier hängt sich der uC auf:
1
*(unsigned long *)&SpecLightDummy[0] = *(unsigned long *)&Settings0.WaterChange[0];
2
*(unsigned int *)&SpecLightDummy[4] = *(unsigned int *)&Settings0.WaterChange[4];

die Frage ist, wieso hängt sich der uC dort auf?

Ich habe schon Copy/Paste gemacht und dann ".Dimming" durch 
".WaterChange" ersetzt, jedoch führt das zum selben Problem. Ein 
Tipfehler ist somit ausgeschlossen.

Danke für jegliche hilfe.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Master Snowman schrieb:
> Da der PIC32 32bit-Befehle ausführen kann, möchte ich folgendes machen

Was Du eigentlich machen willst, hängt davon ab, was das Programm tun 
soll. Also was die Anforderungen sind. Wie man diese dann umsetzt, steht 
auf einem anderen Blatt. Es gibt ziemlich sicher einen besseren Weg, das 
zu erreichen was Du willst - ohne wildes Rumgecaste.

von memcpy (Gast)


Lesenswert?

Mark Brandis schrieb:
> Es gibt ziemlich sicher einen besseren Weg, das
> zu erreichen was Du willst - ohne wildes Rumgecaste.

memcpy

von B. S. (bestucki)


Lesenswert?

XC32 User guide, Seite 140:
unsigned int hat eine Grösse von 32Bits. Wenn, dann müsstest du unsigned 
short verwenden (16Bits). Ich würde aber solche Hacks grundsätzlich sein 
lassen und die Arrays in einer for Schleife oder mit memcpy kopieren. 
Denn woher willst du wissen, wie gross ein int auf einer anderen 
Plattform ist?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Master Snowman (snowman)

>Definiert habe ich folgendes (hintendran, die Adressen während des
>Debuggens)

Da geht das Problem schon los. Als C-Programmierer haben dich die 
expliziten Adressen keine Sekunde zu interessieren. Die verwaltet der 
Compiler!

>Da der PIC32 32bit-Befehle ausführen kann, möchte ich folgendes machen,
>was auch funktioniert (die 6 Dimming-Variablen werden auf die 6
>SpecLightDummy-Variablen kopiert):

>*(unsigned long *)&SpecLightDummy[0] = *(unsigned long >*)&Settings0.Dimming[0];
>*(unsigned int *)&SpecLightDummy[4] = *(unsigned int >*)&Settings0.Dimming[4];

Solche Monster-Cast sind ein sicheres Zeichen für Murks.
Was zum Geier spricht gegene eine GANZ NORMALE Zuweisung?
1
SpecLightDummy[0] = Settings0.Dimming[0];

Denkst du der Compiler is zu doof, das halbwegs gescheit auszuführen?
ASM-Denkweise beim C-Programmieren ist nicht sinnvoll. Das geht nur in 
gaaanz wenigen Situationen gut. Und meist auch nicht nötig und sinnvoll!

Selbst eine Schleife für mehrere Elemente setzt jeder zurechnungsfähige 
Compiler gut um, einfach über zwei Pointer.
1
for (i=0; i<6; i++) {
2
  SpecLightDummy[i] = Settings0.Dimming[i];
3
}

Und das ist in 99,99% aller Fälle schnell genug. Hochoptimierten 
Assembler braucht man da nicht. Und wenn DOCH, dann nimmt man WIRKLICH 
Assembler und keine vergewaltigten C-Konstrukte! Oder man nimmt DMA.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

One PIC zu kennen -- viele 32-Bit Architekturen verlangen, daß 
Speicherzugriffe entsprechend aligned sind, d.h. 32-Bit-Zugriffe sind 
nure erlaubt, wenn die Speicherstelle an einer 32-Bit Grenze liegt.

Jedoch greifst du auf .WaterChange, das nicht auf einer 32-Bit-Grenze 
liegt, durch den Cast 32-bittig drauf zu.

Lass das Gehampel mit den Cast-Schweinereien und verwende wie oben 
empfohlen memcpy.

von Luther B. (luther-blissett)


Lesenswert?

Bei PIC32 müssen IIRC Zugriffe aligned sein, d.h. du kannst ein 4 Byte 
long nicht aus einer Adresse lesen, die nicht 4 byte aligned ist. Wenn 
ab Dimming[0] noch ein long gelesen werden kann, dann scheitert dass 
natürlich an WaterChange[0], dass 6 bytes weiter liegt.

Ausserdem solltest du mal nachgucken, was bei deinem Compiler 
sizeof(int) ist. Du scheinst von 2 ausgehen, was bei PIC32 auch nicht 
der Fall ist, oder?

Die Felder kopierst du überhaupt besser mit memcpy(). Das ist beim PIC32 
Compiler (der auf GCC basiert) ein intrinsic, d.h. der Compiler "weiss" 
was memcpy bedeutet und kann optimalen code generieren.

von Master S. (snowman)


Lesenswert?

wow! vielen dank für die vielen beiträge. das mit dem aligned habe ich 
noch nie gehört, macht aber logischerweise sinn - danke!

> Solche Monster-Cast sind ein sicheres Zeichen für Murks.
> Was zum Geier spricht gegene eine GANZ NORMALE Zuweisung?
> SpecLightDummy[0] = Settings0.Dimming[0];
weil dann nur das erste element kopiert wird ;-)

dass in einer for-schlaufe das byte-weise kopieren auch geht, ist mir 
klar; jedoch wieso das in 6 schritten machen plus 6 bedingungsabfragen, 
wenn's auch in 2 zuweisungen geht? daher dieser ansatz.

ich gebe zu, das ist natürlich murks aus jetztiger sicht nachdem ich das 
oben gelesen habe. ich verwende jetzt memcpy, braucht sogar noch etwas 
weniger platz als mein hack mit pointer :-)

vielen dank nochmals, auch für die superschnellen antworten!

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Luther Blissett schrieb:
> Bei PIC32 müssen IIRC Zugriffe aligned sein, d.h. du kannst ein 4 Byte
> long nicht aus einer Adresse lesen, die nicht 4 byte aligned ist. Wenn
> ab Dimming[0] noch ein long gelesen werden kann, dann scheitert dass
> natürlich an WaterChange[0], dass 6 bytes weiter liegt.

Dieser Einwand ist nicht stichhaltig, denn wenn es harte Alignment- 
forderungen geben sollte, dann würde der Compiler die struct-member 
ohnehin alignen.

Tatsächlich sind diese Forderungen aber meist gar nicht hart, schon gar 
nicht in einer Hochsprache. Im Zweifel werden halt einfach mehr Daten 
gelesen bzw. geschrieben (ein write wird dann ein read-modify-write). 
Das ist zwar sicherlich suboptimal, aber nicht unmöglich.

> Die Felder kopierst du überhaupt besser mit memcpy()

Das sowieso.


XL

von Axel S. (a-za-z0-9)


Lesenswert?

Master Snowman schrieb:
> dass in einer for-schlaufe das byte-weise kopieren auch geht, ist mir
> klar; jedoch wieso das in 6 schritten machen plus 6 bedingungsabfragen,
> wenn's auch in 2 zuweisungen geht?

Woher willst du denn wissen, wie das der Compiler umsetzt?

Du machst dich gerade der so ziemlich größten Sünde schuldig, die es für 
einen Programmierer gibt: premature optimization. Du optimierst(?) 
Dinge, für die weder klar ist ob sie a) optimierungswürdig noch b) 
optimierungsbedürftig sind.

Die erste Priorität bei der Programmierung in einer Hochsprache sollte 
die einfache Verständlichkeit (vulgo: Lesbarkeit, Wartbarkeit) des Codes 
sein. Ein richtiger Programmierer hätte vermutlich die Größen der Arrays 
in ein #define gepackt und würde sich evtl. später darüber freuen, daß 
er das jetzt an einer einzigen Stelle ändern kann. Vergleiche das mal 
mit den Klimmzügen, die deine "Lösung" erfordert, wenn die Arrays mal 9 
statt 6 Elemente haben sollten.


XL

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.