AnsweredAssumed Answered

Code Read Protection (CRP)

Question asked by LPCware Support on Mar 31, 2016



NXP's LPC Cortex-M and ARM7 based MCUs which contain internal flash memory contain "Code Read Protection" (CRP) support. This mechanism uses one of a number of known values being placed in a specific location in flash memory to provide a number of levels of protection. When the MCU boots, this specific location in flash memory is read and depending upon its value, the MCU may prevent access to the flash memory by external devices. This location is typically at 0x2FC for Cortex based systems and 0x1FC for ARM7 based systems. Note that for LPC18xx/43xx parts with internal flash, the CRP location is at an offset of 0x2FC from the start of the flash bank being used.


Important Note - You should take particular care when modifying the value placed in the CRP word, as some CRP settings can disable some or all means of access to your MCU (including debug). Before making use of CRP, you are strongly advised to read NXP's documentation on this functionality. You can access the documentation for your MCU at Microcontrollers and Processors|NXP


Support for CRP in LPCXpresso IDE


Support for setting up the CRP memory location is provided via a combination of the Project Wizard, a header file and a number of macros. This support allows specific values to be easily placed into the CRP memory location, based on the user's requirements.


The New Project wizard contains an option to allow linker support for placing a CRP word to be enabled when you create a new project. This is typically enabled by default. This wizard option actually then controls the  "Enable CRP" checkbox of the Project Properties linker Target tab.


In addition the wizard will create a file, 'crp.c' which defines the  'CRP_WORD' variable which will contain the required CRP value. A set of possible values are provided by the NXP/crp.h header file that this then includes. Thus for example 'crp.c' will typically contain:

#include <NXP/crp.h>
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

which is then placed at the correct location in Flash by the linker script generated by LPCXpresso IDE

. = 0x000002FC ; /* or 1FC for LPC2000 */

Note the value CRP_NO_CRP ensures that the flash memory is fully accessible. When you reach the stage of your project where you want to protect your image, you will need to modify the CRP word to contain an appropriate value. Remember doing this will prevent future debugger access.


Reducing Code Size when CRP enabled


One of the consequences of this support is that the memory between the CPU's vector table and the CRP word is by default left largely unused. This typically increases the size of the application image by around 400 bytes (depending upon the MCU being used).


However this ~400 bytes of space can easily be reclaimed by choosing one or more functions to be placed into this "spare" memory. To do this, you simply need to decorate their definitions with the macro __AFTER_VECTORS which is supplied in the "cr_section_macros.h" header file


Obviously in order to do this effectively, you need to identify functions which will occupy as much of the "spare" memory as possible. The best way to do this is to look at the linker map file


The default LPCXpresso IDE generated startup code already uses this macro to place the various initialization functions and default exception handlers that it contains into this space, thus reducing the 'default' unused space. You can also place additional functions there by decorating their definitions with the macro, for example

__AFTER_VECTORS void myStartupFunction(void);

Note you will get a link error if the __AFTER_VECTORS space grows beyond the CRP (when CRP support is enabled):

myproj_Debug.ld:98 cannot move location counter backwards (from 00000334 to 000002fc)
collect2: ld returned 1 exit status
make: *** [myproj.axf] Error 1

In this case, you will need to remove the __AFTER_VECTORS macro from the definition of one or more of your functions.