-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SCPI commands list in flash (PROGMEM) on AVR #60
Comments
I know this limitation, but I don't know, how to handle this in pure c. It is possible to have full table in PROGMEM and have RAM buffer for one item. Then while iterating over commad list, every command list item is coppied to RAM buffer and evaluated as usual. This can save some space, but I'm not able to do this. If you can produce some working modification and way how to compile it and verify it (toolchain/ide/project), I will be happy. I can also add |
Here are some more hints: So
Type of Redefine some variables and fields to be in I can't simulate it, so I will not do it blindfolded. If you give me some more hints, options for AVR-GCC, or so, I can do more. |
You can now change |
Thanks. I will try to do the rest by myself using your tips. I will post here about the progress. |
I forked your project and created avr_progmem branch. By now, I created two commits:
It is slightly different to support only first 64K of program memory compared to the support of all memory (for example, AVR Mega 2560 has 256K of program memory). This is because AVR is using 16-bit pointers. Also, there is some overhead when you work with the full memory. So, my idea is first to add support only for 64K progmem, and I did it with these commits. To use first 64K of progmem for command list you must set BTW I found and fixed small bug with I tested the code on Arduino platform. You can download Arduino IDE and compile test-arduino example for yourself, but to be able to test it you will need one of the Arduino boards (I tested on Arduino Mega 2560). To compile test-arduino under Arduino IDE you need to execute build-arduino-library.py first (more about this script below) than open test-arduino.ino sketch in Arduino IDE and press Verify button. Unfortunately, there are some general quirks when you compile the code under Arduino IDE, especially when you use external libraries like scpi-parser. Because of that, I wrote the script called build-arduino-library.py to build Arduino compatible library from scpi-parser source code. It will build arduino library and copy it to the standard place for the arduino libraries (for example, on my Windows machine it is in C:\Users\Martin\Documents\Arduino\libraries) so Arduino sketches can use it. I'm running this script every time I change something in scpi-parser and in scpi_user_config.h located in test-arduino. There is no way you can set define variables in Arduino IDE so I need to place my define's in scpi_user_config.h and include it with the library. I also modify config.h on the fly when creating library for Arduino so that scpi_user_config.h is always included. Here is screenshot of running the test-arduino with It is using 2164 bytes of dynamic memory. And here is when It is using 2706 bytes. |
Nice! |
I added support for the full program memory, here is the commit: To support, not only first 64K, but full program memory there are some (minor) complications. TLDR; there is a question at the end :) This is how SCPI commands are normally defined:
If we want scpi_commands array to be inside program memory, we can just add PROGMEM in scpi_commands declaration:
And this is how
(Field context->param_list.cmd_s is added as temporary storage in dynamic memory for the found command.) But, command pattern strings ("MEASure:VOLTage:DC?" and "CONFigure:VOLTage:DC") will not be stored in PROGMEM. To store pattern strings in program memory we must add PROGMEM specification for those strings too:
And here is how
(Field context->param_list.cmd_pattern_s is added as temporary storage in dynamic memory for the found command pattern.) Now, both scpi_commands array and all the patterns strings are stored in progmem. But, pointers are 16-bit so you can only address first 64K. There is a way to get 32-bit (actually 24-bit) address of variable stored in program memory by using function We can have a partial solution where scpi_commands array can be anywhere in the program memory, but pattern strings can only be inside first 64K (please read the code comments for the explanations):
And here is how
To put everything anywhere in program memory space we need to do something like this (again, please read the code comments for the explanations):
And here is the implementation
Now, the question is do you want to add all these changes in the scpi parser? I want blame you if you find it too specific (or even ugly) to add it. Another possible solution, which will solve my problem, is to give a user of the library a way to implemenent his own version of
Of course, With this solution, you could still include test-arduino in the scpi parser examples with the custom implementation of |
Wow, it is very interesting, but I have currently not much time to incorporate so big change. I have just few things. Are there any drawbacks to leave it under 64k? Or the linker is not intelligent much and can place progmem section over this boundary? Is it possible to add struct _scpi_command_progmem_t {
const PROGMEM char * pattern;
scpi_command_callback_t callback;
#if USE_COMMAND_TAGS
int32_t tag;
#endif /* USE_COMMAND_TAGS */
};
typedef struct _scpi_command_progmem_t PROGMEM scpi_command_progmem_t; So you can leave command list as it was in original source but with I don't like dividing command list to two more arrays, because this will cause big problems. If this is really needed, you can read somethink about x-macro https://en.wikipedia.org/wiki/X_Macro and automate generation of all lists so it is not possible to make a mistake. I'm using X-macro in this file |
Linker will use program memory under 64k until we full this region. If our static data is bigger than 64K then it will use the memory above 64K (and pointers will overflow without warning). In my case, I need to store lots of static data like fonts, bitmaps, etc... so it is possible that at the end I will need more than 64K. Maybe I could put SCPI commands definition under 64K and other data above (still, I need to learn how to do that).
No, this is not possible. You can only place global const variables in PROGMEM section and you need to initialize those variables at the compile time.
Actually, in my example test-arduino I was using something like x-macro (although I didn't know it is called x-macro). If you take a look on this file: https://github.com/mvladic/scpi-parser/blob/avr_progmem/examples/test-arduino/scpi-def.cpp. you will find the following (for the sake of brevity I removed some parts):
So, you only need to define one array. (I forgot to I just learned that you actually don't need this trick. You can declare commands array like before by using PSTR macro:
Now, both scpi_commands array and command patterns will be stored in program memory. Still, for the full memory access we will need x-macro.
BTW I would like to store error messages in program memory also ;) What do you think of idea that user could provide implementation of |
Sorry, I didn't look into the source. I just read the comment. So it is much nicer with this. I have played little bit with Arduino IDE and it seems, that your previous solution is the only one saving some RAM.
So I will think about some API for |
How much of trouble is to support SCPI commands list in PROGMEM on AVR? Usually, there is not much SRAM on these microcontrollers (in my case 8K) and my SCPI commands list is taking a lots of it and soon it will became unsustainable :(
BTW We are using your SCPI parser on this hobby project:
http://www.eevblog.com/forum/projects/diy-programmable-dual-channel-bench-psu-0-50v3a/
Once more, thanks for your excellent parser!
The text was updated successfully, but these errors were encountered: