|
|
View previous topic :: View next topic |
Author |
Message |
franckcl
Joined: 12 Sep 2003 Posts: 32 Location: France (Paris)
|
const array on strings : Exception in module PCH.DLL !!!!!!! |
Posted: Mon Dec 15, 2003 6:53 am |
|
|
Hi,
Using PCH 3.174 With PIC18F6520 :
I would like to create an constant array of constant pointers on strings :
// -------- here is the strings :
const char C_USER[] = "LEVEL 1 USER";
const char C_OPER[] = "LEVEL 2 OPERATOR";
const char C_MAST[] = "LEVEL 2 MASTER";
// ------- And, here is my constant arrays :
const char * Menu1[3] ={&C_USER, &C_OPER, &C_MAST};
const char * Menu2[3] ={&C_OPER, &C_USER, &C_MAST};
When I compile this, I have an exception error : "Exception EInOutError in module PCH.DLL at 000B1474" and I have to restart PCW IDE !!!!
How to solve this problem ? I am using array of pointer into strings to decrease the code size (this is a little example of my code which is of course bigger)
Thanks
Franck (PARIS) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 15, 2003 12:41 pm |
|
|
You are trying to create pointers to constant strings.
CCS does not allow this.
On page 1 of the compiler manual (page 13 in Acrobat reader) it says:
Quote: | As an example of the limitations, the compilers will not permit
pointers to constant arrays. This is due to the separate code/data
segments in the PICmicroŽ MCU hardware and the inability to treat
ROM areas as data. |
Also, on page 63 of the manual (page 75 in the Acrobat reader) it says:
Quote: |
If the keyword CONST is used before the identifier, the identifier is
treated as a constant. Constants must have an initializer and may
not be changed at run-time. Pointers to constants are not permitted. |
|
|
|
franckcl
Joined: 12 Sep 2003 Posts: 32 Location: France (Paris)
|
|
Posted: Tue Dec 16, 2003 2:35 am |
|
|
Ok, thank you for your quick reply
Franck |
|
|
Ttelmah Guest
|
|
Posted: Tue Dec 16, 2003 4:49 am |
|
|
franckcl wrote: | Ok, thank you for your quick reply
Franck |
Worth adding some possible 'work arounds', depending on what you actually want to do.
The first is to remember that you can directly access program memory, in the flash based chip, using the 'read_program_eeprom' function. So (for instance), you can (using the #rom statement), generate a block of data at a location in memory, and then access this, using the address, and an 'offset', treating the offset to some extent, like a pointer.
You can also use the 'array address', in a somewhat similar way.
It is also worth 'being aware', of the cost (in ROM terms), of normal const arrays. When the system generates these, _each array_, has a 'header', containing the retrieval code attached. So if you declare two strings (as in your example), two retrieval routines are generated (this is done, because of the limitation with the standard (non flash) chips, on retrieving data rom the ROM, which makes it hard to handle arrays any significant distance from the code, hence it is easier to keep the retrieval code tightly 'associated' with each array. This though does impose a significant overhead when dealing with lots of small words, which may make it worth saving the space, by putting these together to form a single array, and adding your own 'seperator' characters, and 'addresses'.
Hence:
const char E_general[] = {
"Manual~Data~Setup~Alarms~Cal ~Wash ~Sample ~IP span~Zero~Timings~Clock~Language~High~XHigh~for ~"
"every ~secs~hours~mins~continuously~Cal Hi~"
};
Combined with a set of defined 'addresses', like:
#define M_MANUAL 0
#define M_DATA 7
#define M_SETUP 12
and an output routine that stops at (in the case of the table shown), 'tilde' characters, makes very much more efficient use of the ROM storage.
I also have a situation, with one system, where I have to handle multiple languages. Now the table of words/phrases for one language will happily fit in RAM, but all four will not. Hence the solution here, is to pre-allocate a RAM area to hold the table, and then (according to the language selected), copy a ROM language table into RAM, and generate pointers to the 'breaks' between the messages, while copying. This uses a similar table to the one shown above, and an array of pointers to the various messages.
A bit of 'ingenuity' is needed, to make both efficient use of the ROM/RAM, and easy to use code as well. A bit of 'non traditional' thinking is needed in this area, because of the limitations of the Hoffmann architecture used in the PIC...
Best Wishes |
|
|
franckcl
Joined: 12 Sep 2003 Posts: 32 Location: France (Paris)
|
|
Posted: Tue Dec 16, 2003 6:54 am |
|
|
Thanks a lot,
but if I had known that before to build my prototype, I would have taken another micro controller because I have a lot of strings to display in a LCD display !!
Thanks
Franck |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Dec 16, 2003 7:14 am |
|
|
It is not the fault of the microcontroller but rather your choice in compilers. The Microchip C18 compiler will do just what you want. There is a 30 day evaluation copy on their website if you want to try it out. |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Tue Dec 16, 2003 7:18 am |
|
|
You can still display strings on the LCD display without the need to use pointers. You will only need to re-structure your menu design scheme.
Post your code and maybe we can help you with it. |
|
|
franckcl
Joined: 12 Sep 2003 Posts: 32 Location: France (Paris)
|
|
Posted: Tue Dec 16, 2003 8:00 am |
|
|
Then, I have found a solution to replace the pointers. But I still have problem with the space taken in ROM by the constants.
I use 2 kind of string, one is for the menu and the other one is for events.
(This is just en example, because I have a total of 4500 characters to put in ROM)
1) For the menu (with 2 language : french and english)
(this is a very little example of my code)
//************************
// MAIN MENU
//************************
const char C_MAIN[10][2][19]={
{"Archivage evenemen", "Events log"} ,
{"Archivage extincti", "Extinction log"},
{"Reglage date/heure", "Set date/time"} ,
{"Archivage config" , "Setup log"},
{"Config generale" , "General setup"},
{"Config detection" , "Detection setup"},
{"Config extinction" , "Extinction setup"},
{"Version logiciel" , "Software version"},
{"Impression" , "Print"},
{"Contraste" , "Contrast"}
};
//****************************
// GENERAL SETUP MENU
//****************************
const char C_CONFIG_GEN[7][2][19]={
{"Arret sign sonores" , "Stop buzzer"},
{"Essais signalisati" , "Light test"},
{"Signal sonore test" , "Test buzzer"},
{"Nombre de RS.Rep" , "Number of RsRep"},
{"[spam] UT/RS.Rep" , "S.Buz UT/RsRep"},
{"[spam] RS.Rep/RS.Rep" , "S.Buz RsRep/RsRep"},
{"Delais avant rearm" , "Delay before reset"}
};
etc...
2) For the events :
const char C_EVT_RESET [2] [6]={"RESET" , "RESET" };
const char C_EVT_FEU_ZONE [2][11]={"FEU zone " , "FIRE area " };
const char C_EVT_PREALARME [2][16]={"Prealarme zone " , "Prealarm area" };
const char C_EVT_DER_DETECT [2][17]={"DER detect zone " , "DER detect area " };
etc....(50 events)
----------------------------------------------------------
For the menu, I use this code (I have a 2 lines LCD display) :
LCD_DisplayXY(1,1,C_MAIN[element][language]); --> COMPILER ERROR Bad expression syntax -1 is not 0.65535
LCD_DisplayXY(1,2,C_MAIN[element+1][language]); --> COMPILER ERROR Bad expression syntax -1 is not 0.65535
The function is declared as follow : LCD_DisplayXY(BYTE X,BYTE Y,char * S);
----------------------------------------------------------
For the events, I don't use a 3D array to preserve memory space, I use something like that:
char EventStr[21];
void EventToStr(BYTE Event)
{
Switch (Event)
{
case 0 : strcpy(EventStr,C_EVT_RESET [language]); break;
case 1 : strcpy(EventStr,C_EVT_FEU_ZONE [language]); break;
case 2 : strcpy(EventStr,C_EVT_PREALARME [language]); break;
case 3 : strcpy(EventStr,C_EVT_DER_DETECT[language]); break;
etc..
}
}
***********************************************************
My problem is :
1) the ROM space used by the compiler
2) THE COMPILER ERROR Bad expression syntax -1 is not 0.65535 on LCD_DisplayXY(1,1,C_MAIN[element][language]);
Thank you
Franck |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Dec 16, 2003 9:43 am |
|
|
Declaring the arrays in the way that you have will waste a lot of space unless each phrase is the same length. You might think about declaring each of the strings separately. Create an enum or use the #define to define an integer value for each of these strings. Think of this as being a pointer. Now you will need to create a function that accesses a string based on the simulated pointer (switch statement would work). This is basically the way you handled your events. |
|
|
franckcl
Joined: 12 Sep 2003 Posts: 32 Location: France (Paris)
|
|
Posted: Tue Dec 16, 2003 10:04 am |
|
|
The problem with the way I handled events is I use strcpy for each line :
Switch (Event)
{
case 0 : strcpy(EventStr,C_EVT_RESET [language]); break;
case 1 : strcpy(EventStr,C_EVT_FEU_ZONE [language]); break;
case 2 : strcpy(EventStr,C_EVT_PREALARME [language]); break;
case 3 : strcpy(EventStr,C_EVT_DER_DETECT[language]); break;
etc..
}
AND EACH "case x:" TAKES 42 BYTE !!!
Is there a solution by using a variable ?
Thanks |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Tue Dec 16, 2003 5:02 pm |
|
|
What if you use a loop for copying the strings? Will it be as big? I mean something like:
Code: |
char c;
int i=0;
while ((c=C_EVT_RESET [language][i])!='\0')
{
EventStr[i]=c;
i++;
}
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|