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 CCS Technical Support

String initialization

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



Joined: 29 Sep 2006
Posts: 120

View user's profile Send private message

String initialization
PostPosted: Tue Jan 13, 2009 2:31 pm     Reply with quote

Hi,

Using StrCpy or sprintf to load short strings seems to be quite a waste of program memory.

- sprintf(Ts,"0123456789"); uses 92 bytes (18LF4685)
- strcpy(Ts,"0123456789"); uses 90 bytes

The "cheapest" with 40 bytes is:
-ts[0]='0'; ts[1]='1'; ts[2]='3'; ts[3]='4'; ts[4]='5';
ts[0]='6'; ts[1]='7'; ts[2]='8'; ts[3]='9';

Has anyone created a macro that can easy the typing burden of the above choice? Or has ccs a built in feature for this?

Regards,
Edwin
Torello



Joined: 29 Sep 2006
Posts: 120

View user's profile Send private message

PostPosted: Tue Jan 13, 2009 2:57 pm     Reply with quote

..
I can think of:

Code:
#define dStrLoad5(Dest,a,b,c,d,e) {Dest[0]=a; Dest[1]=b; Dest[2]=c; Dest[3]=d; Dest[4]=e;}


Which can be used:
Code:
dStrLoad5(ts,'E','d','w','i','n');



That does compile as requested. But now how to get rid of the quotes and comma's and make it variable of length....
Ttelmah
Guest







PostPosted: Tue Jan 13, 2009 3:08 pm     Reply with quote

You don't say what processor.
Key is to understand that constant strings are stored as a complete _program_, which returns the specified data. The program header is attached to each string. If you have (say) 20 strings, then it is vastly more efficient, to simply declare _one_ multi-dimensional array containing all the required strings (limited to 256 bytes on 16 processors), and then strcpy the individual lines out of this. Downside is that there will be gaps if the strings are different lengths, re-introducing waste. You can declare a single long string (again with the limit on 16 chips), using your own delimiter character, and just copy the data from this.

Best Wishes
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Tue Jan 13, 2009 3:19 pm     Reply with quote

There is another way of creating an array of pointers to constant strings:
Code:

UCHAR const Str_table[][*] = {
       "DIAGNOSE",         
       "KEYS",       
       "SETUP",           
       "SYNC",   
       "TEST COMM.",     
       "TEST ENDPOINT", 
       "HANDLE USERS",   
       };


  strcpy(ts, Str_table[5]);


_________________
Every solution has a problem.
mathewss



Joined: 07 Aug 2008
Posts: 17

View user's profile Send private message

Constants and strings storing in eeprom to save code ROM
PostPosted: Fri Feb 20, 2009 6:31 pm     Reply with quote

I have been trying to figure out a good way to keep all of my constant stings in ROM to free up as much program memory as possible.

This does not seem to work.

I am using pcml on an PIC16F877a chip

# ../ccsc +V
PCM compiler version 4.081;10/8/2008

Code:
char const Str_table[][*] = {
       "DIAGNOSE",
       "KEYS",
       "SETUP",
       "SYNC",
       "TEST COMM.",
       "TEST ENDPOINT",
       "HANDLE USERS",
       };

gives me the error
Expression must evaluate to a constant

I noticed that a recent release 4.085 talks about some fixes in using ROM? Am i hitting a bug?

I have lots of strings I want to get out of my almost exhausted program ROM into the eeprom.

I have found some very interesting posts to a vb program that will generate rom statements but the program is not available anymore.

http://www.ccsinfo.com/forum/viewtopic.php?t=17342&highlight=int8+rom+array

As an example i want to do the following this is not tested code just a sample.
Some of my strings are printf format strings that I would expect I would need to copy into a local ram string buffer prior to sending to printf();

I have been over these forums and found a few topics but all seem to have examples and methods that seem to not compile or don't actually put data in eeprom or are not complete with a full working example.

Any help would be appreciated.

Code:

char startup_msg[][]={
 "Hello\r\n",
 "World\r\n"
}

void send_hello_world() {
  int i;
  for(i=0;i<2;i++)
    send_usb(startup_msg[i]);
}

/* note that send_usb takes 1 char at a time i expect the compiler to deal with this or I will end up calling the function for every character if needed */
void send_usb(int8 thebyte)
{
 /* some code to talk to my usb hardware not relivent to this example */
}



PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Feb 20, 2009 7:27 pm     Reply with quote

I think it's highly variable whether this feature works or not.
By playing with it for some time, I was able to get the following
output in PCH from vs. 4.068. It didn't work in vs. 4.086.
It didn't work in PCM. Even so, I had to expand out all the strings
so they were the same length. There may well be some other
syntax that works with the current version. I just don't have any
more time to play with it now.
Quote:

DIAGNOSE
KEYS
SETUP
SYNC
TEST COMM.
TEST ENDPOINT
HANDLE USERS


Code:
#include <18F452.h>
#device PASS_STRINGS=IN_RAM
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define NUM_STRINGS 7

char const Str_table[NUM_STRINGS][14] = {
"DIAGNOSE     ",
"KEYS         ",
"SETUP        ",
"SYNC         ",
"TEST COMM.   ",
"TEST ENDPOINT",
"HANDLE USERS ",
};

void display_string(char *ptr)
{
printf("%s\n", ptr);
}

//======================================
void main()
{
int8 i;

for(i = 0; i < NUM_STRINGS; i++)
    display_string(Str_table[i]); 
   
while(1);
}
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Feb 20, 2009 11:17 pm     Reply with quote

mathewss,
I have just compiled my code in V4.086 and it passes compilation with no problem.
You need to add a line to the beginning of code to allow passing strings to RAM:
#device PASS_STRINGS=IN_RAM
I notice PCM Programmer has included it in his sample code.
The difference between your code and mine may be the fact that you are using PCM with PIC16F877A and I am using PCH with PIC18F6527 processor.

Code:

#define NUM_STRINGS 7
char const Str_table[NUM_STRINGS][14] = {
"DIAGNOSE     ",
"KEYS         ",
"SETUP        ",
"SYNC         ",
"TEST COMM.   ",
"TEST ENDPOINT",
"HANDLE USERS ",
};

PCM Programmer's suggestion for creating fixed length records definitely works. It requires paying a price in code size if many of the strings are short compared to record length.

Regards,
Noam
_________________
Every solution has a problem.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Feb 20, 2009 11:26 pm     Reply with quote

Compiling is one thing, but working is another. It has to do both.
Try running it in MPLAB simulator or in hardware before declaring that it
works with any particular version. There is more testing and research
to be done, but I just ran out of time today.
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Feb 20, 2009 11:40 pm     Reply with quote

PCM Programmer,
You are right.
For real code I am using V4.079. Up to that version it IS working.
The reason for not using newer versions is that something changed in V4.080, which made one of my project stop working and I do not have the time to research the undocumented "improvements" put in by CCS.
I will give it a try in V4.086.

Regards
Noam
_________________
Every solution has a problem.
Jim Hearne



Joined: 22 Dec 2003
Posts: 109
Location: West Sussex, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Feb 25, 2009 9:41 am     Reply with quote

I ended up using #rom to put lots of strings into memory as nothing else worked or used too much ROM

Code:

#define STRING_ROM_ADDRESS 0x00010000
#define NUMBER_OF_LANGUAGES 3
#define STRING_ROM_SIZE_MAX 0xffff


#ROM STRING_ROM_ADDRESS ={
   //  English           Spanish             Portuguese
   " ",                 " ",                 " ",             //   0  // menu and data screens
   "% Post Bl'd",       "% Pos Prga",        "% Pós Bld",     //   1
   "12hr Clock",        "Reloj 12hr ",       "Relógio 12hr",  //   2
   "20mA Output",       "Salida 20mA",       "Saída 20mA",    //   3
   "24hr Clock",        "Reloj 24hr",        "Relógio 24hr",  //   4
   "4-20 Output",       "Salida 4-20",       "Saída 4-20",    //   5
   "4mA Output",        "Salida 4mA",        "Saída 4mA",     //   6
   "Accum Count",       "Cntdr de Fljo",     "Vazão Agua",    //   7
   "Accum Set",         "Set flujo Ac",      "Accum Set",     //   8
// 200 more here normally.
    "~" //end character

#define NUMBER_OF_STRINGS 9 // one more than last string above.


Then at startup create an index by looking for the nulls at the end of each string.

Code:
int16 string_offsets[NUMBER_OF_STRINGS][NUMBER_OF_LANGUAGES];

void create_message_index(void)
{
   int32 message_pointer=0;
   int16 number_nulls=0;
   int16 number_strings=0;
   int16 temp_value=0;
   int16 temp_start_addr=0;
   
   for(message_pointer=0; message_pointer<STRING_ROM_SIZE_MAX && number_strings<=NUMBER_OF_STRINGS; message_pointer++)
   {
      temp_value=read_program_eeprom(message_pointer+STRING_ROM_ADDRESS); // read program memory returns 16 bits but it's easier to just use the bottom 8
      temp_value &= 0x00ff;
      if((temp_value)==0) // scan for nulls after each string
      {
         string_offsets[number_strings][number_nulls]=temp_start_addr;
         temp_start_addr=message_pointer+1; // save current value plus one for next time.
         number_nulls++;
         if(number_nulls==NUMBER_OF_LANGUAGES)// got string for each language, increment number of messages.
         {
            number_nulls=0;
            number_strings++;
         }
      }
      else if(temp_value=='~')
         break;
   }
}


And copy the strings into a local buffer for sprintf or whatever using:

Code:
void copystring(int8 *dest,int8 msg)
{
   int32 copy_address=0;
   int16 copy_temp=0;
   int8 language=0;
   
   language=nvram.language; // get language
   if(language>NUMBER_OF_LANGUAGES) // range check
      language=0;
   
   if(msg>NUMBER_OF_STRINGS)
      msg=135; // if msg is out of range then use error as msg
   copy_address=STRING_ROM_ADDRESS+string_offsets[msg][language];
 
   do
   {
      copy_temp = read_program_eeprom(copy_address);
      copy_temp &= 0x00ff;
      *dest=(int8)copy_temp;
      dest++;
      copy_address++;
   }
   while(copy_temp!=0);

}


Example

Code:

copystring(text_buffer,2); // "12 hr clock"
printf(text_buffer);           // print it



These are code snippets so you'll need to change the rom address etc to match your pic but it works on a 18F6722 in PCW 4.086 and all previous versions i've tried.

Jim
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 25, 2009 10:03 am     Reply with quote

I just noticed you talking about the VB program. I've got a copy of it.
string2rom2.exe
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