|
|
View previous topic :: View next topic |
Author |
Message |
allenhuffman
Joined: 17 Jun 2019 Posts: 569 Location: Des Moines, Iowa, USA
|
PIC24 question about #ROM and embedding data. |
Posted: Mon Dec 02, 2019 11:02 am |
|
|
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
|
|
Posted: Mon Dec 02, 2019 12:17 pm |
|
|
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.
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
|
|
Posted: Mon Dec 02, 2019 12:31 pm |
|
|
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
|
|
Posted: Mon Dec 02, 2019 1:36 pm |
|
|
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
|
|
Posted: Mon Dec 02, 2019 1:53 pm |
|
|
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
|
|
Posted: Mon Dec 02, 2019 7:26 pm |
|
|
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
|
|
Posted: Mon Dec 02, 2019 7:33 pm |
|
|
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
|
|
Posted: Tue Dec 03, 2019 2:56 am |
|
|
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
|
|
Posted: Tue Dec 03, 2019 9:44 am |
|
|
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
|
|
Posted: Tue Dec 03, 2019 9:46 am |
|
|
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
|
|
Posted: Tue Dec 03, 2019 9:51 am |
|
|
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
|
|
Posted: Tue Dec 03, 2019 7:48 pm |
|
|
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
|
|
Posted: Wed Dec 04, 2019 3:21 am |
|
|
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
|
|
Posted: Wed Dec 04, 2019 9:01 am |
|
|
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
|
|
Posted: Wed Dec 04, 2019 9:04 am |
|
|
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. |
|
|
|
|
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
|