Storing font array in PROGMEM

Hi, I'm Devon.

I'm working with a graphic lcd where I have defined my own font and character placement function. What I want to do is store all of the font support data into PROGMEM so that it's not wasting my precious RAM. I've searched everywhere for help and i can't find anything related to my specific situation. I've even asked on stackoverflow and they couldn't help me.

Here's how I have the arrays defined:

prog_uchar fontLookUp[265] PROGMEM = {....}; //Converts ascii code to character location in font array.
prog_uchar font[96][8] PROGMEM = {...}; //contains character code. 96 characters at 8 bytes per character.

My placement function loads each byte of a character into a small buffer and then dumps the buffer to the display. To read a single byte of a character my function calls this line:

int pixels = font[fontLookUp[character][x]; //where character is the character being placed and x is the byte of the character being read.

I can't seem to get my program to read in from flash correctly. Here's what I've tried:

pgm_read_byte_near(font + pgm_read_byte_near(fontLookUp + character) * 8 + x);

This just outputs garbage to my display... Can anyone please help me out with what i'm doing wrong?

There are several full featured glcd libraries out there that handle all of this if you want a ready to go solution.

As far as your code goes. It looks like you have reserved room for 96 characters in your font[][] array. Why do you need the fontLookUp[] array and what are you putting in it?

to get the 8 bit pixel data of a colum/row directly from the font array you would do something like:

 unsigned char pixels = pgm_read_byte_near(font + character * 8 + x);

Where x increments to get a particular 8 bit row/column of pixels.

--- bill

Hi Devon,

Below are extracts from code I currently use that may give you pointers to what you want. I have a 6x7 number font stored in progmem and a routine that reads the font data one byte at a time and displays it on a 16x8 LED matrix.

#include <avr/pgmspace.h>

// Number font
prog_uchar font6x7 [] PROGMEM = {       // Small Numeric Font Matrix
    B00011110,	//0
    B00110011,
    B00110011,
    B00110011,
    B00110011,
    B00110011,
    B00011110,
    
    B00000110,	//1
    B00001110,
    B00011110,
    B00000110,
    B00000110,
    B00000110,
    B00000110,
    
    B00111110,	//2
    B00000011,
    B00000011,
    B00011110,
    B00110000,
    B00110000,
    B00111111,
    
    B00111111,	//3
    B00000110,
    B00001100,
    B00011110,
    B00000011,
    B00110011,
    B00011110,
    
    B00110011,	//4
    B00110011,
    B00110011,
    B00111111,
    B00000011,
    B00000011,
    B00000011,
    
    B00111111,	//5
    B00110000,
    B00110000,
    B00011110,
    B00000011,
    B00000011,
    B00111110,
    
    B00011110,	//6
    B00110000,
    B00110000,
    B00111110,
    B00110011,
    B00110011,
    B00011110,
    
    B00111111,	//7
    B00000011,
    B00000110,
    B00001100,
    B00011000,
    B00011000,
    B00011000,
    
    B00011110,	//8
    B00110011,
    B00110011,
    B00011110,
    B00110011,
    B00110011,
    B00011110,
    
    B00011110,	//9
    B00110011,
    B00110011,
    B00011111,
    B00000011,
    B00000011,
    B00011110,
};

// number = decimal number to display (0-9), address = MAX7219 chip address
void printLED(int number, int address){
    for (int a=0;a<7;a++){                              // Loop 7 times for a 6x7 font
        prog_uchar c = pgm_read_byte_near(font6x7 + (number * 7) + a);
        
        lc.setRow(address,a,c);                         // Send row to relevent MAX7219 chip
    }
}

I have fonts for graphics LCDs stored in PROGMEM here:

http://gammon.com.au/forum/?id=10940

The fontLookUp was used so I could pass standard ascii codes to the function and it would point to the correct entry in the font array. The font array starts with space which is ascii 3210 so I suppose I could just subtract 32 from the ascii codes…

I tried:

pixels = pgm_read_byte_near(font + (character - 32) * 8 + x);

and I’m still getting garbage on my display. Any suggestions as to how to troubleshoot this? (The - 32 is so that space(3210) is at the first entry of the font array)

@bperrybap
I’m using a display based on the ST7920 controller. The libraries available for this chip aren’t very well developed so I just decided to learn the ins and outs so I could write my own code for it. I have everything I need working perfectly except for getting this array into PROGMEM…

For st7920 this library is pretty good:
http://code.google.com/p/u8glib/

As far as debugging goes, print out your addresses and values to the serial port to see where things are:
print out the value of ‘character’, ‘x’, the address of ‘font’ and the final calculated address
being handed to pgm_read_byte_near()

That will tell you where you are looking in flash and should give you the information
you need to identify where the problem is.

— bill

I also use a ASCII (characters 0x20 to 0x7F) font stored in PROGMEM and access it using below subroutine. The font I pull out is 10x7 so I need to read 2x bytes per row. The font is stored lice this…

// Character font 0x20-07F
prog_uchar font10x7 [] PROGMEM = {      // Large Ascii Font Matrix
---
SNIP
---
    B11111111, B11000000,	//F
    B11000000, B00000000,
    B11000000, B00000000,
    B11111111, B00000000,
    B11000000, B00000000,
    B11000000, B00000000,
    B11000000, B00000000,
---
SNIP
---
    B00111100, B00000000,	// (Char 0x7F)
    B11000011, B00000000,
    B11000011, B00000000,
    B00111100, B00000000,
    B00000000, B00000000,
    B00000000, B00000000,
    B00000000, B00000000,
};

I store my fonts differently to you but the principle should be the same.

// Load character into scroll buffer
void loadBufferLong(int ascii){
    if (ascii >= 0x20 && ascii <=0x7f){
        for (int a=0;a<7;a++){                    // Loop 7 times for a 10x7 font
            unsigned long x = bufferLong [a];       // Load current scroll buffer
            prog_uchar y = pgm_read_byte_near(font10x7 + ((ascii - 0x20) * 14) + (a*2)+0);
            unsigned long c = y;     // Index into character table to get row data
            y = pgm_read_byte_near(font10x7 + ((ascii - 0x20) * 14) + (a*2)+1);
            unsigned long d = y;     // Index into character table to get row data
            c = c<<8;
            c = c | d;
            x = x | c;                              // OR the new character onto end of current
            bufferLong [a] = x;                     // Store in buffer
        }
    }
}

Yahoo, many thanks for all your comments. I just updated and published the v1.1.0 of my library LcdProgressBarDouble with PROGMEM and pgm_read_byte_near() usage.

Substantial gain:

  • v1.0.5: DoubleBarPot.ino uses 7446 bytes and 310 bytes of RAM
  • v1.1.0: DoubleBarPot.ino uses 7538 bytes and 230 bytes of RAM