Author Topic: Fixed: My charlyplex seems crashing - problem with char-array -> Low Mem  (Read 4362 times)

bb

  • Newbie
  • *
  • Posts: 9
hi!
i started out with the basic charlyplex example and extended it further and further. but very quickly i ran into funny problems. patterns going out of whack. multiplexed letters not looking right etc. i continued simplifying the code because i thought i had a problem with pointers and function-calling, which just moved the funk somewhere else.


i called my local C-guru and he cannot find any fault.


the latest version actually seems to crash in the third iteration of the loop o_0


can anyone please look at this code and tell me how to debug this?
Code: [Select]



void setup() {               
  // initialize the digital pin as an output.


}


// the loop routine runs over and over again forever:
void loop() { 
repeatski:   
    //should spell HAI, then go blank
    Letter ( "x  xx  xxxxxx  xx  x", 500);
    Letter ( " xx x  xx  xxxxxx  x", 500);
    Letter ( " xxx  x   x   x  xxx", 500);
    Letter ( "                    ", 1000);
   
   //should turn each LED on once
    Letter ( "x                   ", 500);
    Letter ( " x                  ", 500);
    Letter ( "  x                 ", 500);
    Letter ( "   x                ", 500);
    Letter ( "    x               ", 500);
    Letter ( "     x              ", 500);
    Letter ( "      x             ", 500);
    Letter ( "       x            ", 500);
    Letter ( "        x           ", 500);
    Letter ( "         x          ", 500);
    Letter ( "          x         ", 500);
    Letter ( "           x        ", 500);
    Letter ( "            x       ", 500);
    Letter ( "             x      ", 500);
    Letter ( "              x     ", 500);
    Letter ( "               x    ", 500);
    Letter ( "                x   ", 500);
    Letter ( "                 x  ", 500);
    Letter ( "                  x ", 500);
    Letter ( "                   x", 500);


//shut down matrix and wait so i can see a pattern
LEDoff();
delay(2000);


goto repeatski;
}


void Letter ( char disp[25], long duration ) {
 int steptime  = 1;
 int tick      = 0;
 
redo:
 //see if we need to do all this again or if we are done
  if (duration <= 20) {return;} //20 because there are 20 LEDs. prevents duration running negative.
  tick      = 0;
 
 //run through displaying the matrix once as fast as possible
 if (disp[ 0] != ' ') {  LEDon(0, 4); delay(steptime); tick++;}
 if (disp[ 1] != ' ') {  LEDon(0, 3); delay(steptime); tick++;}
 if (disp[ 2] != ' ') {  LEDon(0, 2); delay(steptime); tick++;}
 if (disp[ 3] != ' ') {  LEDon(0, 1); delay(steptime); tick++;}
 if (disp[ 4] != ' ') {  LEDon(1, 4); delay(steptime); tick++;}
 if (disp[ 5] != ' ') {  LEDon(1, 3); delay(steptime); tick++;}
 if (disp[ 6] != ' ') {  LEDon(1, 2); delay(steptime); tick++;}
 if (disp[ 7] != ' ') {  LEDon(1, 0); delay(steptime); tick++;}
 if (disp[ 8] != ' ') {  LEDon(2, 4); delay(steptime); tick++;}
 if (disp[ 9] != ' ') {  LEDon(2, 3); delay(steptime); tick++;}
 if (disp[10] != ' ') {  LEDon(2, 1); delay(steptime); tick++;}
 if (disp[11] != ' ') {  LEDon(2, 0); delay(steptime); tick++;}
 if (disp[12] != ' ') {  LEDon(3, 4); delay(steptime); tick++;}
 if (disp[13] != ' ') {  LEDon(3, 2); delay(steptime); tick++;}
 if (disp[14] != ' ') {  LEDon(3, 1); delay(steptime); tick++;}
 if (disp[15] != ' ') {  LEDon(3, 0); delay(steptime); tick++;}
 if (disp[16] != ' ') {  LEDon(4, 3); delay(steptime); tick++;}
 if (disp[17] != ' ') {  LEDon(4, 2); delay(steptime); tick++;}
 if (disp[18] != ' ') {  LEDon(4, 1); delay(steptime); tick++;}
 if (disp[19] != ' ') {  LEDon(4, 0); delay(steptime); tick++;}
 //done, now turn matrix off so we don't leave any residue pixel on
 LEDoff();
 
 //if no LED was on, tick will be zero. then recursion cannot be used, so just sleep for the requested duration and be done
 if (tick == 0) {
   delay(duration);
   return;
 }
 else { //otherwise reduce the requested duration by the number of ticks already done
   duration = duration - (tick * steptime);
  // Letter(disp, duration);
  goto redo;
   return;
 }
}


void LEDon(int vin, int gnd) {
  pinMode(0, INPUT);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
//  pinMode(5, INPUT);
 
  pinMode(vin, OUTPUT);   
  pinMode(gnd, OUTPUT);
  digitalWrite(vin, HIGH);
  digitalWrite(gnd, LOW);
}


void LEDoff() {
//original code
/*  pinMode(0, INPUT);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT); */


//alternative - did not fix the problem
  for (int i = 0 ; i < 5 ; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW); 
  }


}


« Last Edit: May 03, 2013, 10:10:27 am by bb »

semicolo

  • Full Member
  • ***
  • Posts: 137
The loop() function will automatically loop, you don't need the goto.

You should keep the original code in the ledon/off, set all the pins as inputs not low outputs (the difference is the pin don't sink/source any current when set as inputs).

Maybe try to change the goto in the Letter function by a while loop.

Looks like you were using recursion before, don't do that on a memory limited device like a MCU

Try commenting out some of your Letter calls, if it runs better the string constants somehow overrun the memory and you'd need to switch to something else, bitmasks for example.

bb

  • Newbie
  • *
  • Posts: 9
Thank you. I will look into this :)

kamots

  • Newbie
  • *
  • Posts: 13
I'd suggest also using the F() wrapper around the text constants in each of the Letter function calls. This will also save some memory but use some more flash space.

bb

  • Newbie
  • *
  • Posts: 9
i read a bit about the F() wrapper and it sounds good. but it does not work:


Code: [Select]
    Letter ( F("x  xx  xxxxxx  xx  x"), 500); ->
Charlieplex:11: error: cannot convert 'fstr_t*' to 'char*' for argument '1' to 'void Letter(char*, long int)'


looks like whatever the F-wrapper spits out is not the right type for my function to digest :(
->
Code: [Select]
void Letter ( char disp[25], long duration ) {


one of the pages that i read said that simple arduino coding quickly became advanced. ya. i can second that.

ssross

  • Newbie
  • *
  • Posts: 3
You are likely overrunning the program memory, you have (if I counted right) 24, 21 character string which will use 504 bytes of the 512 available.  The system probably needs more the the 8 bytes left to do its work.


There are a couple of ways to fix this.  One that has already been suggested is to use the F() macro.  Another would be to use bits instead of bytes to store the on/off flags.


The F() macro does two things for you; changes a linker flag so the string lands in the flash memory instead of ram **, and it casts the type to fstr_t* so you can create functions to handle it either way.   If the strings are stored in flash you have to handle them differently, you can not access them directly (Harvard architecture) so you need to use pgm_read_byte(...) to access each byte.  Change Letter() to take fstr_t*disp instead of char disp[25], and instead of  disp[3], use pgm_read_byte(&disp[3]).  And of course call Letter with Letter(F("..."),500).  //warning, I haven't tested this so some adjustments may be needed//   I would probably create an accessor function to make less typing.


Code: [Select]
bool not_space(fstr_t * disp, int idx) {
    return pgm_read_byte(&disp[idx]) != ' ';
}

if (not_space(disp, 3) {  LEDon(0, 1); delay(steptime); tick++;}



Doing this with bits takes more drastic changes. You need 3 bytes per line instead of 21, and they probably won't be stored in ram since they are constants in the calling parameters.  There are many ways to work this but to keep it simple you could just pass three individual bytes


Code: [Select]
void Letter ( byte b1, byte b2, byte b3, long duration ) {
      if (b1 & B10000000) { ......}
      if (b1 & B01000000) {.......}
}
Letter (B10011001, B11111001 B10010000, 500); // first 20 bits used + 4 unused




** actually I think it is always in the flash, F() sets it so that it is not automatically copied to ram at startup.


bb

  • Newbie
  • *
  • Posts: 9
WHOOT!
works exactly as you predicted!
now i just need to understand what i did and impove on it.
my guess is that i'd be happier coding this in assembler than in C. so many detours for a blinkenlight?


here's the complete code if someone fancies to copy it :)
Thank you all!


Well, my letter-stencils are not done yet but i am too tired to get this done right. i'd rather do it some time else.
Code: [Select]
void setup() {               
  // initialize the digital pin as an output.


}


// the loop routine runs over and over again forever:
void loop() { 
  LEDcheck(100);
 
    //should spell HAI, then go blank
    Letter ( F("x  xx  xxxxxx  xx  x"), 500);
    Letter ( F(" xx x  xx  xxxxxx  x"), 500);
    Letter ( F(" xxx  x   x   x  xxx"), 500);
    Letter ( F("                    "), 1000);
   
   //should turn each LED on once
    Letter ( F("x                   "), 500);
    Letter ( F(" x                  "), 500);
    Letter ( F("  x                 "), 500);
    Letter ( F("   x                "), 500);
    Letter ( F("    x               "), 500);
    Letter ( F("     x              "), 500);
    Letter ( F("      x             "), 500);
    Letter ( F("       x            "), 500);
    Letter ( F("        x           "), 500);
    Letter ( F("         x          "), 500);
    Letter ( F("          x         "), 500);
    Letter ( F("           x        "), 500);
    Letter ( F("            x       "), 500);
    Letter ( F("             x      "), 500);
    Letter ( F("              x     "), 500);
    Letter ( F("               x    "), 500);
    Letter ( F("                x   "), 500);
    Letter ( F("                 x  "), 500);
    Letter ( F("                  x "), 500);
    Letter ( F("                   x"), 500);


//shut down matrix and wait so i can see a pattern
LEDoff();
delay(2000);


  char st[30]     = "abcdefghijklmnopqrstuvwxyz";
  int duration    = 1000;
  int increase    = 500;
  int number;
  for (number = 0; number < 29; number = number + 1) {
                                 // 1...2...3...4...5...
    if (st[number] == 'a') {Letter ( F(" xx x  xx  xxxxxx  x") , duration);}
    if (st[number] == 'b') {Letter ( F("xxx x  xxxx x  xxxx ") , duration);}
    if (st[number] == 'c') {Letter ( F(" xx x  xx   x  x xx ") , duration);}
    if (st[number] == 'd') {Letter ( F("xxx x  xx  xx  xxxx ") , duration);}
    if (st[number] == 'e') {Letter ( F("xxxxx   xxx x   xxxx") , duration);}
    if (st[number] == 'f') {Letter ( F("xxxxx   xxx x   x   ") , duration);}
    if (st[number] == 'g') {Letter ( F(" xx x  xx   x x  xxx") , duration);}
    if (st[number] == 'h') {Letter ( F("x  xx  xxxxxx  xx  x") , duration);}
    if (st[number] == 'i') {Letter ( F(" xxx  x   x   x  xxx") , duration);}
    if (st[number] == 'j') {Letter ( F(" xxx  x   x x x  xx ") , duration);}
    if (st[number] == 'k') {Letter ( F("x  xx x xx  x x x  x") , duration);}
    if (st[number] == 'l') {Letter ( F("x   x   x   x   xxxx") , duration);}
    if (st[number] == 'm') {Letter ( F("x  xxxxxxxxxx  xx  x") , duration);}
    if (st[number] == 'n') {Letter ( F("x  xxx xxx xx xxx  x") , duration);}
    if (st[number] == 'o') {Letter ( F(" xx x  xx  xx  x xx ") , duration);}
    if (st[number] == 'p') {Letter ( F("xxx x  xx  xxxx x   ") , duration);}
   
    if (st[number] == 'q') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'r') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 's') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 't') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'u') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'v') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'w') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'x') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'y') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == 'z') {Letter ( F("x x  x xx x  x xx x ") , duration);}
    if (st[number] == ' ') {Letter ( F("                    ") , duration);}
  }
  duration = duration + increase;
 
}


bool not_space(fstr_t * disp, int idx) {
    return pgm_read_byte(&disp[idx]) != ' ';
}


void Letter ( fstr_t * disp, long duration ) {
 int steptime  = 1;
 int tick      = 0;
 
redo:
 //see if we need to do all this again or if we are done
  if (duration <= 20) {return;} //20 because there are 20 LEDs. prevents duration running negative.
  tick      = 0;
 
 //run through displaying the matrix once as fast as possible
 if (not_space(disp,  0)) {  LEDon(0, 4); delay(steptime); tick++;}
 if (not_space(disp,  1)) {  LEDon(0, 3); delay(steptime); tick++;}
 if (not_space(disp,  2)) {  LEDon(0, 2); delay(steptime); tick++;}
 if (not_space(disp,  3)) {  LEDon(0, 1); delay(steptime); tick++;}
 if (not_space(disp,  4)) {  LEDon(1, 4); delay(steptime); tick++;}
 if (not_space(disp,  5)) {  LEDon(1, 3); delay(steptime); tick++;}
 if (not_space(disp,  6)) {  LEDon(1, 2); delay(steptime); tick++;}
 if (not_space(disp,  7)) {  LEDon(1, 0); delay(steptime); tick++;}
 if (not_space(disp,  8)) {  LEDon(2, 4); delay(steptime); tick++;}
 if (not_space(disp,  9)) {  LEDon(2, 3); delay(steptime); tick++;}
 if (not_space(disp, 10)) {  LEDon(2, 1); delay(steptime); tick++;}
 if (not_space(disp, 11)) {  LEDon(2, 0); delay(steptime); tick++;}
 if (not_space(disp, 12)) {  LEDon(3, 4); delay(steptime); tick++;}
 if (not_space(disp, 13)) {  LEDon(3, 2); delay(steptime); tick++;}
 if (not_space(disp, 14)) {  LEDon(3, 1); delay(steptime); tick++;}
 if (not_space(disp, 15)) {  LEDon(3, 0); delay(steptime); tick++;}
 if (not_space(disp, 16)) {  LEDon(4, 3); delay(steptime); tick++;}
 if (not_space(disp, 17)) {  LEDon(4, 2); delay(steptime); tick++;}
 if (not_space(disp, 18)) {  LEDon(4, 1); delay(steptime); tick++;}
 if (not_space(disp, 19)) {  LEDon(4, 0); delay(steptime); tick++;}
 //done, now turn matrix off so we don't leave any residue pixel on
 LEDoff();
 
 //if no LED was on, tick will be zero. then recursion cannot be used, so just sleep for the requested duration and be done
 if (tick == 0) {
   delay(duration);
   return;
 }
 else { //otherwise reduce the requested duration by the number of ticks already done
   duration = duration - (tick * steptime);
  // Letter(disp, duration);
  goto redo;
   return;
 }
}


void LEDon(int vin, int gnd) {
  pinMode(0, INPUT);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
//  pinMode(5, INPUT);
 
  pinMode(vin, OUTPUT);   
  pinMode(gnd, OUTPUT);
  digitalWrite(vin, HIGH);
  digitalWrite(gnd, LOW);
}


void LEDoff() {
  for (int i = 0 ; i < 5 ; i++) {
    pinMode(i, INPUT);
  }
}


//the example program in a function to see if the thing is still running at all
void LEDcheck (int duration) {
  LEDon(0, 1);
  delay(duration);
  LEDon(0, 2);
  delay(duration);
  LEDon(0, 3);
  delay(duration);
  LEDon(0, 4);
  delay(duration);
  LEDon(1, 0);
  delay(duration);
  LEDon(1, 2);
  delay(duration);
  LEDon(1, 3);
  delay(duration);
  LEDon(1, 4);
  delay(duration);
  LEDon(2, 0);
  delay(duration);
  LEDon(2, 1);
  delay(duration);
  LEDon(2, 3);
  delay(duration);
  LEDon(2, 4);
  delay(duration);
  LEDon(3, 0);
  delay(duration);
  LEDon(3, 1);
  delay(duration);
  LEDon(3, 2);
  delay(duration);
  LEDon(3, 4);
  delay(duration);
  LEDon(4, 0);
  delay(duration);
  LEDon(4, 1);
  delay(duration);
  LEDon(4, 2);
  delay(duration);
  LEDon(4, 3);
  delay(duration); 
  LEDoff();}