* New Firmware OTA for NVM/mcuboot (nRF5)

- Support for mcuboot (nRF5)
- Support for run length encoded data
- Support for smaller FIRMWARE_BLOCK_SIZE, if required

* Update NVM

* New MY_LOCK_MCU for NRF5

* Test with Sensebender GW + Sensebender Micro was successful
This commit is contained in:
d00616
2018-02-28 20:03:34 +01:00
committed by Mikael Falkvidd
parent 599c0bada6
commit fe42dbdcca
9 changed files with 292 additions and 106 deletions

View File

@@ -52,12 +52,14 @@ uint32_t *FlashClass::page_address(size_t page)
uint32_t *FlashClass::top_app_page_address()
{
#if !defined(MCUBOOT_PRESENT)
// Bootcode at the top of the flash memory?
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Flib_bootloader.html
if (NRF_UICR->NRFFW[0]<0xFFFFFFFF) {
// Return pointer calculated by SoftDevice/bootloader
return (uint32_t *)NRF_UICR->NRFFW[0];
}
#endif
// Return flash length
return (uint32_t *)(Flash.page_count() << Flash.page_size_bits());

View File

@@ -21,37 +21,45 @@
VirtualPageClass VirtualPage;
#ifndef VNM_VIRTUAL_PAGE_SIZE_BITS
#define VNM_VIRTUAL_PAGE_SIZE_BITS 12
#elif VNM_VIRTUAL_PAGE_SIZE_BITS < 12
#error "VNM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
#ifndef NVM_VIRTUAL_PAGE_SIZE_BITS
#define NVM_VIRTUAL_PAGE_SIZE_BITS 12
#elif NVM_VIRTUAL_PAGE_SIZE_BITS < 12
#error "NVM_VIRTUAL_PAGE_SIZE_BITS must be >= 12"
#endif
// Calculate virtual page count, when mcuboot is present
#if defined(MCUBOOT_PRESENT) && !defined(NVM_VIRTUAL_PAGE_COUNT)
// mcuboot zephyr build via generated_dts_board.h
#include "generated_dts_board.h"
// Calculate number of free pages after scratch area
#define NVM_VIRTUAL_PAGE_COUNT (((CONFIG_FLASH_SIZE_0<<10)-(FLASH_AREA_IMAGE_SCRATCH_OFFSET_0+FLASH_AREA_IMAGE_SCRATCH_SIZE_0)) >> NVM_VIRTUAL_PAGE_SIZE_BITS)
#endif
// check page size
#ifndef VNM_VIRTUAL_PAGE_COUNT
#ifndef NVM_VIRTUAL_PAGE_COUNT
#if FLASH_ERASE_CYCLES >= 20000
// use 16k of flash memory
#define VNM_VIRTUAL_PAGE_COUNT 4
#define NVM_VIRTUAL_PAGE_COUNT 4
#else
// use 32k of flash memory
#define VNM_VIRTUAL_PAGE_COUNT 8
#define NVM_VIRTUAL_PAGE_COUNT 8
#endif
#endif
/*
* How many virtual pages are skipped from top of flash
*/
#ifndef VNM_VIRTUAL_PAGE_SKIP_FROM_TOP
#define VNM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
#ifndef NVM_VIRTUAL_PAGE_SKIP_FROM_TOP
#define NVM_VIRTUAL_PAGE_SKIP_FROM_TOP 0
#endif
/*
* Calculate things around VNM_VIRTUAL_PAGE_SIZE
* Calculate things around NVM_VIRTUAL_PAGE_SIZE
*/
#define VNM_VIRTUAL_PAGE_SIZE (1 << (VNM_VIRTUAL_PAGE_SIZE_BITS))
#define VNM_VIRTUAL_PAGE_ADDRESS_MASK (~(VNM_VIRTUAL_PAGE_SIZE - 1))
#define VNM_VIRTUAL_PAGE_ALIGN(address) \
{ address = (uint32_t *)((uint32_t)address & VNM_VIRTUAL_PAGE_ADDRESS_MASK); }
#define NVM_VIRTUAL_PAGE_SIZE (1 << (NVM_VIRTUAL_PAGE_SIZE_BITS))
#define NVM_VIRTUAL_PAGE_ADDRESS_MASK (~(NVM_VIRTUAL_PAGE_SIZE - 1))
#define NVM_VIRTUAL_PAGE_ALIGN(address) \
{ address = (uint32_t *)((uint32_t)address & NVM_VIRTUAL_PAGE_ADDRESS_MASK); }
/*
* Defines the position of status words in a page.
@@ -79,8 +87,8 @@ VirtualPageClass VirtualPage;
#define OFFSET_MAGIC 1
#define OFFSET_COUNTER 0
#define MASK_ERASE_COUNTER 0x00FFFFFF
#define OFFSET_STATUS_RELEASE_PREPARE VNM_VIRTUAL_PAGE_SIZE - 8
#define OFFSET_STATUS_RELEASE_END VNM_VIRTUAL_PAGE_SIZE - 4
#define OFFSET_STATUS_RELEASE_PREPARE NVM_VIRTUAL_PAGE_SIZE - 8
#define OFFSET_STATUS_RELEASE_END NVM_VIRTUAL_PAGE_SIZE - 4
#define METADATA_SIZE 16
#define OFFSET_DATA 4
#endif
@@ -88,45 +96,45 @@ VirtualPageClass VirtualPage;
#define BIT_STATUS_RELEASE_PREPARE (1 << 30)
#define BIT_STATUS_RELEASE_END (1 << 31)
#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - METADATA_SIZE)
#else
// use first 8 byte for magic and erase counter and last 8 byte for page release
#define OFFSET_MAGIC 1
#define OFFSET_ERASE_COUNTER 0
#define OFFSET_DATA 2
#define OFFSET_STATUS_RELEASE_PREPARE \
((VNM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
((NVM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t))
#define OFFSET_STATUS_RELEASE_END \
((VNM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
((NVM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t))
#define MASK_ERASE_COUNTER 0xFFFFFFFF
#define BIT_STATUS_RELEASE_PREPARE 1
#define BIT_STATUS_RELEASE_END 1
#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - 16)
#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - 16)
#endif
uint16_t VirtualPageClass::size() const
{
return (VNM_VIRTUAL_PAGE_DATA_SIZE);
return (NVM_VIRTUAL_PAGE_DATA_SIZE);
}
uint16_t VirtualPageClass::length() const
{
return (VNM_VIRTUAL_PAGE_DATA_SIZE / 4);
return (NVM_VIRTUAL_PAGE_DATA_SIZE / 4);
}
uint16_t VirtualPageClass::page_count() const
{
return (VNM_VIRTUAL_PAGE_COUNT - 1);
return (NVM_VIRTUAL_PAGE_COUNT - 1);
}
uint32_t VirtualPageClass::wear_level()
{
uint32_t max_erase_cycles = 0;
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t erase_cycles = get_page_erase_cycles(get_page_address(i));
if (erase_cycles > max_erase_cycles) {
max_erase_cycles = erase_cycles;
@@ -140,7 +148,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
{
// Give back a page prepared for release and not closed
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -156,7 +164,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic)
}
// check if a unreleased page is available
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if (
// correct magic is set
@@ -177,7 +185,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic)
uint32_t max_erase_cycles = (uint32_t)~0;
// Avoid duplicate allocation of pages, look for the less used page
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
// Delete duplicated pages
@@ -225,7 +233,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic, uint32_t max_writes)
void VirtualPageClass::release_prepare(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -244,7 +252,7 @@ void VirtualPageClass::release_prepare(uint32_t *address)
void VirtualPageClass::release(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// Nothing to do at a empty page
if (address[OFFSET_MAGIC] == (uint32_t)~0) {
@@ -263,7 +271,7 @@ void VirtualPageClass::release(uint32_t *address)
bool VirtualPageClass::release_started(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
return (address[OFFSET_STATUS_RELEASE_PREPARE] &
BIT_STATUS_RELEASE_PREPARE) == 0;
@@ -272,7 +280,7 @@ bool VirtualPageClass::release_started(uint32_t *address)
void VirtualPageClass::fail(uint32_t *address)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
build_page(address, 0x00000000);
return;
@@ -281,7 +289,7 @@ void VirtualPageClass::fail(uint32_t *address)
void VirtualPageClass::clean_up()
{
// No page found -> try to give back a page prepared for release
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *page = get_page_address(i);
if ((page[OFFSET_STATUS_RELEASE_END] & BIT_STATUS_RELEASE_END) == 0) {
build_page(get_page_address(i), ~0);
@@ -292,7 +300,7 @@ void VirtualPageClass::clean_up()
void VirtualPageClass::format()
{
for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) {
for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) {
uint32_t *address = get_page_address(i);
build_page(address, (uint32_t)~0);
}
@@ -301,25 +309,25 @@ void VirtualPageClass::format()
uint32_t *VirtualPageClass::get_page_address(uint16_t page)
{
return (uint32_t *)(Flash.top_app_page_address() -
((page + VNM_VIRTUAL_PAGE_SKIP_FROM_TOP)
<< VNM_VIRTUAL_PAGE_SIZE_BITS));
((page + NVM_VIRTUAL_PAGE_SKIP_FROM_TOP)
<< NVM_VIRTUAL_PAGE_SIZE_BITS));
}
void VirtualPageClass::build_page(uint32_t *address, uint32_t magic)
{
// move pointer to beginning of the page
VNM_VIRTUAL_PAGE_ALIGN(address);
NVM_VIRTUAL_PAGE_ALIGN(address);
// get erase counter
uint32_t erase_counter = get_page_erase_cycles(address);
// Check if a magic is set
if (address[OFFSET_MAGIC] != (uint32_t)~0) {
Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
} else {
// check if page is empty
for (int i = OFFSET_DATA; i < (VNM_VIRTUAL_PAGE_SIZE / 4); i++) {
for (int i = OFFSET_DATA; i < (NVM_VIRTUAL_PAGE_SIZE / 4); i++) {
if (address[i] != (uint32_t)~0) {
Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE);
Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE);
break;
}
}