So everything allocated with the PROGMEM macro must be retrieved with pgm_read_xxxxx()?
I read this:
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.
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.
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.
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.
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:
//------------------------------------------------------------
// 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");
}
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.
I'm working on a program to automatically generate code, to support the code written in the IDE. It will be a huge time saver if it works, but it needs a method for including files without the IDE disrupting them.
paulrd:
it needs a method for including files without the IDE disrupting them.
The IDE only mucks about with the .INO source files. If you generate .CPP files the IDE leaves them alone and compiles them as they are. You need to have a .INO file of the same name as the sketch, but there's no restriction on how much or how little code it has in it and you can add as many separate .c, .cpp and .h files to the sketch as you want.
That would be great, but my experience is that the IDE opens all 3 of these file types in tabs when the project is opened, ignores changes to the original files, compiling instead the version that is open in the IDE, and then saves over the top of them when you save the project.
Am I missing something? Can you provide an example that allows an include file to be modified behind the scenes without the problems listed above?
Is using a library the only way? The drawback is that I'd need different include files for each program the library was used with, but perhaps I could achieve this with compiler directives and #defines in the Arduino code.
paulrd:
That would be great, but my experience is that the IDE opens all 3 of these file types in tabs when the project is opened, ignores changes to the original files, compiling instead the version that is open in the IDE, and then saves over the top of them when you save the project.
If you don't want to use the Arduino IDE to edit your files, you can either not use the IDE at all, or use it but configure an external editor and just use the IDE to perform the builds.
If you want to have some of your code edited within the IDE and some edited externally, putting the 'external' code in a library would achieve what you want. If you want to automate that part, perhaps you could give the externally generated 'library' the same name as the sketch file so that you don't need to deal with name collisions etc. One drawback of this is that although sketches can be stored in arbitrary sub-directories, libraries can only be stored at the top level of the libraries folder. So, for that scheme to work you'd need to restrict where users saved their sketches. I suspect a lot of people save their sketches in a flat directory structure so perhaps nobody will care in practice, but you need to be aware of it as an issue.