Currently I have a serial number hard-coded in my firmware for a design I'm working with. The firmware can read and report back the serial number. That works fine for what I need. The trouble is that each new serial number requires me to change my code and recompile. This is cumbersome when there are a lot of units to be built, has the possibly to introduce errors, and is all-around bad practice. The serial numbers are given to me and the hardware design is set in stone, so I can't add any features in hardware to serialize the units (EEPROM/Silicon ID Chip/Pull-Ups). What I would like to do is locate the serial number at a fixed address, compile the code once, then edit that address in the compiled HEX file for each new serial number. The number is referenced in several places, so ideally, I want to define & locate it once, then reference that "variable" everywhere else in my code. Does anyone know how to locate constant data at a specific addressable memory location of my choosing, using the C18 Compiler? Is there a better way anyone can suggest?
Electronic – Editable PIC Serial Number in HEX File
compilermicrocontrollerpic
Related Solutions
One annoying misfeature of the UART on every PIC I've worked with is that a data overrun error will shut down the receiver until code disables and re-enables it. It is thus imperative to have code that will periodically check the overrun-error flag and, if it is set, disable and re-enable the UART receive function. Otherwise if the receive buffer overruns, you won't just lose a received byte--you'll lose all data forevermore.
I'm not really sure why Microchip designed their UARTs this way. My guess would be that in early PICs a receive overrun would cause the receive state machine to lose frame sync, and that disabling the receiver was considered preferable to receiving randomly-framed data (I might agree with them on that point, though I would consider dropping whole bytes while maintaining sync to be better still); later PICs maintained the behavior for compatibility, despite substantial redesigns of the UART subsystem.
In any case, the PIC's UART implementation is what it is. Check to ensure that the UART receiver is enabled and the receive-overflow isn't tripped. If not, disable the UART receive function and re-enable it. Note, btw, that on some PICs the master disable for the UART function will not disable the receiver; you need to clear and re-set the receiver enable.
You have two separate issues:
- Building the code for the external RAM address range.
This is actually very easy. All you have to do is make a linker file that contains only the address ranges you want the code to occupy. Note that you not only need to reserve a particular program memory address range for these external apps, but also some RAM space. This RAM space, like the program memory addresses, needs to be fixed and known. Simply make only those fixed and known address ranges available for use in the linker file. Don't forget to make them NOT available in the base code linker file.
After the base code loads a new app into external memory, it has to know how to execute it. The easiest thing is probably to have execution start at the first external RAM location. This means your code will need one CODE section at that absolute start address. This contains a GOTO to the right label in the rest of the code, which will all be relocatable.
- Linking apps to library routines in the base code.
There is no immediately simple way to do this with the existing Microchip tools, but it's not that bad either.
A much bigger issue is how you want to deal with base code changes. The simplistic strategy is to build your base code, run a program over the resulting map file to harvest global addresses, then have it write a import file with EQU statements for all the globally defined symbols. This import file would then be included in all app code. There is nothing to link, since the app source code essentially contains the fixed address references to the base code entry points.
That is easy to do and will work, but consider what happens when you change the base code. Even a minor bug fix could cause all the addresses to move around, and then all existing app code would be no good and have to be rebuilt. If you never plan to provide base code updates without updating all apps, then maybe you can get away with this, but I think it is a bad idea.
A better way is to have a defined interface area at a chosen fixed known address in the base code. There would be one GOTO for every subroutine that app code can call. These GOTOs would be placed at fixed known addresses, and the external apps would only call to those locations, which would then jump to wherever the subroutine actually ended up in that build of the base code. This costs 2 program memory words per exported subroutine and two extra cycles at run time, but I think is well worth it.
To do this right you need to automate the process of generating the GOTOs and the resulting export file that external apps will import to get the subroutine (actually GOTO redirector) addresses. You might be able to do with with some clever usage of MPASM macros, but if I were doing this I would definitely use my preprocessor since it can write to a external file at preprocessing time. You can write a preprocessor macro so that each redirector can be defined by a single line of source code. The macro does all the nasty stuff under the hood, which is to generate the GOTO, the external reference to the actual target routine, and add the appropriate line to the export file with the known constant address of that routine, all with appropriate names. Perhaps the macro just makes a bunch of preprocessor variables with regular names (kindof like a run-time expandable array), and then the export file is written once after all the macro calls. One of the many things my preprocessor can do that MPASM macros can't is to do string manipulation to build new symbol names from other names.
My preprocessor and a bunch of other related stuff is available for free at www.embedinc.com/pic/dload.htm.
Related Topic
- Electronic – Unable to use compiler built-in functions to write to dsPIC EEPROM
- Electronic – What PIC processor was this HEX-file meant for
- Electronic – Writing data on EEPROM or Flash memory of the PIC18F47J53
- Electronic – PIC to PIC serial communication
- Electronic – PIC Serial Programmer
- Electrical – Two PIC 18f4620 , one as master & the second is slave I2C communication problem
- Electronic – How to preset an I2C IO expander
- Electronic – AVR – strange communication between ATmega8A and bluetooth module
Best Answer
Specifically to resolve the question of binding variables to specific addresses in flash memory on the PIC18 with the C18 compiler, please reference the section "Pragmas" in the hlpC18ug.chm in the doc directory where the compiler is installed.
To do this you need to define a new "section" in memory and bind it to a start address so
#pragma romdata serial_no_section=0x1700
This creates a new section called "serial_no_section" that starts at address 0x1700 in flash (program) memory (because we defined "romdata" in the #pragma).
Directly after the #pragma line, define your variable(s) so:
Now you have 0x12 at address 0x1700 and 0x34 at address 0x1701 in memory (because PIC18 uses the little-endian model). The "const rom" ensure that the compiler knows that this is a const variable type, and that the variable lies in "rom" memory and thus need to be accessed via table read instructions.
The final
#pragma romdata
statement ensures that any following variable declarations are linked to default memory sections as the linker sees fits rather than following on in the "serial_no_section" section.Now all code can simply reference the variable "mySerialNumber", and you know exactly what address the serial number can be found at in memory.
Editing the HEX code can be a bit challenging as you need to calculate the checksum for each line you edit. I am working on a C++ class to decode and encode Intel HEX files which should make this easier, but it is not finished yet. Decoding files works, encoding again is not yet implemented. The project (if you are interested) is here https://github.com/codinghead/Intel-HEX-Class
Hope this helps