Skip to content

Instantly share code, notes, and snippets.

@Koepel
Last active March 27, 2024 15:16
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Koepel/2a4ae36ae6397cd260f2c7ae2a50610e to your computer and use it in GitHub Desktop.
Save Koepel/2a4ae36ae6397cd260f2c7ae2a50610e to your computer and use it in GitHub Desktop.
Test PROGMEM beyond 64k
// Test PROGMEM beyond 64k
//
// This test is with Arduino IDE 1.8.5 and a Arduino Mega 2560.
//
// 29 december 2017
//
// For: http://forum.arduino.cc/index.php?topic=519175
//
// 2019: See https://forum.arduino.cc/index.php?topic=622922.0
// for multiple PROGMEM segments.
//
// public domain
//
// There are no far pointers to data.
// The tric is to use a 32-bit variable that represents a far pointer.
// The macro pgm_get_far_address() will create such a variable from
// a label in PROGMEM.
// That can be used for the pgm_read_..._far() functions.
// Note that it is a 32-bit number, not a real pointer.
// The pgm_get_far_address() creates a 24-bits value, it is stored in a 32-bit variable.
// The <avr/pgmspace.h> is already included by the Arduino IDE.
//
// Disadvantages ! (major disadvantages)
// Most functions are not compatible with far PROGMEM pointers.
// Only pgm_read_..._far() may be used, all other functions are not compatible.
// Using Serial.println() with a text in PROGMEM will no longer work.
// The F() macro will no longer work.
// The memcpy_P() functions are not compatible.
//
#define R10(a) (a+0),(a+1),(a+2),(a+3),(a+4),(a+5),(a+6),(a+7),(a+8),(a+9)
#define R100(a) R10(a),R10(a),R10(a),R10(a),R10(a),R10(a),R10(a),R10(a),R10(a),R10(a)
#define R1000(a) R100(a),R100(a),R100(a),R100(a),R100(a),R100(a),R100(a),R100(a),R100(a),R100(a)
// This test sketch is for 16-bits data in PROGMEM.
// 30k per block (below 32767 to avoid trouble)
// 5 blocks make 150kbyte
// Do not use these names of the data.
// They are converted to far pointers and those far pointers should be used.
const uint16_t block1[15000] PROGMEM = { R1000(100) };
const uint16_t block2[15000] PROGMEM = { R1000(200) };
const uint16_t block3[15000] PROGMEM = { R1000(300) };
const uint16_t block4[15000] PROGMEM = { R1000(400) };
const uint16_t block5[15000] PROGMEM = { R1000(500) };
// These are 32-bit addresses to far PROGMEM data.
// Far pointers are used for PROGMEM data below and above the 64k border.
// They are forced to far pointers by "pgm_get_far_address" and that
// macro has to be executed at runtime in a function.
uint32_t far_block1, far_block2, far_block3, far_block4, far_block5;
void setup()
{
Serial.begin(9600);
// Make 32-bit variables that represent far pointers to PROGMEM data
createFarPointers();
Serial.println();
Serial.println( "Test sketch for large size PROGMEM"); // The F() macro may not be used
#if defined (__AVR_ATmega2560__)
Serial.println( "__AVR_ATmega2560__ is defined"); // The F() macro may not be used
#else
Serial.println( "__AVR_ATmega2560__ is not defined !"); // The F() macro may not be used
#endif
Serial.print( "Microcontroller has "); // The F() macro may not be used
Serial.print( FLASHEND);
Serial.println( " bytes of flash."); // The F() macro may not be used
Serial.print( "The size of a single block of data is "); // The F() macro may not be used
Serial.print( sizeof( block1));
Serial.println( " bytes");
// The function "useFarData" shows how to use the data in far PROGMEM.
useFarData( far_block1);
useFarData( far_block2);
useFarData( far_block3);
useFarData( far_block4);
useFarData( far_block5);
}
void loop()
{
}
void createFarPointers()
{
far_block1 = pgm_get_far_address( block1);
far_block2 = pgm_get_far_address( block2);
far_block3 = pgm_get_far_address( block3);
far_block4 = pgm_get_far_address( block4);
far_block5 = pgm_get_far_address( block5);
}
void useFarData( uint32_t far_address)
{
Serial.print( "Far data is : ");
for( int i=0; i<5; i++)
{
// No index is used. The address is a 32-bit value, representing a pointer.
// It is not a real pointer.
// Since two bytes are read, the offset is (2 * i).
uint16_t data = pgm_read_word_far( far_address + (2 * i));
Serial.print( data);
Serial.print( ", "); // The F() macro may not be used
}
Serial.println();
}
@Podgyhodgy
Copy link

Thankyou very much for this. It was just what I needed to get things working.

@JuergenLo
Copy link

JuergenLo commented Mar 18, 2021

I have been trying to use Flash memory with string data on the mega 2560 for months now. This article sorted the problem for me

When storing strings in flash memory use:-
const char eA1[] PROGMEM = {"Abcde "};
const char eA2[] PROGMEM = {“Fghijkl "};
const char * const A_Table[] PROGMEM = {eA1,eA2};

When retrieving strings from flash memory (in the useFarData function above) use:-
char buffer[41];
strncpy_PF(buffer, (char*)pgm_read_word_far(far_address + (i * 2)),40);

@Koepel
Copy link
Author

Koepel commented Mar 18, 2021

strncpy_PF(buffer, (char*)pgm_read_word_far(far_address + (i * 2)),40);

@JuergenLo The "_PF" functions are a good addition. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment