Need Help in PROGMEM.

Hello guys. I would appreciate some help in optimizing my code. I developed an SMS-based LED Matrix Display using Arduino. Here's a link to the thread.
http://arduino.cc/forum/index.php/topic,126897.0.html

and here's the video: SMS-Based LED Matrix Display using Gizduino (version 2) - YouTube

I used a 8x32 LED Matrix Display back then. But now I'm developing the same project, only this time, i'm using a 8x64 LED Matrix Display.

I edited the code to apply the two Matrices, but I encountered problems when it displays the text messages. It shows text message 1 then displays random characters. I'm guessing this is a memory problem. any help? here's the new code:

#include "cmap.h"             // character map libarary
#include <SIM900.h>           // SIM900D library
#include <sms.h>              // SMS libarart
#include <SoftwareSerial.h>   // Software Serial Library
SMSGSM sms;
#define INTEN 6500 //scroll speed. 
                   //the higher the value, the slower the scroll

//-----------------LED MATRIX PINS------------------

#define CLK  5    // clock pin connected to digital pin 5
#define DAT  6    // Data pin connected to digital pin 6
#define STR  7    // Strobe pin connected to digital pin 7 
#define K0  A0    // Data 0 connected to analog pin 0
#define K1  A1    // Data 1 connected to analog pin 1
#define K2  A2    // Data 2 connected to analog pin 2
#define K3  A3    // Data 3 connected to analog pin 3
#define K4  8     // Data 4 connected to digital pin 8
#define K5  9     // Data 5 connected to digital pin 9
#define K6  10    // Data 6 connected to digital pin 10
#define K7  11    // Data 7 connected to digital pin 11

//-------------------GSM VARIABLES-----------------------

boolean MSG_RCVD    = false;            // no message recieved as initial value
const char regnum[] = "639177915470";   // admin number
const char passRx[] = "default#";       // holds password, must be 8 char only! and ends with #
char smsdata[160];                      // sms only accept 160 characters
char numberRx[20];                      // holds sender number
char *inbox[5];                         // holds text messages
int message_no;                         // message counter
int loop_count = 1;                     // loop count of messages
int inbox_no = -1;                      // inbox no index (starts at 0)
unsigned int d;                         // for INTEN and strobe


//-----------------LED MATRIX VARIABLES------------------

char Display_Ram[76];           // locates the the ASCII Character Map Display
char count;                             // counter for 	
unsigned char char_pointer = 0x00;      // character pointer for smsdata and LED_DATA arrays
unsigned char mask;                     // for masking the display 
unsigned char shift_counter;            // for scrolling the message

int pins[]  = { CLK, DAT, STR, K0,      // pins for LED Matrix
                K1, K2, K3, K4, K5, 
                K6, K7 };
int mask_data[]  = {0x80, 0x40, 0x20,  // mask for LED Matrix Display
                    0x10, 0x08, 0x04, 
                    0x02, 0x01};
                    
// unsigned int matrix_size = 64;                    
                    
void setup() 
{ 
  // ---------- serial setup ----------
  gsm.begin(4800);                       // initialize GSM
  pinsetup();                            // setup the pins for LED
}

void loop()
{
  Display();                             // call display
  shift();                               // shift from right to left
}

void pinsetup()                          // setup pins for display
{
  for (int x =0; x<=10; x++){            // all pins OUTPUT
    pinMode(pins[x], OUTPUT);     
  } 
  
  for (int y=3; y <=10; y++){            // K0-K7 HIGH
    digitalWrite(pins[y],HIGH);  
  }  

  for(d=0;d<64;d++){                     
    clock();
  }
  strobe();
  d = 0;
}

void checkSMS ()
// ---------- check if there is new message ----------
{
  int i;
  if(gsm.readSMS(smsdata, 160, numberRx, 20))
// read new message and store in smsdata and numberRx  
  {
    if (strncmp (numberRx, regnum, 11) == 0 && strncmp (smsdata, passRx, 8) == 0)
 // check if sender number and password is correct, then continue   
    {
      while (smsdata[i] != '\0')
        {
          smsdata[i] = smsdata[i+8];   // delete the password from the string
          i++;                 
        }
        sms.SendSMS("09177915470", "Message was Recieved");
        MSG_RCVD = true;               // confirm that new message is recieved
        loop_count++;                  // increment loop count
        store();                       // store new message in inbox array
    }
  }
}

void store()
{
  inbox_no++;                          // increment from -1
  if (inbox_no >= 5)                   // check if inbox is full
  {
    inbox_no = 0;                      // reset inbox_no
    inbox[0];                          // clear inbox from 0-4
    inbox[1]; 
    inbox[2];  
    inbox[3];  
    inbox[4];  
  }
  inbox[inbox_no] = strdup(smsdata);   // dump string into inbox number
}

void Display (void)                    // display the data to the LED Matrix
{
  int i = 0;
  for (i = 7; i >=0 ; i--)
  {
    mask = mask_data[i] ;
    scan();
    digitalWrite(pins[i],LOW);         // pin ON
    for(d=0;d<INTEN;d++){}
    digitalWrite(pins[i],HIGH);        // pin OFF
  }
}

void scan(void)
{
  int matrix_size = 64;
  for (count = matrix_size;count>(-1);count--){
    if ((Display_Ram[count] & mask) == mask)
      digitalWrite(DAT,LOW);           // data pin OFF
    else
      digitalWrite(DAT,HIGH);          // data pin ON
    clock();
  }
  strobe();
}

void clock(void){
  digitalWrite(CLK,HIGH);			// clock hi
  digitalWrite(CLK,LOW);		        // clock low
}

void strobe(void){
  digitalWrite(STR,HIGH);			// strobe hi
  digitalWrite(STR,LOW);			// strobe low
}

void shift(void)                                // Scroll display
{
  for (int val=0; val<74; val++)
  {
    Display_Ram[val] = Display_Ram[val+1];
  }
  
  shift_counter++;
  
  if(shift_counter == 6)
  {
    shift_counter = 0;
    load_data();                                 // call load_data
  }
}

void load_data(void)
{ 
  int counter1 = 0;
  int matrix_size = 64;
  char *LED_DATA = announcement(message_no);     // dump message to LED_DATA
  
  if(LED_DATA[char_pointer+1]  == '\0')          // If end of message
  {
    char_pointer = 0;                            // reset character pointer
    message_no++;                                // go to next message
  }
    
  for(counter1 = 0; counter1 < 5; counter1++)
  {
    Display_Ram[matrix_size + counter1] = pgm_read_byte(&(character_data[(LED_DATA[char_pointer] - 0x20)][counter1])); 
  // locate the appropriate character at the CMAP.H
  }
  
  Display_Ram[matrix_size + 10] = 00;	
  char_pointer++;
  
  if (message_no > loop_count)    // only check new messages when the message)no > loop_count
  { 
     checkSMS();                  // check for new message
     if (MSG_RCVD == false)       // if there are no new messages, continue loop
     {
       message_no = 0;            // continue loop from the start
     }
  MSG_RCVD = false;               // then declare no new messages
  }
  else if (message_no >= 7)       // if messages is 7 or above
  {
    message_no = 0;               // go back to first message
    checkSMS();                   // then check for new messages
  }
  
}

char *announcement(int message_no2)      // where the strings and text messages are stored
{
  char *LED_message[]={"    LCoES Announcements         ",    
                       "    Hello Letranites!           ",    
                              inbox[0]                   ,    
                              inbox[1]                   ,    
                              inbox[2]                   ,    
                              inbox[3]                   ,   
                              inbox[4]                   };   
  
  // FIXED MESSAGE 1 = LCOES ANNOUNCEMENTS
  // FIXED MESSAGE 2 = HELLO LETRANITES
  // INBOX 0 - 4 = TEXT MESSAGES
  
  return LED_message[message_no2];      // returns message index based from message no.
}

would really appreciate some help with PROGMEM. thanks! :smiley:

    inbox[0];                          // clear inbox from 0-4
    inbox[1]; 
    inbox[2];  
    inbox[3];  
    inbox[4];

These statements do nothing. Nothing is assigned to the array element. The [] operator returns a value that is not used.

What do you want to store in PROGMEM? You are aware that PROGMEM is read-only, right?

some tips -> use minimal datatypes, that always save memory.


int mask_data[] = {0x80, 0x40, 0x20, // mask for LED Matrix Display
0x10, 0x08, 0x04,
0x02, 0x01};

can be of the type uint8_t instead of int ==> saves 8 bytes

but you can calculate these even on the fly with:
#define MASK(n) (0x80 >> n)


int pins[] => uint8_t pins[]


for (int x =0; x<=10; x++)
for (uint8_t x =0; x<=10; x++)

d can be uint8_t too I think. uint8_t is one byte with the following range [0..255]


inbox[0]; // clear inbox from 0-4
inbox[1];
inbox[2];
inbox[3];
inbox[4];

These commands do nothing so they can be removed. Just setting the index to zero is enough.

PaulS:

    inbox[0];                          // clear inbox from 0-4

inbox[1];
    inbox[2]; 
    inbox[3]; 
    inbox[4];



These statements do nothing. Nothing is assigned to the array element. The [] operator returns a value that is not used.

What do you want to store in PROGMEM? You are aware that PROGMEM is read-only, right?

oh, yeah. good point. :smiley: i initially thought they erase inbox[0-4] but then, i remembered they dont. :)) i want to use PROGMEM to save up on RAM since my Arduino is only ATMEGA32. I've used PROGMEM in the original 8x32 matrix because it encountered similar problems.

Just setting the index to zero is enough.

Actually, it isn't because inbox is an array of pointers to dynamically allocated memory. If that memory is never freed, eventually, there will be no more memory available. If the 6th message is to be stored, whatever memory is currently being pointed to needs to be freed before the pointer is overwritten.

robtillaart:
#define MASK(n) (0x80 >> n)

i got a little bit confused about this. how can this be done? and is "uint8_t" same as unsigned int? haven't used that before.

thanks for the reply! :slight_smile: i'll go check it out.

In Arduno an int or unsigned int is 16 bits, the equivalent to int16_t or uint16_t accordingly.

An int (int16_t) can store -32767 to +32767. An unsigned int (uint16_t) can store 0 to 65535.

If you only need to store 0 to 255 then you can save 8 bits of memory by declaring more accurately as uint8_t as an 8 bit unsigned integer. If you need -127 to +127 then you can declare as int8_t.

It can help save some memory when you only have a couple of KB to play in.

(0x80 >> n) => read - << - Arduino Reference -

A quick look makes me think this is the only place where the mask is used so you can replace it

void Display (void)                    // display the data to the LED Matrix
{
  int i = 0;
  for (i = 7; i >=0 ; i--)
  {
    mask = 0x80 >> i ;
    scan();
    digitalWrite(pins[i],LOW);         // pin ON
    for(d=0;d<INTEN;d++){}
    digitalWrite(pins[i],HIGH);        // pin OFF
  }
}

and is "uint8_t" same as unsigned int?

uint8_t is an unsigned int of 8 bits a.k.a. byte
unsigned int is a unsigned int of 16 bits == uint16_t
There is also unsigned long == uint32_t

robtillaart:
(0x80 >> n) => read - << - Arduino Reference -

A quick look makes me think this is the only place where the mask is used so you can replace it

void Display (void)                    // display the data to the LED Matrix

{
 int i = 0;
 for (i = 7; i >=0 ; i--)
 {
   mask = 0x80 >> i ;
   scan();
   digitalWrite(pins[i],LOW);         // pin ON
   for(d=0;d<INTEN;d++){}
   digitalWrite(pins[i],HIGH);        // pin OFF
 }
}

i tried this out and it actually made the program larger. hehe. I'll edit out my ints with uint8_t. :slight_smile: hopefully it would make the code smaller. thanks again!

robtillaart:

    for(d=0;d<INTEN;d++){}

This doesn't look right. Am I missing something?

PeterH:

robtillaart:

    for(d=0;d<INTEN;d++){}

This doesn't look right. Am I missing something?

that's actually for the scroll speed. it just makes the scroll slower by adding FOR statements without any "do" conditions/instructions.

I can imagine the compiler optimizes this away. Does it really has the effect you describe?

maskinao:
that's actually for the scroll speed. it just makes the scroll slower by adding FOR statements without any "do" conditions/instructions.

I would have thought the delay would only be a few milliseconds, even supposing the compiler doesn't optimise that do-nothing code out. If you want the sketch to have a delay before the next statement, a call to delay() would be a more predictable way to achieve it.

The logic in load_data() for changing between messages is all screwy - it looks at the next character to see if its NULL,
then increments the message_no and resets char_pointer, but that means the last true character of the message is lost.

Also it fails to update LED_DATA when message_no changes so that it uses a character from the previous message
when this stepping has taken place.

I suggest drinking a caffeine containing drink and rewriting it carefully!