Thursday, August 22, 2013

BLE112 IAR and moving bitmaps from RAM to FLASH (PROGMEM in IAR)

In previous article about converting st7565 library from AVR to IAR after compiling there was error about not enough memory

Error[e104]: Failed to fit all segments into specified ranges. Problem discovered in segment XDATA_N. Unable to place 2 block(s) (0xc02 byte(s) total) 
in 0x96c byte(s) of memory. The problem occurred while processing the segment placement command 
"-P(XDATA)XDATA_N=_XDATA_START-_XDATA_END", where at the moment of placement the available memory ranges were "XDATA:1594-1eff"


Quick fix about that to just run example was to minimize the heap size in IAR linker options.
Its ok if you want just to run the examples and see the results, but what if you need to store more images in flash - you need to move them to flash memory.

To see current memory consumption in IAR you need to tell the linker to save this information for you.
Go to Project Options > Linker > List (tab). Set is as follows:


Then after compiling source look for List folder in your build directory, there should be the file with .map extension. At the end of file you will found something like this:

 119 888 bytes of CODE  memory
      35 bytes of DATA  memory (+ 77 absolute )
   7 052 bytes of XDATA memory
     194 bytes of IDATA memory
       8 bits  of BIT   memory
   4 259 bytes of CONST memory


XDATA is your RAM. It is almost reaching 8KB what is RAM size in 8051. After moving images into flash its getting better:

 119 632 bytes of CODE  memory
      35 bytes of DATA  memory (+ 77 absolute )
   6 401 bytes of XDATA memory
     194 bytes of IDATA memory
       8 bits  of BIT   memory

   4 259 bytes of CONST memory

Its getting better. But how to move variables into flash ? In AVR like you can use PROGMEM, but syntax in IAR is different. Just add __code before variable name:

const unsigned char   __code stop_glcd_bmp[]={
0xFF, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0,
 
You need to use const keyword as well.

After that your array will go to the flash memory freeing RAM. But then you will probably face another problem. After passing such variable to function you will notice that all you can read from that pointer are some random data or zeros.

You need to tell compiler that these variables are located in flash. In function definition you need to specify __code as well:

void drawbitmap(uint8_t *buff, int x, int y, 
uint8_t __code *bitmap, int w, int h,
int color);

That's all. Works like PROGMEM from AVR world.