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

PIC24 question about #ROM and embedding data.
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
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PIC24 question about #ROM and embedding data.
PostPosted: Mon Dec 02, 2019 11:02 am     Reply with quote

I was curious about placing some data inside our program flash at a specific location. Using examples from the help file, I did this:

Code:
#org 0x2000,0x2100
char const ID1[10] = {"123456789"};

#org 0x3000,0x3100
char const ID2[10] = {"123456789"};


When I looked at the CCS-generated .hex file, I see these lines (adding the ^s to point out my data):

Code:
:104000005420EF00C3002200008041001040BA009D
:104010000160EF0000000600313200003334000080
                         ^^^^    ^^^^
:104020003536000037380000390000000000060077
         ^^^^    ^^^^    ^^

:106000005420EF00C3002300008041001040BA007C
:106010000160EF0000000600313200003334000060
                         ^^^^    ^^^^
:106020003536000037380000390000000000060057
         ^^^^    ^^^^    ^^


Looking at the .lst file, I see there is code being added before each block of data:

Code:
*
02000 EF2054         CLR     54             : TBLPAG = 0
02002 2200C3         MOV     #200C,W3       : W3 = 200C
02004 418000         ADD     W3,W0,W0       : W0 = W3+W0
02006 BA4010         TBLRDL.B[W0],W0L       : W0L = ROM[[W0]] for even ROM
02008 EF6001         CLR.B   1              : W0H = 0
0200A 060000         RETURN                 : Return 
0200C 003231         DATA    31,32,00       :
0200E 003433         DATA    33,34,00       :
02010 003635         DATA    35,36,00       :
02012 003837         DATA    37,38,00       :
02014 000039         DATA    39,00,00       :
02016 060000         RETURN                 : Return 
*
03000 EF2054         CLR     54             : TBLPAG = 0
03002 2300C3         MOV     #300C,W3       : W3 = 300C
03004 418000         ADD     W3,W0,W0       : W0 = W3+W0
03006 BA4010         TBLRDL.B[W0],W0L       : W0L = ROM[[W0]] for even ROM
03008 EF6001         CLR.B   1              : W0H = 0
0300A 060000         RETURN                 : Return 
0300C 003231         DATA    31,32,00       :
0300E 003433         DATA    33,34,00       :
03010 003635         DATA    35,36,00       :
03012 003837         DATA    37,38,00       :
03014 000039         DATA    39,00,00       :
03016 060000         RETURN                 : Return


Questions:

1) Could someone shed some light on what this is for? I expect there's something I can add to truly get data where I want it. The help file mentions this "extra code":

Code:
#ORG 0x1C00, 0x1C0F               //This ID will be at 1C00
CHAR CONST ID[10}= {"123456789"}; //Note some extra code will
                                  //proceed the 123456789


2) When I look at the hex files, I see "xx xx xx 00" patterns for the 24-bit setup of this PIC. In the source above, I see "31,32,00" and so on. The HEX file then shows "31 32 00 00"... What is the 00 in the source code for? I was expecting the flash to be "31 32 33 00". I expect this is the hex file representing each as a word (0031, 0032, etc.).

Thanks...
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 02, 2019 12:17 pm     Reply with quote

Out of curiosity, I ran some tests to help me visualize the HEX file versus program memory. I placed 256 bytes in memory like this (plus another 8 after that):

Code:
#rom int8 0x2000 = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
}
#rom int8 0x2200 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }


The #rom keyword does not give me a C handle to the data, but does put it where I expect:

Code:
ROM data:
002000: 0100 0002 0403 0005 0706 0008 0A09 000B    ................
002008: 0D0C 000E 100F 0011 1312 0014 1615 0017    ................


...and inside the .hex file I see (removing length, type and checksum bytes):

Code:
:  4000 0001 0200 0304 0500 0607 0800 090A 0B00
:  4010 0C0D 0E00 0F10 1100 1213 1400 1516 1700


This shows me that the program memory address appears to be based on words, while the hex file is showing me bytes. Is this correct?

If I have some data, like:

Code:
int8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // 16 bytes


...and I write that to memory 0x2000 using something like:

Code:
write_program_memory (0x2000, data, 16);


...I thought that would place those 16 bytes from 0x2000-0x200f.

But in the .lst file, it shows it as words, from 0x2000-0x2010 (?).

And in the .hex file, it shows it as 0x4000-0x4014...

No wonder I am confused. Smile

This mixture of words vs bytes, and showing 24-bit values in 32-bit spaces is taking me a bit to get used to.

So... I forgot about the 24-bit thing, so I think my data really needed to be something like:

Code:
int8 data[] = { 0, 1, 2, 0x0, 3, 4, 5, 0x0,  6, 7, 8, 0x0, 9, 10, 11, 0x0, 12, 13, 14, 0x0, 15  }; // 21 bytes

write_program_memory (0x2000, data, 21);

_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.


Last edited by allenhuffman on Mon Dec 02, 2019 1:01 pm; edited 3 times in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 12:31 pm     Reply with quote

In the const case, label_address will tell you where the data actually is.
The header is retrieval code to access it. Has been discussed here before.
With #ROM, remember you can only store 3 bytes per word.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 1:36 pm     Reply with quote

Are you actually using them/doing something with them in your test program? Just wondering if perhaps the compiler is optimizing them out if your program doesn't actually use them, or is inconsistent in how it optimizes unused bits away?
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 1:53 pm     Reply with quote

Do you have PSV enabled in the code?. Using PSV only two bytes can
be stored in each word.
jeremiah



Joined: 20 Jul 2010
Posts: 1357

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 7:26 pm     Reply with quote

I haven't gone through the assembly personally in a few years, but in the past PCD would insert some code instructions ahead of the table to facilitate the array indexing operation of the data. Data declared with the const keyword can be accessed directly as an array (but not as a pointer) using []. Since the pic24 can only store 24bits at a time with a 4th "0" byte inbetween, the data isn't contiguous and, at least in the past, CCS inserted those instructions so that when you did something like:

char temp = ID1[1];

instead of a pointer + index operation (which it cannot do), it called a small function that would calculate the ROM address based on the index you specified and read data from that ROM location and return it. Basically calling a function "under the hood".

Note that the ROM keyword stores data differently (see the manual for specific descriptions on const vs rom).

Again, I haven't checked in a few years, but I would suspect if you evaluated those bytes at the beginning as instructions it will probably be some special indexing math.
jeremiah



Joined: 20 Jul 2010
Posts: 1357

View user's profile Send private message

PostPosted: Mon Dec 02, 2019 7:33 pm     Reply with quote

One small comment on write_program_memory(). If you call it on an address that is on a "page" boundary (see your datasheet for that number), it will erase the whole page, even if you are only writing a small amount of data. If you have code on that page after your data, it will be erased. Make sure you are using #org to reserve that space and prevent the compiler from putting other things in the space you don't use.
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Tue Dec 03, 2019 2:56 am     Reply with quote

As a comment, the really 'tidy' way to put a block of raw data into your
file, is to use #IMPORT.
Have the data you want to include as raw binary values in a file, then use:

#IMPORT(FILE=.\your.bin, RAW, LOCATION=where_stored, BPI=3)

Then 'where_stored' will tell you where this is. It is stored 3 bytes per
word. If you want the data to go at a specific location then instead have
the data a an Intel hex file containing just the data required and specify
an import range.
Now to read a byte at an index from this data, something like:
Code:

union access {
    unsigned int32 whole;
    unsigned int8 bytes[4];
};


//routine to give access to ROM stored data
BYTE getval(unsigned int32 locn, unsigned int32 index)
{
    unsigned int32 calc;
    union access rdg;
    unsigned int8 bval;
    //Now I need to calculate the actual cell I need to read, fetch this
    //then extract the byte
    calc=(index/3)*2;
    //This gives the actual cell offset from locn.
    read_program_memory(locn+calc, &rdg, 4);
    //Gives the 32bit value containing the byte required.
    bval=index % 3;
    //Now gives the byte number required
    return rdg.bytes[bval];
    //return the physical byte
}

locn is the start of the data, index the byte required.

The complexity of this is why CCS are storing 2 bytes per word, not 3....
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Dec 03, 2019 9:44 am     Reply with quote

Wow, great responses, gang. Thank you.

Earlier this year, we thought we might have need to place a large configuration table in flash. I was experimenting to see how that worked -- i.e., embedding a constant C structure in ROM, versus raw memory that is loaded into a buffer using read_program_memory().

The only Harvard architecture I have used previous to this (this is Harvard, isn't it?) is the AVR found in small Arduinos.

I was also confused between the addresses in the HEX file versus the addresses used by the PIC24.

I am also confused when I read "24-bits stored in a word" since a word to me means 16-bits.

Our existing firmware update routine was hard-coded based on knowing there will be a section (range of memory) for the vector table, program code, and flash config area (haven't gotten to that yet to see what that is for).

When we start using new #ORG statements to place things in other areas, that creates new breaks in the HEX file which our update code doesn't currently handle, so I figured I'd try to learn how this works.

I plan to just detect breaks in the HEX file (any time there is a jump more than 0x10 bytes between lines).

4000 - new segment, goes to PIC 0x2000
4010
4020
4400 - jump, new segment, goes to PIC 0x2200
4410
5000 - jump, new segment, goes to PIC 0x2800
...etc...
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Dec 03, 2019 9:46 am     Reply with quote

Ttelmah wrote:
Do you have PSV enabled in the code?. Using PSV only two bytes can
be stored in each word.


I am unfamiliar with this -- I will read up on it.

Am I correct to assume that internally, storing bytes like "1, 2, 3, 4, 5, 6" is only using 6 bytes of flash, but the way memory is accesses with the 24-bits, it just presents the extra 00s? i.e. (ignoring endieness):

[ 0x01 0x02 0x03 0x00 ] [ 0x04 0x05 0x06 0x00 ]
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Dec 03, 2019 9:51 am     Reply with quote

jeremiah wrote:
One small comment on write_program_memory(). If you call it on an address that is on a "page" boundary (see your datasheet for that number), it will erase the whole page, even if you are only writing a small amount of data. If you have code on that page after your data, it will be erased. Make sure you are using #org to reserve that space and prevent the compiler from putting other things in the space you don't use.


Good point -- I did see that mentioned in the help. My first PIC24 assignment was a flash data logger using an external SPI flash part that operated similarly (format an entire page, then could write anywhere to it).

Ultimately, I want to make our firmware code more independent so if we receive an instruction to write something like:

Code:
writeDataToFlash (0x1234, dataPtr, 5); // Write 5 bytes to location 0x1234


...it can transparently read the entire ERASE_SIZE block that contains that area, erase it, then update those 5 bytes and write it back, transparent to the user.

"Smart" code would know to update using ERASE_SIZE blocks in order, but it would give us the ability to update a small table somewhere inside of a block if we ever needed to, without pushing that work on the firmware updater side (a PC, talking via I2C).
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
jeremiah



Joined: 20 Jul 2010
Posts: 1357

View user's profile Send private message

PostPosted: Tue Dec 03, 2019 7:48 pm     Reply with quote

allenhuffman wrote:


The only Harvard architecture I have used previous to this (this is Harvard, isn't it?) is the AVR found in small Arduinos.



Yes it is a "pure" Harvard architecture where code and data are stored on 2 physically separate memory spaces that are addressed separately. There is also a "modified" Harvard architecture where the two memory spaces are still physically separate, but they use a hardware abstraction layer to have them share an address space. I don't think any of the Microchip PIC series uses modified Harvard that I have seen, but I have used plenty of Arm Cortex products that do.

allenhuffman wrote:

I was also confused between the addresses in the HEX file versus the addresses used by the PIC24.

I have PCWHD, and it defaults to an intel 32bit hex file format, which uses addresses that are 2x the ones I actually use on the PIC. There are options to compile to other formats I think, but I haven't tried.

allenhuffman wrote:

I am also confused when I read "24-bits stored in a word" since a word to me means 16-bits.

I'd have to see the full quote for that (Seems off, but would need the context of where you read it). However, keep in mind, even though Microsoft defines a WORD as 16 bits, in the embedded world a WORD can simply mean the standard atomic size of something (so 32bits on a 32bit architecture). So for the pic24 a data word is 16bits, but I don't recall if they refer to program memory words as 24 bits or not off the top of my head.
Ttelmah



Joined: 11 Mar 2010
Posts: 19549

View user's profile Send private message

PostPosted: Wed Dec 04, 2019 3:21 am     Reply with quote

The key here is between 'word', and 'instruction word'.

The PIC 24, has a 24bit instruction word. So 24bits are stored in an instruction
word. Sounds as if somebody used this and dropped the 'instruction' when
writing (probably the actual word 'instruction' was implicit in the context or
paragraph), but then taking a quote from this without this implicit context,
makes it seem rather 'odd'....
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Dec 04, 2019 9:01 am     Reply with quote

Ttelmah wrote:
The key here is between 'word', and 'instruction word'.

The PIC 24, has a 24bit instruction word. So 24bits are stored in an instruction
word. Sounds as if somebody used this and dropped the 'instruction' when
writing (probably the actual word 'instruction' was implicit in the context or
paragraph), but then taking a quote from this without this implicit context,
makes it seem rather 'odd'....


I wish I could say that makes it clearer ;-)

Seeing a 24-bit instruction padded with 00s to make it 32-bits is what throws newbies like me off. At first I thought it was just a nice friendly translation to the outside world, rounding up to a 32-bit value.

I've seen that trying to write a series of bytes and read them back has the zeros every fourth byte:

Code:
unsigned int8 data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
write_program_memory (0x4000, data, 10);


I think I need to test embedding data in the ROM and then using read_program_memory () to see if I get all the bytes I put in, or if it returns a 00 as well every four bytes.

On the plus side, now that I understand this a bit better, my firmware update process is getting an instant 25% speed boost since I can strip out those 00s on the updater side, and have them added back on the PIC24 side.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
allenhuffman



Joined: 17 Jun 2019
Posts: 569
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Dec 04, 2019 9:04 am     Reply with quote

jeremiah wrote:
I'd have to see the full quote for that (Seems off, but would need the context of where you read it). However, keep in mind, even though Microsoft defines a WORD as 16 bits, in the embedded world a WORD can simply mean the standard atomic size of something (so 32bits on a 32bit architecture). So for the pic24 a data word is 16bits, but I don't recall if they refer to program memory words as 24 bits or not off the top of my head.


Thanks for the info on Harvard arch.

It was in a response to me earlier in this thread. I think I'm just having trouble with semantics -- I've just not been around architecture where a word could hold 24-bits.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
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