|
|
View previous topic :: View next topic |
Author |
Message |
Torello
Joined: 29 Sep 2006 Posts: 120
|
String initialization |
Posted: Tue Jan 13, 2009 2:31 pm |
|
|
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
|
|
Posted: Tue Jan 13, 2009 2:57 pm |
|
|
..
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
|
|
Posted: Tue Jan 13, 2009 3:08 pm |
|
|
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
|
|
Posted: Tue Jan 13, 2009 3:19 pm |
|
|
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
|
Constants and strings storing in eeprom to save code ROM |
Posted: Fri Feb 20, 2009 6:31 pm |
|
|
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
|
|
Posted: Fri Feb 20, 2009 7:27 pm |
|
|
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
|
|
Posted: Fri Feb 20, 2009 11:17 pm |
|
|
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
|
|
Posted: Fri Feb 20, 2009 11:26 pm |
|
|
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
|
|
Posted: Fri Feb 20, 2009 11:40 pm |
|
|
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
|
|
Posted: Wed Feb 25, 2009 9:41 am |
|
|
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
|
|
Posted: Wed Feb 25, 2009 10:03 am |
|
|
I just noticed you talking about the VB program. I've got a copy of it.
string2rom2.exe |
|
|
|
|
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
|