Forum: Compiler & IDEs pgm_read_byte_far


von neuling (Gast)


Lesenswert?

guten tag,

ich habe mal eine frage, und zwar benutze ich einen Mega128,habe mehre 
bilddaten im flash ligen alles bis 64K wird korrekt angezeigt aber alles 
über 64K eben nicht,dann habe ich mit pgm_read_byte_far das ganze 
versucht, aber das haut auch nich hin.

meine bilddaten;
#include <avr/pgmspace.h> //WinAVR
prog_uchar 63bmp[]= { //AVR-GCC, WinAVR
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};


mein aufruf;
by=pgm_read_byte_far(bitmap);


vielleicht kann mir jemand bischen weiterhelfen

mfg

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


Lesenswert?

pgm_read_byte_far() braucht eine 32-bit-Zahl als Adresse.  Zeiger
sind im AVR-GCC aber nur 16 bit groß.

von neuling (Gast)


Lesenswert?

hallo,
in Assembler ist das ganze eigendlich ganz einfach
ldi ZL, byte3(2*63bmp)
out rampz,ZLldi ZL, low(2*63bmp)
ldi ZH, high(2*63bmp)
elpm WL, Z+
das Funktioniert herforragend von 0-128K beim Mega128
warum ist das in AVR-GCC so schwierig
vielleicht könnt mir da jemand ein stück weiterhelfen


mfg

von Peter (Gast)


Lesenswert?

Ich hab dazu ein Macro, welches einen 32 Bit-Pointer (bzw. 24 Bit) für 
Memory-Adressen oberhalb 64 kByte liefert:
1
//======================================================================
2
// Macro to access strings defined in PROGMEM above 64kB
3
//----------------------------------------------------------------------
4
#define FAR(var)                     \
5
({ uint_farptr_t tmp;                \
6
   __asm__ __volatile__(             \
7
       "ldi    %A0, lo8(%1)"  "\n\t" \
8
       "ldi    %B0, hi8(%1)"  "\n\t" \
9
       "ldi    %C0, hh8(%1)"  "\n\t" \
10
       "clr    %D0"           "\n\t" \
11
       : "=d" (tmp)                  \
12
       : "p"  (&(var)));             \
13
   tmp;                              \
14
})
15
//----------------------------------------------------------------------

Dann gehts einfach so:
1
by=pgm_read_byte_far(FAR(bitmap));

Ich verstehe nicht, wieso die AvrLib-C kein eintsprechendes Macro im 
pgmspaceModul enthält. Es existieren zwar "far"-Funktionen die einen 32 
Bit Pointer erwarten, aber eben kein FAR-Macro, welches diesen Pointer 
liefert.

Vermutlich könnte man das Macro z.B. direct in die pgm_read_far Funktion 
integrieren, so dass man der Funktion bloss den 16-Bit Pointer mitgeben 
müsste...

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


Lesenswert?

Peter schrieb:
> Ich verstehe nicht, wieso die AvrLib-C kein eintsprechendes Macro im
> pgmspaceModul enthält.

Weil du es noch nicht als Patch eingereicht hast?

(Bitte nicht vergessen, dafür doxygen-Dokumentation mit zu liefern.
Sonst benutzt den Makro keiner, weil ihn keiner kennt.)

https://savannah.nongnu.org/patch/?group=avr-libc

von neuling (Gast)


Lesenswert?

so ich habs in der pgmspace.h eingefügt nun kommt allerdings 3x der 
Fehler
undeundefined reference t 'r30'
undeundefined reference t 'r30'
undeundefined reference t 'r30'


vielleicht könnte mir wer sagen was ich falsch mache

mfg

von Detlev T. (detlevt)


Lesenswert?

Hm. So wie ich das sehe, wird ein Pointer beim Zugriff aufs Flash 
ohnehin zu einem uin16_t bzw. uint32_t gecasted. Da stellt sich für mich 
schon die Frage, ob man 32-Bit-Pointer in gcc-avr einführen sollte, nur 
um sie anschließend wieder auf uint32_t zu casten. Sonst wird doch 
nirgendwo ein 32-Bit-Poiter benötigt, noch ist das SRAM ja nicht so 
groß, ;)

Gruß, DetlevT

von neuling (Gast)


Lesenswert?

mit dem Macro bekomme ich mein Quelltext nicht Compilliert da er mir 
immer den Fehler 3x ausgibt,
undefined reference t 'r30'
das einzigste was funktioniert ist halt dies,
by=pgm_read_byte_far(   0x10000UL +  (uint32_t) (uint16_t) bitmap);
schade das es keine funktion gibt wo ich den gesamten Flash lesen kann

mfg

von Peter (Gast)


Lesenswert?

Nach den Backslashs "\" muss direkt eine neue Zelie (Newline) folgen, 
kein Leerschlag, Tab oder Kommentar. Vielleicht liegts daran?

von neuling (Gast)


Lesenswert?

Hallo Peter,
wiegesagt habe das Macro in pgmspace.h eingefügt so wie es weiter oben 
gepostet ist
und dazu dann der aufruf  by=pgm_read_byte_far(FAR(bitmap));
es kommt dann immer der Fehler mit undefined reference to 'r30'
Schade das das nicht funktioniert,
oder mach ich da was verkehrt

mfg

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


Lesenswert?

neuling schrieb:
> mach ich da was verkehrt

Gib mal den Code, den du wirklich compilieren willst.  Ich wollte
gerade dein Beispiel von ganz oben testen, aber das ist offensichtlich
nicht per copy&paste aus deinem Editor, denn "63bmp" ist zwar
vielleicht ein gültiger Domainname im Internet, aber es ist kein
gültiger Bezeichner in der Sprache C.

p.s.: Bitte markiere den C-Code als solchen.

von Peter (Gast)


Lesenswert?

Also ich hab hier mal ein Beispiel mit dem aktuellen WinAVR erzeugt, das 
lässt sich ohne Fehler oder Warning compilieren (AtMega128)
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
4
//====================================================================
5
// Macro to access strings defined in PROGMEM above 64kB
6
//--------------------------------------------------------------------
7
#define FAR(var)                     \
8
({ uint_farptr_t tmp;                \
9
   __asm__ __volatile__(             \
10
       "ldi    %A0, lo8(%1)"  "\n\t" \
11
       "ldi    %B0, hi8(%1)"  "\n\t" \
12
       "ldi    %C0, hh8(%1)"  "\n\t" \
13
       "clr    %D0"           "\n\t" \
14
       : "=d" (tmp)                  \
15
       : "p"  (&(var)));             \
16
   tmp;                              \
17
})
18
//-------------------------------------------------------------------
19
20
//===================================================================
21
// Define a section above 64kB (FAR_SECTION)
22
// and add the required linker argument below
23
// -Wl,--section-start=.far_section=0x10000
24
//--------------------------------------------------------------------
25
#define FAR_SECTION   __attribute__((section(".far_section")))
26
//--------------------------------------------------------------------
27
28
//====================================================================
29
// Just a Sample
30
//--------------------------------------------------------------------
31
32
char MyBitmap[] FAR_SECTION = "Hier liegt mein Teststring!";
33
char bmp64[]    FAR_SECTION = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00};
34
35
int main(void)
36
{
37
  char MyChar;
38
  DDRC = 0xFF;
39
  do
40
  {
41
    MyChar = pgm_read_byte_far(FAR(MyBitmap));
42
    PORTC  = MyChar;
43
  }
44
  while(MyChar);
45
}

Built Log:
1
Create eeprom image (ihex format)
2
avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex Test.elf  "Test.eep"
3
Finished building: Test.eep
4
 
5
Invoking: Print Size
6
avr-size --format=avr --mcu=atmega128 Test.elf
7
AVR Memory Usage
8
----------------
9
Device: atmega128
10
11
Program:     236 bytes (0.2% Full)
12
(.text + .data + .bootloader)
13
14
Data:          0 bytes (0.0% Full)
15
(.data + .bss + .noinit)
16
17
Finished building: sizedummy

Wenn ich mir die dabei erzeugten LSS- und HEX-Files angucke, so sehe ich 
dass alles richtig rauskommt..

von Peter (Gast)


Lesenswert?

Ups, ich hatte da nicht das ganze Buit-Log erwischt! ;o)
1
**** Build of configuration Release for project Test ****
2
3
make all 
4
Building file: ../main.c
5
Invoking: AVR Compiler
6
avr-gcc -Wall -O1 -fpack-struct -fshort-enums -std=gnu99 -funsigned-char -funsigned-bitfields -mmcu=atmega128 -DF_CPU=14745600UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c"
7
Finished building: ../main.c
8
 
9
Building target: Test.elf
10
Invoking: AVR C Linker
11
avr-gcc -Wl,-Map,Test.map -Wl,--section-start=.far_section=0x10000 -mmcu=atmega128 -o"Test.elf"  ./main.o   
12
Finished building target: Test.elf
13
 
14
Invoking: AVR Create Extended Listing
15
avr-objdump -h -S Test.elf  >"Test.lss"
16
Finished building: Test.lss
17
 
18
Create Flash image (ihex format)
19
avr-objcopy -R .eeprom -O ihex Test.elf  "Test.hex"
20
Finished building: Test.hex
21
 
22
Create eeprom image (ihex format)
23
avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex Test.elf  "Test.eep"
24
Finished building: Test.eep
25
 
26
Invoking: Print Size
27
avr-size --format=avr --mcu=atmega128 Test.elf
28
AVR Memory Usage
29
----------------
30
Device: atmega128
31
32
Program:     236 bytes (0.2% Full)
33
(.text + .data + .bootloader)
34
35
Data:          0 bytes (0.0% Full)
36
(.data + .bss + .noinit)
37
38
Finished building: sizedummy

von Peter (Gast)


Lesenswert?

Im Macro kann mann sogar die Zeile mit dem [clr  %D0"  "\n\t" \] 
weglassen, das 4. Adressbeyte wird ja nicht benötigt. => Spart 2 Bytes 
und einen CPU-Zyklus pro Aufruf.
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
4
//====================================================================
5
// Macro to access strings defined in PROGMEM above 64kB
6
//--------------------------------------------------------------------
7
#define FAR(var)                     \
8
({ uint_farptr_t tmp;                \
9
   __asm__ __volatile__(             \
10
       "ldi    %A0, lo8(%1)"  "\n\t" \
11
       "ldi    %B0, hi8(%1)"  "\n\t" \
12
       "ldi    %C0, hh8(%1)"  "\n\t" \
13
       : "=d" (tmp)                  \
14
       : "p"  (&(var)));             \
15
   tmp;                              \
16
})
17
//-------------------------------------------------------------------
18
19
//===================================================================
20
// Define a section above 64kB (FAR_SECTION)
21
// and add the required linker argument below
22
// -Wl,--section-start=.far_section=0x10000
23
//--------------------------------------------------------------------
24
#define FAR_SECTION   __attribute__((section(".far_section")))
25
//--------------------------------------------------------------------
26
27
//====================================================================
28
// Just a Sample
29
//--------------------------------------------------------------------
30
31
char MyString[] FAR_SECTION = "Hier liegt mein FAR-Teststring!";
32
char MyBmp64[]  FAR_SECTION = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00};
33
34
int main(void)
35
{
36
  char MyChar;
37
  DDRC = 0xFF;
38
  do
39
  {
40
    MyChar = pgm_read_byte_far(FAR(MyBmp64));
41
    PORTC  = MyChar;
42
  }
43
  while(MyChar);
44
}

von Martin R. (martin63)


Lesenswert?

Hallo Peter,

die Lösung sieht gut aus, aber wie läßt sich ein Element im FAR-Bereich 
referenzieren? In dem Beispiel gibt's ja immer nur 0xAA zurück. Wie 
komme ich z.B. an 0xDD? mit FAR(&MyBmp64[3]) komme ich nicht weiter wg. 
Lvalue.

Danke!
Martin

von Peter (Gast)


Lesenswert?

>mit FAR(&MyBmp64[3]) komme ich nicht weiter wg. Lvalue.

Da müsste ich mal bisschen pröbeln, aber eigentlich müsste es zum 
Beispiel folgendermassen klappen:


pgm_read_byte_far(FAR(MyBmp64)+3);

von Martin R. (martin63)


Lesenswert?

Hallo Peter,

ja, so mit direkter Pointerarithmetik scheint es zu gehen, hatte ich 
auch schon probiert. Wenn es aber komplexere Tabellen sind, wäre ein 
Indexzugriff sicher besser. Falls also beim "pröpeln" was rauskommen 
sollte, wäre das sicher nicht nur für mich sehr hilfreich.

Nochmal Danke!

Martin

von Peter (Gast)


Lesenswert?

@Martin R.

Mit direkter Indexangabe, die der Compiler auflösen kann, funktioniert 
es folgendermassen: (ohne &)
1
MyChar = pgm_read_byte_far(FAR(MyBmp64[3]));

Aber leider nicht mit variablem Index:
1
int n=3;
2
MyChar = pgm_read_byte_far(FAR(MyBmp64[n]));
3
=>main.c:(.text+0x32): undefined reference to `r30'
4
=>main.c:(.text+0x34): undefined reference to `r30'
5
=>main.c:(.text+0x36): undefined reference to `r30'

Da muss man sich offenbar mit direkter Pointerarithemetik begnügen:
1
int n=3;
2
MyChar = pgm_read_byte_far(FAR(MyBmp64)+n);

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.