www.mikrocontroller.net

Forum: GCC Zugriff auf einzelne Bytes in avrgcc


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Sam .. (sam1994)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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).
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?

Autor: Peter II (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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;

Autor: Andreas B. (andreas_b77)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Tjaja (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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?

Autor: Sam .. (sam1994)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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...

Autor: Geri (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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

Autor: Florian Pfanner (db1pf)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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

Autor: Andreas B. (andreas_b77)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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?

Autor: Sam .. (sam1994)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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.

Autor: Werner B. (werner-b)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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"

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net