To avoid piracy is very important for software and firmware development. Of course, you should protect your source code would not be spread out. But from firmware prospect, it is a way to piracy your intelligence: he might clone your WHOLE device, including the mechanism, circuit and firmware. It is not necessary to get your source code.
In nRF51822 and 52832, There is a mechanism to prevent that happens. I will demonstrate that:
My SDK versions are 10 for nRF51, and 11 for nRF52.
To Simplify the demonstration. I copy the peripheral\uicr_config\uicr_config.h to my project folder, and the main.c include the file.
Open the uicr_config.h, you could read that there is many address listed, you could modify the values on those addresses. The values I changing be :
// const uint32_t UICR_CLENR0 __attribute__((at(0x10001000))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_RBPCONF __attribute__((at(0x10001004))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_XTALFREQ __attribute__((at(0x10001008))) __attribute__((used)) = 0xFFFFFFFF; const uint32_t UICR_ADDR_0x80 __attribute__((at(0x10001080))) __attribute__((used)) = 0x12345678; // const uint32_t UICR_ADDR_0x84 __attribute__((at(0x10001084))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0x88 __attribute__((at(0x10001088))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0x8C __attribute__((at(0x1000108C))) __attribute__((used)) = 0xFFFFFFFF; const uint32_t UICR_ADDR_0x90 __attribute__((at(0x10001090))) __attribute__((used)) = 0x11223344; const uint32_t UICR_ADDR_0x94 __attribute__((at(0x10001094))) __attribute__((used)) = 0x55667788; // const uint32_t UICR_ADDR_0x98 __attribute__((at(0x10001098))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0x9C __attribute__((at(0x1000109C))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xA0 __attribute__((at(0x100010A0))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xA4 __attribute__((at(0x100010A4))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xA8 __attribute__((at(0x100010A8))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xAC __attribute__((at(0x100010AC))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xB0 __attribute__((at(0x100010B0))) __attribute__((used)) = 0xFFFFFFFF; const uint32_t UICR_ADDR_0xB4 __attribute__((at(0x100010B4))) __attribute__((used)) = 0xAABBCCDD; // const uint32_t UICR_ADDR_0xB8 __attribute__((at(0x100010B8))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xBC __attribute__((at(0x100010BC))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xC0 __attribute__((at(0x100010C0))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xC4 __attribute__((at(0x100010C4))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xC8 __attribute__((at(0x100010C8))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xCC __attribute__((at(0x100010CC))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xD0 __attribute__((at(0x100010D0))) __attribute__((used)) = 0xFFFFFFFF; // const uint32_t UICR_ADDR_0xD4 __attribute__((at(0x100010D4))) __attribute__((used)) = 0xFFFFFFFF;
By the way, What is UICR ? UICR is the short for User Information Configuration Registers, where the values are non-alterable. The purpose for UICR is to make a space for manufacturer signing.
Build and download the hex to your device, and type the command line (I use nRF52832 as my target device):
> nrfjprog --family NRF52 --memrd 0x10001080 --n 128 0x10001080: 12345678 FFFFFFFF FFFFFFFF FFFFFFFF |xV4.............| 0x10001090: 11223344 55667788 FFFFFFFF FFFFFFFF |D3"..wfU........| 0x100010A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| 0x100010B0: FFFFFFFF AABBCCDD FFFFFFFF FFFFFFFF |................| 0x100010C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| 0x100010D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| 0x100010E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| 0x100010F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
The address values have been changed.
You could use the command the dump the whole hex :
> nrfjprog --family NRF52 --readcode output.hex
That is what I prevent from.
To avoid the dumping, Add below code in the beginning of main function :
#include "ble_flash.h" /**@brief Function for application main entry. */ int main(void) { #if(1) if(UICR_RBPCONF_PALL_Enabled != (uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos)) { ble_flash_word_write((uint32_t *)&NRF_UICR->RBPCONF, (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk)); }/*if */ #endif uint32_t err_code; bool erase_bonds;
and you should include folder SDK_ROOT\components\drivers_nrf\ble_flash and the file SDK_ROOT\components\drivers_nrf\ble_flash\ble_flash.c in your working porject.
Take Keil C as the project modification example:
After download to the device, you could find the readback command would not work:
> nrfjprog --family NRF52 --memrd 0x10001080 --n 128 ERROR: The operation attempted is unavailable due to readback protection in ERROR: your device. Please use --recover to unlock the device.
That is, the SWD (Serial Wired Debug) function has been forbidden, the SWD could accept recover request from now.
NOTE :If you use Keil C, the IDE would not reset the device after the downloading. but you could press the download button twice to make sure the SWD has been disabled:
* JLink Info: Found SWD-DP with ID 0x2BA01477 * JLink Info: Found Cortex-M4 r0p1, Little endian. * JLink Info: FPUnit: 6 code (BP) slots and 2 literal slots * JLink Info: CoreSight components: * JLink Info: ROMTbl 0 @ E00FF000 * JLink Info: ROMTbl 0 [0]: FFF0F000, CID: B105E00D, PID: 000BB00C SCS * JLink Info: ROMTbl 0 [1]: FFF02000, CID: B105E00D, PID: 003BB002 DWT * JLink Info: ROMTbl 0 [2]: FFF03000, CID: B105E00D, PID: 002BB003 FPB * JLink Info: ROMTbl 0 [3]: FFF01000, CID: B105E00D, PID: 003BB001 ITM * JLink Info: ROMTbl 0 [4]: FFF41000, CID: B105900D, PID: 000BB9A1 TPIU * JLink Info: ROMTbl 0 [5]: FFF42000, CID: B105900D, PID: 000BB925 ETM ROMTableAddr = 0xE00FF000 * JLink Info: SYSRESETREQ has confused core. Trying to reconnect and use VECTRESET. * JLink Info: Found SWD-DP with ID 0x2BA01477 **JLink Warning: Failed to reset CPU. VECTRESET has confused core. * JLink Info: Core is locked-up, trying to disable WDT. **JLink Warning: Could not set S_RESET_ST * JLink Info: Found SWD-DP with ID 0x2BA01477 * JLink Info: SYSRESETREQ has confused core. Trying to reconnect and use VECTRESET. * JLink Info: Found SWD-DP with ID 0x2BA01477 **JLink Warning: Failed to reset CPU. VECTRESET has confused core. * JLink Info: Core is locked-up, trying to disable WDT. **JLink Warning: Could not set S_RESET_ST
Now you could see, the dumping has not been permitted, the only way to manipulate the storage (ROM) is to recover whole space: it is, erase all.