Strange bug with myGLCD.drawBitmap when called 6 times

Hello!
This post is related to

Mega + Sainsmart TFT 320x240 very slow displaying bmp from SD card

The idea is to display 6 icons on the TFT and execute functions depending on which icon is pressed on the touch screen,

I tried to:

  • load all the icons as a single file, "wallpaper" bmp, from the SD card then using myGLCD.setColor; and myGLCD.drawPixel but this is way too slow.
  • convert the "wallpaper" with the 6 icons to a c_array file const unsigned short wallpaper[0x12C00] PROGMEM ={... but I got the error size of array 'wallpaper1’ is too large.
    Now I'm trying this which is according to the bitmap example found in the UTFT library:
  • I converted the icons as 84x84 c_array files: icon1.c, icon2.c, ...
  • Loading them with extern unsigned int icon1[0x1B90]; ...
  • Displaying with myGLCD.drawBitmap (10, 26, 84, 84, icon1); ...
    The images load quite fast.

The strange bug is this: if I try to display the 6 icons by using myGLCD.drawBitmap 6 times, the tft doesn't show anything. But if I comment one of the icons ( //myGLCD.drawBitmap ... ) the remaining 5 show up quite nice and fast.
And if I use 6 icons but at least 2 of them are the same image displayed in another place, it's also ok.

Can anyone explain what's wrong and how to fix it?
I'm guessing it's a size issue: 6 different images is too much for arduino.

Regards

Can you read a c_array file from the SD Card and display it using myGLCD.drawBitmap or does it have to be in the flash memory of arduino?
If so, how?

Your 6 icons in PROGMEM are 41kb

If your sketch size is close to, or greater than 64kb, you could be pushing certain functions to far into memory.
You can work around it by putting some or all icons into far progmem space ( you are using near progmem space. ), which leaves the near range free for code.

Your 6th icon is most probably removed during compilation when you do not reference it. By adding the myGLCD.drawBitmap it is left in pushing the sketch over 64k.

The code below shows how to read from the FAR PROGMEM range. The GET_FAR_ADDRESS macro converts the 16bit pointer to a 32bit pointer.

Like the SD card option, you probably will have to manually write the image. Or you could modify the glcd function to accept another parameter to decide weather to use near or far progmem.

//#include <avr\pgmspace.h>

#define GET_FAR_ADDRESS(var)                          \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    __asm__ __volatile__(                             \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
}) 

#define PROGMEM_FAR  __attribute__((section(".fini7")))

char pgmData[] PROGMEM_FAR = { 'T', 'e', 's', 't', 'i', 'n', 'g', ' ', 'P', 'G', 'M', '\0' };

void setup() {
  Serial.begin( 9600 );  

  byte c, i =0;
  while( c = pgm_read_byte_far( GET_FAR_ADDRESS( pgmData  ) + i++ ) ){
     Serial.print( ( char ) c );
  }
}

void loop() {}

Creating your own extension to the glcd library makes it easy.

class GlcdEx : public glcd{
  
  public:
  
    void DrawBitmapFar( uint_farptr_t bitmap, uint8_t x, uint8_t y, uint8_t color= BLACK ){

      uint8_t width, height;
      uint8_t i, j;

      width = pgm_read_byte_far(bitmap++); 
      height = pgm_read_byte_far(bitmap++);

      #ifdef BITMAP_FIX
        if( (y & 7) || (height & 7))
        {
        	this->FillRect(x, y, width, height, WHITE);
        }
      #endif

      for(j = 0; j < height / 8; j++) {
        glcd_Device::GotoXY(x, y + (j*8) );
        for(i = 0; i < width; i++) {
	  uint8_t displayData = pgm_read_byte_far(bitmap++);
	  if(color == BLACK)
  	    this->WriteData(displayData);
          else
            this->WriteData(~displayData);
      	 }
      }
    }
};

GlcdEx GLCDEX;

byte data0[] PROGMEM = { 3,3,1,2,3,4,5,6,7,8,9 };
byte data1[] PROGMEM = { 3,3,1,2,3,4,5,6,7,8,9 };
byte data2[] PROGMEM_FAR = { 3,3,1,2,3,4,5,6,7,8,9 };

void setup() {
  
    GLCDEX.Init();
    GLCDEX.DrawBitmap( data0, 0, 0 );
    GLCDEX.DrawBitmap( data1, 0, 3 );
    GLCDEX.DrawBitmapFar( GET_FAR_ADDRESS( data2 ), 0, 6 );
}

void loop() {}

Thank you very much, Pyro.

I'm a newcomer to arduino and to programming and I never heard of near/far Progmem before.
You are correct, my sketch is above 64kb, it's almost 100kb.

The idea is to have a look-a-like ipod / smartphone appearance with icons being displayed.

I'll implement the code you've given.

Kind regards,
Nuno

Thank you very much, Pyro.

No worries. :slight_smile:

I'm a newcomer to arduino and to programming and I never heard of near/far Progmem before.

It is quite rare for people to run into the far range of memory ( while using Arduino ), but there is a load of information out there about it.

If you are using loads of images/sprites it may be better to use an SD to store large sets of images. It is far slower than PROGMEM, but writing them as one large file might speed things up when it comes around to reading the data back.

Not to worry though, at 100k you still have a fair bit of PROGMEM room on a Mega 2560

I've adapted the UTFT_Bitmap example (thank you Henning Karlsen).

Now it has a tux icon on PROGMEM_FAR and it shows rotation example:

The make the tuxfar.c file just copy | paste the tux.c file, rename it to tuxfar.c and change to the following:

//#include <avr/pgmspace.h>

#define GET_FAR_ADDRESS(var)                          \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    __asm__ __volatile__(                             \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
})

#define PROGMEM_FAR  __attribute__((section(".fini7")))

const unsigned short tuxfar[0x400] PROGMEM_FAR ={

The rest is the same as in tux.c

The UTFT_Bitmap.pde must be:

// UTFT_Bitmap (C)2012 Henning Karlsen
// web: http://www.henningkarlsen.com/electronics
//
// This program is a demo of the drawBitmap()-function.
//
// This demo was made to work on the 320x240 modules.
// Any other size displays may cause strange behaviour.
//
// This program requires the UTFT library.
//

#include <UTFT.h>
#include <avr/pgmspace.h>

// Declare which fonts we will be using
extern uint8_t SmallFont[];

// Uncomment the next line for Arduino 2009/Uno
//UTFT myGLCD(ITDB32S,19,18,17,16);   // Remember to change the model parameter to suit your display module!

// Uncomment the next line for Arduino Mega
UTFT myGLCD(ITDB32S,38,39,40,41);   // Remember to change the model parameter to suit your display module!

extern unsigned int info[0x400];
extern unsigned int icon[0x400];
extern unsigned int tux[0x400];
extern unsigned int tuxfar[0x400];

void setup()
{
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont);
}

void loop()
{
  myGLCD.fillScr(255, 255, 255);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print(" *** A 10 by 7 grid of a 32x32 icon *** ", CENTER, 228);
  for (int x=0; x<10; x++)
    for (int y=0; y<7; y++)
      myGLCD.drawBitmap (x*32, y*32, 32, 32, info);

  delay(5000);
  
  myGLCD.fillScr(255, 255, 255);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("   Two different icons in scale 1 to 4  ", CENTER, 228);
  int x=0;
  for (int s=0; s<4; s++)
  {
    x+=(s*32);
    myGLCD.drawBitmap (x, 0, 32, 32, tux, s+1);
  }
  x=0;
  for (int s=4; s>0; s--)
  {
    myGLCD.drawBitmap (x, 224-(s*32), 32, 32, icon, s);
    x+=(s*32);
  }

  delay(5000);
  
  myGLCD.fillScr(255, 255, 255);
  myGLCD.setColor(255, 255, 255);
  myGLCD.print("Near and far PROGMEM with icon rotation", CENTER, 228);
  x=0;
  for (int s=0; s<4; s++)
  {
    myGLCD.drawBitmap (39+x, 40, 32, 32, tux, 45*s, 16, 16);
    x+=70;
  }
  x=0;
  for (int s=4; s<8; s++)
  {
    myGLCD.drawBitmap (39+x, 170, 32, 32, tuxfar, 45*s, 16, 16);
    x+=70    ;
  }

  delay(5000);

}

Which is basically the original file with adding tuxfar and showing the rotation example in the end.

As I understand, avr/pgmspace.h is a macro.
Can another macro be defined? Something like avr/farpgmspace.h that has the code given by pYro:

#define GET_FAR_ADDRESS(var)                          \
({                                                    \
    uint_farptr_t tmp;                                \
                                                      \
    __asm__ __volatile__(                             \
                                                      \
            "ldi    %A0, lo8(%1)"           "\n\t"    \
            "ldi    %B0, hi8(%1)"           "\n\t"    \
            "ldi    %C0, hh8(%1)"           "\n\t"    \
            "clr    %D0"                    "\n\t"    \
        :                                             \
            "=d" (tmp)                                \
        :                                             \
            "p"  (&(var))                             \
    );                                                \
    tmp;                                              \
})

#define PROGMEM_FAR  __attribute__((section(".fini7")))

so that it would be easier to address this memory, kind of like

#include <avr/farpgmspace.h>

const unsigned short tuxfar[0x400] PROGMEM_FAR ={

As I understand, avr/pgmspace.h is a macro.

It contains macros, among other things. avr/pgmspace.h
Just create a library called farpgmspace and include it where you need it.

Hello everybody,
I buy a display with a capacitive touchscreen, i try to use myGLCD.drawBitmap, using PROGMEM and load my image on Flash, without SD/card.

I look my image on display, i want to change the screeen background (with another image) when I press with a touch on the screen.

For example like principal menu and under menu.

Have you some ideas?
Thanks
Francesco Noto