PIC32 Compilers

I have been using the PIC32 compiler since version 1 (commercial expensive version) and here is a bit of history about the changes.

Upgrading from C32 V 1 to C32 V2 (June 2012)

Microchip has produced a new compiler for the PIC32, version 2 and this has caused some problems for me as the boot loader that is on all of the PIC32 products are written in version 1.

The problem was noticed when some customers could not get the C tutorial to work but I could not reproduce any of the problems. I have a full commercial copy of version 1 and so have stuck with it and was unaware of the changes between version 1 and version 2 that are quite significant. The problem is in the way the compiled code is linked, this is different, probably better, but totally incompatible with previous boot loaders in its standard form.

The problem was with the start up code that was being placed in a different location. A simple adjustment of the procdef.ld would not do the trick. After a full day the answer was reviled here:
http://www.microchip.com/forums/m658373.aspx

Somewhere towards the bottom thanks to ‘cgiordan’ A non-standard linker script is required and this should then be linked to a custom procdef.ld file. The script file ‘elf32pic32mx.ld’ can be found in:

C:\Program Files\Microchip\mplabc32\v2.02\examples\c32_examples\explicit_linker_script\ldscript

or somewhere similar. It will work in either MPLAB-X or MPLAB8 and just needs adding to the project under linker. The file requires modifications so that it will cause the generated hex file to be created properly for the original boot loader. Two areas of the file need modification:

 .reset _RESET_ADDR :
 {
   KEEP(*(.reset))
/*    KEEP(*(.reset.startup)) */
 } > kseg1_boot_mem
 .bev_excpt _BEV_EXCPT_ADDR :
 {

Rem the above line out as shown – this is somewhere near line 28. Add:

 .startup ORIGIN(kseg0_boot_mem) :
 {
 	KEEP(*(.reset.startup)) <<<<< This line
   KEEP(*(.startup))
 } > kseg0_boot_mem

Which is around line 371. The hex file should now load to the correct place.

 

Upgrading from C32 V 2 to XC32 V1.31 (August 2014)

And here we go again. I note from the above that it took a day to go from version 1 to 2 well, for me, it took the best part of a week to bottom out all of the changes. This time there is a single linker file rather than the two:

  • elf32pic32mx.ld
  • procdefs.ld

The above was the arrangement for the C32 (version 1 and 2 compilers). The procdefs.ld file changes for each device. Now we have a single file that is named after the device,thus:

  • p32MX370F512H.ld (name different for each device)

This single file combines both files. I must say that is is a better arrangement as my makefile can now point to just that single file. The BIG difference now is that the old compiler used kseg0_boot_mem as the reset location for the program and using my existing boot loader the linker relevant bit of script looked like this:

_RESET_ADDR              = 0xBFC00000;

  kseg0_program_mem    (rx)  : ORIGIN = 0x9D002000, LENGTH = 0x7E800    /* main */
  kseg0_boot_mem                : ORIGIN = 0x9D000000, LENGTH = 0x7F0      /* startup code */
  exception_mem                   : ORIGIN = 0x9D001000, LENGTH = 0x1000
  kseg1_boot_mem                : ORIGIN = 0xBFC00000, LENGTH = 0x490

The reset address was in kesg1_boot_mem which was the reset of the boot loader. The boot loader word discover a program at kseg0_boot_mem and run that start up code. It should be noted that in any case the PIC has to restart somewhere and this is fixed in hardware so regardless of where the reset is, the boot loader will always run first.

The XC32 compiler does not and WILL not use kseg0_boot_mem OUCH. The length of this memory area can be set to zero as it is completely ignored. So initial thoughts is that the new XC32 compile cannot produce code that will work with the old boot loader - how can it? Like I said a week later ("never give up never surrender") there is in fact a way to do it.

_RESET_ADDR                        = (0x9D000000);
_BEV_EXCPT_ADDR                = (0x9D000000 + 0x1000  + 0x380);
_DBG_EXCPT_ADDR                = (0x9D000000 + 0x1000  + 0x480);
 

  kseg0_program_mem     (rx)  : ORIGIN = 0x9D003000, LENGTH = 0x80000-0x3000
  kseg0_boot_mem                 : ORIGIN = 0x9D000000, LENGTH = 0 /* not used in XC32 */
  exception_mem                    : ORIGIN = 0x9D002000, LENGTH = 0x1000
  kseg1_boot_mem                 : ORIGIN = 0x9D000000, LENGTH = 0x1ff0 /* start up code */

This works with the old boot loader. This time the reset address is at 9d000000 and so after the boot loader runs (which always happens) the application start up code is then run.

I will be honest and say that I don't fully understand the linking process, if I had another week I think that I may be able to sort this out better and probably tighten up the addresses a bit. But this works fine so I will probably wait until the next upgrade - roll on 2016.