I am trying to implement a bootloader with rewrite protection on nrf52840 with SDK: 14.0.0. But it seems that there is no flash write protection registers in nrf52840. So is there a way to implement a flash rewrite protection?
Thanks.
I am trying to implement a bootloader with rewrite protection on nrf52840 with SDK: 14.0.0. But it seems that there is no flash write protection registers in nrf52840. So is there a way to implement a flash rewrite protection?
Thanks.
Hi,
The BPROT peripheral that is found in the nRF52832, has been replaced with the ACL peripheral on the nRF52840. ACL works similar to the BPROT(erase/write protection), but also adds support for protection against reading the flash.
You can find more information about the ACL here.
Are you testing this in an active debug session? I think the current implementation of ACL is that erase/write is allowed while debugging.
Here is the code I used to test this. LED3 will light if the data is successfully deleted, and re-written. If tested in non-debug mode session, the LED3 and LED4 will not light, indicating that the device hardfaults because there is an attempt to erase/write to protected flash.
#include <stdbool.h>
#include <stdint.h>
#include "boards.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_nvmc.h"
#define LED_PIN1 13 // Pin P0.13
#define LED_PIN2 14 // Pin P0.14
#define LED_PIN3 15 // Pin P0.15
#define LED_PIN4 16 // Pin P0.16
#define PAGE_SIZE 4096
#define REGION1_START 0xF0000 //0xF0000
#define REGION1_SIZE PAGE_SIZE*10 //PAGE_SIZE*10
void led_off(uint8_t led)
{
NRF_GPIO->OUTSET = (1UL << led);
}
void led_on(uint8_t led)
{
NRF_GPIO->OUTCLR = (1UL << led);
}
void configure_leds(void)
{
uint8_t led_pins[4] = {LED_PIN1, LED_PIN2, LED_PIN3, LED_PIN4};
for (int i = 0; i < sizeof(led_pins); i++)
{
// setup led gpio in output mode
led_off(led_pins[i]);
NRF_GPIO->PIN_CNF[led_pins[i]] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
}
}
int test_writeProtect(void)
{
uint32_t errcode = 0;
// Start by erasing region 1
nrf_nvmc_page_erase(REGION1_START);
//Writing to region 1
nrf_nvmc_write_word(REGION1_START, 0xABBA1234);
// Read before ACL region is configured
uint32_t orig_data = 0;
orig_data = *((uint32_t *)REGION1_START);
// Disable write/erase for region 1 with ACL
NRF_ACL->ACL[0].ADDR = REGION1_START;
NRF_ACL->ACL[0].SIZE = REGION1_SIZE;
NRF_ACL->ACL[0].PERM = ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos;
//Try to erase region 1
nrf_nvmc_page_erase(REGION1_START);
// Write to region 1
nrf_nvmc_write_word(REGION1_START, 0xABBADEAD);
// Try to read from region using CPU
uint32_t new_data = 0;
new_data = *((uint32_t *)REGION1_START);
if (new_data == 0xABBADEAD) // data successfully deleted, and re-written
{
errcode = 1;
led_on(LED_PIN3);
}
return errcode;
}
int main(void)
{
configure_leds();
led_on(LED_PIN1); // Start
test_writeProtect();
led_on(LED_PIN4);
while (true)
{
// Do nothing.
}
}
/** @} */
Are you testing this in an active debug session? I think the current implementation of ACL is that erase/write is allowed while debugging.
Here is the code I used to test this. LED3 will light if the data is successfully deleted, and re-written. If tested in non-debug mode session, the LED3 and LED4 will not light, indicating that the device hardfaults because there is an attempt to erase/write to protected flash.
#include <stdbool.h>
#include <stdint.h>
#include "boards.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_nvmc.h"
#define LED_PIN1 13 // Pin P0.13
#define LED_PIN2 14 // Pin P0.14
#define LED_PIN3 15 // Pin P0.15
#define LED_PIN4 16 // Pin P0.16
#define PAGE_SIZE 4096
#define REGION1_START 0xF0000 //0xF0000
#define REGION1_SIZE PAGE_SIZE*10 //PAGE_SIZE*10
void led_off(uint8_t led)
{
NRF_GPIO->OUTSET = (1UL << led);
}
void led_on(uint8_t led)
{
NRF_GPIO->OUTCLR = (1UL << led);
}
void configure_leds(void)
{
uint8_t led_pins[4] = {LED_PIN1, LED_PIN2, LED_PIN3, LED_PIN4};
for (int i = 0; i < sizeof(led_pins); i++)
{
// setup led gpio in output mode
led_off(led_pins[i]);
NRF_GPIO->PIN_CNF[led_pins[i]] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
}
}
int test_writeProtect(void)
{
uint32_t errcode = 0;
// Start by erasing region 1
nrf_nvmc_page_erase(REGION1_START);
//Writing to region 1
nrf_nvmc_write_word(REGION1_START, 0xABBA1234);
// Read before ACL region is configured
uint32_t orig_data = 0;
orig_data = *((uint32_t *)REGION1_START);
// Disable write/erase for region 1 with ACL
NRF_ACL->ACL[0].ADDR = REGION1_START;
NRF_ACL->ACL[0].SIZE = REGION1_SIZE;
NRF_ACL->ACL[0].PERM = ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos;
//Try to erase region 1
nrf_nvmc_page_erase(REGION1_START);
// Write to region 1
nrf_nvmc_write_word(REGION1_START, 0xABBADEAD);
// Try to read from region using CPU
uint32_t new_data = 0;
new_data = *((uint32_t *)REGION1_START);
if (new_data == 0xABBADEAD) // data successfully deleted, and re-written
{
errcode = 1;
led_on(LED_PIN3);
}
return errcode;
}
int main(void)
{
configure_leds();
led_on(LED_PIN1); // Start
test_writeProtect();
led_on(LED_PIN4);
while (true)
{
// Do nothing.
}
}
/** @} */