Troubles with PROGMEM and a large pokemon database

Hi,

I am building a hand held Pokemon IV calculator using an Arduino Uno, an LCD screen, a few buttons, and a potentiometer for use while playing the Pokemon RPG game line for the Nintendo DS.

For a little bit of background information on my project, Pokemon have six battle stats named HP, Attack, Defense, Special Attack, Special Defense, and Speed. All Pokemon also have hidden bonus stats to each stat category, called IVs. For example, a larger IV in Attack will ultimately lead to a Pokemon with a relatively strong Attack stat compared to others of the same type and level. I like to figure out what my hidden bonus stats are to see if a Pokemon will be relatively strong in a certain area before I go to the trouble of raising and training it properly to battle other players. My calculator asks for the shown stats as well as the name and nature of the Pokemon you wish calculate hidden IV stats for, and then prints out the hidden IV stats on the LCD screen.

In order to do this, I need to store a very large amount of data, the base stats on each Pokemon, and there are over 600 of them. I have gotten the program and calculator to work perfectly when I store only a select few Pokemon into the Arduino's memory, but when I attempt to put all 600+ in at the same time, I crash. I have identified the problem, and it is that I am overflowing my SRAM. By doing some online research, I discovered the path I need to travel to remedy the problem. I need to use a header file called <avr/pgmspace.h>: Program Space Utilities to store all of my data, the library of base stats for all 600+ Pokemon, in Flash rather than SRAM using PROGMEM commands.

Here is what the relevant section of my code looks like so far, starting with the declaration of my structs. I declare a struct named Pokemon that contains a char* and six unsigned integers. The char* is the Pokemons name, and the unsigned integers are the six base stats that I need for calculating my IVs. I then declare an array of these Pokemon structs named PokemonDatabase. I currently have it showing only a few Pokemon, but in reality it will be much much longer. The Pokemon I wish to select will be indexed by the potentiometer by using an analogRead command. Turning the potentiometer will scroll through the array and display the name of the Pokemon I am currently indexing. Currently the program prints out the first stat stored in the struct on the lcd screen rather than the name, as I was having troubles with getting the name to print out. (I had the name printing on the screen perfectly fine before I started messing with PROGMEM commands however). The three lines of code I was attempting to print the name with are commented out for the moment. Even still though, when I upload with the entire database of Pokemon rather than these select 16, the Arduino crashes immediately and in the same manner as when I was not using PROGMEM commands. I feel like despite my best efforts I am not correctly telling the Arduino to store this PokemonDatabase array of structs into Flash rather than SRAM. It works, allowing me to scroll through the first stat rather than the name, when I upload with a greatly shortened array though.

I am kind of new to C programming and the Arduino, and any help and/or advice would be greatly appreciated.

Thanks,
Matthew Weiss

#define NUMBER_OF_POKEMON 16
struct Pokemon {prog_char* NAME;
uint16_t BASEHP;
uint16_t BASEATTACK;
uint16_t BASEDEFENSE;
uint16_t BASESPATK;
uint16_t BASESPDEF;
uint16_t BASESPEED;};
Pokemon PokemonDatabase[NUMBER_OF_POKEMON+1] PROGMEM=
{{"Abomasnow",90,92,75,92,85,60},
{"Abra",25,20,15,105,55,90},
{"Absol",65,130,60,75,60,75},
{"Snorlax",160,110,65,65,110,30},
{"Yamask",38,30,85,55,65,30},
{"Yanma",65,65,45,75,45,95},
{"Yanmega",86,76,86,116,56,95},
{"Zangoose",73,115,60,60,60,90},
{"Zapdos",90,90,85,125,90,100},
{"Zebstrika",75,100,63,80,63,116},
{"Zekrom",100,150,120,120,100,90},
{"Zigzagoon",38,30,41,30,41,60},
{"Zoroark",60,105,60,120,60,105},
{"Zorua",40,65,40,80,40,65},
{"Zubat",40,45,35,30,40,55},
{"Zweilous",72,85,70,65,70,58},
{"END", 1, 1, 1, 1, 1, 1}};

void loop()
{
delay(BUTTONDEBOUNCETIME);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("IV Calculator");
lcd.setCursor(0,1);
lcd.print("by Matthew Weiss");
lastpushtime=millis();
while(!digitalRead(button1)){} //waiting to begin program with pressing of the enter button-----------
lastpushtime=millis();
delay(BUTTONDEBOUNCETIME);
//getting the pokemon -----------------------------------------------------------------------------------
lcd.clear();
lcd.setCursor(0,0);
lcd.print("select pokemon");
unsigned int pokemonindex;
while(!digitalRead(button1))
{
pokemonindex=analogRead(potinput)(NUMBER_OF_POKEMON)/1023;
lcd.setCursor(0,1);
// char buffer[32];
// char
thingtoprint=strcpy_P(buffer, (char*)pgm_read_word(&(PokemonDatabase[pokemonindex].NAME)));
// lcd.print(buffer[0]);
lcd.print(" ");
lcd.print(pgm_read_word(&PokemonDatabase[pokemonindex].BASEHP));
lcd.print(" ");
}
PokemonStats[0]=pgm_read_word(&PokemonDatabase[pokemonindex].BASEHP);
PokemonStats[1]=pgm_read_word(&PokemonDatabase[pokemonindex].BASEATTACK);
PokemonStats[2]=pgm_read_word(&PokemonDatabase[pokemonindex].BASEDEFENSE);
PokemonStats[3]=pgm_read_word(&PokemonDatabase[pokemonindex].BASESPATK);
PokemonStats[4]=pgm_read_word(&PokemonDatabase[pokemonindex].BASESPDEF);
PokemonStats[5]=pgm_read_word(&PokemonDatabase[pokemonindex].BASESPEED);
lastpushtime=millis();
delay(BUTTONDEBOUNCETIME);
..............the program continues from here asking the user to input various stats, and this has been working perfectly.

First off, please edit your post to put 'code' blocks around your code, using the '#' button.

Ah, well you are storing the names of your Pokemon still in flash memory.

You could try one of these

prog_char name_Abomasnow[] PROGMEM = "Abomasnow";

Pokemon PokemonDatabase[NUMBER_OF_POKEMON+1] PROGMEM=
{{name_Abomasnow,90,92,75,92,85,60}
...

I think you can also do this, but I've not tried it exactly.

Pokemon PokemonDatabase[NUMBER_OF_POKEMON+1] PROGMEM=
{{PSTR("Abomasnow"),90,92,75,92,85,60}
...

Maniac has the idea. As you have it now, you are putting your pointers to pokemon names in flash, but the names themselves will end up in RAM. It does get tricky getting strings within a structure to end up in flash. You may want to look at the tutorial and discussion here:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003

I got it working now!!!

I tried your second method first, but got a bunch of compiler errors, so I tried the first method and it worked perfectly. Thank you :slight_smile:

Sorry about the lacking of code boxes, it is my first time posting here and I didn't know about them.