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

storing large 24 bit unsigned ints in 18F prog memory

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



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

storing large 24 bit unsigned ints in 18F prog memory
PostPosted: Sat Jan 23, 2010 1:09 pm     Reply with quote

I am contemplating IF it is feasible to store on the order of appx 10,000
24bit unsigned INT values ( up to appx 640,000 largest value) in program memory ( roughly 30,000 bytes of space ) using an 18f4620 - the actual code space for the program itself is under 10k and the part has 64K of total prog flash available .

The data will always be read sequentially from said table using a unique RLL ending 'tag' numeric value of 0xFFFFFF - no issues with managing the offset.

The dual unknowns for me are :

1- I don't know how to define or use a 24 bit, unsigned INT type.

While I assume I can write an efficient pair of conversion functions to go
between 32Bit unsigned & this special space conserving 24 bit type - I don't know how to go about defining a custom type to do the job for me.

2- It is not clear if the compiler is up to the job of doing this sort of custom var type in such a large prog mem table format - and I'm wondering if I have to approach this from a complete custom-on-my-own standpoint using direct access using read_program_memory().

Anybody been over this territory before ?
Ttelmah
Guest







PostPosted: Sat Jan 23, 2010 3:16 pm     Reply with quote

Unions and structures are your friend.
You can declare a structure of three bytes, then a union between this, and a int32. If your 'space saving', is being done by just dropping the high byte (values are unsigned), then you can still use the normal 32bit operations to work with the values (though possibly worth considering adding 'limit' handling).

Since values are stored LSB first in memory, you can just let the union 'throw away' the high byte.

You can then just assign an array of 3byte structures. To put these into an int32, just copy an entry from the array, into the structure in the union, and then read the int32 in the union. You can do exactly the same in the other direction, _but_, I'd suggest you test if the int32 is > 16777215, and if it is, set it to 16777216 (limit handling).

If you want to handle signs, then you'd need to test the top bit of the 4 bytes, and move this to the 24th bit, and do the opposite, when transferrig the other way.

As an example, of dong this with a signed value, the following may give you some ideas.

Code:

/* This union is used internally to allow access to the various parts of each
32bit 'value' as bytes, 16bit integers etc. */
union lblock {
    unsigned int16 ui[2];
    signed int16 i[2];
    int8 b[4];
    signed int32 word;
};

//Trims an incoming 32bit value to a 24bit value.
signed int32 trim24(union lblock val) {
   if (val.b[3] & 0x80) {
   //Here -ve
        if ((val.b[3] != 0xFF) || !(val.b[1] & 0x80)) val.word=0xff800001l;
   }
   else {
   if ((val.b[3]) || (val.b[1] & 0x80)) val.word=0x7FFFFFl;
   }
   return(val.word);
}


This returns an int32, but trimmed so the useable data is all in the low three bytes.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

thnaks for tyhat answer BUT....
PostPosted: Sat Jan 23, 2010 4:45 pm     Reply with quote

i don't have a CLUE of how to apply that UNION example in practice - really.
meanwhile this is what i had come up with - as all i care to do is lookup ONE data item at a time - convert back to 32 bit format and put the looked up value in a local array for immediate use . this is what I had come up with but is it WRONG ??

or is some other way unworkable? the LST file shows that TBL lookups
are being done. but i cant find where the data i load in the CONST array is placed. this is the critical snippet that i wrote - that compiles ok.

is this OK or what am i missing ??
Code:

// this SEEMS like it works for the  simple assignment i want to do
// via big lookup  but the LST obscures what is happening
// from early on in the defs portion of the program
struct bl24
{
   int  lobx     :8;
   int midbx     :8;
   int hibix     :8;
} const fblkk[733]={
0,1,2,3,4,5,6,7,
33,71,82,93,104,255,664,722,
//                  many more values here .... omitted
// for clarity but there are HUNDREDS more loaded in this short example
77110,136811,226372,303177,444187,555519,6671982,777817,};
// is the above is going to load what i am hoping ? ie 24 bit LONG unsigned ints?


// later on ptvx is an unsigned  16 bit variable   
// freqlist is a 32bit int array of [4][16] size that is selectively loaded
// from the table based on current needs as commanded by a host
// this code in the LST file does seem to be doing a tbl lookup

      freqlist[3][0]=fblkk[ptvx]; 
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Jan 23, 2010 5:16 pm     Reply with quote

Defining a struct to handle a 24-bit int does not imply, that the compiler is able to understand 24-bit
constants as you try in your code. The compiler can only work with constants of known types as int8 or int16.

You didn't mention this initializing point before. Basically it should work with a macro, that splits a long integer
value into three int8 values respectively an int16 and an int8.
Ttelmah
Guest







PostPosted: Sun Jan 24, 2010 3:18 am     Reply with quote

Yes.
If you look at my example, wat is happening, is that an int32 signed value, is being 'cut down' to a 24 bit signed value, and then returned _in_ an int32. The only 'package' that CCS will understand as containing 3 bytes, is an array of 3 bytes (in a structure say). All the default types contain 1,2, or four bytes. Once the value has been 'cut down', it is no longer useable with the CCS arithmetic. You can assign the cut down value to an array of 3 byte structures, and to come 'back' do the same in the opposite direction, but you have to convert the value _back to an int32 before using any arithmetic, or write your own 24bit arithmetic routines.

It'd help massively if you said whether the values are to be signed or unsigned (the later is simpler).

However unless you want to get involved in writing 24bit arithmetic (one program I posted here some time ago, had a 24bit addition routine in it), you need to extract the numbers from your 'compressed' form, back to the full size _before_ performing any arithmetic.

As an example of the 'structire/union', doing this for you, and how to handle the storage, the following should give some ideas:
Code:

typedef struct {
    int8 low;
    int8 med;
    int8 high;
} b24;  //Create a new 24bit data type 'b24'

b24 array[10]; //small array of these

union {
    int32 word;
    b24 parts;
}mixer; //Now create the structure to transfer values


    unsigned int32 ui32;
   
    mixer.word=30000;
    array[0] = mixer.parts; //Put first 24bit value into array[0]
    mixer.word=100;
    array[1] = mixer.parts; //transfer second 24bit value to the array
   
    mixer.parts=array[1];
    ui32 = mixer.word; //get back one 24bit value

    mixer.parts=array[2];
    //Get back the second value

    ui32*=mixer.word; //multiply them
//ui32, now contains the 32bit product of the two 24bit values from the
//array. You can store thisback into the array the same way.


Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun Jan 24, 2010 4:57 am     Reply with quote

You can use a macro for the compile time conversion of initializing constants:
Code:
#define itobl24(i24) (int8)i24,(int8)(i24 >> 8),(int8)(i24 >> 16)

fblkk[]={itobl24(1),itobl24(2),itobl24(123456)};
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Jan 25, 2010 8:37 am     Reply with quote

Sorry for the lack of important detail.

The values are ALWAYS Unsigned and never greater than 2,000,000.

In practice these are a set of stored frequencies that are later input to
a routine that drives an AD9833 DDS /DNO circuit via the SPI sync port.

I had to use a table as the list is quite long ( up to 10,000 items)
and there is no regular/calculable interval between values - no way to algorithmically generate the frequency steps required.

And worse - different variations on the finished instrument will have different tables. The fix for that is to have the table generating code be an include file and to have several different includes depending on the requirements for specific product.

BTW_ thanks for the extra help - it grows clearer as I read.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Jan 25, 2010 8:41 am     Reply with quote

BTW- T H A N K Y O U

Ttelmah & FVM 4 your most generous help

i believe i have got this knocked now!!!
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