|
|
View previous topic :: View next topic |
Author |
Message |
Miniman
Joined: 30 Apr 2007 Posts: 44
|
big arrays |
Posted: Thu Jan 03, 2008 8:40 am |
|
|
Hi
I want to have a function that can take a big array as parameter. The array is going to be bigger then the ram can fit so it needs to be a constant. I know I can't have pointers to a constant, so how do i do it then?
Do I have to use the READ_PROGRAM_MEMORY( ) funciton to get the data? But how do i know the address to the constant then?
Hope you understand what I'm trying to accomplish, otherwise ask me and I will try to explain better
BR
miniman |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Thu Jan 03, 2008 12:41 pm |
|
|
I had this situation in a program a while ago, and I started with using read_program_eeprom() to get the data (only one byte at a time, as opposed to read_program_memory(), which gets multiple bytes).
You need to define the area of memory where your data will reside, so you'll know where to find it. The easy way to do this is with the #ROM directive, i.e.
Code: |
#define LOOKUP_AREA 0x1000
#rom LOOKUP_AREA = {1, 2, 3, 4, 0x3FFF};
|
I don't think this shows up in the LST file at all, but it's in the HEX file:
:0A2000000100020003000400FF3F8E
Note that the address of the data is doubled (2000 instead of 1000) but that's normal. Also, that last data word 0x3FFF was acceptable (14 bits) but the hex file format comes from Intel and hence is little-endian, low byte first, so it shows up as FF3F. Obviously you have to choose an area of memory which the compiler isn't putting code into!
There were two problems that I ran into. One was that the compiler would only let me use 256 words of memory, though my compiler is ancient and maybe that restriction is gone.
The other thing was that the CCS functions use memory inefficiently. I was using the PIC16F877A, which is one of the 14-bit memory word chips, and the functions only read bytes, so each word would have 6 bits I could never read. I ended up going to the Microchip manual and writing my own version of the function. When you look up how the hardware works, you find that the operation returns the bottom 8 bits in register "eedata" and the top 6 bits in "eedath".
To get the amount of data I needed into the memory, I made up a supplemental HEX file containing my data, and linked it with the compiler's HEX file.
To access the data, you'd want a call like
ret_val = read_program_eeprom(LOOKUP_AREA + index);
I don't know if "index" there can actually be a long integer, which it would need to be if you want access to more than 256 words (maybe that's why it's restricted to 256 words). If that situation applies, you'd have to write your own function, loading "eeadrh" and "eeadr" with the high and low address bytes, then setting whatever bit it is that calls for a program memory read. It's easy to do and doesn't require assembly language. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 03, 2008 1:12 pm |
|
|
If your data is text, then see this note from the CCS Readme.txt file.
You can pack two 7-bit characters into one ROM word in the 16F PICs.
This feature was added starting with vs. 4.050.
Quote: |
A new option has been added to #rom to pack 7 bit characters into the PCM 14 bit word.
For example:
#ROM CHAR 0x1000={"THIS STRING TAKES 22 INSTRUCTION LOCATIONS"} |
|
|
|
Miniman
Joined: 30 Apr 2007 Posts: 44
|
|
Posted: Thu Jan 03, 2008 2:28 pm |
|
|
thanks for the guidance. But I use a 18F4550 with 32K rom and 2K ram. The array will be more then 256 bytes. It will consist of ~6K of bytes, so only 8bit storage and no text.
Quote: | Note that the address of the data is doubled (2000 instead of 1000) but that's normal | Is that due to the Intel Hex format, or do I have to use the dubbled address in the programming, didn't quite understand that?
I found this in the compiler help: "A special method allows the use of pointers to ROM. This method does not contain extra code at the start of the structure as does constant..
For example:
char rom commands[] = {“put|get|status|shutdown”};"
I tried it but it did not work, do I have to access the bytes in a special way if I use "int8 rom data[] = ....."? Or does it not work at all?
Thanks for all help
BR
miniman |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Thu Jan 03, 2008 3:57 pm |
|
|
I recalled after I sent in that excessively long message that I was a annoyed at the time to discover that the compiler is very poor (basically, it can't do it for anything reasonably sized) at lookups from program space, and there's no way to store large amounts of data in one's code. If there's any feedback from here to CCS about "features to add" I'd suggest adding that to some future version. Who knows, I might buy it! But no, they should give it to me free for making the suggestion.
The two-characters-in-one-word scheme is progress in the right direction, but Mr PCM Programmer didn't say anything about a way to get the data out of ROM. I assume you'd have to read your two characters simultaneously, rotate the one that's in "eedath" one place left, take the top bit of the one in "eedat" and insert it in the bottom of the one that was just shifted and delete that bit from its original location. I wonder how many instructions that would compile to! Sometimes it's tempting to add just a few lines in assembler.
Yes, that doubling of the address is related to Intel Hex Format, but you never need to think about it unless you have to go into the HEX file for some reason. It happens because the 14-bit word the PIC processors need is encoded in two bytes, and so there are twice as many bytes as words. And the little-endian format makes it almost unreadable! But it's not there for us mere humans to read anyway. |
|
|
Miniman
Joined: 30 Apr 2007 Posts: 44
|
|
Posted: Thu Jan 03, 2008 4:16 pm |
|
|
Thanks for all your help! I think I have found the soulution now. I do as you John P said, but changed it a bit have a look:
Code: |
const int8 data[] = {0x34 .... 6kB of data here};
void writebuffer(int16 romaddress, int16 size)
{
int8 d;
int16 i;
for(i = 0; i<size; i++)
{
d = Read_Program_EEPROM(romaddress+i);
DoSomethingWithData(d);
}
}
void main()
{
writebuffer(label_address(data),sizeof(data));
}
|
Thats the way. It seems to work. Thanks once again!
/miniman |
|
|
Zer0flag Guest
|
|
Posted: Fri Jan 04, 2008 2:56 am |
|
|
What about defining a const array of chars like this:
Code: |
#define NUMBER_OF_ELEMENTS 50
const char myarray[NUMBER_OF_ELEMENTS][*]
{
"ELEMENT1",
"ELEMENT2",
.... and so on ....
};
|
Now you can access the elements like this:
myarray[1][7] will give you the char '2'.
Best regards,
Zer0 |
|
|
|
|
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
|