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.

[quote author=Nick Gammon link=topic=272202.msg1918473#msg1918473 date=1413164286] See: http://gammon.com.au/callbacks

Particularly near the bottom of the page. [/quote]

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.

[quote author=Nick Gammon link=topic=272202.msg1918552#msg1918552 date=1413172325] As for the Atmel Studio issue, I'll have to try to reproduce that. [/quote]

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. :)