chairn
January 10, 2016, 2:02pm
#1
Here's my problem : I have several arrays of 16383 ints which means that the address of the second array is over an int possibility. When i try to access this array, the address is cast to an int and therefore is wrong.
Here's a snippet of code:
const uint16_t tab0[16383] PROGMEM = {...};
const uint16_t tab1[16383] PROGMEM = {...};
void loop() {
Serial.println(long(&tab0), HEX); //prints 0xFFFF810a instead of 0x1810a
}
Is there a way to cast an address as long, or do i have to manually write the correct address by looking at the disassembly code?
Thx for your help.
system
January 10, 2016, 2:10pm
#2
Here's a snippet of code:
In which the Serial.print() statement has 5 parens... Post some code that ACTUALLY compiles.
What board are you using?
aarg
January 10, 2016, 2:30pm
#6
Cast to an unsigned long. Serial.println((unsigned long)(&tab0), HEX);
chairn
January 10, 2016, 2:39pm
#7
aarg:
Cast to an unsigned long.
Serial.println((unsigned long)(&tab0), HEX);
Doesn't work, same result.
robtillaart:
What board are you using?
ATmega 2560
PaulS:
NOT fixed.
... When the anti-spam protection will allow me to edit.
Anyway, i think it's not possible because pointers are treated as int, i.e 16 bits int, which does not allow addressing more than 32KB.
aarg
January 10, 2016, 2:43pm
#8
Then you have to post all your code.
guix
January 10, 2016, 2:54pm
#9
Hello and welcome,
Try
Serial.println( pgm_get_far_address( tab0 ), HEX );
PROGMEM above 64k example:
const char above[1024] PROGMEM = "above 64";
const char filler1[31 * 1024] PROGMEM = "filler1";
const char filler2[31 * 1024] PROGMEM = "filler2";
const char below[4 * 1028] PROGMEM = "below 64";
void setup() {
Serial.begin(115200);
dumpFF(pgm_get_far_address(below), 0x20);
dumpFF(pgm_get_far_address(filler1), 0x20);
dumpFF(pgm_get_far_address(filler2), 0x20);
dumpFF(pgm_get_far_address(above), 0x20);
}
void dumpFF(unsigned long adr, int len) {
byte idx;
if (len) {
for (; len > 0; len -= 16, adr += 16) {
phBytesB((byte*)&adr, 4);
Serial.write(':');
Serial.write(' ');
for (idx = 0; idx < 16; idx++) {
if (idx < len ) {
phByte(pgm_read_byte_far(adr + idx));
Serial.write(' ');
} else {
Serial.print(F(" "));
}
}
Serial.write('\'');
for (idx = 0; (idx < 16) && (idx < len); idx++) {
byte curr = pgm_read_byte_far(adr + idx);
Serial.write(curr < 0x20 ? '.' : curr);
}
Serial.write('\'');
Serial.println();
}
}
}
void psdec(void (*pprint)(byte), byte* ptr, byte len) {
for (ptr += len - 1; len--;) {
(*pprint)(*ptr--);
}
}
void phBytesB(byte* ptr, byte len) {
psdec(phByte, ptr, len);
}
void phByte(byte val) {
phNibble(val >> 4);
phNibble(val);
}
void phNibble(byte val) {
val &= 0xF;
Serial.write(val + (val < 10 ? '0' : 'A' - 10));
}
void loop() {}
chairn
January 10, 2016, 2:57pm
#11
Here is how i’ve done it + using pgm_read_word_far for reading.
const uint16_t tab0[16383] PROGMEM = {0};
const uint16_t tab1[16383] PROGMEM = {0};
const uint16_t tab2[16383] PROGMEM = {0};
const uint16_t tab3[16383] PROGMEM = {0};
const uint16_t tab4[16383] PROGMEM = {0};
const long tab[] = {(long)&tab0, (long)&tab1, (long)&tab2, (long)&tab3, (long)&tab4};
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println(tab[0], HEX); //104
Serial.println(tab[1], HEX); //FFFF8106
Serial.println(tab[2], HEX); //108
Serial.println(tab[3], HEX); //FFFF810A
Serial.println(tab[4], HEX); //10C
Serial.println(pgm_read_word_far(&tab0 + 12); //example
}
And the real addresses are (looking at the assembly code) :
0000010c <__trampolines_end>: //tab4
…
0000810a <_ZL4tab3>:
…
00010108 <_ZL4tab2>:
…
00018106 <_ZL4tab1>:
…
00020104 <_ZL4tab0>:
…
edit: with pgm_get_far_address, i have the following results:
20104
18106
10108
810A
10C
So, i guess my problem is solved. I just dont get why this function is not there :
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html