Jump to content
edeca

Character Strings In Rom

Recommended Posts

Below is some code that takes a 16 bit reading from a temperature sensor and converts it to the whole and fraction part. The lookup table takes a lot of RAM, is there some way to store it in ROM?

 

I have seen some other threads but I don't quite understand. If there is no way to store this entirely in ROM then I will have to look for alternate methods, an array in RAM of January..December is going to take way more memory than I can spare :rolleyes:

 

// DS620 temperature sensor format
// SIGN | 2^7..2^0 | 2^-1..2^-4 | 0 0 0
void convert(unsigned short reading) {
unsigned char whole;
unsigned char fract;
bool positive = true;

// This table is good for 3 bit resolution
char* fractions[8] = {
	"0",
	"125", 
	"25",
	"375",
	"5",
	"625",
	"75",
	"875"
};

if (reading & 0x8000)	{
	positive = false;
	reading = ~reading + 1; // 2s complement
}

whole = reading >> 7;
fract = (reading >> 4) & 0x7;

if (!positive) {
	serial_printf('-');
} else {
	serial_printf('+');
}
serial_print_dec(whole);
serial_printf('.');
puts(fractions[fract]);
}

Share this post


Link to post
Share on other sites

Hi edeca,

 

Try this way:

 

rom char	*fractions = { 0, 125, 25, 375, 5, 625, 75, 875 };

// DS620 temperature sensor format
// SIGN | 2^7..2^0 | 2^-1..2^-4 | 0 0 0
void convert(unsigned short reading) {
unsigned char whole;
unsigned char fract;
bool positive = true;

// This table is good for 3 bit resolution
/*
char* fractions[8] = {
	"0",
	"125",
	"25",
	"375",
	"5",
	"625",
	"75",
	"875"
};
*/
if (reading & 0x8000)	{
	positive = false;
	reading = ~reading + 1; // 2s complement
}

whole = reading >> 7;
fract = (reading >> 4) & 0x7;

if (!positive) {
	serial_printf('-');
} else {
	serial_printf('+');
}
serial_print_dec(whole);
serial_printf('.');
puts(fractions[fract]);
}

 

Regards

Joli

Edited by joli

Share this post


Link to post
Share on other sites

Thanks, but 375, 625 and 875 are definitely outside the 2^8 limit for ROM and therefore a char is unsuitable.

 

If it is impossible to store character strings in ROM then I will have to think of an alternative.

Share this post


Link to post
Share on other sites

Thanks, but 375, 625 and 875 are definitely outside the 2^8 storage limit for ROM.

 

If there is no way to store character arrays in ROM instead of RAM I will have to think of an alternative. I also wanted to be able to store months and days of the week in a similar fashion.

Share this post


Link to post
Share on other sites

edeca,

Thanks, but 375, 625 and 875 are definitely outside the 2^8 storage limit for ROM.

 

If there is no way to store character arrays in ROM instead of RAM I will have to think of an alternative. I also wanted to be able to store months and days of the week in a similar fashion.

Have to store as each as two separate bytes.

 

Regards

Dave

Share this post


Link to post
Share on other sites

Thanks Dave. Is this something that a PIC compiler can support at some point? Or is it a feature which wont appear?

 

I looked at using strtok to do the same, but it doesn't seem to accept ROM chars.

Share this post


Link to post
Share on other sites

Could you use something like this?

 

char fraction()
{ fract &= 15;
 fract *= 10;
 return(fract>>4|"0");
}

	whole = reading >> 7;
fract = (reading >> 3) & 0xF;

if (!positive) {
	serial_printf('-');
} else {
	serial_printf('+');
}
serial_print_dec(whole);
serial_printf('.');
puts(fraction());	// "0625", "1250", etc...
puts(fraction());
puts(fraction());
puts(fraction());

Share this post


Link to post
Share on other sites
Thanks, but 375, 625 and 875 are definitely outside the 2^8 limit for ROM and therefore a char is unsuitable.

 

If it is impossible to store character strings in ROM then I will have to think of an alternative.

 

My apologies, i forgot completely that these values were 16 bit.

As Dave said, you can have all values in 16 bit format.

 

So, maybe the best idea is to show an example i made to test it working.

 

rom char	*fractions = { 
0x00,   //   0
0x00,
0x00,   // 125
0x7d,
0x00,   //  25
0x19,
0x01,   // 375
0x77,
0x00,   //   5
0x05,
0x02,   // 625
0x71,
0x00,   //  75
0x4b,
0x03,   // 875
0x6b
};

unsigned char x;
for( x=0; x<8; x++)  // Only show first 8 to fit on my LCD
{
Bin2Hex( fractions[x] );   // My data conversion  function
LcdPrintChr( hexhi);	   // My LCD function
LcdPrintChr( hexlo);
}

 

As a result, my Alphanumeric LCD shows:

 

"0000007D00190177"

 

Note1: declared values are in big endian i.e. msb byte first, obvious you can change it.

For your needs you can do as you want.

 

Note2: As stated in the BoostC Manual page 42 "rom can be used with char data types only", this means that all 16 bit values must be separated into 2 bytes and declared thus.

 

My example that uses LCD is not important, what matters is how you can declare and read data placed in rom.

 

Tell us about your progress

 

Regards,

Joli

Edited by joli

Share this post


Link to post
Share on other sites

IMHO showing three digits of decimal fractions is *SPURIOUS* accuracy. The sensor resolution is 1/16 deg C, not 1/1024 deg C and the absolute accuracy is no doubt a lot worse.

 

You should therefore round to a single decimal place, which will have a maximum rounding error of +/- 0.0375 deg C

 

Try this, which returns a single digit to be displayed after a decimal point.

// DS620 temperature sensor format
// SIGN | 2^7..2^0 | 2^-1..2^-4 | 0 0 0

char  fastdecfract(unsigned int x)
{
char r;

r=(x>>3)&0x0F;
if (x.6) r-=3;
if (x.5)
   {
   r-=2;
   if (!x.3) r+=1;
   }
if (x.4) r-=1;
return(r);
}

if you want the result in ASCII, make the fourth line:

r=(x>>3)&0x0F+'0';

The assembly is pretty compact, definately better than a lookup table.

For days and months you need to zero pad the strings to *exactly* the same length and concatinate them:

 

rom char* weekdays = "Monday\0\0\0\0"
				  "Tuesday\0\0\0"
				  "Wednesday\0"
				  "Thursday\0\0"
				  "Friday\0\0\0\0"
				  "Saturday\0\0"
				  "Sunday";

rom char* months = "January\0\0\0"
				"February\0\0"
				"March\0\0\0\0\0"
				"April\0\0\0\0\0"
				"May\0\0\0\0\0\0\0"
				"June\0\0\0\0\0\0"
				"July\0\0\0\0\0\0"
				"August\0\0\0\0"
				"September\0"
				"October\0\0\0"
				"November\0\0"
				"December";

Note there is no padding after the last entry as C automatically adds a null at the end of strings and we can save 5 bytes total by eliminating the nulls that are never accessed.

 

To access them one letter at a time, start with letter_num=0 and use the expression: months[10*this_month+letter_num++] which returns 0 at the end of each month string. this_month starts from 0 for Jan and goes upto 11 for Dec.

 

Its a total pain to work out by hand but is all pretty easy to do in MS Excel then past the resulting text into your C program, which is how the rom char strings above were generated. Here is the Excel expression:

=CHAR(34)&A1&REPT("\0",10-LEN(A1))&CHAR(34)

Just paste that formula into cell B1, fill down for as many strings as you want and type all the strings (or caculate them) in colum A. Copy the result to the IDE editor window, job done!

 

The space saving alternative would be to generate an offset array and leave out the padding, only keeping a single null per string, so we could access for example months[month_ptr[this_month]+letter_num++]

 

Edited to correct number format in fastdecfract() and clarify what it does.

Edited by IanM

Share this post


Link to post
Share on other sites

Try this for integers in rom:

#define _RI(n) n&0xff, n>>8
#define romint(rcptr,ofs) (rcptr[ofs+ofs]+256*(rcptr[ofs+ofs+1]))

rom unsigned char* fractions_int = {
		  _RI(000),
		  _RI(125),
		  _RI(250),
		  _RI(500),
		  _RI(625),
		  _RI(750),
		  _RI(875)
		  };

 

you can then use the expression romint(fractions_int,x) instead of fractions[x] that would work if BoostC supported other types in rom and we could define

//WARNING: NOT (YET) LEGAL in BoostC
rom int* fractions = { 000, 125, 250, 500, 625, 750, 875 };

Share this post


Link to post
Share on other sites

IanM,

 

The problem is BoostC doesn't support rom 16 bit values.

So, in my humble opinion we have one of two choices, use method likely one i put on my last example or, declare those values as a strings in rom:

 

e.g.: rom unsigned char *fractions = "127,125,025,000,375,005,625,075,875\0";

 

For the present case, i made my own strtoint() crude function to extract above values that work as expected.

 

I was wondering if someone publishes a function to convert rom string to integer with following parameters:

 

- unsigned int strtoint( unsigned char strindex );

- function returns a integer from a rom string number collection, indexed by strindex.

 

Of course, if this function were smart we could declare:

> rom unsigned char *fractions = "127,125,25,0,375,5,625,75,875\0";

 

Remember that this post is related to the question originally posted by edeca.

 

What you suggest IanM?

 

Regards,

Joli

Edited by joli

Share this post


Link to post
Share on other sites

Did you actually try my romint code under BoostC? It works around the limitation.

 

_RI() splits the integer into two (unsigned) char values seperated by a comma for the rom char string definition and romint() puts them back together. romint() could be implemented as a function instead of an inline #defined macro, but that would use up an extra level of return stack, and rom chars are already fairly costly in terms of stack usage. The tradeoff is increased code size if you use many seperate invocations of romint(), but if your program is well structured, it should be localised in one or at most a few of rom parameter access functions so won't have much impact.

 

ASCII is *NEVER* the right choice for number storage on a resource limited system as there is an overhead of approximately 4 2/3 wasted bits per digit

Packed BCD is better as it only wastes about 2/3 of a bit per digit. Of course ASCII is essential if you need to output or input numbers in human readable format but the conversion to/from BCD or pure binary is less costly in terms of processing cycles and code size than either storing more than a couple of numbers in ASCII or implementing ASCII arithmatic. If ASCII looks like a good option, you've over-specced the processor . . .

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...