Moving an array of function pointers to Flash

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a working menu system that uses an array of function pointers, but I would like to move it to flash to save RAM space.  I've tried using PROGMEM in various forms but can't seem to figure it out.

 


void (*Menus[9][4])() = {{RunMenuB1,RunMenuB2,RunMenuB3,RunMenuB4},
                {LearnMenuB1,LearnMenuB2,DoNothing,DoNothing},
                {StatusMenuB1,DoNothing,DoNothing,DoNothing},
                {DebugMenuB1,DebugSensorMenuB2,DebugSensorMenuB3,DoNothing},
                {DebugMenuB1,DebugCodeMenuB2,DebugCodeMenuB3,DoNothing},
                {DiagMenuB1,DiagSteerMenuB2,DiagSteerMenuB3,DiagSteerMenuB4},
                {DiagMenuB1,DiagThrottleMenuB2,DiagThrottleMenuB3,DiagThrottleMenuB4},
                {DiagMenuB1,DiagRCMenuB2,DoNothing,DoNothing},
                {CompleteMenu,CompleteMenu,CompleteMenu,CompleteMenu}};

And it's called with

Menus[CurrentMenu][Button]();           //run the selected function

 

The problem appears to be the use of void, where PROGMEM wants to see something besides void there.

 

Last Edited: Tue. Jan 31, 2017 - 02:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But to run the function you need to read the fn-ptr into a RAM var (pgm_read_word) and then call through that as the indirect call mechanism is by an ICALL and it needs the target address ultimately in Z.

(using phone so cannot post code example)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PS forgot to say that work with fn-ptr is much easier if you put all the complex syntax into a typedef at the start.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
PS forgot to say that work with fn-ptr is much easier if you put all the complex syntax into a typedef at the start.

 

That's interesting, the stuff I was reading in the Arduino forums was basically "don't bother with the typedef, just do it this way", so I changed it from the typedef I was originally using. frown

 

Ok, so you're saying I won't be able to place this array is Flash anyway?  That should be ok, this board is a SAMD21 and has 32K of RAM, I just wanted to be efficient.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The reason I say typedef is that if you have something like this:

typedef int (*fp_t) (char, long, long);

fp_t fp_array[2][3] = {
    { fn1, fn2, fn3 },
    { fn4, fn5, fn6 }
};

...

  fp_t callit;
  
  callit = fp_array[0][2];
  
  int retval = callit('Q', 12345, 0xBABEFACE);

then you later choose to change the function types to "int fn(char,int,long)" then it's little more than editing the one line typedef. If you do it with:

int (*fp_array[2][3])(char, long, long) = {
    { fn1, fn2, fn3 },
    { fn4, fn5, fn6 }
};

...

  int (*callit)(char, long, long);
  
  callit = fp_array[0][2];
  
  int retval = callit('Q', 12345, 0xBABEFACE);

you may find yourself editing this kind of "monstorous" syntax all over the shop. Doing it in typedef keeps all the "messy stuff" on one line.

 

As for putting the FP array in flash and accessing it, I see you posted in "Arduino" so I rather thought that might probably mean an ATmega328P or an ATmega2560 or something. For ARM I have no idea. But if it's a device with 32K (Cortex are like that - tons of RAM versus flash size - in fact usually *4 versus equivalent AVR) then why sweat it? Surely you aren't going to be running out of RAM for a few fn ptrs in the near future are you?

 

(now you've made me want to go and find out about how arm-gcc puts stuff in .rodata, I assume its just the application of "const"? That's the way it's done in most compilers. As ARM have linear address spaces then I would have thought the access to the fn ptr would be the same mem access whether it's located in RAM or ROM as they don't have differing access mechanism like the LDS/LPM distinction in AVR8.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I don't see running out of RAM anytime soon.  Even with 4 mission arrays (it's a rover), I think my RAM usage is still around 3K so far.  And fortunately my pointer array is all the same type, no mixing.  Well since it's working I'll leave it alone.

 

Thanks!

Last Edited: Tue. Jan 31, 2017 - 04:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't find anything definitive to say that "const" alone will put ARM data into .rodata which is a component of ".rom" in the linker script but I found this thread:

 

http://www.eevblog.com/forum/microcontrollers/what's-eating-my-ram-(atmel-sam-d11)/

 

interesting and it has contributions from Freaks regulars (both current and old).

Last Edited: Tue. Jan 31, 2017 - 05:10 PM