Forum: Compiler & IDEs Union Problem


von Michael Wilhelm (Gast)


Lesenswert?

Hallo Forumsgemeinde,

folgendes System:
AVR Mega 64,
Schrittmotorsteuerung,

Der Schrittmotortreiber ist ein Trinamic mit SPI. Es wird ein 12 Bit 
Wert übergeben, der die Werte von Spule A und Spule B beinhaltet. Diese 
Werte stehen in einer Tabelle
IAR Compiler (jetzt bitte nicht die Augen rollen, es ist ein C-Problem)

struct
{
 unsigned int sollwert;
 unsigned int istwert;
 unsigned char richtung;
 ...
 unsigned int spulenwert;
 ...
} dimmer;

Folgende Konstruktion funktioniert:

dimmer.spulenwert = sinus_tab[dimmer.mikro_schritt];

cs_dimmer_low;
SPDR = dimmer.spulenwert >> 8; //Highbyte ausmaskieren u. senden
while (!(SPSR & (1 << SPIF)));

SPDR = (unsigned char) dimmer.spulenwert;  //Lowbyte senden
while (!(SPSR & (1 << SPIF)));
cs_dimmer_high;

folgendes aber nicht:

struct
{
 unsigned int sollwert;
 unsigned int istwert;
 unsigned char richtung;
 ...
 union
 {
  unsigned cvhar low_byte;
  unsigned char dimmer;
  unsigned int spulenwert;
 }
 motor;
 ...
} dimmer;


dimmer.motor.spulenwert = sinus_tab[dimmer.mikro_schritt];
cs_dimmer_low;   //Dimmer-CS einschalten
SPDR = dimmer.motor.high_byte;
while (!(SPSR & (1 << SPIF)));

SPDR = dimmer.motor.low_byte;
while (!(SPSR & (1 << SPIF)));
cs_dimmer_high;  //Dimmer-CS ausschalten

Das High und Lowbyte habe ich schon getauscht, aber das war der Fehler 
nicht. Der Motor läuft unsauber und ruckelig. Die Tabelle mit den 
Spulenwerten ist die gleiche.

Hat einer von euch eine Idee?

MW

von Karl heinz B. (kbucheg)


Lesenswert?

Hast du hier nicht einen Tippfehler gemacht?

>  union
>  {
>   unsigned cvhar low_byte;
>   unsigned char dimmer;
>   unsigned int spulenwert;
>  }
>  motor;

die union enthält kein high_byte.

Bitte mach immer ein Copy&Paste um Quelltext
zu posten. Sonst suchen wir uns die Hacken nach
Fehlern ab, die in deinem wirklichen Program gar
nicht vorhanden sind.

von Michael Wilhelm (Gast)


Lesenswert?

Richtig,sollte low und highbyte sein. Sorry.

MW

von Karl heinz B. (kbucheg)


Lesenswert?

Trotzdem. Ich rate mal:

Deine union sieht in Wirklichkeit so aus:

 union
 {
   unsigned char low_byte;
   unsigned char high_byte;
   unsigned int spulenwert;
 }
 motor;

Dann ist klar, dass das nicht gehen kann.
high_byte und low_byte teilen sich ein und
denselben Speicher. Dazu kommt dann noch
spulenwert, der auch noch drüber liegt.

Im Speicher spielt sich also folgendes ab:


     +---+---+
     |   |   |
     +---+---+

      ^
      hier liegt low_byte

      ^
      hier liegt high_byte

      ^     ^
      hier liegt spulenwert (2 Bytes)


Ansonsten bleibt nur noch das Problem der Endianess.
Abhängig vom Prozessor kann der int mit dem
High Byte oder mit dem Low Byte zuerst im Speicher
abeglegt sein. Es ist also Prozessorbahängig, welches
Byte vom int du tatsächlich über low_byte zu Gesicht
bekommst.


Du könntest folgendes machen:

  struct Bytes {
    unsigned char low;
    unsigned char high;
  }

  ...

  struct {
     ...
     union {
       struct Bytes bytes;
       unsigned int spulenwert;
     }
     motor;

  } dimer;

Der Zugriff wäre dann:

 dimmer.motor.spulenwert = ....

 SPDR = dimmer.motor.bytes.low

 SPDR = dimmer.motor.bytes.high

Jetzt muss nur noch der Compiler mitspielen:

  * Ob die Bytes tatsächlich in der Reihenfolge
    low / high im Speicher liegen

  * Ob der Compiler nicht zwischen Bytes.high und Bytes.low
    im Speicher noch sog. 'Padding Bytes' unterbringt.
    Kein Mensch zwingt den Compiler nämlich, dass struct
    Member im Speicher direkt aufeinanderfolgend sein müssen :-)



von Michael Wilhelm (Gast)


Lesenswert?

Danke Karl Heinz,
das war der entschidende Wink. So gehts:
  unsigned char speed;
  unsigned char richtung;
  union
  {
    unsigned int spulenwert;
    struct
    {
      unsigned char low_byte;
      unsigned char high_byte;
    }bytes;
  }motor;
}  dimmer;

  dimmer.motor.spulenwert = sinus_tab[dimmer.mikro_schritt];
      cs_dimmer_low;                    //Dimmer-CS einschalten
      SPDR = dimmer.motor.bytes.high_byte;
      while (!(SPSR & (1 << SPIF)));

      SPDR = dimmer.motor.bytes.low_byte;
      while (!(SPSR & (1 << SPIF)));
      cs_dimmer_high;             //Dimmer-CS ausschalten

Beim Copy und Paste ist die Formatierung nicht so dolle. Liegt aber an 
den Einstellungen meines Editors.

MW

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Michael Wilhelm wrote:

> Beim Copy und Paste ist die Formatierung nicht so dolle. Liegt aber an
> den Einstellungen meines Editors.
>
> MW

Hm, sorry, aber das sieht immer n och nicht nach C&P aus:
1
   unsigned char speed;
2
   unsigned char richtung;
3
   union
4
   {
5
     unsigned int spulenwert;
6
     struct
7
     {
8
       unsigned char low_byte;
9
       unsigned char high_byte;
10
     }bytes;
11
   }motor;
12
 }  dimmer;
13
 
14
   dimmer.motor.spulenwert = sinus_tab[dimmer.mikro_schritt];
15
       cs_dimmer_low;                    //Dimmer-CS einschalten
16
       SPDR = dimmer.motor.bytes.high_byte;
17
       while (!(SPSR & (1 << SPIF)));
18
 
19
       SPDR = dimmer.motor.bytes.low_byte;
20
       while (!(SPSR & (1 << SPIF)));
21
       cs_dimmer_high;             //Dimmer-CS ausschalten

...da ist ne Klammer zu viel.
Highlighting macht die Sache angenehmer zu lesen ;)

von Michael Wilhelm (Gast)


Lesenswert?

Na, den oberen Teil der Grundstruktur habe ich weggelassen. Ausserdem, 
im Editorfenster hier sieht es komplett anders aus als nachher im 
Thread.

MW

von Wolfram (Gast)


Lesenswert?

>Kein Mensch zwingt den Compiler nämlich, dass struct
>Member im Speicher direkt aufeinanderfolgend sein müssen :-)
doch zumindest beim gcc mit __attribute__((_packed_)) für die Struktur
bei anderen compilern meist mit irgendwelchen #pragma
Solange du beim AVR bleibst wirst du ueber padding bytes nicht stolpern, 
nur denk dran wenn du den Code wo anders verwnedest.

von Michael Wilhelm (Gast)


Lesenswert?

Gemäss meinem C-Buch dürfen keine Padding Bytes vom Compiler eingesetzt 
werden. Wenn doch, wäre die Union als solche nicht zu gebrauchen, 
jedenfalls nicht mit dem Merkmal, dass sich verschiedene Datentypen 
einen Speicherbereich teilen.

MW

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Eine union fuegt keine padding bytes ein, eine struct kann das aber
schon.  Die gewuenschte union war ja eine aus struct + int.

Allerdings duerfen selbst hier nur dann vom Compiler padding bytes
eingefuegt werden, wenn "unsigned char" groeßer als 8 bits waere
(was beim AVR nicht der Fall ist).  Abhilfe waere die Benutzung
von uint8_t (aus <stdint.h>), da es diesen Datentyp auf einer
Maschine einfach nicht gibt, die keine 8-Bit-Integers beherrscht.

von Karl H. (kbuchegg)


Lesenswert?

> Allerdings duerfen selbst hier nur dann vom Compiler padding bytes
> eingefuegt werden, wenn "unsigned char" groeßer als 8 bits waere
> (was beim AVR nicht der Fall ist).

Klar. Beim AVR kommt das nicht vor.
Bei anderen Prozessoren (ab 16 Bit) ist es aber durchaus
nicht ungewöhnlich, dass der Compiler zwischen 2 unsigned
char ( mit je 8 Bit) ein Padding Byte einfügt.
Wenn ich mich recht erinnere war es doch zb. bei einer 68000
so, dass Speicherzugriffe auf ungerade Adressen zu einer
Exception führt. Also hat der Compiler speziell unsigned
char so ausgerichtet, dass jeder der beiden auf jeweils
einer geraden Adresse zu liegen kommt.

Bei einer
struct xyz {
  unsigned char a;
  unsigned char b;
};

führt daher der Zugriff auf xyz.b ohne Padding Byte zu
einem kräftigen Penalty. Mit einem Padding Byte ist
der Zugriff aber 'straight forward'.


von Karl H. (kbuchegg)


Lesenswert?

> Wenn doch, wäre die Union als solche nicht zu gebrauchen,
> jedenfalls nicht mit dem Merkmal, dass sich verschiedene Datentypen
> einen Speicherbereich teilen.

Wenn wir ganz streng C programmieren, dann ist obige
Verwendung der union eigentlich gar nicht erlaubt. Na, ja
nicht erlaubt ist der falsche Ausdruck. Es ist undefiniert
was passiert. Laut C Standard darf man aus einer union
nur über denselben Member lesen über den der letzte Schreib-
zugriff erfolgt ist.
Damit ist aber das reinschreiben in einen int und das
rauslesen über 2 unsigned char schon im Bereich undefiniertes
Verhalten.
Klar: Ich weiss auch, dass das in der Praxis überall funktioniert.
Aber ganz streng genommen muss es das nicht.

von Michael Wilhelm (Gast)


Lesenswert?

So Leute,

noch einmal Dank an alle, die sich mit dem Problem befasst haben.

Simulation im AVR-Studio:

Version 1 mit der ganz normalen Struktur und dem "hinschieben" des 
INT-Wertes für die Motorausgabe: 92 Taktzyklen.

Version 2 mit der union 90 Taktzyklen.

Also, ich hatte mir mehr versprochen.

Aber, Erkenntnisse hat es trotzdem gbracht.

MW

von Stefan K. (_sk_)


Lesenswert?

D.h. Dir geht es um die Geschwindigkeit?

Die ist doch hauptsächlich durch das Warten auf den SPI gegeben.
Wenn Du etwas Zeit sparen willst, dann lade während der ersten Wartezeit 
den 2. Wert schonmal vor:
1
cs_dimmer_low;
2
SPDR = dimmer.spulenwert >> 8; //Highbyte ausmaskieren u. senden
3
local_spule_low = (unsigned char) dimmer.spulenwert;  //Lowbyte senden
4
while (!(SPSR & (1 << SPIF)));
5
6
SPDR = local_spule_low;
7
while (!(SPSR & (1 << SPIF)));
8
cs_dimmer_high;
Statt faul auf SPIF zu warten, kann der mc ruhig schonmal vorarbeiten 
...

Übrigens setzt gcc diesen Ausdruck meines Wissens nicht mit 8*Shiften 
um, sondern kopiert das High- ins Low-Byte:
1
SPDR = dimmer.spulenwert >> 8;
Einziger Unterschied zum Byte-Zugriff per union: es wird ein 16-Bit-Wert 
geladen und das High- ins Low-Byte kopiert, anstatt direkt das 
8-Bit-Lowbyte zu verwenden. Das kommt auch gut an Deine 2 Zyklen 
Unterschied hin.

Schau mal in den Assembler-Output.

Viele Grüße, Stefan

von Michael Wilhelm (Gast)


Lesenswert?

Gute Idee Stefan, obwohl die SPI mit 4MHz arbeitet, ist die Wartezeit 
lästig. Ich werde deine Idee aufgreifen und berichten.

MW

von Michael Wilhelm (Gast)


Lesenswert?

P.S.
Ich habe keine Ahnung von Assembler.

MW

von Stefan K. (_sk_)


Lesenswert?

Und Dein ATmega hat einen 16Mhz-Quarz? Dann wartest Du min. 64 Takte auf 
den SPI von den gemessenen 90.

>P.S.
>Ich habe keine Ahnung von Assembler.

Musst Du auch nicht. Schau einfach mal den Quellcode bei verschiedenen 
Programmversionen an. Ob z.B. irgendwo geshiftet wird, siehst Du auch 
ohne viel Assembler-Ahnung. Aber Du erhälst mit der Zeit ein Gefühl 
dafür, welcher C-Code aufwendigen und welcher Code effizienten Output 
erzeugt. Allein die Länge des Assembler-Outputs ist ein guter 
Anhaltspunkt.

Gruß, Stefan

von Michael Wilhelm (Gast)


Lesenswert?

Na ja, was ich im Studio simuliert und getestet habe, waren die 
Taktzyklen und nicht die Zeit. AVR-Studio löst die Stoppuhr ja nur mit 
0,5 µs auf und das ist bei taktgenauer Analyse doch etwas grob.
Ich kopiere mal den schnellsten C-code rein und das, was der Assembler 
macht. Du wirst staunen, wie der mit den X,Y und Z Registern am 
jonglieren ist.

Wenn du Lust hast, werf einen Blick drauf.

C-Code:
      dimmer.spulenwert = sinus_tab[dimmer.mikro_schritt];

      cs_dimmer_low;                        //Dimmer-CS einschalten
      SPDR = dimmer.spulenwert >> 8;         //Highbyte ausmaskieren u. 
senden
      while (!(SPSR & (1 << SPIF)));

      SPDR = (unsigned char) dimmer.spulenwert;  //Lowbyte senden
      while (!(SPSR & (1 << SPIF)));
      cs_dimmer_high;                   //Dimmer-CS ausschalten
      dimmer.daten_berechnet = 0;


Assembler-Code:

    402                dimmer.motor.spulenwert = 
sinus_tab[dimmer.mikro_schritt];
   \                     ??timer_3_over_isr_12:
   \                     ??timer_3_over_isr_11:
   \   000000F8   ....                       LDI     R30,LOW(sinus_tab)
   \   000000FA   ....                       LDI     R31,(sinus_tab) >> 
8
   \   000000FC   9696                       ADIW    R27 : R26,38
   \   000000FE   911C                       LD      R17,X
   \   00000100   9796                       SBIW    R27 : R26,38
   \   00000102   E002                       LDI     R16,2
   \   00000104   9F10                       MUL     R17,R16
   \   00000106   0DE0                       ADD     R30,R0
   \   00000108   1DF1                       ADC     R31,R1
   \   0000010A   9105                       LPM     R16,Z+
   \   0000010C   9114                       LPM     R17,Z
   \   0000010E   9699                       ADIW    R27 : R26,41
   \   00000110   930D                       ST      X+,R16
   \   00000112   931C                       ST      X,R17
   \   00000114   979A                       SBIW    R27 : R26,42
    403                cs_dimmer_low;                    //Dimmer-CS 
einschalten
   \   00000116   981F                       CBI     0x03,0x07
    404                SPDR = dimmer.motor.bytes.high_byte;
   \   00000118   969A                       ADIW    R27 : R26,42
   \   0000011A   910C                       LD      R16,X
   \   0000011C   979A                       SBIW    R27 : R26,42
   \   0000011E   B90F                       OUT     0x0F,R16
    405                while (!(SPSR & (1 << SPIF)));
   \                     ??timer_3_over_isr_13:
   \   00000120   9B77                       SBIS    0x0E,0x07
   \   00000122   CFFE                       RJMP 
??timer_3_over_isr_13
    406
    407                SPDR = dimmer.motor.bytes.low_byte;
   \   00000124   9699                       ADIW    R27 : R26,41
   \   00000126   910C                       LD      R16,X
   \   00000128   9799                       SBIW    R27 : R26,41
   \   0000012A   B90F                       OUT     0x0F,R16
    408                while (!(SPSR & (1 << SPIF)));
   \                     ??timer_3_over_isr_14:
   \   0000012C   9B77                       SBIS    0x0E,0x07
   \   0000012E   CFFE                       RJMP 
??timer_3_over_isr_14
    409                cs_dimmer_high;             //Dimmer-CS 
ausschalten
   \   00000130   9A1F                       SBI     0x03,0x07
    410                dimmer.daten_berechnet = 0;
   \   00000132   E000                       LDI     R16,0
   \   00000134   965F                       ADIW    R27 : R26,31
   \   00000136   930C                       ST      X,R16
   \   00000138   975F                       SBIW    R27 : R26,31

von Stefan K. (_sk_)


Lesenswert?

>Na ja, was ich im Studio simuliert und getestet habe, waren die
>Taktzyklen und nicht die Zeit. AVR-Studio löst die Stoppuhr ja nur mit
>0,5 µs auf und das ist bei taktgenauer Analyse doch etwas grob.

Ich habe wegen dem Teiler-Verhältnis für den SPI nach dem Takt gefragt, 
4 CPU-Takte -> ein SPI-Clock.

>Ich kopiere mal den schnellsten C-code rein und das, was der Assembler
>macht. Du wirst staunen, wie der mit den X,Y und Z Registern am
>jonglieren ist.

Der Code sieht doch garnicht so schlecht aus. Viel besser schafft man es 
auch von Hand nicht.

Viele Grüße, Stefan

von Karl heinz B. (kbucheg)


Lesenswert?

Die allerschnellste Variante geht nicht über ein union
sondern durch direkten Byte-Zugriff:

   int i;

davon wollen wir jetzt das low Byte:

   unsigned char low = *((unsigned char*)&i);

und das High Byte

   unsigned char high = *(((unsigned char*)&i)+1);

Also nichts mit vorher umkopieren oder dergleichen.
Man nimmt einfach die Adresse der Speicherstelle an
der der Wert gespeichert ist und teilt dem Compiler
mit, das mal als die Adresse eines Bytes aufzufassen und
das Byte zu holen. Dann dieselbe Adresse, wieder als
Adresse auf ein Byte umgecastet, 1 dazu (weil ja das nächste
Byte gefragt ist) und eben dieses Byte geholt.


Wenn du also den Spulenwert eigntlich überhaupt
nicht brauchst, dann probiere mal
1
   unsigned char* sinTab;
2
3
...
4
5
       cs_dimmer_low;                    //Dimmer-CS einschalten
6
7
       sinTab = ( unsigned char* )sinus_tab + dimmer.mikro_schritt;
8
9
       //
10
       // High Byte
11
       //
12
       SPDR = *( SinTab + 1 );
13
       while (!(SPSR & (1 << SPIF)));
14
 
15
       //
16
       // Low Byte
17
       //
18
       SPDR = * SinTab;
19
       while (!(SPSR & (1 << SPIF)));
20
21
       cs_dimmer_high;             //Dimmer-CS ausschalten

  

von Michael Wilhelm (Gast)


Lesenswert?

Karl Heinz, deine Lösung benötigt 118 Takte. Deine Idee mit der union 
ist um 28 Takte schneller.

Trotzdem danke für die Mühe.

MW

von Karl heinz B. (kbucheg)


Lesenswert?

> Karl Heinz, deine Lösung benötigt 118 Takte.

Ehrlich? (Ich habs nicht ausprobiert).
Das hätte ich nicht gedacht.

Welchen Code hast du konkret probiert.
Das interessiert mich jetzt, möchte in bischen
mit dem Compiler spielen. Die Vorgabe von 90
Takten steht ja.

von Karl heinz B. (kbucheg)


Lesenswert?

Also bei meinen Versuchen kommt mit einer
Optimierung von -Os bei der Pointervariante durchaus
was kürzeres heraus:
1
void foo()
2
{
3
       unsigned char* SinTab = ( unsigned char* )sinus_tab + dimmer.mikro_schritt;
4
  ca:  80 91 06 01   lds  r24, 0x0106
5
  ce:  e8 2f         mov  r30, r24
6
  d0:  ff 27         eor  r31, r31
7
  d2:  e0 50         subi  r30, 0x00  ; 0
8
  d4:  ff 4f         sbci  r31, 0xFF  ; 255
9
10
       //
11
       // High Byte
12
       //
13
       SPDR = *( SinTab + 1 );
14
  d6:  81 81         ldd  r24, Z+1  ; 0x01
15
  d8:  8f b9         out  0x0f, r24  ; 15
16
       while (!(SPSR & (1 << SPIF)));
17
  da:  77 9b         sbis  0x0e, 7  ; 14
18
  dc:  fe cf         rjmp  .-4        ; 0xda <foo+0x10>
19
 
20
       //
21
       // Low Byte
22
       //
23
       SPDR = * SinTab;
24
  de:  80 81         ld  r24, Z
25
  e0:  8f b9         out  0x0f, r24  ; 15
26
       while (!(SPSR & (1 << SPIF)));
27
  e2:  77 9b         sbis  0x0e, 7  ; 14
28
  e4:  fe cf         rjmp  .-4        ; 0xe2 <foo+0x18>
29
  e6:  08 95         ret
30
31
000000e8 <main>:
32
33
}

Vor allem die Zuweisungen an SPDR kriegt man nicht mehr
kürzer hin.

Die Variante über die union ist deutlich länger (und komplizierter).
Bedingt durch das rel. komplizierte Holen des Wertes in
den Zwischenspeicher der union.
1
void foo()
2
{
3
  dimmer.motor.spulenwert = sinus_tab[dimmer.mikro_schritt];
4
  ca:  80 91 06 01   lds  r24, 0x0106
5
  ce:  e8 2f         mov  r30, r24
6
  d0:  ff 27         eor  r31, r31
7
  d2:  ee 0f         add  r30, r30
8
  d4:  ff 1f         adc  r31, r31
9
  d6:  e0 50         subi  r30, 0x00  ; 0
10
  d8:  ff 4f         sbci  r31, 0xFF  ; 255
11
  da:  80 81         ld  r24, Z
12
  dc:  91 81         ldd  r25, Z+1  ; 0x01
13
  de:  90 93 08 01   sts  0x0108, r25
14
  e2:  80 93 07 01   sts  0x0107, r24
15
16
  SPDR = dimmer.motor.bytes.high_byte;
17
  e6:  80 91 08 01   lds  r24, 0x0108
18
  ea:  8f b9         out  0x0f, r24  ; 15
19
  while (!(SPSR & (1 << SPIF)));
20
  ec:  77 9b         sbis  0x0e, 7  ; 14
21
  ee:  fe cf         rjmp  .-4        ; 0xec <foo+0x22>
22
23
  SPDR = dimmer.motor.bytes.low_byte;
24
  f0:  80 91 07 01   lds  r24, 0x0107
25
  f4:  8f b9         out  0x0f, r24  ; 15
26
  while (!(SPSR & (1 << SPIF)));
27
  f6:  77 9b         sbis  0x0e, 7  ; 14
28
  f8:  fe cf         rjmp  .-4        ; 0xf6 <foo+0x2c>
29
  fa:  08 95         ret
30
31
000000fc <main>:
32
}

von Stefan K. (_sk_)


Lesenswert?

@Karlheinz,

die Sinustabelle scheint im Flash zu liegen. Michael benutzt den 
IAR-Compiler, nicht den gcc, deswegen sind seine Ergebnisse nicht ganz 
vergleichbar.

Gruß, Stefan

von FBI (Gast)


Lesenswert?

@Karlheinz,

die Pointer Variante ist nicht immer die günstigste, da das immer übers 
Ram abgewickelt wird. Besser ist meist ein direkter Cast auf eine Union, 
den kann der Compiler dann unter Umständen direkt über Register 
optimieren.

z.B. so:
1
typedef union {
2
   uint16_t w;
3
   struct {
4
     uint8_t h,l;
5
   };
6
} uint16_t_u;
7
8
uint16_t i;
9
10
unsigned char low = ((uint16_t_u)i).l;
11
unsigned char high = ((uint16_t_u)i).h;

siehe auch folgenden Thrread: Beitrag "GCC inline assembler"

CU Frank

von Michael Wilhelm (Gast)


Lesenswert?

So meine Struktur:

[c]
volatile struct
{
  unsigned int soll_wert;
  unsigned int ist_wert;
  unsigned char analog_wert;
  unsigned char vorteiler;
  unsigned char dmx_wert;
  unsigned char tabellen_wert;
  unsigned char vorhanden;
  unsigned char daten_berechnet;
  unsigned int differenz;
  unsigned char ziel_erreicht;
  unsigned char modus;
  unsigned char zaehler;
  unsigned char warte_zaehler;
  unsigned char mikro_schritt;
  unsigned int spulenwert;
  unsigned char speed;
  unsigned char richtung;
  unsigned char * zeiger;
/*  union
  {
    unsigned int spulenwert;
    struct
    {
      unsigned char low_byte;
      unsigned char high_byte;
    }bytes;
  }motor;*/
}  dimmer;

[/]

und die Motorausgabe:
[c]

      dimmer.zeiger = (unsigned char *)sinus_tab[dimmer.mikro_schritt];
      cs_dimmer_low;                    //Dimmer-CS einschalten
      SPDR = *(dimmer.zeiger + 1);

      while (!(SPSR & (1 << SPIF)));

      SPDR = * dimmer.zeiger;

      while (!(SPSR & (1 << SPIF)));
      cs_dimmer_high;             //Dimmer-CS ausschalten

      dimmer.daten_berechnet = 0;
[/]

Die Takte im Simulator habe ich gemessen von dimmer.zeiger = (unsigned 
char *)sinus... bis dimmer.daten_berechnet = 0;

Und das ergibt 118 Takte. Auch wenn ich den Zeiger global und ausserhalb 
der Struktur definiere, sind es 118 Takte. Bei Interesse kann ich das 
Ass-Listing mal posten.

MW

von Karl H. (kbuchegg)


Lesenswert?

> Michael benutzt den IAR-Compiler, nicht den gcc,

Ah, ok. Das habe ich verpennt.

> die Pointer Variante ist nicht immer die günstigste, da das immer
> übers Ram abgewickelt wird. Besser ist meist ein direkter Cast auf
> eine Union, den kann der Compiler dann unter Umständen direkt über
> Register optimieren.

Netter kleiner Trick. Muss ich mir merken.
Danke

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.