Can only use less than 21K of 32K Flash Memory Arduino Uno

Hello Everyone,

I am using a Seedstudio 2.8 TFT touch shield v2.0 with the mini sd card and the TFT and TouchShield libraries provided through the wiki page for the device. I am specifically using the bitmap example as the basis to my program. I have created several bitmaps to use as menu screens and stored them on a micro sd card and everything was working fine. I was adding several if statements to allow for navigation between menus and ran into a problem. The basic example program "tftbmp" ,when compiled, uses 17596 of the 32256 available. As I added more code to my program I found that once I hit about 21000 the UNO becomes very unstable and unusable. Most times it will load the first bitmap image but if you go to touch a button to navigate to the next the Uno will reset. Sometimes you can navigate a screen or two and then it just locks up until I manually reset it. Othertimes it won't even initialize the sd card or the display will just flash off an on resetting constantly. If I remove a few lines of code to reduce the file size under about 21K then everything works fine. I removed the Serial debugger parts of my program which allowed me to add several more if statements for screen navigation but I still need to add about 5k of programming to incorporate the remainder of the functionality of my program.

My intention is a graphical interface for a bluetooth attached ELM327 interface for my vehicle with an integrated nitrous controller which uses the Throttle position, rpm and speed data from the vehicles data port and a track computer that will calculate 0-60 and 1/4 mile times. I have all of that already working fine with a 16x2 lcd but would like to have a more consumer looking display and the touch screen eliminates having to have buttons. I know the easy way would be to use a mega but I want to keep the device small and within the arduino uno footprint. I also could just make crude menus using the draw commands but the bitmaps look much better.

What I don't understand is why I can't use the other 10K of my on board flash on the UNO. Here is my program that causes problems with the Serial debugger lines added back (size 21770). :

Thank you for any assistance. Code to follow...

#include <SD.h>
#include <SPI.h>
#include "TFTv2.h"
#include <stdint.h>
#include <TouchScreen.h>

File bmpFile;
//screen number-screen name-bmp file name
//1  HOME NIRTOUS OFF     home.bmp
//2  HOME NIRTOUS ON      homeblue.bmp
//3  TRACK COMPUTER APPS  trkcomp.bmp
//4  ZERO TO 60 APP       zero60.bmp
//5  1/8 MILE APP         18mile.bmp
//6  1/4 MILE APP         14mile.bmp
//7  NITROUS ON           nitron.bmp
//8  NITROUS OFF          nitroff.bmp
//9  NITROUS SETTINGS     nitroset.bmp
//10  TPS WOT CALIBRATE   wotcalb.bmp
//11  RPM N20 ON SET      rpmonset.bmp
//12  RPM N20 OFF SET     rpmofset.bmp
//13  OBDII DATA          getdata.bmp
//14  LIVE obdii DATA     livedata.bmp

unsigned char saved_spimode;
int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;

#define chipSelect 4

//set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

int imagedrawn = 0;
int buttonpress = 0;
int nitrous = 0;
int firstpress = 0;

#define TS_MINX 116*2
#define TS_MAXX 890*2
#define TS_MINY 83*2
#define TS_MAXY 913*2

TouchScreen ts = TouchScreen(XP, YP, XM, YM); //init TouchScreen port pins

void setup()
{
  Tft.TFTinit();  //init TFT library
  pinMode(11,INPUT);
  pinMode(12,INPUT);
  pinMode(13,INPUT);
  TFT_CS_HIGH;
  pinMode(chipSelect,OUTPUT);
  digitalWrite(chipSelect,HIGH);

  Serial.begin(9600);
  SPI.begin(); 
  Tft.TFTinit();
  //SPI.setClockDivider(SPI_CLOCK_DIV4);
  //SDcard_info();
  /**/
  DDRB |= 0x04;
  card.init(SPI_FULL_SPEED,chipSelect);//SPI_QUARTER_SPEED   SPI_HALF_SPEED, SPI_FULL_SPEED,
  if(!SD.begin(chipSelect))//SPI_QUARTER_SPEED,
  { //53 is used as chip select pin
    Serial.println("failed!");
    while(1);
  }
  Serial.println("SD OK!");
}

void loop()
{
  Serial.print("Nitrous:");
  Serial.print(nitrous);
  Serial.print(", ");
  Serial.print("Button:");
  Serial.print(buttonpress);
  Serial.print(", ");
  Serial.print("Screen:");
  Serial.println(imagedrawn);
  buttonpress = 0;
  //Serial.print(buttonpress);
  
//DRAW HOME SCREEN ONCE 
  if(imagedrawn <= 0){ //LINES CONTAINED IN THE "IF" STATEMENT DRAW AN IMAGE FROM THE SD CARD
    bmpFile = SD.open("home.bmp");
    if (! bmpReadHeader(bmpFile)) { 
      Serial.println("bad bmp");
      return;
    }
    bmpdraw(bmpFile, 0, 0);
    bmpFile.close();
    imagedrawn = 1;
  }
    
  //GET TOUCH COORDINATE
  Point p = ts.getPoint();   
  p.x = map(p.x, TS_MINX, TS_MAXX, 0, 240);
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, 320);  
  if (p.z > __PRESURE) {
     Serial.print("X = "); Serial.print(p.x);
     Serial.print("\tY = "); Serial.println(p.y);
  }
  //DETERMINE ACTION FROM COORDINATE
  if (p.x >= 10 && p.x <= 230 && p.y >= 10 && p.y <= 310 && imagedrawn == 1)
  {
    buttonpress = 100; //exit home screen
  }  
  if (p.x >= 120 && p.x <= 180 && p.y >= 20 && p.y <= 120)
  {
    Serial.println("NITROUS ON/OFF");
    buttonpress = 5;
  }
   if (p.x >= 190 && p.x <= 233 && p.y >= 4 && p.y <= 75)
  {
    Serial.println("NEXT");
    buttonpress = 4;
  }
   if (p.x >= 190 && p.x <= 233 && p.y >= 85 && p.y <= 150)
  {
    Serial.println("HOME/RETURN");
    buttonpress = 3;
  }
   if (p.x >= 190 && p.x <= 233 && p.y >= 175 && p.y <= 235)
  {
    Serial.println("SELECT");
    buttonpress = 2;
  }
   if (p.x >= 190 && p.x <= 233 && p.y >= 240 && p.y <= 311)
  {
    Serial.println("PREVIOUS");
    buttonpress = 1;
  }
   
   if (imagedrawn == 1 && buttonpress == 100 && firstpress == 1){
    displaybmp(1); //track comp
    imagedrawn = 3;
  }
  
  if (imagedrawn == 3 && buttonpress == 4 && nitrous == 0){
    displaybmp(2); //nitrous off
    imagedrawn = 8;
  }
  
  if (imagedrawn == 3 && buttonpress == 4 && nitrous == 1){
    displaybmp(3); //nitrous on
    imagedrawn = 8;
  }
  
  if (imagedrawn == 3 && buttonpress == 2){
    displaybmp(5); //0-60
    imagedrawn = 4;
  }
  
  if (imagedrawn == 4 && buttonpress == 3){
    displaybmp(1); //track comp
    imagedrawn = 3;
  }
  
  if (imagedrawn == 4 && buttonpress == 4){
    displaybmp(6); //1/4mile
    imagedrawn = 5;
  }
  
  if (imagedrawn == 5 && buttonpress == 3){
    displaybmp(1); //track comp
    imagedrawn = 3;
  }
  
  if (imagedrawn == 5 && buttonpress == 4){
    displaybmp(5); //0-60
    imagedrawn = 4;
  }
  
  if (imagedrawn == 5 && buttonpress == 3){
    displaybmp(1); //track comp
    imagedrawn = 3;
  }
  
  if (imagedrawn == 8 && buttonpress == 3 && nitrous == 0){
    displaybmp(0); //nitrous off home
    imagedrawn = 1;
  }
  if (imagedrawn == 8 && buttonpress == 3 && nitrous == 1){
    displaybmp(4); //nitrous on home
    imagedrawn = 1;
  }

  if (imagedrawn == 8 && buttonpress == 4){
    displaybmp(1);
    imagedrawn = 3;
  }

  if (imagedrawn == 3 && buttonpress == 3 && nitrous == 0){
    displaybmp(0); //nitrous off home
    imagedrawn = 1;
  }
   
   if (imagedrawn == 3 && buttonpress == 3 && nitrous == 1){
    displaybmp(4); //nitrous on home
    imagedrawn = 1;
  }
  
  if (imagedrawn == 8 && buttonpress == 5 && nitrous == 0){
    displaybmp(3);
    imagedrawn = 8;
    nitrous = 1;
  }
  if (imagedrawn == 8 && buttonpress == 5 && nitrous == 1){
    displaybmp(2);
    imagedrawn = 8;
    nitrous = 0;
  }
  delay(50);
  firstpress = 1;
}


void displaybmp(int i)
{
    char bmpfiles[][18]=
  {
    "home.bmp","trkcomp.bmp","nitroff.bmp","nitron.bmp","homeblue.bmp","zero60.bmp","14mile.bmp"
  };
    Serial.println(bmpfiles[i]);
    bmpFile = SD.open(bmpfiles[i]);
//    if (! bmpFile) 
//    {
//      Serial.println("didnt find image:");
//      Serial.println(bmpfiles[i]);
//      while (1);
//    }
//  
    if (! bmpReadHeader(bmpFile)) { 
      Serial.println("bad bmp");
      return;
    }
    bmpdraw(bmpFile, 0, 0);
    bmpFile.close();
    buttonpress = 0;
}

/*********************************************/
// This procedure reads a bitmap and draws it to the screen
// its sped up by reading many pixels worth of data at a time
// instead of just one pixel at a time. increading the buffer takes
// more RAM but makes the drawing a little faster. 20 pixels' worth
// is probably a good place


#define BUFFPIXEL 20

void bmpdraw(File f, int x, int y) 
{
  bmpFile.seek(bmpImageoffset);

  uint32_t time = millis();
  uint16_t p;
  uint8_t g, b;
  int i, j;

  uint8_t sdbuffer[3 * BUFFPIXEL];  // 3 * pixels to buffer
  uint8_t buffidx = 3*BUFFPIXEL;


  for (i=0; i< bmpHeight; i++) 
  {

    for (j=0; j<bmpWidth; j++) 
    {
      // read more pixels
      if (buffidx >= 3*BUFFPIXEL) 
      {
        bmpFile.read(sdbuffer, 3*BUFFPIXEL);
        buffidx = 0;
      }

      // convert pixel from 888 to 565
      b = sdbuffer[buffidx++];     // blue
      g = sdbuffer[buffidx++];     // green
      p = sdbuffer[buffidx++];     // red

      p >>= 3;
      p <<= 6;

      g >>= 2;
      p |= g;
      p <<= 5;

      b >>= 3;
      p |= b;

      // write out the 16 bits of color
      Tft.sendData(p);
    }
  }
  Serial.print(millis() - time, DEC);
  Serial.println(" ms");
}

boolean bmpReadHeader(File f) {
  // read header
  uint32_t tmp;

  if (read16(f) != 0x4D42) {
    // magic bytes missing
    return false;
  }

  // read file size
  tmp = read32(f);  
  Serial.print("size 0x"); 
  Serial.println(tmp, HEX);

  // read and ignore creator bytes
  read32(f);

  bmpImageoffset = read32(f);  
  Serial.print("offset "); 
  Serial.println(bmpImageoffset, DEC);

  // read DIB header
  tmp = read32(f);
  Serial.print("header size "); 
  Serial.println(tmp, DEC);
  bmpWidth = read32(f);
  bmpHeight = read32(f);


  if (read16(f) != 1)
    return false;

  bmpDepth = read16(f);
  Serial.print("bitdepth "); 
  Serial.println(bmpDepth, DEC);

  if (read32(f) != 0) {
    // compression not supported!
    return false;
  }

  Serial.print("compression "); 
  Serial.println(tmp, DEC);

  return true;
}

/*********************************************/
// These read data from the SD card file and convert them to big endian 
// (the data is stored in little endian format!)

// LITTLE ENDIAN!
uint16_t read16(File f) 
{
  uint16_t d;
  uint8_t b;
  b = f.read();
  d = f.read();
  d <<= 8;
  d |= b;
  return d;
}

// LITTLE ENDIAN!
uint32_t read32(File f) 
{
  uint32_t d;
  uint16_t b;

  b = read16(f);
  d = read16(f);
  d <<= 16;
  d |= b;
  return d;
}

I don't know anything about some of those libraries, but it could well be that the SRAM is the limiting factor (2048 bytes on an Uno, of which maybe a couple hundred are used by the Arduino core software).

This library will give an idea of how much SRAM is available:
http://playground.arduino.cc/Code/AvailableMemory

Thanks for the reply. I ordered a new UNO and a MEGA so I can trouble shoot. By the way the SD library uses the most memory at about 14k. I will update when I get the other units.

By the way the SD library uses the most memory at about 14k

You STILL don't get it. The Arduino has 3 kinds of memory. You REALLY need to get it clear which of the 3 kinds of memory you are referring to, and which you are running out of.