Memory Considerations When Using Flash Routines in the MPLAB XC8 Compiler

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

Flash routines, like those generated by MPLAB® Code Configurator (MCC), can be used to access program flash memory, but before using these routines to erase or write memory blocks, you must first ensure that the MPLAB XC8 compiler will not allocate this memory for other objects.

Flash routines can be used with any program memory, but they are often used when accessing the special memory regions that are implemented by some PIC® devices, such as the High-Endurance Flash (HEF) memory, implemented by the PIC16F1619 device, for example. Even if a memory region has a special function, the compiler will usually consider it as part of the normal program memory space, and store regular code or data in this region. If you use flash routines to erase or write such a region of memory, you run the risk of clobbering any code or data that the compiler has stored there. The same would be true if you invoke a flash erase or write by manipulating the relevant Special Function Registers (SFR) of the device, whether that be in C code or hand-written assembly. Erasing or overwriting compiler-generated code or data at runtime will almost certainly result in erratic and erroneous program behaviour that can be difficult to debug.

Whenever you change the content of any device memory—regardless of whether it has a special function or not—the compiler must be informed that this memory is in use. In most cases, this is performed automatically when you define C functions and objects, as the compiler will allocate them memory. However, this is not the case if you arbitrarily assign a region of memory for a special purpose and access that region using only a flash routine, as in the following example, where the word at address 0x1F80 has been written using an MCC-generated flash write routine.

FLASH_WriteWord(0x1F80, &writeBuffer, data);

To erase or write to memory using flash routines, you can:

  • reserve the memory you require, or
  • place absolute objects in that memory as placeholders.

If, for example, you intend to use the HEF memory for special data in your program, you can reserve this region of program memory using a compiler option. For a 16F1619 device, HEF exists from address 0x1F80 thru 0x1FFF in program memory. Use the XC8 driver option -mreserve to remove this range from the memory managed by the compiler, for example, -mreserve=rom@1F80:1FFF. Alternatively, you can use the -mrom option to perform the same task: -mrom=default,-1F80-1FFF. (If you are using a version 1.xx compiler, use the —rom option.) With this memory reserved, the compiler will not use this memory for ordinary objects, allowing you to read or write it in any way you desire.

A better way to utilize an arbitrary memory region is to define one or more placeholder objects over this memory rather than reserve the memory. This will ensure that the memory is not being used by the compiler, but will also allow you to reference the memory region via the placeholder’s identifier. For example, to place an object over the HEF, use an object definition similar to the following in your program.

const HEFregion[128] __at(0x1F80);

The const qualifier signifies that the object is to be placed in program memory. Ensure that the address in the __at() matches the start address of the region and the size of the object matches the amount of memory you intend to use.

Rather than using the literal address 0x1F80, the call to the flash write function used above could then become:

FLASH_WriteWord((uint16_t)HEFregion, &writeBuffer, data);

And, of course, having this object defined means that you can read the object directly, as in the following example:

if(HEFregion[idx] == 0x13)
    markAsSet(CLOSED);