Last active
March 27, 2024 15:16
-
-
Save Koepel/2a4ae36ae6397cd260f2c7ae2a50610e to your computer and use it in GitHub Desktop.
Test PROGMEM beyond 64k
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@JuergenLo The "_PF" functions are a good addition. Thank you.