Pages: 1 [2] 3   Go Down
Author Topic: Call functions numerically with pointers  (Read 1726 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

nilton61, I used 9600 because I've known the serial monitor to crash when it receives large volumes of data. Your last example isn't using pgm_read_word, perhaps this is the problem.

Nick, accessing the compiled code is useful, how do you do that? Seems the optimiser is overstepping its responsibilities if it makes code work that would otherwise fail! Your code compiled fine for me. Packaging it into a macro and implementing it in my example gives the following, which now also works!

Code:
typedef void (* myFunction) ();
PROGMEM myFunction FunctionArray[] = {FuncA, FuncB, FuncC};
#define CallF(Num) ((myFunction) pgm_read_word (&FunctionArray [Num])) ()

byte Global;

void setup(){
  Serial.begin(115200);
 
  Global = 1;
  byte Local = 1;
  // Local = Global; // THIS NO LONGER SCREWS EVERYTHING UP
 
  // Global and Local display as expected:
  Serial.print("Global = ");
  Serial.println(Global);
  Serial.print("Local = ");
  Serial.println(Local);
 
  // These work fine:
  CallF(0);
  CallF(1);
  CallF(2);
 
  // These now work too!
  CallF(Local); // Calls FuncB
  CallF(Global); // Calls FuncB
 
  // For good measure so does this:
  for(byte a = 0; a <= 2; a++)
  {
    CallF(a);
  }
}

void loop(){}

void FuncA(){
  Serial.println("Function A");
}

void FuncB(){
  Serial.println("Function B");
}

void FuncC(){
  Serial.println("Function C");
}

Thanks for the advice!
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As an aside, yes I'm using PROGMEM because I want the potential to handle much larger arrays of functions, and because storing constants in RAM just seems wrong to me!
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick, accessing the compiled code is useful, how do you do that?

http://www.gammon.com.au/forum/?id=12153#info1
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Helsingborg, Sweden
Offline Offline
God Member
*****
Karma: 24
Posts: 589
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So everything  allocated with the PROGMEM macro must be retrieved with pgm_read_xxxxx()?

I read this:
Quote
GCC has a special keyword, __attribute__ that is used to attach different attributes to things such as function declarations, variables, and types. This keyword is followed by an attribute specification in double parentheses. In AVR GCC, there is a special attribute called progmem. This attribute is use on data declarations, and tells the compiler to place the data in the Program Memory (Flash).

AVR-Libc provides a simple macro PROGMEM that is defined as the attribute syntax of GCC with the progmem attribute. This macro was created as a convenience to the end user, as we will see below. The PROGMEM macro is defined in the <avr/pgmspace.h> system header file.
here:http://www.atmel.no/webdoc/AVRLibcReferenceManual/pgmspace_1pgmspace_introduction.html

A few pages down it says this:
Quote
Now that your data resides in the Program Space, your code to access (read) the data will no longer work. The code that gets generated will retrieve the data that is located at the address of the mydata array, plus offsets indexed by the i and j variables. However, the final address that is calculated where to the retrieve the data points to the Data Space! Not the Program Space where the data is actually located. It is likely that you will be retrieving some garbage. The problem is that AVR GCC does not intrinsically know that the data resides in the Program Space.
http://www.atmel.no/webdoc/AVRLibcReferenceManual/pgmspace_1pgmspace_data.html

Any reason why the compiler isnt aware of its own __attribute__ keyword?
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I believe C++ can distinguish types but not attributes.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So everything  allocated with the PROGMEM macro must be retrieved with pgm_read_xxxxx()?

It is in a different memory space, so, yes.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suspect in this case the attribute is applied by the linker rather than the compiler, in which case it would be reasonable for the compiler to be ignorant of its implications.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the help everyone.

Part of what I'm hoping to do with this code is to move the functionality out of my Arduino projects and into an external '.h' include file. More on this here:
http://forum.arduino.cc/index.php?topic=201954.msg1488368#msg1488368

However when I try and move this line into my include file:

Code:
PROGMEM myFunction FunctionArray[] = {FuncA, FuncB, FuncC};

The compiler complains:

Code:
error: 'PROGMEM' does not name a type

Anyone know what might be causing this? My guess is that it's caused be a difference in the way Arduino code and C are handled, but I don't know how to 'translate' the above line to make it C-friendly.
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Post code that demonstrates this. For example, zip up the whole project and attach that to a post.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Helsingborg, Sweden
Offline Offline
God Member
*****
Karma: 24
Posts: 589
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

your progmen.h file should look like this:

Code:
#include <arduino.h>
typedef void (* myFunction) ();
void FuncA(void);
void FuncB(void);
void FuncC(void);
PROGMEM myFunction Farr[] PROGMEM  = {FuncA, FuncB, FuncC};
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a zip file that demonstrates the problem. If you unzip it at the root of your C drive it should work. The main file is this:

Code:
//------------------------------------------------------------
// Option A: Set up locally: WORKS
typedef void (* myFunction) ();
PROGMEM myFunction Farr[] = {FuncA, FuncB, FuncC};
#define CallF(Num) ((myFunction) pgm_read_word (&Farr [Num])) ()

// Option B: Set up using external include - DOESN'T WORK
//#include "C:\Arduino\IncludeTest\Includes\Include.h"
//------------------------------------------------------------

byte Global;

void setup(){
  Serial.begin(115200);
 
  Global = 1;
  byte Local = 1;
 
  // Global and Local display as expected:
  Serial.print("Global = ");
  Serial.println(Global);
  Serial.print("Local = ");
  Serial.println(Local);
 
  // These work fine:
  CallF(0);
  CallF(1);
  CallF(2);
 
  // These now work too!
  CallF(Local); // Calls FuncB
  CallF(Global); // Calls FuncB
 
  // For good measure so does this:
  for(byte a = 0; a <= 2; a++)
  {
    CallF(a);
  }
}

void loop(){}

void FuncA(){
  Serial.println("Function A");
}

void FuncB(){
  Serial.println("Function B");
}

void FuncC(){
  Serial.println("Function C");
}

And the include file is this:

Code:
#include <arduino.h>

typedef void (* myFunction) ();

void FuncA(void);
void FuncB(void);
void FuncC(void);

PROGMEM myFunction Farr[] PROGMEM  = {FuncA, FuncB, FuncC};

If you comment out the lines under 'option A' and uncomment 'option B', it won't compile. This is the problem I'm trying to solve.

* Arduino.zip (1.13 KB - downloaded 4 times.)
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Why the lengthy path to the include? Put the Include.h file in the same folder as the .ino file. Then this compiles:

Code:
#define CallF(Num) ((myFunction) pgm_read_word (&Farr [Num])) ()
#include "Include.h"

...
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Offline Offline
Jr. Member
**
Karma: 0
Posts: 59
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I wanted to avoid that if possible. If it's in the same folder as the rest of the Arduino code, the IDE will open it, ignore changes to it, and save over it. It's a similar problem to the one discussed in the other thread I mentioned.

The best solution there was to use an alternate editor, with only some of the files open. But if there's a way to keep compatibility with the Arduino IDE and compile it in its current location, that would be even better.
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Make a library then.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19334
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Or edit the .h file in the IDE. What's the big deal with that?
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Pages: 1 [2] 3   Go Up
Jump to: