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

Replacement methods of pointer assignment
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
ye



Joined: 11 May 2005
Posts: 57
Location: london

View user's profile Send private message

Replacement methods of pointer assignment
PostPosted: Wed Nov 23, 2005 5:53 am     Reply with quote

HI all,

Since CCS doesn't support pointer assignment, are there any good ways to do that? I am using PIC18F8722 and I want to copy one array to another.

Certainly FOR loops will not be optimistic. I used to use 'memcpy' to copy the memory content of one array to another which was quick but it took too much space in memory.

Are there any efficient and 'light' ways?

cheers
Ttelmah
Guest







PostPosted: Wed Nov 23, 2005 8:23 am     Reply with quote

You can just point a pointer at the same target. CCS allows this fine (pointer assignment), _but_ there is the major caveat, that the target must exist in both locations where it is used. You have to remember that normal variables inside a function, do not remain allocated when the function exits, so the object pointed to by the second pointer, must be declared as static, or have it's scope launched in a function outside the location where it is used.
So CCS, _does_ allow 'pointer assignment', but _you_ have to ensure the target will exist.

Best Wishes
ye



Joined: 11 May 2005
Posts: 57
Location: london

View user's profile Send private message

PostPosted: Wed Nov 23, 2005 8:39 am     Reply with quote

Thankyou, Ttelmah.

Sorry, I think I need to make myself more clearly undertood. When I was saying CCS doesn't support pointer assignment, I was actually saying the statements like below do not work:

Code:
char array1[4] = "abc";
char array2[4];

array2 = array1;
[/quote]


All I want to do is copy arrays.

I used to do it this way:
Code:
memcpy(array2, array1, 4);


It worked but as I said, took too much space.

Certainly you can do it like

Code:
for(i=0;i<4;i++)
array2[i] = array1[i];

But i don't wanna do that.

Are there any quick and efficient ways of doing it?

Thx
Ttelmah
Guest







PostPosted: Wed Nov 23, 2005 10:19 am     Reply with quote

The second declaration, declares the complete array. You are not trying to perform 'pointer assignment', but array copying. Pointer assignment, would be:
Code:


char array1[4]="abc";
char *array2;

array2=array1;



If you perform this, array2[3] will be 'c'.
You can copy the arrays with memcpy, or strcpy. So if you perform:
Code:


char array1[4]="abc";
char array2[4];

memcpy(array2,array1,sizeof(array1));


This will happily copy the first array to the second.

Best Wishes
ye



Joined: 11 May 2005
Posts: 57
Location: london

View user's profile Send private message

PostPosted: Wed Nov 23, 2005 10:37 am     Reply with quote

Ttelmah, thanks.

But I think I have stressed that I was using memcpy but realised this command sacrifice too much rom.

Quote:
I used to do it this way:
Code:
memcpy(array2, array1, 4);


It worked but as I said, took too much space.


I am seeking other 'light' method other than memcpy

cheers
Ttelmah
Guest







PostPosted: Wed Nov 23, 2005 4:18 pm     Reply with quote

Memcpy, doesn't use much ROM. Seriously, this is about as closely coded as the chip can manage. How large it is, depends on the chip you are using. On (for instance), an 18F chip, which supports table reads/writes, the entire operation to move a 128byte array, only occupies 11 instructions. I assume you are on a smaller chip like the 16F, in which case the problem is that there is only one indirect addressing register to talk to the RAM, so the code has to calculate the source address, place this in the INDF registers, fetch the addressed byte, save this, calculate the destination address, place this in the INDF registers, write the saved byte, then increment the counter, and start again. The size will be almost exactly the same, even if you coded it in assembler...
At the end of the day, the compiler is stuck with the limitations of the chip.

Best Wishes
Guest








PostPosted: Thu Nov 24, 2005 3:40 am     Reply with quote

Thanks, Ttelmah.

If you are right, I think there is no other better way to do array coping than memcpy. Yes, I am using 18f. The reason I desperately want to reduce the number of assembly instructions contributed by memcpy is I have so many memcpy in my code! The characteristic of my code defines that I need to copy arrays a lot and the accumulated impact on rom space given by memcpy is big at the end of the day. I would think if I could somehow reduce the number of assembly instructions by 2 or 3, significant amount of rom space will be saved.

Cheers
Ttelmah
Guest







PostPosted: Thu Nov 24, 2005 4:40 am     Reply with quote

You don't need to have seperate versions.
If you code the standard 'memcpy' command, it is produced 'inline'. If instead, you 'encapsulate' the command, as:
Code:

void mymemcpy(char * dest,char * source,int8 len) {
    memcpy(dest,source,len);
}

Then only one copy of 'memcpy', will be generated. _However_there is a big caveat, that the total space used will remain about the same, and may even get bigger!. The encapsulated memcpy, will be larger, because the values are variables in each case, and the calling locations, have to transfer three variables into temporary registers, and then call the routine....
I have to say though, that having a lot of memcpy routines, sounds more as if you should 'rethink' how you are using memory. At the end of the day, if a value needs to be used in multiple locations, then make it static, or global, and just transfer a pointer. Moving data around in memory, is wasteful on processing time, and space,and should be possible to avoid almost completely. The only times I use such routines, are when re-ordering data inside an array, or in one case for a block of data transferred over SPI, inside an interrupt handler, where the block is moved from the 'live' version, to the area used by the interrupt handler.

Best Wishes
ye



Joined: 11 May 2005
Posts: 57
Location: london

View user's profile Send private message

PostPosted: Thu Nov 24, 2005 5:11 am     Reply with quote

Yes, I have been paying attention to reusability and defining all variables requiring multiple uses as static, global or even dump them into rom by defining them as constant.

The problem with my code is, since I am designing a system GUI on an LCD, I need a lot of things like menus, text backgrounds, etc and on these various screens there are different texts, which means I have a vast number of different text templates defined as constant and stored in rom. Initially I stored the templates in ram but realised the ram couldn't accommordate so many!

Since I couldn't directly access these constants, I have to copy them into a general array to use them and this is why I am using so many memcpys!

If I could find a better way to store the massive amount of templates in which case I wouldn't have to use any array copying (I actually raise this question in another post), or if I could find a better way of array copying to reduce the memory usage contributed by the massive amount of memcpy uses, I will be on the moon!! Razz

My ultimate goal is to save ROM! Smile

Cheers
Ttelmah
Guest







PostPosted: Thu Nov 24, 2005 5:31 am     Reply with quote

I do a similar array system on a LCD, and have the messages stored as a single large 'block' in ROM, not as constants. They are seperated by marker characters,and during boot, the system scans the block, and stores just the location of each message in RAM. I have three different blocks, containing messages for different languages, and according to a EEPROM value, the decision is made as to which block to scan. The output is then done, for a given message 'number', by reading it's address from the RAM array, and then starting at this address, outputting the characters in turn, till the next 'marker'. I have a total of about 600 messages (200 each from three different languages), and only use 400 bytes of RAM for the address table. On another system the massages are stored in a similar way in an external FRAM.
You can directly access data in the program ROM (you must be doing this to copy the data into the RAM). Reads fom program memory are fast (it is only writes that are slow), so using some similar index system, may be an answer for you.
It is worth remembering that if you store data as a 'constant' (using const), the access code is added to the dront of each declaration, wasting a lot of space. Storing such data using a #ROM declaration, avoids this, and you can use a single copy of 'read_program_memory', to access such data.

Best Wishes
Guest








PostPosted: Thu Nov 24, 2005 6:13 am     Reply with quote

Your idea souds to work!

I will be very happy if I could apply this to my code to save space and at the mean time keep the speed but before that I would like to get more details from you about practical implementation.

Quote:
They are seperated by marker characters,and during boot, the system scans the block, and stores just the location of each message in RAM


What are the marker characters? You mean the null characters? If I store 3 messages in one rom block, are the marker characters those that are placed at the end of each message to separate them, or those placed at the end of the entire block to mark the end of block? How do I access the location of each message in RAM?

Quote:
according to a EEPROM value, the decision is made as to which block to scan

How do you practically access each block using the starting address of them? Does the complier work in this way that blocks are allocated a memory space first and actual code is stored in other rom space so as not to overlap with the reserved blocks?

Quote:
The output is then done, for a given message 'number', by reading it's address from the RAM array, and then starting at this address, outputting the characters in turn, till the next 'marker'

I are still not quite with you about how to build this address table in Ram and how to use markers to pick up a specific message in a block...

Sorry for so many questions and hope they don't bother you. This project is important to me and I need to get it done nicely.

Finally, could you post your code or an example code for a more explicit demo? Razz

Cheers
Ttelmah
Guest







PostPosted: Thu Nov 24, 2005 6:50 am     Reply with quote

I actually use the '~' character. This was 'ancestral', since I originally used the same approach for a large array held on another C system, and did not want to use the null character. I also use the null inside the input routine, so want to avoid this.
I have the message numbers declared as #defines. So (for example):
Code:

#define M_ZEROMSG   30
#define M_OVER   31
#define M_INPUT   32
#define M_UNDER   33
#define M_PURGE   34
#define M_MV            35
#define M_CALCOR    36


The message 'printer', is called like:
Code:

void mputs(int num,int flag)
{
    int32 ptr;
    char buffer[17];
    int locn;
    /* routine to put a value from the constant data array to the display */
    if (num>MAXMSGNO) return;
    //I only hold the address of the message inside the ROM 'block'
    ptr=msg[num]+STARTOFMESSAGES;
    //STARTOFMESSAGES is cast as an INT32, and is the address of the
    //whole block.
    buffer[17]='\0';
    while (true) {
       //transfer 16bytes
       read_program_memory(ptr,buffer,16);
       for (locn=0;locn<17;locn++) {
           if (buffer[locn]=='\0') {
               //Here I have reached the end of the buffer
               ptr+=16;
               //Get another block
               continue;
           }
           if (buffer[locn]=='~') {
               //Here end of message
               break;
           }
           //If I get here, I have a character to display
           MY_LCD(buffer[locn]);
       }
    }
    //I clear the rest of the line, if 'flag' is set
    if (flag) MY_LCD(CEOL);
}

This is sort of "cut out" of my real code, but hopefully contains what you need to see how it works.
I call it like:

mputs(M_ZEROMSG,NOCLR);

To display the message 'Zeroing system'.
ye



Joined: 11 May 2005
Posts: 57
Location: london

View user's profile Send private message

PostPosted: Thu Nov 24, 2005 8:39 am     Reply with quote

Ttelmah, the code is great ! Razz


I can see how you think here with the code: store the messages in one single block using #ROM and call them back using 'read_program_memory' according to the message address table stored in ram, right?

However,

Code:
    //I only hold the address of the message inside the ROM 'block'
    ptr=msg[num]+STARTOFMESSAGES;

In what way you do you get the address table msg[]? Do you do it this way that if you are storing 3 messages, a[3], b[5] and c[2], you manually define msg[3] = {3,5,2}?
Guest








PostPosted: Thu Nov 24, 2005 9:05 am     Reply with quote

1. another question is, how to use #rom to store multiple messages into the rom?

for simple integers you can do it like:

#rom 0x300 = {1,2,3}

but for arrays,how?

2. also, when you did it, did you define the block start address as the first rom address? would the content of this block be overlapped with the actual code

3. I browsed some posts in the forum and found people saying using #rom would store stuff into internal eeprom rather the actual ROM?


Cheers
Ttelmah
Guest







PostPosted: Thu Nov 24, 2005 10:42 am     Reply with quote

There is no code in a ROM declaration (this is how it differs from the 'const' declaration). I mentioned in one of the earlier posts, that I scan the area concerned during boot, to find the start of message characters. So the simple 'initialisation', involves setting msg[0] = 0, then scanning till I find the '~', and setting msg[1] to the next character. I repeat this to 'MAXMSGNO'. In fact I have the three language blocks one after the other, and for the second language, I start again, so that msg[0], now has the address of the first word in the next language. Obviously since I use an INT16, for the addresses, I can potentially have a maximum of 64KB, for the total of all the messages.
You can just directly declare strings into the ROM, with:
#ROM 0xnnnn = {
"Message one~Message two~Message three~",
"Message four~Message five~Message six"
}

#ROM, can store data _anywhere_. If the address '0xnnnn', is the address of the start of the internal EEPROM, then it's data is put here. If instead you point it to an address in the main memory, it's data goes here instead. If you are on a chip like the 18F252, which has memory, that reaches 0x7FFF, then if you declare:
#ORG 0x7c00,0x7FFF {}

#ROM 0x7C00 = {
"Required strings here"
}

Then the ROM block is placed at 0x7C00, and the area is reserved by the 'ORG', so that code cannot be placed here.

Best Wishes
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