CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

const array on strings : Exception in module PCH.DLL !!!!!!!

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
franckcl



Joined: 12 Sep 2003
Posts: 32
Location: France (Paris)

View user's profile Send private message

const array on strings : Exception in module PCH.DLL !!!!!!!
PostPosted: Mon Dec 15, 2003 6:53 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Dec 15, 2003 12:41 pm     Reply with quote

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)

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 2:35 am     Reply with quote

Ok, thank you for your quick reply
Franck
Ttelmah
Guest







PostPosted: Tue Dec 16, 2003 4:49 am     Reply with quote

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)

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 6:54 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Tue Dec 16, 2003 7:14 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 7:18 am     Reply with quote

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)

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 8:00 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Tue Dec 16, 2003 9:43 am     Reply with quote

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)

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 10:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Dec 16, 2003 5:02 pm     Reply with quote

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++;
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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