I'm currently working on a project that uses a graphical display. Up to now I've put my array for the fonts in the RAM-space. However the space is getting full now and I decided to move all my font-data to the progmem space. The problem is that I use a two-dimensional Array (One dimension for the Symbol, the other for the pixel-data) and I have to pass the array to different functions.
A (simplified) example:
const byte Numberss [] [10] = {
{ 0x3F, 0x65, 0x67, }, // Pixel data for number 0
{ 0x4C, 0x67, 0xE4, }, // Pixel data for number 1
//...
};
In main loop I call this function:
DrawNumber(Numbers[1]); // Im passing only one dimension of the array
Then the function does:
void DrawNumber(const byte _numb[]) {
for(int bytecount = 0; bytecount < 3, bytecount++) { //scan through all bytes
for(int bitcount = 0; bitcount < 8, bitcount++) { //scan through all bits
boolean _pixel = bitRead(_numb[bytecount], bitcount);
// Stuff that draws Pixel on display
}
}
}
A PROGMEM pointer/array acts just like a character pointer/array except the data is in a different address space.
You can use a regular pointer or array directly:
char array[100];
char * pointer = array;
// These all reference the same character:
array[10];
pointer[10];
*(pointer+10);
*(array+10);
Because the PROGMEM array is in a different address space and the compiler doesn't keep track, you have to use pgm_byte_read() to do any fetches. If you let the compiler generate code to fetch the data it will fetch it from the same address in SRAM:
char array[100] PROGMEM;
char * pointer = array; // No PROGMEM here since we want our pointer in SRAM
// These all reference the same character:
pgm_byte_read(&array[10]);
pgm_byte_read(&pointer[10]);
pgm_byte_read(pointer+10);
pgm_byte_read(array+10);
Maybe change the function prototype to DrawNumber( byte number ) and you call it with DrawNumber(1) instead of DrawNumber(Numbers[1]). Of course you need to modify the function by adding something like..
Maybe change the function prototype to DrawNumber( byte number ) and you call it with DrawNumber(1) instead of DrawNumber(Numbers[1]). Of course you need to modify the function by adding something like..
Thanks guix for your answer, but I can't do this because of this reason:
Beside the Numbers Array I have to pass Also other arrays to the Funktion, like letters[] or Symbols[] and so on.
Why don't I use only one array? Because the arrays have different sizes. By combining them together I would waste a large amount of data.
andyb:
Why don't I use only one array? Because the arrays have different sizes. By combining them together I would waste a large amount of data.
You could have an array of pointers that points to your other arrays Numbers, Letters etc. Look at the exemple Arrays of strings in PROGMEM - Arduino Reference
andyb:
Why don't I use only one array? Because the arrays have different sizes. By combining them together I would waste a large amount of data.
You could have an array of pointers that points to your other arrays Numbers, Letters etc. Look at the exemple Arrays of strings in PROGMEM - Arduino Reference
Thanks, I didn't know that. But what would that change in my example?
The whole display library is in the attachments.
Note that I put the array data at the bottom, it is normally the very first thing in my whole program.
Consider that the code worked perfectely with array in RAM.
However, that's the entire function used to draw a character or symbol:
Note that the first byte of my array data tells the width of the character.
Thanks
/*
?????????????????????????????????????????????????????????????????????????
? print single Char ?
?????????????????????????????????????????????????????????????????????????
*/
void Display_printChar(byte _x, byte _y, const byte _character [], byte _size, int _color, int _background) {
byte length = _character [0]; // first byte indicates width of character
byte countByte = 1;
byte countBit = 0;
// Setting the starting pixel
writeCommand(SSD1331_CMD_SETCOLUMN);
writeCommand(_x);
writeCommand(95);
writeCommand(SSD1331_CMD_SETROW);
writeCommand(_y);
writeCommand(63);
for (byte row = 0; row < (15- (7 * _size)); row++) {
for (byte column = 0; column < length; column++) {
if ((column < (((length-1)/2)+1)) || (!_size))
{
//if (bitRead(_character [countByte], 7 - countBit)) { // uncomment this line when Array is located in RAM
if (bitRead(pgm_read_byte(&_character[countByte]), 7 - countBit)) { // uncomment this line when Array is located in PROGMEM
writeData(_color);
}
else {
writeData(_background);
}
}
countBit = countBit + 1 + _size;
if (countBit == 8) {
countBit = 0;
countByte++;
}
}
// next pixel row:
writeCommand(SSD1331_CMD_SETCOLUMN);
writeCommand(_x);
writeCommand(95);
_y++;
writeCommand(SSD1331_CMD_SETROW);
writeCommand(_y);
writeCommand(63);
}
}