Functions Pointers, Arrays, PROGMEM - Oh My

I got a problem that has me pulling my hair out trying to resolve. It is with an array of function points I am trying to put into program memory. Here is what I have (parts have been left out to reduce the total size)

void StatusHome()
{
	lcd.print(F("Home"));
}

void StatusSim()
{
	lcd.print(F("Sim"));
}

void StatusManual()
{
	lcd.print(F("Manual"));
}

void StatusDark()
{
	lcd.print(F("Dark"));
}

void StatusOff()
{
	lcd.print(F("Off"));
}


typedef void (*ShowStatusFunction)();

const ShowStatusFunction StatusFuncArray[] PROGMEM =
{
	StatusHome,
	StatusSim,
	StatusManual,
	StatusDark,
	StatusOff
};

/************************************************************************************************/

void disp_status(int8_t Status)
{
	lcd.setCursor(0, 0);
	StatusFuncArray[Status]();
}

This causes the script to crash. However, if I use...

StatusFuncArray[0]();

It works perfectly. However, I think this might also be a fluke. I have been playing around with pgm_read_ptr and just haven't found the right combination to get it to work correctly. Any suggestions on how this is suppose to be done?

See: http://gammon.com.au/callbacks

Particularly near the bottom of the page.

How much SRAM are you going to save keeping a few pointers out? Is it really worth the hassle?

PaulS:
How much SRAM are you going to save keeping a few pointers out? Is it really worth the hassle?

This is only a sample of the actual code. There are a lot more functions in the final code so the memory saving can be significant, especially since I am already really tight on RAM as is.

There are a lot more functions in the final code so the memory saving can be significant, especially since I am already really tight on RAM as is.

Without seeing your code, I find that hard to believe. I suspect that there are other things you could do to save more memory.

In any case, you can't call a function whose address is in PROGMEM as though its address was in SRAM. You have to fetch the address from PROGMEM, and then call the function at that address.

Thanks. That does show exactly what I needed. I did try that before though and it didn't work. I am developing in Atmel Studio 6.2 and when I compiled, it reported the array needed to be a const (no problem doing that) and 'Error 1 expression cannot be used as a function' on

((ShowStatusFunction)pgm_read_word(&StatusFuncArray[Status])();

Just to check it out, I was able to successfully compile, upload, and run the sketch using the Arduino IDE though. So there is something different in the compile options I need to sort out.

Edit: Duh - Forgot a parenthesis

@Nick: Good explanation of callbacks. The const that is needed, at least on 1.5.7, is:

const GeneralFunction PROGMEM doActionsArray [] =
 {
 doAction0,
 doAction1,
 doAction2,
 };

Damnit I keep forgetting that. It is new in 1.5.x.

// array of function pointers
const GeneralFunction doActionsArray [] PROGMEM =
 {
 doAction0,
 doAction1,
 doAction2,
 };

Make it const and put PROGMEM at the end for safety.

As for the Atmel Studio issue, I'll have to try to reproduce that.

That was my error. I left off a parenthesis. Added it in and it compiled and worked perfectly.

Ach, you had me going for a minute there. I fired up my old Windows PC, got Atmel studio going, and couldn't reproduce your problem. :slight_smile: