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

Storing strings in ROM
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

Storing strings in ROM
PostPosted: Tue Jan 21, 2014 2:45 pm     Reply with quote

Hello, this is my first post.
I am trying to display stored text on an LCD 2*16 char display.
The used chip is 16F628A.
The "flex-driver" is used for the lcd.
Code:

#include "flex_lcd.c"

void main() {

 char *strings[] =
{
 "Monday    01",
 "Saterday  02",
 "Noday     00",
 "Sunday    07" 
};


lcd_init();   
lcd_putc("Start");
delay_ms(1000);

{
int8 i;
//Access the above const pointers
 
  char *ptr;

for (i=0; i<4;i++)
{
   ptr = strings[i];
   printf(lcd_putc,"\f%s ", ptr);
   delay_ms(600);
}
   lcd_putc("\nEnd");
}

This code works but used up ram, so I changed:
char *strings[] =
to:
const char *strings[] =
This compiles fine but gives scrambled results on the lcd.
It has to do something with the pointer, but I cannot work it out.

Some help is appreciated.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jan 21, 2014 4:46 pm     Reply with quote

Here is one way to do it, just to get you going quickly. Use an
intermediate RAM buffer and strcpy the line into the buffer, then
call printf. I tested this in MPLAB simulator, so I removed the LCD
stuff, but you can put it back in.
Code:

#include <16F628A.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

//===============================

void main()
{

const char strings[4][13] =
{
 "Monday    01",
 "Saterday  02",
 "Noday     00",
 "Sunday    07" 
};

int8 i;
char buffer[13];
char *ptr;

for (i=0; i<4;i++)
  {
   strcpy(buffer, strings[i]);
   ptr = buffer;
   printf("\f%s ", ptr);
  }

}
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 1:49 am     Reply with quote

I'd suggest a search here on 'pointer to ROM'.
It is a small part of the PIC/CCS, that differs from 'normal' C.

Problem is that the PIC, unlike chips like the 8086 etc., has separate ROM/RAM data spaces (Harvard architecture). So there are two "address 0's", one in RAM, and one in ROM. Worse though, the more basic chips (yours included), don't actually have any instruction to allow you to directly read from ROM!. Because of this, you can't directly use a 'const', in quite the same way as data stored in RAM.
When you declare a 'const' (on these chips), the compiler actually generates a small program, that when called with an 'address', returns the byte required for this address. All done as program code, rather than a 'table' of data.

The strcpy function, is 'overloaded', and knows when it is called with a const as the source, how to deal with this, and can copy the data into RAM (allowing it then to be used as PCM_programmer shows).
There is also a CCS 'shortcut', that if you give a 'string' declared like this to a function expecting to receive a single character, the compiler will repeatedly call the function with each character in turn. This though only works with single strings, not an entry in an array.

On later chips that do have instructions to allow the program memory to be read, there are options to allow you to create pointers to this (still a separate memory space, so still slightly special code).

There is also though one more trick:
Code:

#include <16F628A.h>
#fuses INTRC_IO, NOWDT
#device PASS_STRINGS=IN_RAM
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

//===============================

void main()
{

   const char strings[4][13] =
   {
      "Monday    01",
      "Saturday  02",
      "Noday     00",
      "Sunday    07"
   };

   int8 i;

   for (i=0; i<4;i++)
   {
      printf("%s\n",strings[i]);
   }
   while (TRUE) ;
}


The option 'PASS_STRINGS=IN_RAM', tells the compiler that when you use a const string and access it, it should automatically copy it into a RAM buffer, so that pointer access can be used.

As for PCM_programmer's code, I've done the I/O to serial for demo purposes, not an LCD. Added a line feed as well for testing. Smile

This is efficient in RAM use, only copying characters as needed.

Have fun.
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 5:51 am     Reply with quote

Thanks Ttelmah,

Adjusted your code for output to lcd and added PASS_STRINGS=IN_RAM to the .h file.

Code:
#include <main.h>
#include "flex_lcd.c"

void main() {

const char *strings[4][13] =
{
 "Monday    01",
 "Saterday  02",
 "Noday     00",
 "Sunday    07" 
};


lcd_init();   
lcd_putc("Start");
delay_ms(1000);

{
static int8 i;
 
for (i=0; i<4;i++)
{
   printf(lcd_putc,"\f%s",strings[i]);
   delay_ms(2000);
}
   lcd_putc("\nEnd");
while(TRUE);
}
When running it starts fine, lcd shows, Start, Monday 01, but then jumps to Noday 00, so i++ increases 2 instead of 1?
After that the display is garbled, but ends with "End"

Changing i to a static made no changes.

Tried adding extra strings to test if i++ jumps by 2:

Code:
const char *strings[7][13] =
{
 "Monday    01",
 "x           ",
 "Saturday  02",
 "x           ",
 "Noday     00",
 "x           ",
 "Sunday    07"
 
};

but left the loop at:
Code:
for (i=0; i<4;i++)

The display order is now ok (Monday,Saturday,Noday,Sunday)

Any suggestions?
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 8:45 am     Reply with quote

Try printing out the actual value of 'i'.
As it stands you're making an assumption from a printout of something else.

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 10:06 am     Reply with quote

I'd also ask what compiler version you have?.

I tested with 5.016, and get:
Code:

Monday    01
Saturday  02
Noday     00
Sunday    07


exactly as expected....

You are also indirecting the pointer - wrong.

const char *strings[4][13] =

Extra '*' not wanted.....

Best Wishes
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 10:07 am     Reply with quote

Mike,


printf(lcd_putc,"%u",i);
results in 0123 on the lcd.

Maybe the lcd-flexdriver forces 2 strings on each call?
Could a NULL terminator be the solution?

Regards
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 10:42 am     Reply with quote

In 'C' ,'strings' MUST have a null terminator ! That's what 'tells' the program it is a 'string'.
If your message is 13 characters long, you must add 1 to the length( ie: string_data[14] ) and put a null (\0) as the 14th byte.

hth
jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 11:42 am     Reply with quote

His strings are 12 characters long. The compiler automatically inserts a
0x00 byte at the end of quoted string initialization text. The array row
length is 13 bytes, so it's fine and it's not a problem.

He needs to post his compiler version and his latest test program.
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 2:04 pm     Reply with quote

Hello,

I did a test with following strings:

const char *strings[4][2] =
{
"AA",

"BB",

"CC",

"DD"

};

Checked the ASM after compilation:

0010: RETLW 41
0011: RETLW 41
0012: RETLW 00
0013: RETLW 42
0014: RETLW 42
0015: RETLW 00
0016: RETLW 43
0017: RETLW 43
0018: RETLW 00
0019: RETLW 44
001A: RETLW 44
001B: RETLW 00

So PCM programmer is right, the nulls are inserted.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 22, 2014 2:25 pm     Reply with quote

acexbe wrote:
Hello,

I did a test with following strings:

const char *strings[4][2] =
{
"AA",

Why are you still using the asterisk '*' in front of the array ?
Ttelmah told you not to do that. Earlier in the thread he said:
Ttelmah wrote:

You are also indirecting the pointer - wrong.

const char *strings[4][13] =

Extra '*' not wanted.....


That means, remove the asterisk. Like this:
Code:
const char strings[4][13] =
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

PostPosted: Thu Jan 23, 2014 2:04 pm     Reply with quote

Thanks everyone for your help!
I tried the two solutions, see the final code below:
Code:

#include <16F628A.h>
#DEVICE PASS_STRINGS=IN_RAM
#use delay(internal=4000000)
#fuses NOWDT,INTRC_IO, NOPUT, NOPROTECT, BROWNOUT, NOMCLR, NOLVP, NOCPD


void main() {

const char strings[4][21] =
{
 "Message one     01B7",
 
 "Warning         0263",

 "System running  03DE",
 
 "Shutting down   04FF"
 
};


lcd_init();   
lcd_putc("Start");
delay_ms(1000);

{

 int8 i;
 
// Method one consumes 18% RAM and 26% ROM
//!  char buffer[21];
//! char *ptr;
//!
//! for (i=0; i<4;i++)
//!   {
//!    strcpy(buffer, strings[i]);
//!    ptr = buffer;
//!    //printf("\f%s ", ptr);
//!     printf(lcd_putc,"\f%s ",ptr);
//!     delay_ms(2000);
//!   }
 
 
// Method two consumes 8% RAM and 24% ROM
for (i=0; i<4;i++)
{
   printf(lcd_putc,"\f%s",strings[i]);
   delay_ms(2000);
   
}
   lcd_putc("\nEnd");
while(TRUE);
}

Sorry for the mixup before with the added * (copy/paste user error)

The used compiler version is 5.008, 5967
The programmer is an original serial ICD from microchip converted to a icd-S20.
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Jan 23, 2014 2:27 pm     Reply with quote

comment: interesting ,you've save 10% of RAM !

comment: You should put the delay_ms(1000); before the lcd_init() function.

LCD modules are very slow to powerup and get 'organized'. I use a delay_ms(500); and it has always worked.Depending on the make/mfr of the LCD you may run into the 'it worked before, now what's wrong' problem...

hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Thu Jan 23, 2014 2:33 pm     Reply with quote

As I said: "This is efficient in RAM use, only copying characters as needed."

With strcpy, you add the space for a RAM buffer as long as the string...

Best Wishes
acexbe



Joined: 21 Jan 2014
Posts: 6

View user's profile Send private message

PostPosted: Fri Jan 24, 2014 5:30 am     Reply with quote

[quote="temtronic"]comment: You should put the delay_ms(1000); before the lcd_init() function.

The flex driver uses the R/W line of the lcd to check if the lcd has finished the given command, so extra delays are not needed.
Disadvantage is that you need one extra io line.

Fixing this line to ground requires indeed delays to compensate for the lcd lag.

The delay in my case is just to show the 'start' message for one second on the lcd.

Regards
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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