Forum: Compiler & IDEs Zugriff auf einzelne Bytes in avrgcc


von Sam .. (sam1994)


Lesenswert?

Hi

Gibt es eine komfortable Möglichkeit auf einzelne Bytes in einem 
größerem Datentyp zuzugreifen?

Folgendes habe ich zuerst probiert (x ist als volatile uint32_t 
definiert, a als uint8_t).
1
x = (x & ~(uint32_t)0xFF) | a;

Hier wird jedoch das ganze Byte aus dem SRAM geladen wieder gespeichert.

Über Pointer (-Pfusch) funktioniert es, allerdings unschön, da es nur 
auf Littleendian-Systemen funktionieren würde:
1
uint8_t* ptr = &x;
2
*ptr = a;

Geht das schöner?

von Peter II (Gast)


Lesenswert?

Samuel K. schrieb:
> Geht das schöner?

wenn du schreibst eine stuktur dann ist es erstmal egal ob Littleendian 
oder big. Denn eine Struktur ist nie irgendwie ausgerichtet. Und damit 
ist deine zeiger lösung schon ok

uint8t_t r = ((uint8_t*)&x)[0...x];

Wenn es um eine zahl geht, dann geht es so

uint8t_t r = (x>>x)&0xff;

von Andreas B. (andreas_b77)


Lesenswert?

Samuel K. schrieb:
> x ist als volatile uint32_t definiert

> Hier wird jedoch das ganze Byte aus dem SRAM geladen wieder gespeichert.

Ich vermute, du meinst die ganzen 32 Bit von x. Aber x ist volatile, da 
bleibt dem Compiler so oder so keine andere Wahl.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Samuel K. schrieb:
> Hi
>
> Gibt es eine komfortable Möglichkeit auf einzelne Bytes in einem
> größerem Datentyp zuzugreifen?

Das hat alles nix mit avr-gcc zu tun.

Du kannst alles machen, was auch in C geht.

Was in C nicht geht, geht auch mit avr-gcc nicht.

von Tjaja (Gast)


Lesenswert?

Bei anderen uC gibts da teilweise intrinics dafür.
TI hat z.B. __byte(uint16* adr, uint16 pos);

Gibts sowas auch evtl. für die Controller von Atmel?

von Sam .. (sam1994)


Lesenswert?

Andreas B. schrieb:
> Ich vermute, du meinst die ganzen 32 Bit von x.

Ja ich meinte die 32bit.

Andreas B. schrieb:
> Aber x ist volatile, da
> bleibt dem Compiler so oder so keine andere Wahl.

Das volatile muss leider bleiben, da der Wert in einem Interrupt 
gebraucht wird, allerdings ist der Interrupt diesem Zugriff sicher 
ausgeschaltet. Aber das lässt sich dem Compiler wohl nicht mitteilen.

Johann L. schrieb:
> Das hat alles nix mit avr-gcc zu tun.
> Du kannst alles machen, was auch in C geht.
> Was in C nicht geht, geht auch mit avr-gcc nicht.

Naja, avrgcc bietet schon ein paar Funktionen, die z.B. auf einem PC 
recht sinnfrei wären. Und das Problem hier ist auch ziemlich spezifisch, 
da der Avr als 8-bit µC viele Instruktionen braucht, um irgendetwas mit 
einem uint32_t zu machen.

Ganz sauber finde ich die Pointerlösung nicht, aber wenn es nichts 
besseres gibt...

von Geri (Gast)


Lesenswert?

Hallo Samuel

Ich denke, dein avrgcc versteht auch folgende Anweisungen:
1
uint32_t Value = 0xAABBCCDD;
2
uint8_t Byte1;
3
4
Byte1 = (uint8_t)((Value >> 8) & 0x000000FF);

Beste Grüsse

Geri

von Florian P. (db1pf)


Lesenswert?

Hallo,

du könntest auch ein Union, bestehend aus einem uint_32 und einem char 
array, definieren. Dann kannst dann entweder auf die ganze Zahl oder auf 
jedes einzelne Byte der Zahl zugreifen.

Grüße,
Florian

von Andreas B. (andreas_b77)


Lesenswert?

Samuel K. schrieb:
> Das volatile muss leider bleiben, da der Wert in einem Interrupt
> gebraucht wird, allerdings ist der Interrupt diesem Zugriff sicher
> ausgeschaltet. Aber das lässt sich dem Compiler wohl nicht mitteilen.

Doch, man kann einen Zeiger auf die Variable auf einen Zeiger ohne 
volatile casten. Oder umgekehrt die Variable nur nach volatile casten 
wenn nötig. Oder statt volatile ein memory barrier Makro verwenden.

Ich hab es mal mit einem avr-gcc 4.5.3 ausprobiert und der würde 
trotzdem die ganzen 32 Bit laden. Bei der Und-Verknüpfung erkennt er, 
dass die 0xff Bytes keinen Einfluss haben, aber beim erweiterten uint8_t 
erkennt er nicht, dass alle oberen Bytes gleich 0 sind und führt alle 4 
or-Instruktionen aus.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Samuel K. schrieb:
> Johann L. schrieb:

>> Das hat alles nix mit avr-gcc zu tun.
>> Du kannst alles machen, was auch in C geht.
>> Was in C nicht geht, geht auch mit avr-gcc nicht.
>
> Naja, avrgcc bietet schon ein paar Funktionen, die z.B. auf einem PC
> recht sinnfrei wären. Und das Problem hier ist auch ziemlich spezifisch,
> da der Avr als 8-bit µC viele Instruktionen braucht, um irgendetwas mit
> einem uint32_t zu machen.

So ist das eben, wenn man 32-Bit Arithmetik auf einem 8-Bit auf einem 
8-Bit µC macht.

Und wenn das Ding volatile ist, muss es komplett geladen werden. Alles 
andere wäre ein Compilerbug.

> Ganz sauber finde ich die Pointerlösung nicht, aber wenn es nichts
> besseres gibt...

Das Thema wurde schon 100* durchgekaut.

Neben der fehlenden Portirebarkeit und Hack durch verkorksen der 
Poointer, ist ein weiteres Probleme die Verletzung der Aliasing-Regeln 
von C.

Wozu wird der Hack überhapt gebraucht?

Reine Kosmethik im erzeugten Code?
Oder gibt's wirklich ein Performance-Problem?

von Sam .. (sam1994)


Lesenswert?

Es lässt sich verkraften, da der Zugriff nicht alzuoft erfolgt. 
Allerdings war ich schon erstaunt wieviel Flash mich diese Zeile 
gekostet hat.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dürfte in die Richtung gehen von

http://gcc.gnu.org/PR27663
http://gcc.gnu.org/PR41076
1
#include <stdint.h>
2
3
uint32_t volatile x;
4
5
void insert_0 (uint8_t a)
6
{
7
    x = (x & ~0xFFUL) | a;
8
}
Mit aktuellem avr-gcc -S -Os übersetzt wird das zu
1
insert_0:
2
  lds r20,x
3
  lds r21,x+1
4
  lds r22,x+2
5
  lds r23,x+3
6
  clr r20
7
  or r20,r24
8
  sts x,r20
9
  sts x+1,r21
10
  sts x+2,r22
11
  sts x+3,r23
12
  ret
Hat 1 überflüssige Instruktion die noch optimierbar wäre.

Das "clr" ist ein 32-Bit AND und das "or" ein 8-Bit OR.

von Werner B. (werner-b)


Lesenswert?

Traumhaft genial optimiert würde rauskommen...
1
insert_0:
2
  sts x,r24
3
  ret

Halt, geht noch besser:
 Das Ganze inline ;-)

Träumen darf man dann noch von der neuen Programmiersprache
  "DWIM = Do What I Mean"

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Werner B. schrieb:
> Traumhaft genial optimiert würde rauskommen...
>
> insert_0:
>   sts x,r24
>   ret

Nö, der Code wäre falsch da nicht volatile-korrekt.

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.