Datum:
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).
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:
uint8_t* ptr = &x; *ptr = a; |
Geht das schöner?
Datum:
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;
Datum:
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.
Datum:
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.
Datum:
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?
Datum:
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...
Datum:
Hallo Samuel Ich denke, dein avrgcc versteht auch folgende Anweisungen:
uint32_t Value = 0xAABBCCDD; uint8_t Byte1; Byte1 = (uint8_t)((Value >> 8) & 0x000000FF); |
Beste Grüsse Geri
Datum:
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
Datum:
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.
Datum:
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?
Datum:
Es lässt sich verkraften, da der Zugriff nicht alzuoft erfolgt. Allerdings war ich schon erstaunt wieviel Flash mich diese Zeile gekostet hat.
Datum:
Dürfte in die Richtung gehen von http://gcc.gnu.org/PR27663 http://gcc.gnu.org/PR41076
#include <stdint.h> uint32_t volatile x; void insert_0 (uint8_t a) { x = (x & ~0xFFUL) | a; } |
Mit aktuellem avr-gcc -S -Os übersetzt wird das zu
insert_0: lds r20,x lds r21,x+1 lds r22,x+2 lds r23,x+3 clr r20 or r20,r24 sts x,r20 sts x+1,r21 sts x+2,r22 sts x+3,r23 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.
Datum:
Traumhaft genial optimiert würde rauskommen...
insert_0:
sts x,r24
ret
|
Halt, geht noch besser: Das Ganze inline ;-) Träumen darf man dann noch von der neuen Programmiersprache "DWIM = Do What I Mean"
Datum:
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.