Forum: Compiler & IDEs Source von pgm_read_byte


von Lorenz (Gast)


Lesenswert?

Hallo Zusammen

Ich möchte einen String aus dem FlashRom eines AVR (ATemga32) ins Ram 
kopieren. Das ist genau das, was pgm_read_byte aus der avr-libc macht. 
Nur verwende ich diese Library nicht und schreibe daher eine eigene.

Jetzt bin ich auf der Suche nach source der Funktion pgm_read_byte. Wo 
krieg ich diese? Sie kann auch in Assembler sein.

Vielen Dank für eure Hilfe!
Gruss
Lorenz

von Karl H. (kbuchegg)


Lesenswert?


von peter (Gast)


Lesenswert?

@Karl: FLASH, nicht EEPROM

@Lorenz:
Wenn Du den AVR-GCC Compiler verwendest, dann werfe mal einen Blick in 
die Dokumentation bzw Library Referenc zur avr-libc. In der Beschreibung 
zu <avr/pgmspace.h>: "Program Space String Utilities" findest Du Makros 
wie zum Beispiel: pgm_read_byte(address_short)

MfG  Peter

von Ronny (Gast)


Lesenswert?

Im Grunde hat man immer 2 Möglichkeiten:

1.Man vertraut darauf das die Lib vernünftig arbeitet und kann damit 
leben das es keine 100%ig Massgeschneiderte Lösung ist.Dann benutzt man 
sie.

2.Man will wissen was unter der Haube passiert oder kann aus irgendeinem 
Grund nicht mit der Lib leben (zuviel unbenötigte Features,zu gross,zu 
langsam,etc)


Da es hier allerdings nicht um ein gewachsenes Stück Software in dem 
viele Mann-Stunden Arbeit stecken handelt,reicht ein Blick ins 
Datenblatt.Dieser offenbart,zumindest bei Controllern die selbigen 
Unterstützen,dass der Assembler-Befehl LPM (Load Program Memory) das 
zusammengesetzte Register Z (R31:R30) als Zeiger in den Programmspeicher 
benutzt und das entsprechende Byte in das Register R0 laden 
kann.Weiterhin würde man erfahren,ob der verwendete Controller eventuell 
auch flexiblere addressierungsmöglichkeiten besitzt,das der Flash 
wort-weise organisiert ist und welche Bedingungen erfüllt werden 
müssen,um mit SPM auch Daten ins Flash schreiben zu können.Von den 
unterschiedlichen Addressräumen für SRAM,EEPROM und Flash mal 
abgesehen...

von Karl H. (kbuchegg)


Lesenswert?

peter wrote:
> @Karl: FLASH, nicht EEPROM
>

Wie bin ich bloss auf EEPROM gekommen.
Egal. Auf derselben Seite finden sich auch die
Flash Routinen. Er wird ja hoffentlich doch so
intelligent sein und ein bischen rumscrollen.

von Oliver (Gast)


Lesenswert?

G O O G L E

Und welchen Compiler willst du verwenden?


Oliver

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


Lesenswert?

Oliver wrote:

> G O O G L E

Unsinn.  Einfach den Sourcecode des avr-libc-Projektes nehmen.
Allerdings dürfte im Falle von pgm_read_byte() wirklich alles
bereits im Headerfile <avr/pgmspace.h> stehen.

> Und welchen Compiler willst du verwenden?

Diese Frage erübrigt sich in diesem Forum. ;-)

von Oliver (Gast)


Lesenswert?

Lorenz fragt:

"...was pgm_read_byte aus der avr-libc macht...Jetzt bin ich auf der 
Suche nach source der Funktion pgm_read_byte. Wo krieg ich diese?"

Antwort 1: "G O O G L E"
Antwort 2: "Einfach den Sourcecode des avr-libc-Projektes nehmen."

ROTFL

Oliver
P.S. Das nächste mal gibt es immer ganz viele :-) :-) :-) dazu

von Rahul, der Trollige (Gast)


Lesenswert?

>"...was pgm_read_byte aus der avr-libc macht...Jetzt bin ich auf der
>Suche nach source der Funktion pgm_read_byte. Wo krieg ich diese?"

>Antwort 1: "G O O G L E"
>Antwort 2: "Einfach den Sourcecode des avr-libc-Projektes nehmen."

... oder bei OBI...

von Lorenz (Gast)


Lesenswert?

Vielen Dank für eure ausführlichen Antworten

@Ronny: Ich bin der Typ, welcher 2. bevorzugt und verwende daher die 
avr-libc nicht.

Zudem muss ich gestehen, dass ich praktisch nichts von Assembler 
verstehe. Ich wurde natürlich schon einige Male damit konfrontiert doch 
ein eigenes Programm habe ich noch nie in Assembler geschrieben.
Seit ich Software für uC schraube benutze ich den AVR-GCC-Compiler (dies 
sollte in diesem Forum eigentlich wirklich klar sein :)).
Daher fürchte ich mich davor aus dem Datenblatt selber diese Funktion zu 
implementieren.

Also einfach den Source-Code der avr-libc zu verwenden dachte ich auch 
schon. Das Haederfile rpmspace.h fand ich. Nur fand ich dann nirgens ein 
C-File wo diese Funktion implementiert war. Und ganz allgemein finde ich 
mich in dieser Library überhaut nicht zurück (dutzende Ordner die alle 
AVR heissen und ineinander stecken etc.).

Und noch zu GOOGLE. In diesem Fall bin ich einfach zu blöd zum googlen. 
Denn ich habe die source nicht gefunden. Zurzeit findet man unter 
"pgm_read_byte +source" an erster Stelle diese Topic :)

Danke für eure Hilfe!
Lorenz

von Falk (Gast)


Lesenswert?

@Lorenz

>@Ronny: Ich bin der Typ, welcher 2. bevorzugt und verwende daher die
>avr-libc nicht.

Was schon mal nicht sehr sinnvoll ist . . .

>Daher fürchte ich mich davor aus dem Datenblatt selber diese Funktion zu
>implementieren.

. . . nicht nur aus diesem Grund.

>Also einfach den Source-Code der avr-libc zu verwenden dachte ich auch
>schon. Das Haederfile rpmspace.h fand ich. Nur fand ich dann nirgens ein
>C-File wo diese Funktion implementiert war. Und ganz allgemein finde ich

Wozu auch. Binde das header-File ein und benutzt die Funktion gemäss 
Doku der avr-libc und alles läuft. Wo ist das Problem? Vor allem mit 
deinen nichtvorhanden Assemblerkentnissen wirst du keine bessere Lösung 
als die in der avr-libc hinbekommen.

MfG
Falk

P.S. Man muss das Rad nicht neu erfinden.

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


Lesenswert?

> Nur fand ich dann nirgens ein
> C-File wo diese Funktion implementiert war

Das gibt es nicht.  Wie ich schon weiter oben schrob, ist sie komplett
im Headerfile implementiert.

Am einfachsten ist das, wenn du dir ein Stück C-Programm schreibst:
1
#include <avr/pgmspace.h>
2
3
int
4
foo(void)
5
{
6
  unsigned char bar = pgm_read_byte((void *)42);
7
  return bar;
8
}
...und das durch den C-Präprozessor schickst:
1
$ avr-gcc -E foo.c
Das hier kommt dabei raus:
1
...
2
int
3
foo(void)
4
{
5
  unsigned char bar = (__extension__({ uint16_t __addr16 = (uint16_t)((uint16_t)((void *)42)); uint8_t __result; __asm__ ( "lpm" "\n\t" "mov %0, r0" "\n\t" : "=r" (__result) : "z" (__addr16) : "r0" ); __result; }));
6
  return bar;
7
}
Das ist die Implementierung.
Fühlst du dich jetzt schlauer? :-)

OK, dann compilieren wir es einfach mal richtig:
1
avr-gcc -mmcu=atmega8 -S -Os foo.c
Hier das Ergebnis:
1
        .file   "foo.c"
2
        .arch atmega8
3
__SREG__ = 0x3f
4
__SP_H__ = 0x3e
5
__SP_L__ = 0x3d
6
__tmp_reg__ = 0
7
__zero_reg__ = 1
8
        .global __do_copy_data
9
        .global __do_clear_bss
10
        .text
11
.global foo
12
        .type   foo, @function
13
foo:
14
/* prologue: frame size=0 */
15
/* prologue end (size=0) */
16
        ldi r30,lo8(42)
17
        ldi r31,hi8(42)
18
/* #APP */
19
        lpm r30, Z
20
21
/* #NOAPP */
22
        mov r24,r30
23
        clr r25
24
/* epilogue: frame size=0 */
25
        ret
26
/* epilogue end (size=1) */
27
/* function foo size 9 (8) */
28
        .size   foo, .-foo
29
/* File "foo.c": code    9 = 0x0009 (   8), prologues   0, epilogues   1 */

  

von Lorenz (Gast)


Lesenswert?

@Falk: Dass man das Rad nicht neu erfinden muss ist schon richtig. Als 
ich jedoch (vor ca. 2 Jahren) mit der Programmierung vor AVRs begonnen 
habe habe ich mich zuerst entschieden die Programme in C zu schreiben, 
da ich schon einiges auf Java geschrieben habe. Auf das Lernen von 
Assembler habe ich zuerst einmal verzichtet. Das schien mir zu 
aufwendig.
Die avr-libc war für mich dann anfangs eine riesige Black-Box. Ich 
wollte nicht verstehen, wie der avr-gcc funktioniert, denn das werde ich 
wohl in meinem Leben nie, doch ich wollte verstehen, was ich ihm 
füttere. Daher habe ich das io.h File mehr oder weniger kopiert und 
sonst noch ein paar Sachen herauskopiert (für die Interrupts etc.) und 
damit begonnen zu programmieren. Ich hatte dann also eine Library, 
welche anfangs nur wenige Hundert Zeilen umfasst. Nun habe meine io.h 
Files schon relativ stark modifiziert (zB. verstehe ich nicht, wieso 
dort *#define PA7 7* drinn steht, denn PA7 ist doch länger zum tippen 
als 7, nicht?).
Zudem arbeite ich mit anderen Typen-Bezeichnern: byte, int8, word, 
int16, dword, int32 etc. Ich weiss dass dies eigentlich nur unpraktisch 
ist, doch bis jetzt hatte ich noch keine Lust dies zu ändern.

@Jörg: Vielen Dank für deine geniale Hilfe. Ich habe bis jetzt nicht 
verstanden, dass pgm_read_byte eine reine Präprozessor Angelegenheit 
ist. Ich habe mir die entsprechende Zeile nun in meine Library kopiert 
und es funktioniert perfekt.
Vielleicht hört man sich ja einmal auf der QRG...

Gruss Lorenz

von Karl H. (kbuchegg)


Lesenswert?

> Zudem muss ich gestehen, dass ich praktisch nichts von Assembler
> verstehe.

Dann solltest du dich mit der Library anfreunden.
So schwer ist das nicht.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29


Alles andere ist vertrödelte Zeit.

von Falk (Gast)


Lesenswert?

@Lorenz

>da ich schon einiges auf Java geschrieben habe. Auf das Lernen von
>Assembler habe ich zuerst einmal verzichtet. Das schien mir zu
>aufwendig.

Ist erstmal OK.

>Die avr-libc war für mich dann anfangs eine riesige Black-Box. Ich

Das soll sie auch sein. Dich (und vor allem MICH) interessiert nicht WIE 
eine Funktion im Inneren aufgebaut ist, sondern wie ich sie nutzen kann.

>wollte nicht verstehen, wie der avr-gcc funktioniert, denn das werde ich
>wohl in meinem Leben nie, doch ich wollte verstehen, was ich ihm
>füttere.

Ja eben.

>Daher habe ich das io.h File mehr oder weniger kopiert und
>sonst noch ein paar Sachen herauskopiert (für die Interrupts etc.) und
>damit begonnen zu programmieren. Ich hatte dann also eine Library,

DAS ist aber genau NICHT der Weg, eine Bibliothek zu nutzen. Und du bist 
sicher, dass du grundlegende Dinge beim Programmieren verstanden hast?
Ich fürchte nein.

>welche anfangs nur wenige Hundert Zeilen umfasst. Nun habe meine io.h
>Files schon relativ stark modifiziert (zB. verstehe ich nicht, wieso
>dort *#define PA7 7* drinn steht, denn PA7 ist doch länger zum tippen
>als 7, nicht?).

Du hast nicht! :-(

Weil PA7 intuitiv verstanden wird (PortA, Bit 7) während 7 alles und 
nichts bedeuten kann.
Du solltest DRINGEND mal ein Buch zum Thema Stuckturierter 
Softwareentwurf lesen. Dir fehlen wichtige Grundlagen.

>Zudem arbeite ich mit anderen Typen-Bezeichnern: byte, int8, word,
>int16, dword, int32 etc. Ich weiss dass dies eigentlich nur unpraktisch
>ist, doch bis jetzt hatte ich noch keine Lust dies zu ändern.

Starrköpiger Einzelkämpfer? Schon mal was von Standardisierung gehört? 
Und welche Vorteile sie bringt?

MfG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Sicher.

Man kann sich auch zur Drehbank stellen und sich seine
M4 Schrauben selber drehen, einen schönen Sechskant drauffeilen
und ein Gewinde schneiden.

Man kann aber auch in den nächsten Baumarkt gehen und sich
für wenig Geld eine Handvoll M4 Schrauben kaufen.

Was hat man gelernt, wenn man seine Schrauben selber fertigt?
Im Grunde .... gar nichts.
Man hat nur sinnlos ein paar Stunden an der Drehbank gestanden.

von Ralf R. (voltax)


Lesenswert?

Jörg Wunsch wrote:

> ... Wie ich schon weiter oben schrob, ...

sagt man da nicht "schrub" ?-)

nichternstgemeint
Ralf

von Lorenz (Gast)


Lesenswert?

Ou, das wird ja immer schwieriger meinen Standpunkt zu vertreten.

Ich muss gestehen, ich habe noch nie in einem Team Software entwickelt.
Und in einigen Punkt hast du, Falk, sicher recht. Eigene 
Typen-Bezeichnungen zu verwenden ist absolut sinnlos. Doch als ich 
angefangen habe mit dem avr-gcc zu arbeiten wurde es mir schnell zu 
blöde signed char zu schreiben. Daher habe ich mir einfach einen eigenen 
Typ definiert. Das nun int8_t vielleicht schlauer ist, ist mir jetzt 
auch klar. Nur ist die Wahrscheinlichkeit, dass ich zu dieser Zeit genau 
auf die selbe Idee gekomemen wäre schon ziemlich gering. Daher ist halt 
int8 draus geworden. Ich sollte dies einmal ändern, ja, nur hatte ich 
bis jetzt noch nie den Mumm dazu.

Dann noch was zu PA7.
Ob ich jetzt "sbi(DDRA,PA7);" oder "sbi(DDRA,7)" schreibe spielt für 
mich vom Verständnis der Source eigentlich keine Rolle. Daher nehme ich 
das Zweite, weil es kürzer ist.

>Das soll sie auch sein. Dich (und vor allem MICH) interessiert nicht WIE
>eine Funktion im Inneren aufgebaut ist, sondern wie ich sie nutzen kann.
Das stimmt bezogen auf mich zumindest am Anfang nicht. Ich hatte das 
Datenblatt, dort stand in Worten drinn, wie die Hardware des AVRs zu 
bedienen ist. Ich war nun einfach neugierig zu sehen, wie man dies 
Implementieren kann. Ich habe einen USART Treiber, eine sehr 
ausführliche I2C Bibliotheck (mit Fifo-Buffern beim Senden und Empfagen 
für alle 4 Modis geschrieben) eine eigene Library für LCD-Display. Klar 
wäre ich schneller gewesen, wenn ich einfach eine fertige Library 
verwendet hätte, doch dann hätte ich nie so viel gelernt. Wenn du daran 
intressiert bist den Drehbank bedienen zu lernen ist es unter umständen 
schon sinnvoll eine M4-Schraube selber herzustellen. Hey, ich 
programmiere diese Kontroller als Hobby und nicht weil ich möglichst 
effizient etwas erreichen möchte.

>Starrköpiger Einzelkämpfer? Schon mal was von Standardisierung gehört?
>Und welche Vorteile sie bringt?

Vermutlich schon ja, denn ich bin auf die Standardisierung nicht 
angewiesen, da ich nun mal bis jetzt alleine Arbeite. Der Punkt wo ich 
mich an Normen halten werde wird bald kommen, die Vorteile kenne ich.

von Karl H. (kbuchegg)


Lesenswert?

Lorenz wrote:

> Ich muss gestehen, ich habe noch nie in einem Team Software entwickelt.

Das hat nichts mit Team zu tun.
Das hat eher was damit zu tun sein Werkzeug zu kennen. Werkzeug
ist in diesem Fall die Programmiersprache UND die zugehörigen
Bibliotheken.
Beides sind integraler Bestandteile, das eine macht ohne
das andere wenig Sinn.
Wenn du Schwierigkeiten mit der eigentlich überschaubaren
Standardlibrary und mit den noch viel überschaubareren
AVR-Erweiterungen hast, dann warte erst mal, bis du auf
einem Desktop System mit einer grafischen Oberfläche
programmierst. Da geht ohne die Verwendung von Bibliotheken
gar nichts mehr. Und da sind es dann plötzlich 300 oder 400
Funktionen die man so einigermassen im Kopf haben soll und
nicht 30 wie hier.

> Und in einigen Punkt hast du, Falk, sicher recht. Eigene
> Typen-Bezeichnungen zu verwenden ist absolut sinnlos. Doch als ich
> angefangen habe mit dem avr-gcc zu arbeiten wurde es mir schnell zu
> blöde signed char zu schreiben. Daher habe ich mir einfach einen eigenen
> Typ definiert. Das nun int8_t vielleicht schlauer ist, ist mir jetzt
> auch klar. Nur ist die Wahrscheinlichkeit, dass ich zu dieser Zeit genau
> auf die selbe Idee gekomemen wäre schon ziemlich gering. Daher ist halt
> int8 draus geworden. Ich sollte dies einmal ändern, ja, nur hatte ich
> bis jetzt noch nie den Mumm dazu.

Ach was. Machs einfach. Ich hab nach 20 Jahren noch mal umgelernt.
Der springende Punkt ist:
Wenn du nur für dich im eigenen Keller arbeitest, ist es piep-
schnurz-egal. In dem Moment, in dem aber die Welt da draussen
auf der Bildfläche auftaucht, kann es nur von Vorteil sein,
wenn eine gemeinsame Sprache gesprochen wird. Dadurch ist
gewährleistet, dass alle dasselbe meinen wenn ein bestimmter
Begriff fällt.

>
> Dann noch was zu PA7.
> Ob ich jetzt "sbi(DDRA,PA7);" oder "sbi(DDRA,7)" schreibe spielt für
> mich vom Verständnis der Source eigentlich keine Rolle. Daher nehme ich
> das Zweite, weil es kürzer ist.

Du sollst sbi überhaupt nicht mehr verwenden.

   DDRA |= ( 1 << PA7 );

Kürzer ist nicht unbedingt besser.

>
>>Das soll sie auch sein. Dich (und vor allem MICH) interessiert nicht WIE
>>eine Funktion im Inneren aufgebaut ist, sondern wie ich sie nutzen kann.
> Das stimmt bezogen auf mich zumindest am Anfang nicht. Ich hatte das
> Datenblatt, dort stand in Worten drinn, wie die Hardware des AVRs zu
> bedienen ist.

Ich bin beeindruckt. Ohne Scheiss. Endlich mal jemand der
sich das Datenblatt reinzieht.

> Ich war nun einfach neugierig zu sehen, wie man dies
> Implementieren kann.

Dagegen ist auch nichts einzuwenden.

> Ich habe einen USART Treiber, eine sehr
> ausführliche I2C Bibliotheck (mit Fifo-Buffern beim Senden und Empfagen
> für alle 4 Modis geschrieben) eine eigene Library für LCD-Display.

Moment.
Das ist schon eine ganz andere Kategorie.
Sozusagen ein ganz anderer Level auf dem eine Library
aufsetzt.

Die Library um die es geht (die Zugriffe auf das Flash
ermöglicht) ist Bestandteil vom WinAVR. Das heist: die kriegst
du, weil du WinAVR benutzt. Die ist also automatisch Bestandteil
deines Werkzeugkastens.
Es gibt absolut keinen Grund die nicht zu benutzen.
Da mal reinzuschauen, wie es gemacht wird, ist ok.
Das heist aber nicht, das es schlau ist, danach nicht einfach
"Aha, so machen die das" zu sagen, das File zuzumachen, im
Code ganz einfach den include zu machen und die angebotene
Funktionalität zu benutzen.

> Klar
> wäre ich schneller gewesen, wenn ich einfach eine fertige Library
> verwendet hätte, doch dann hätte ich nie so viel gelernt. Wenn du daran
> intressiert bist den Drehbank bedienen zu lernen ist es unter umständen
> schon sinnvoll eine M4-Schraube selber herzustellen.

Nicht wirklich.
Wenn du mit einer Drehbank umgehen lernen willst, dann machst
du ein Lot, oder sonst irgendeinen Teil, den du später auch
gebrauchen kannst. Eine normale M4-Schraube machst du damit nicht,
die holst du dir aus dem Magazin.

In gleicher Manier ist es sinnlos, in einem C-Programm eigene
Assembler inline Funktionen für eine 16-Bit Addition zu schreiben,
sondern du benutzt die, die der Compiler sowieso mitbringt. In
gleicher Weise ist es sinnlos eigene Funktionen zum Flash auslesen
zu schreiben. Mit deinem Compiler hst du welche mitbekommen,
die perfekt funktionieren und die du nur einsetzen musst.
Der Sinn dieser mitgelieferten Funktionen ist es ja gerade,
dass du dich nicht um die Details kümmern musst. Du benutzt
sie einfach.


> Hey, ich
> programmiere diese Kontroller als Hobby und nicht weil ich möglichst
> effizient etwas erreichen möchte.

Darum geht es nicht.

von Oliver (Gast)


Lesenswert?

Warum haben denn eigenlich alle solche Angst vor Assembler?

Wer so etwas (auch noch freiwillig) in C nachprogrammiert,
1
int
2
foo(void)
3
{
4
  unsigned char bar = (__extension__({ uint16_t __addr16 = (uint16_t)((uint16_t)((void *)42)); uint8_t __result; __asm__ ( "lpm" "\n\t" "mov %0, r0" "\n\t" : "=r" (__result) : "z" (__addr16) : "r0" ); __result; }));
5
  return bar;
6
}

nur weil er kein Assembler lernen möchte, sollte doch über noch mal 
drüber nachdenken :-)

Ich nehme da doch lieber C, mit der passenden libc. Egal, auf welchem 
System.

Oliver

von Falk (Gast)


Lesenswert?

@Oliver

>Warum haben denn eigenlich alle solche Angst vor Assembler?

Ich nicht ;-)

>Wer so etwas (auch noch freiwillig) in C nachprogrammiert,
>int
>foo(void)
>{
>  unsigned char bar = (__extension__({ uint16_t __addr16 = (uint16_t)
>((uint16_t)((void *)42)); uint8_t __result; _asm_ ( "lpm" "\n\t" "mov %>0, r0" 
"\n\t" : "=r" (__result) : "z" (__addr16) : "r0" ); __result; }));
>  return bar;
>}

>nur weil er kein Assembler lernen möchte, sollte doch über noch mal
>drüber nachdenken :-)

NIEMAND programmiert sowas in C, das ist ein aufgelöstes Macro, was man 
praktisch nie zu Gesicht bekommt. Man schreibt lediglich

 unsigned char bar = pgm_read_byte((void *)42);

MfG
Falk

P.s. Jaja, der Macroprogrammierer programmiert das, aber nur einmal.

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.