Skip to content

Using AVR Flash Memory

I used the SSD1306-AVR library to drive an OLED display with an ATMega328p. The bitmap image is stored in flash memory in order to save space in RAM. The code can be found here https://github.com/benjohnemmett/avr-oled-progmem and also includes a python script to convert image files to bitmap code.

The Working Example

The image to display takes up 1KB of memory on its own so I put it into flash memory using PROGMEM like so.

const uint8_t smile[32][32] PROGMEM = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },

...

{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
};

Then the pgm_read_byte( address_short ) function is used to access the data stored in flash. This function is defined in <avr/pgmspace.h> which is already included in “SSD1306-AVR/Framebuffer.h” from the SSD1306-AVR library.

#include "SSD1306-AVR/Framebuffer.h"

...

void DrawBitMap(Framebuffer &fb, uint8_t x, uint8_t y) {
  for (int r = 0; r < 32; r++) {
    for (int c = 0; c < 32; c++) {
      fb.drawPixel(c + x, r + y, pgm_read_byte(&smile[r][c]));
    }
  }
}

Side Notes

I’m not sure why but the code would not run if the bitmap was left in RAM. It is 32×32 which is 1KB of data. That is half of the total 2KB available in the ATMega328p. It seems like the extra 1KB would to be enough to run the program, however I could compile and flash the project but it would not run unless the bitmap was in flash memory.

I realize that I could pack in the data better by using one bit per pixel instead of a whole byte per pixel. Doing so would reduce the bitmap size down to 128 bytes.

BitMapper Python Script

A python script called bitmapper.py is included in the repo. It uses opencv to read an image, find the edges, shrink it down, and print out the byte array definition which can be copied into the C/C++ code.

Grayscale
Edge
Reduced Binary

and this is written to the console

uint8_t smile[16][16] = {
{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, },
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, },
{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, },
{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, },
{1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, },
{1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, },
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, },
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, },
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, },
{1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
{1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, },
{1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, },
{0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, },
{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, },
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, },
{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, },
};

Leave a Reply

Your email address will not be published. Required fields are marked *