Powering Out of Reset in the MPLAB® XC8 Compiler

Last modified by Microchip on 2023/11/09 09:13

Runtime Startup Code

Some hardware configurations require special initialization. Often, this needs to be done within the first few instruction cycles after a device resets. To accommodate this, you might be tempted to add statements to the beginning of your main() function, however, this function might not begin execution for some time after reset, so this is far from ideal.

Before any C code can execute, the runtime environment must be prepared. This is performed by the runtime startup code, which is the code that is generated by the compiler and is executed before main() is invoked. The runtime startup code ensures that stacks and operating modes are correctly initialized. It also clears uninitialized global and static variables defined in your program and it sets the initial value of other global and static variables. The code to initialize these variables can be very time-consuming, particularly when there are many values to read from program memory and write to RAM. Given this potential and very significant time delay, what can you do if you have impatient hardware that is threatening to meltdown unless it can be configured?

The MPLAB® XC8 C Compiler provides a special hook to the reset vector to allow the execution of a special code called a "powerup routine". If you define a powerup routine, it will be executed first, before the runtime startup code.

Assembly stubs of powerup routines are provided in your compiler’s sources directory. These can be completed to perform the tasks you require. For PIC18 devices, use the sources/pic18/powerup.as file; for all other devices, use the sources/pic/powerup.as file. Copy the relevant file containing the powerup assembly stub and add the copy to your project or include it in the list of files being compiled, if you are building using the command line.

Edit the powerup file and add the code you require after the powerup label and before the sequence of code that performs the jump to the label start which is the entry point to the runtime startup code. You must keep this jump instruction sequence intact. Do not jump to main(), as this will defeat the runtime startup code and your application might fail. The linking of the powerup routine is fully automatic, provided you place your code in the powerup psect, which is already specified in the assembly stub. When you next build your project, the powerup routine will be automatically linked to the reset vector and executed after reset.

If you use any C preprocessor directives (such as #include) or C-style comments in the powerup file, ensure that the Preprocess assembly files option is enabled. This option can be found in the XC8 Compiler > Preprocessing and Messaging category dialog in the MPLAB X IDE or use the -P option if you are compiling on the command line. There is no harm in enabling this option, even if it is not needed.

Here is an example powerup.as file for a PIC18 device, modified with instructions that set PORT B into a prescribed state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <xc.inc>

    GLOBAL powerup, start
    PSECT powerup,class=CODE,delta=1,reloc=2
powerup:
    nop        ; suggested Microchip errata workaround

    ; code added by the user
    ; RB1/2 must be set as soon as possible; other bits cleared
    clrf     TRISB
    movlw    0x06
    movwf    LATB
    ; end of user-added code

    ; transfer control to the runtime startup code
    ; and then on to main()
    goto    start
    END

Since the powerup code is executed before the C runtime environment has been initialized, it must be written in assembly. This means that you are responsible for all aspects of the powerup code’s operation. You must manually add bank selection instructions and perform address masking when appropriate. Similarly, you must be aware of any published errata for the device you are using and follow any recommended workarounds. See the MPLAB XC8 C Compiler User’s Guide section "What Things Must I Manage When Writing Assembly Code?" for more information. If you include the <xc.inc> assembly header file, your code can use any of the symbols for the device’s special function registers or bits within those registers, as the above example shows.

To confirm that everything has worked correctly, check the startup.as file (or the startup.lst list file) after you build. This file holds some of the runtime startup code and is regenerated each time you build your project. By default, this file will remain after compiling, if you are building on the command line but if you are using the MPLAB X IDE, you will need to set an option for it to be preserved. Enable the XC8 Linker > Runtime > Keep generated startup option. You should see something similar to the following in the generated startup code:

1
2
3
4
5
6
    psect   reset_vec
reset_vec:
    global powerup

; Power-up routine detected. Jumping to powerup...
    goto    powerup

In particular, the goto powerup instruction is linked directly to the reset vector.