Skip to content

Instantly share code, notes, and snippets.

@Koepel
Last active March 27, 2024 15:16
Show Gist options
  • 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();
}
@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