mirror of
https://github.com/espressif/openthread.git
synced 2026-08-05 10:27:49 +00:00
[efr32] add nvm3 support (#4521)
silabs nvm3 support is selected by setting following macro in
openthread-core-efr32-config.h :-
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0
This commit is contained in:
@@ -70,7 +70,6 @@ else
|
||||
$(error Please provide a value for BOARD variable e.g BOARD=BRD4168A (currently supported BRD4168A))
|
||||
endif
|
||||
|
||||
|
||||
EFR32_MBEDTLS_CPPFLAGS = -DMBEDTLS_CONFIG_FILE='\"mbedtls-config.h\"'
|
||||
EFR32_MBEDTLS_CPPFLAGS += -DMBEDTLS_USER_CONFIG_FILE='\"efr32-mbedtls-config.h\"'
|
||||
EFR32_MBEDTLS_CPPFLAGS += -D$(MCU)
|
||||
|
||||
@@ -76,6 +76,8 @@ libopenthread_efr32mg12_a_CPPFLAGS =
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/ustimer/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emlib/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/halconfig/inc/hal-config \
|
||||
-I$(SDK_SRC_DIR)/platform/radio/rail_lib/chip/efr32 \
|
||||
|
||||
@@ -41,8 +41,9 @@ LDADD_COMMON +=
|
||||
$(top_builddir)/examples/platforms/efr32mg12/libopenthread-efr32mg12.a \
|
||||
$(top_builddir)/third_party/silabs/libsilabs-efr32mg12-sdk.a \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/radio/rail_lib/autogen/librail_release/$(LIBRAIL) \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a \
|
||||
$(NULL)
|
||||
|
||||
LDFLAGS_COMMON += \
|
||||
-T $(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/Device/SiliconLabs/EFR32MG12P/Source/GCC/efr32mg12p.ld \
|
||||
-T $(top_srcdir)/examples/platforms/efr32mg12/efr32mg12.ld \
|
||||
$(NULL)
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread linker script for the
|
||||
* Silicon Labs efr32mg12 platform.
|
||||
*
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
}
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapBase
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
* __Vectors_End
|
||||
* __Vectors_Size
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
__Vectors_End = .;
|
||||
__Vectors_Size = __Vectors_End - __Vectors;
|
||||
__end__ = .;
|
||||
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
__etext = .;
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
. = ALIGN (4);
|
||||
PROVIDE (__ram_func_section_start = .);
|
||||
*(.ram)
|
||||
PROVIDE (__ram_func_section_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__HeapBase = .;
|
||||
__end__ = .;
|
||||
end = __end__;
|
||||
_end = __end__;
|
||||
KEEP(*(.heap*))
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
KEEP(*(.stack*))
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/*******************************************************************/
|
||||
/* Define 8K (2000H) byte flash block for OT nvm3- */
|
||||
/* ( == 4 x Flash Pages as configured in flash.c) */
|
||||
.otNvm3_block (LENGTH(FLASH) - 0x2000) (NOLOAD):
|
||||
{
|
||||
. = ALIGN (8192);
|
||||
__nvm3OtBase = .;
|
||||
KEEP(*(otNvm3_section));
|
||||
__nvm3OtCeiling = .;
|
||||
} > FLASH
|
||||
/*******************************************************************/
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
|
||||
/* Check if FLASH usage exceeds FLASH size */
|
||||
ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !")
|
||||
}
|
||||
@@ -28,69 +28,357 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile storage.
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile
|
||||
* storage for the EFR32 platform using the Silabs Nvm3 interface.
|
||||
*/
|
||||
|
||||
#include <openthread/config.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#if !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
#include "nvm3.h"
|
||||
#include "nvm3_hal_flash.h"
|
||||
#include <string.h>
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#include <openthread/instance.h>
|
||||
// Two macros are provided to support the creation of the Silicon Labs NVM3 area and
|
||||
// initialization data- NVM3_DEFINE_SECTION_STATIC_DATA() and NVM3_DEFINE_SECTION_INIT_DATA().
|
||||
// A linker section called 'name'_section is defined by NVM3_DEFINE_SECTION_STATIC_DATA().
|
||||
// The NVM3 area is placed at the top of the device FLASH section by the linker script
|
||||
// file: e.g. efr32mgxx.ld
|
||||
// An error is returned by nvm3_open() on alignment or size violation.
|
||||
|
||||
#include "em_msc.h"
|
||||
// Local version of SDK macro (avoids uninitialized var compile error).
|
||||
#define OT_NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize) \
|
||||
static nvm3_CacheEntry_t name##_cache[cacheSize]; \
|
||||
static uint8_t name##_nvm[nvmSize] SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
|
||||
|
||||
#define FLASH_PAGE_NUM 4
|
||||
#define FLASH_DATA_END_ADDR (FLASH_BASE + FLASH_SIZE)
|
||||
#define FLASH_DATA_START_ADDR (FLASH_DATA_END_ADDR - (FLASH_PAGE_SIZE * FLASH_PAGE_NUM))
|
||||
#define FLASH_SWAP_PAGE_NUM (FLASH_PAGE_NUM / 2)
|
||||
#define FLASH_SWAP_SIZE (FLASH_PAGE_SIZE * FLASH_SWAP_PAGE_NUM)
|
||||
|
||||
static inline uint32_t mapAddress(uint8_t aSwapIndex, uint32_t aOffset)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
address = FLASH_DATA_START_ADDR + aOffset;
|
||||
|
||||
if (aSwapIndex)
|
||||
{
|
||||
address += FLASH_SWAP_SIZE;
|
||||
// Local version of SDK macro (allows OT to configure the maximum nvm3 object size and headroom).
|
||||
#define OT_NVM3_DEFINE_SECTION_INIT_DATA(name, maxObjectSize, repackHeadroom) \
|
||||
static nvm3_Init_t name = { \
|
||||
(nvm3_HalPtr_t)name##_nvm, \
|
||||
sizeof(name##_nvm), \
|
||||
name##_cache, \
|
||||
sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
|
||||
maxObjectSize, \
|
||||
repackHeadroom, \
|
||||
&nvm3_halFlashHandle, \
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
#define NUM_SETTINGS_OBJECTS 7 // == number of enumerated Settings key types (in settings.hpp).
|
||||
#define NUM_INDEXED_SETTINGS \
|
||||
OPENTHREAD_CONFIG_MLE_MAX_CHILDREN // Indexed key types are only supported for kKeyChildInfo (=='child table').
|
||||
#define NUM_USER_OBJECTS 16 // User nvm3 objects (nvm3 key range 0x0000 -> 0xDFFF is available for user data).
|
||||
|
||||
void otPlatFlashInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
}
|
||||
#define OT_NVM3_FLASH_NUM_PAGES 4 // Note- nvm3 requires minimum of 3 pages.
|
||||
#define OT_NVM3_FLASH_PAGE_SIZE FLASH_PAGE_SIZE // Device flash page size (MG12/MG13=2K, MG21=8K)
|
||||
#define OT_NVM3_FLASH_SIZE OT_NVM3_FLASH_NUM_PAGES *OT_NVM3_FLASH_PAGE_SIZE
|
||||
#define OT_NVM3_MAX_NUM_OBJECTS NUM_SETTINGS_OBJECTS + NUM_INDEXED_SETTINGS + NUM_USER_OBJECTS
|
||||
#define OT_NVM3_MAX_OBJECT_SIZE 256
|
||||
#define OT_NVM3_REPACK_HEADROOM 64 // Threshold for automatic nvm3 flash repacking.
|
||||
|
||||
uint32_t otPlatFlashGetSwapSize(otInstance *aInstance)
|
||||
#define OT_NVM3_SETTINGS_KEY_PREFIX 0xE000 // (=> key range 0x0000-0xDFFF is available for OT User nvm3 objects).
|
||||
|
||||
#define ENUM_NVM3_KEY_LIST_SIZE 4 // List size used when enumerating nvm3 keys.
|
||||
|
||||
static nvm3_Handle_t handle = {NULL};
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index);
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res);
|
||||
|
||||
// Declare OT NVM3 data area and cache.
|
||||
// OT data area should be enough for OT 'Settings' and whatwever User data is required.
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_STATIC_DATA(otNvm3, OT_NVM3_FLASH_SIZE, OT_NVM3_MAX_NUM_OBJECTS);
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_INIT_DATA(otNvm3, OT_NVM3_MAX_OBJECT_SIZE, OT_NVM3_REPACK_HEADROOM);
|
||||
|
||||
void otPlatSettingsInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return FLASH_SWAP_SIZE;
|
||||
}
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
void otPlatFlashErase(otInstance *aInstance, uint8_t aSwapIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
uint32_t address = mapAddress(aSwapIndex, 0);
|
||||
|
||||
for (uint32_t n = 0; n < FLASH_SWAP_PAGE_NUM; n++, address += FLASH_PAGE_SIZE)
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
MSC_ErasePage((uint32_t *)address);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatFlashWrite(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
|
||||
void otPlatSettingsDeinit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
MSC_WriteWord((uint32_t *)mapAddress(aSwapIndex, aOffset), aData, aSize);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
|
||||
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index', then reads the nvm3 data into the destination buffer.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
uint16_t valueLength = 0;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if (idx == aIndex)
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
valueLength = objLen;
|
||||
|
||||
// Only perform read if an input buffer was passed in.
|
||||
if ((aValue != NULL) && (aValueLength != NULL))
|
||||
{
|
||||
// Read all nvm3 obj bytes into a tmp buffer, then copy the required
|
||||
// number of bytes to the read destination buffer.
|
||||
uint8_t *buf = malloc(valueLength);
|
||||
err = mapNvm3Error(nvm3_readData(&handle, nvm3Key, buf, valueLength));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength);
|
||||
}
|
||||
free(buf);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
}
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
if (aValueLength != NULL)
|
||||
{
|
||||
*aValueLength = valueLength; // always return actual nvm3 object length.
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
memcpy(aData, (const uint8_t *)mapAddress(aSwapIndex, aOffset), aSize);
|
||||
otError err;
|
||||
|
||||
// Delete all nvm3 objects matching the input key (i.e. the 'setting indexes' of the key).
|
||||
err = otPlatSettingsDelete(aInstance, aKey, -1);
|
||||
if ((err == OT_ERROR_NONE) || (err == OT_ERROR_NOT_FOUND))
|
||||
{
|
||||
// Add new setting object (i.e. 'index0' of the key).
|
||||
err = addSetting(aKey, aValue, aValueLength);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return addSetting(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index' (or index = -1 to delete all), then deletes the nvm3 object.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if ((idx == aIndex) || (aIndex == -1))
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
// Delete the nvm3 object.
|
||||
err = mapNvm3Error(nvm3_deleteObject(&handle, nvm3Key));
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
if (aIndex != -1)
|
||||
{
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void otPlatSettingsWipe(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
// Delete nvm3 objects for all OT Settings keys (and any of their associated 'indexes').
|
||||
// Note- any OT User nvm3 objects in the OT nvm3 area are NOT be erased.
|
||||
for (uint16_t aKey = 0; aKey < 8; ++aKey)
|
||||
{
|
||||
otPlatSettingsDelete(NULL, aKey, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Local functions..
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
// Helper function- writes input buffer data to a NEW nvm3 object.
|
||||
// nvm3 object is created at the first available Key + index.
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
if ((aValueLength == 0) || (aValue == NULL))
|
||||
{
|
||||
err = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = 0; idx <= NUM_INDEXED_SETTINGS; ++idx)
|
||||
{
|
||||
nvm3_ObjectKey_t nvm3Key;
|
||||
nvm3Key = makeNvm3ObjKey(aKey, idx);
|
||||
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
// Use this index for the new nvm3 object.
|
||||
// Write the binary data to nvm3 (Creates nvm3 object if required).
|
||||
err = mapNvm3Error(nvm3_writeData(&handle, nvm3Key, aValue, aValueLength));
|
||||
break;
|
||||
}
|
||||
else if (err != OT_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index)
|
||||
{
|
||||
return (OT_NVM3_SETTINGS_KEY_PREFIX | (otSettingsKey << 8) | (index & 0xFF));
|
||||
}
|
||||
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res)
|
||||
{
|
||||
otError err;
|
||||
|
||||
switch (nvm3Res)
|
||||
{
|
||||
case ECODE_NVM3_OK:
|
||||
err = OT_ERROR_NONE;
|
||||
break;
|
||||
|
||||
case ECODE_NVM3_ERR_KEY_NOT_FOUND:
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = OT_ERROR_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif // !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
* When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_UART_ENABLE
|
||||
|
||||
@@ -76,6 +76,8 @@ libopenthread_efr32mg13_a_CPPFLAGS =
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/ustimer/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emlib/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/halconfig/inc/hal-config \
|
||||
-I$(SDK_SRC_DIR)/platform/radio/rail_lib/chip/efr32 \
|
||||
|
||||
@@ -41,8 +41,9 @@ LDADD_COMMON +=
|
||||
$(top_builddir)/examples/platforms/efr32mg13/libopenthread-efr32mg13.a \
|
||||
$(top_builddir)/third_party/silabs/libsilabs-efr32mg13-sdk.a \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/radio/rail_lib/autogen/librail_release/$(LIBRAIL) \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a \
|
||||
$(NULL)
|
||||
|
||||
LDFLAGS_COMMON += \
|
||||
-T $(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/Device/SiliconLabs/EFR32MG13P/Source/GCC/efr32mg13p.ld \
|
||||
-T $(top_srcdir)/examples/platforms/efr32mg13/efr32mg13.ld \
|
||||
$(NULL)
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread linker script for the
|
||||
* Silicon Labs efr32mg13 platform.
|
||||
*
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
}
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapBase
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
* __Vectors_End
|
||||
* __Vectors_Size
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
__Vectors_End = .;
|
||||
__Vectors_Size = __Vectors_End - __Vectors;
|
||||
__end__ = .;
|
||||
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
__etext = .;
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
. = ALIGN (4);
|
||||
PROVIDE (__ram_func_section_start = .);
|
||||
*(.ram)
|
||||
PROVIDE (__ram_func_section_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__HeapBase = .;
|
||||
__end__ = .;
|
||||
end = __end__;
|
||||
_end = __end__;
|
||||
KEEP(*(.heap*))
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
KEEP(*(.stack*))
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/*******************************************************************/
|
||||
/* Define 8K (2000H) byte flash block for OT nvm3- */
|
||||
/* ( == 4 x Flash Pages as configured in flash.c) */
|
||||
.otNvm3_block (LENGTH(FLASH) - 0x2000) (NOLOAD):
|
||||
{
|
||||
. = ALIGN (8192);
|
||||
__nvm3OtBase = .;
|
||||
KEEP(*(otNvm3_section));
|
||||
__nvm3OtCeiling = .;
|
||||
} > FLASH
|
||||
/*******************************************************************/
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
|
||||
/* Check if FLASH usage exceeds FLASH size */
|
||||
ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !")
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, The OpenThread Authors.
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,69 +28,357 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile storage.
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile
|
||||
* storage for the EFR32 platform using the Silabs Nvm3 interface.
|
||||
*/
|
||||
|
||||
#include <openthread/config.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#if !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
#include "nvm3.h"
|
||||
#include "nvm3_hal_flash.h"
|
||||
#include <string.h>
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#include <openthread/instance.h>
|
||||
// Two macros are provided to support the creation of the Silicon Labs NVM3 area and
|
||||
// initialization data- NVM3_DEFINE_SECTION_STATIC_DATA() and NVM3_DEFINE_SECTION_INIT_DATA().
|
||||
// A linker section called 'name'_section is defined by NVM3_DEFINE_SECTION_STATIC_DATA().
|
||||
// The NVM3 area is placed at the top of the device FLASH section by the linker script
|
||||
// file: e.g. efr32mgxx.ld
|
||||
// An error is returned by nvm3_open() on alignment or size violation.
|
||||
|
||||
#include "em_msc.h"
|
||||
// Local version of SDK macro (avoids uninitialized var compile error).
|
||||
#define OT_NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize) \
|
||||
static nvm3_CacheEntry_t name##_cache[cacheSize]; \
|
||||
static uint8_t name##_nvm[nvmSize] SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
|
||||
|
||||
#define FLASH_PAGE_NUM 4
|
||||
#define FLASH_DATA_END_ADDR (FLASH_BASE + FLASH_SIZE)
|
||||
#define FLASH_DATA_START_ADDR (FLASH_DATA_END_ADDR - (FLASH_PAGE_SIZE * FLASH_PAGE_NUM))
|
||||
#define FLASH_SWAP_PAGE_NUM (FLASH_PAGE_NUM / 2)
|
||||
#define FLASH_SWAP_SIZE (FLASH_PAGE_SIZE * FLASH_SWAP_PAGE_NUM)
|
||||
|
||||
static inline uint32_t mapAddress(uint8_t aSwapIndex, uint32_t aOffset)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
address = FLASH_DATA_START_ADDR + aOffset;
|
||||
|
||||
if (aSwapIndex)
|
||||
{
|
||||
address += FLASH_SWAP_SIZE;
|
||||
// Local version of SDK macro (allows OT to configure the maximum nvm3 object size and headroom).
|
||||
#define OT_NVM3_DEFINE_SECTION_INIT_DATA(name, maxObjectSize, repackHeadroom) \
|
||||
static nvm3_Init_t name = { \
|
||||
(nvm3_HalPtr_t)name##_nvm, \
|
||||
sizeof(name##_nvm), \
|
||||
name##_cache, \
|
||||
sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
|
||||
maxObjectSize, \
|
||||
repackHeadroom, \
|
||||
&nvm3_halFlashHandle, \
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
#define NUM_SETTINGS_OBJECTS 7 // == number of enumerated Settings key types (in settings.hpp).
|
||||
#define NUM_INDEXED_SETTINGS \
|
||||
OPENTHREAD_CONFIG_MLE_MAX_CHILDREN // Indexed key types are only supported for kKeyChildInfo (=='child table').
|
||||
#define NUM_USER_OBJECTS 16 // User nvm3 objects (nvm3 key range 0x0000 -> 0xDFFF is available for user data).
|
||||
|
||||
void otPlatFlashInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
}
|
||||
#define OT_NVM3_FLASH_NUM_PAGES 4 // Note- nvm3 requires minimum of 3 pages.
|
||||
#define OT_NVM3_FLASH_PAGE_SIZE FLASH_PAGE_SIZE // Device flash page size (MG12/MG13=2K, MG21=8K)
|
||||
#define OT_NVM3_FLASH_SIZE OT_NVM3_FLASH_NUM_PAGES *OT_NVM3_FLASH_PAGE_SIZE
|
||||
#define OT_NVM3_MAX_NUM_OBJECTS NUM_SETTINGS_OBJECTS + NUM_INDEXED_SETTINGS + NUM_USER_OBJECTS
|
||||
#define OT_NVM3_MAX_OBJECT_SIZE 256
|
||||
#define OT_NVM3_REPACK_HEADROOM 64 // Threshold for automatic nvm3 flash repacking.
|
||||
|
||||
uint32_t otPlatFlashGetSwapSize(otInstance *aInstance)
|
||||
#define OT_NVM3_SETTINGS_KEY_PREFIX 0xE000 // (=> key range 0x0000-0xDFFF is available for OT User nvm3 objects).
|
||||
|
||||
#define ENUM_NVM3_KEY_LIST_SIZE 4 // List size used when enumerating nvm3 keys.
|
||||
|
||||
static nvm3_Handle_t handle = {NULL};
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index);
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res);
|
||||
|
||||
// Declare OT NVM3 data area and cache.
|
||||
// OT data area should be enough for OT 'Settings' and whatwever User data is required.
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_STATIC_DATA(otNvm3, OT_NVM3_FLASH_SIZE, OT_NVM3_MAX_NUM_OBJECTS);
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_INIT_DATA(otNvm3, OT_NVM3_MAX_OBJECT_SIZE, OT_NVM3_REPACK_HEADROOM);
|
||||
|
||||
void otPlatSettingsInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return FLASH_SWAP_SIZE;
|
||||
}
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
void otPlatFlashErase(otInstance *aInstance, uint8_t aSwapIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
uint32_t address = mapAddress(aSwapIndex, 0);
|
||||
|
||||
for (uint32_t n = 0; n < FLASH_SWAP_PAGE_NUM; n++, address += FLASH_PAGE_SIZE)
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
MSC_ErasePage((uint32_t *)address);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatFlashWrite(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
|
||||
void otPlatSettingsDeinit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
MSC_WriteWord((uint32_t *)mapAddress(aSwapIndex, aOffset), aData, aSize);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
|
||||
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index', then reads the nvm3 data into the destination buffer.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
uint16_t valueLength = 0;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if (idx == aIndex)
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
valueLength = objLen;
|
||||
|
||||
// Only perform read if an input buffer was passed in.
|
||||
if ((aValue != NULL) && (aValueLength != NULL))
|
||||
{
|
||||
// Read all nvm3 obj bytes into a tmp buffer, then copy the required
|
||||
// number of bytes to the read destination buffer.
|
||||
uint8_t *buf = malloc(valueLength);
|
||||
err = mapNvm3Error(nvm3_readData(&handle, nvm3Key, buf, valueLength));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength);
|
||||
}
|
||||
free(buf);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
}
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
if (aValueLength != NULL)
|
||||
{
|
||||
*aValueLength = valueLength; // always return actual nvm3 object length.
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
memcpy(aData, (const uint8_t *)mapAddress(aSwapIndex, aOffset), aSize);
|
||||
otError err;
|
||||
|
||||
// Delete all nvm3 objects matching the input key (i.e. the 'setting indexes' of the key).
|
||||
err = otPlatSettingsDelete(aInstance, aKey, -1);
|
||||
if ((err == OT_ERROR_NONE) || (err == OT_ERROR_NOT_FOUND))
|
||||
{
|
||||
// Add new setting object (i.e. 'index0' of the key).
|
||||
err = addSetting(aKey, aValue, aValueLength);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return addSetting(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index' (or index = -1 to delete all), then deletes the nvm3 object.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if ((idx == aIndex) || (aIndex == -1))
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
// Delete the nvm3 object.
|
||||
err = mapNvm3Error(nvm3_deleteObject(&handle, nvm3Key));
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
if (aIndex != -1)
|
||||
{
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void otPlatSettingsWipe(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
// Delete nvm3 objects for all OT Settings keys (and any of their associated 'indexes').
|
||||
// Note- any OT User nvm3 objects in the OT nvm3 area are NOT be erased.
|
||||
for (uint16_t aKey = 0; aKey < 8; ++aKey)
|
||||
{
|
||||
otPlatSettingsDelete(NULL, aKey, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Local functions..
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
// Helper function- writes input buffer data to a NEW nvm3 object.
|
||||
// nvm3 object is created at the first available Key + index.
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
if ((aValueLength == 0) || (aValue == NULL))
|
||||
{
|
||||
err = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = 0; idx <= NUM_INDEXED_SETTINGS; ++idx)
|
||||
{
|
||||
nvm3_ObjectKey_t nvm3Key;
|
||||
nvm3Key = makeNvm3ObjKey(aKey, idx);
|
||||
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
// Use this index for the new nvm3 object.
|
||||
// Write the binary data to nvm3 (Creates nvm3 object if required).
|
||||
err = mapNvm3Error(nvm3_writeData(&handle, nvm3Key, aValue, aValueLength));
|
||||
break;
|
||||
}
|
||||
else if (err != OT_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index)
|
||||
{
|
||||
return (OT_NVM3_SETTINGS_KEY_PREFIX | (otSettingsKey << 8) | (index & 0xFF));
|
||||
}
|
||||
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res)
|
||||
{
|
||||
otError err;
|
||||
|
||||
switch (nvm3Res)
|
||||
{
|
||||
case ECODE_NVM3_OK:
|
||||
err = OT_ERROR_NONE;
|
||||
break;
|
||||
|
||||
case ECODE_NVM3_ERR_KEY_NOT_FOUND:
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = OT_ERROR_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif // !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
* When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_UART_ENABLE
|
||||
|
||||
@@ -72,6 +72,8 @@ libopenthread_efr32mg21_a_CPPFLAGS =
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/ustimer/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emlib/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/halconfig/inc/hal-config \
|
||||
-I$(SDK_SRC_DIR)/platform/radio/rail_lib/chip/efr32 \
|
||||
|
||||
@@ -41,8 +41,9 @@ LDADD_COMMON +=
|
||||
$(top_builddir)/examples/platforms/efr32mg21/libopenthread-efr32mg21.a \
|
||||
$(top_builddir)/third_party/silabs/libsilabs-efr32mg21-sdk.a \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/radio/rail_lib/autogen/librail_release/$(LIBRAIL) \
|
||||
$(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a \
|
||||
$(NULL)
|
||||
|
||||
|
||||
LDFLAGS_COMMON += \
|
||||
-T $(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.7/platform/Device/SiliconLabs/EFR32MG21/Source/GCC/efr32mg21.ld \
|
||||
-T $(top_srcdir)/examples/platforms/efr32mg21/efr32mg21.ld \
|
||||
$(NULL)
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread linker script for the
|
||||
* Silicon Labs efr32mg21 platform.
|
||||
*
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
|
||||
}
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapBase
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
* __Vectors_End
|
||||
* __Vectors_Size
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
__Vectors_End = .;
|
||||
__Vectors_Size = __Vectors_End - __Vectors;
|
||||
__end__ = .;
|
||||
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
__etext = .;
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
. = ALIGN (4);
|
||||
PROVIDE (__ram_func_section_start = .);
|
||||
*(.ram)
|
||||
PROVIDE (__ram_func_section_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__HeapBase = .;
|
||||
__end__ = .;
|
||||
end = __end__;
|
||||
_end = __end__;
|
||||
KEEP(*(.heap*))
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
KEEP(*(.stack*))
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/*******************************************************************/
|
||||
/* Define 32K (8000H) byte flash block for OT nvm3- */
|
||||
/* ( == 4 x Flash Pages as configured in flash.c) */
|
||||
.otNvm3_block (LENGTH(FLASH) - 0x8000) (NOLOAD):
|
||||
{
|
||||
. = ALIGN (8192);
|
||||
__nvm3OtBase = .;
|
||||
KEEP(*(otNvm3_section));
|
||||
__nvm3OtCeiling = .;
|
||||
} > FLASH
|
||||
/*******************************************************************/
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
|
||||
/* Check if FLASH usage exceeds FLASH size */
|
||||
/*ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !")*/
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, The OpenThread Authors.
|
||||
* Copyright (c) 2020, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,69 +28,357 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile storage.
|
||||
* This file implements the OpenThread platform abstraction for the non-volatile
|
||||
* storage for the EFR32 platform using the Silabs Nvm3 interface.
|
||||
*/
|
||||
|
||||
#include <openthread/config.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#if !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
#include "nvm3.h"
|
||||
#include "nvm3_hal_flash.h"
|
||||
#include <string.h>
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#include <openthread/instance.h>
|
||||
// Two macros are provided to support the creation of the Silicon Labs NVM3 area and
|
||||
// initialization data- NVM3_DEFINE_SECTION_STATIC_DATA() and NVM3_DEFINE_SECTION_INIT_DATA().
|
||||
// A linker section called 'name'_section is defined by NVM3_DEFINE_SECTION_STATIC_DATA().
|
||||
// The NVM3 area is placed at the top of the device FLASH section by the linker script
|
||||
// file: e.g. efr32mgxx.ld
|
||||
// An error is returned by nvm3_open() on alignment or size violation.
|
||||
|
||||
#include "em_msc.h"
|
||||
// Local version of SDK macro (avoids uninitialized var compile error).
|
||||
#define OT_NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize) \
|
||||
static nvm3_CacheEntry_t name##_cache[cacheSize]; \
|
||||
static uint8_t name##_nvm[nvmSize] SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
|
||||
|
||||
#define FLASH_PAGE_NUM 4
|
||||
#define FLASH_DATA_END_ADDR (FLASH_BASE + FLASH_SIZE)
|
||||
#define FLASH_DATA_START_ADDR (FLASH_DATA_END_ADDR - (FLASH_PAGE_SIZE * FLASH_PAGE_NUM))
|
||||
#define FLASH_SWAP_PAGE_NUM (FLASH_PAGE_NUM / 2)
|
||||
#define FLASH_SWAP_SIZE (FLASH_PAGE_SIZE * FLASH_SWAP_PAGE_NUM)
|
||||
|
||||
static inline uint32_t mapAddress(uint8_t aSwapIndex, uint32_t aOffset)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
address = FLASH_DATA_START_ADDR + aOffset;
|
||||
|
||||
if (aSwapIndex)
|
||||
{
|
||||
address += FLASH_SWAP_SIZE;
|
||||
// Local version of SDK macro (allows OT to configure the maximum nvm3 object size and headroom).
|
||||
#define OT_NVM3_DEFINE_SECTION_INIT_DATA(name, maxObjectSize, repackHeadroom) \
|
||||
static nvm3_Init_t name = { \
|
||||
(nvm3_HalPtr_t)name##_nvm, \
|
||||
sizeof(name##_nvm), \
|
||||
name##_cache, \
|
||||
sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
|
||||
maxObjectSize, \
|
||||
repackHeadroom, \
|
||||
&nvm3_halFlashHandle, \
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
#define NUM_SETTINGS_OBJECTS 7 // == number of enumerated Settings key types (in settings.hpp).
|
||||
#define NUM_INDEXED_SETTINGS \
|
||||
OPENTHREAD_CONFIG_MLE_MAX_CHILDREN // Indexed key types are only supported for kKeyChildInfo (=='child table').
|
||||
#define NUM_USER_OBJECTS 16 // User nvm3 objects (nvm3 key range 0x0000 -> 0xDFFF is available for user data).
|
||||
|
||||
void otPlatFlashInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
}
|
||||
#define OT_NVM3_FLASH_NUM_PAGES 4 // Note- nvm3 requires minimum of 3 pages.
|
||||
#define OT_NVM3_FLASH_PAGE_SIZE FLASH_PAGE_SIZE // Device flash page size (MG12/MG13=2K, MG21=8K)
|
||||
#define OT_NVM3_FLASH_SIZE OT_NVM3_FLASH_NUM_PAGES *OT_NVM3_FLASH_PAGE_SIZE
|
||||
#define OT_NVM3_MAX_NUM_OBJECTS NUM_SETTINGS_OBJECTS + NUM_INDEXED_SETTINGS + NUM_USER_OBJECTS
|
||||
#define OT_NVM3_MAX_OBJECT_SIZE 256
|
||||
#define OT_NVM3_REPACK_HEADROOM 64 // Threshold for automatic nvm3 flash repacking.
|
||||
|
||||
uint32_t otPlatFlashGetSwapSize(otInstance *aInstance)
|
||||
#define OT_NVM3_SETTINGS_KEY_PREFIX 0xE000 // (=> key range 0x0000-0xDFFF is available for OT User nvm3 objects).
|
||||
|
||||
#define ENUM_NVM3_KEY_LIST_SIZE 4 // List size used when enumerating nvm3 keys.
|
||||
|
||||
static nvm3_Handle_t handle = {NULL};
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index);
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res);
|
||||
|
||||
// Declare OT NVM3 data area and cache.
|
||||
// OT data area should be enough for OT 'Settings' and whatwever User data is required.
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_STATIC_DATA(otNvm3, OT_NVM3_FLASH_SIZE, OT_NVM3_MAX_NUM_OBJECTS);
|
||||
|
||||
OT_NVM3_DEFINE_SECTION_INIT_DATA(otNvm3, OT_NVM3_MAX_OBJECT_SIZE, OT_NVM3_REPACK_HEADROOM);
|
||||
|
||||
void otPlatSettingsInit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return FLASH_SWAP_SIZE;
|
||||
}
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
void otPlatFlashErase(otInstance *aInstance, uint8_t aSwapIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
uint32_t address = mapAddress(aSwapIndex, 0);
|
||||
|
||||
for (uint32_t n = 0; n < FLASH_SWAP_PAGE_NUM; n++, address += FLASH_PAGE_SIZE)
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
MSC_ErasePage((uint32_t *)address);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatFlashWrite(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
|
||||
void otPlatSettingsDeinit(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
MSC_WriteWord((uint32_t *)mapAddress(aSwapIndex, aOffset), aData, aSize);
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
|
||||
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index', then reads the nvm3 data into the destination buffer.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
uint16_t valueLength = 0;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if (idx == aIndex)
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
valueLength = objLen;
|
||||
|
||||
// Only perform read if an input buffer was passed in.
|
||||
if ((aValue != NULL) && (aValueLength != NULL))
|
||||
{
|
||||
// Read all nvm3 obj bytes into a tmp buffer, then copy the required
|
||||
// number of bytes to the read destination buffer.
|
||||
uint8_t *buf = malloc(valueLength);
|
||||
err = mapNvm3Error(nvm3_readData(&handle, nvm3Key, buf, valueLength));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength);
|
||||
}
|
||||
free(buf);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
}
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
if (aValueLength != NULL)
|
||||
{
|
||||
*aValueLength = valueLength; // always return actual nvm3 object length.
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
memcpy(aData, (const uint8_t *)mapAddress(aSwapIndex, aOffset), aSize);
|
||||
otError err;
|
||||
|
||||
// Delete all nvm3 objects matching the input key (i.e. the 'setting indexes' of the key).
|
||||
err = otPlatSettingsDelete(aInstance, aKey, -1);
|
||||
if ((err == OT_ERROR_NONE) || (err == OT_ERROR_NOT_FOUND))
|
||||
{
|
||||
// Add new setting object (i.e. 'index0' of the key).
|
||||
err = addSetting(aKey, aValue, aValueLength);
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return addSetting(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
// Searches through all matching nvm3 keys to find the one with the required
|
||||
// 'index' (or index = -1 to delete all), then deletes the nvm3 object.
|
||||
// (Repeatedly enumerates a list of matching keys from the nvm3 until the
|
||||
// required index is found).
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
|
||||
bool idxFound = false;
|
||||
int idx = 0;
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
|
||||
{
|
||||
// Get the next nvm3 key list.
|
||||
nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
|
||||
size_t objCnt = nvm3_enumObjects(&handle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
|
||||
makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
|
||||
for (size_t i = 0; i < objCnt; ++i)
|
||||
{
|
||||
nvm3Key = keys[i];
|
||||
if ((idx == aIndex) || (aIndex == -1))
|
||||
{
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NONE)
|
||||
{
|
||||
// Delete the nvm3 object.
|
||||
err = mapNvm3Error(nvm3_deleteObject(&handle, nvm3Key));
|
||||
SuccessOrExit(err);
|
||||
}
|
||||
if (aIndex != -1)
|
||||
{
|
||||
idxFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
|
||||
{
|
||||
// Stop searching (there are no more matching nvm3 objects).
|
||||
break;
|
||||
}
|
||||
++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void otPlatSettingsWipe(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
// Delete nvm3 objects for all OT Settings keys (and any of their associated 'indexes').
|
||||
// Note- any OT User nvm3 objects in the OT nvm3 area are NOT be erased.
|
||||
for (uint16_t aKey = 0; aKey < 8; ++aKey)
|
||||
{
|
||||
otPlatSettingsDelete(NULL, aKey, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Local functions..
|
||||
|
||||
static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
// Helper function- writes input buffer data to a NEW nvm3 object.
|
||||
// nvm3 object is created at the first available Key + index.
|
||||
|
||||
otError err;
|
||||
bool needClose = false;
|
||||
|
||||
err = mapNvm3Error(nvm3_open(&handle, &otNvm3));
|
||||
SuccessOrExit(err);
|
||||
needClose = true;
|
||||
|
||||
if ((aValueLength == 0) || (aValue == NULL))
|
||||
{
|
||||
err = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = 0; idx <= NUM_INDEXED_SETTINGS; ++idx)
|
||||
{
|
||||
nvm3_ObjectKey_t nvm3Key;
|
||||
nvm3Key = makeNvm3ObjKey(aKey, idx);
|
||||
|
||||
uint32_t objType;
|
||||
size_t objLen;
|
||||
err = mapNvm3Error(nvm3_getObjectInfo(&handle, nvm3Key, &objType, &objLen));
|
||||
if (err == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
// Use this index for the new nvm3 object.
|
||||
// Write the binary data to nvm3 (Creates nvm3 object if required).
|
||||
err = mapNvm3Error(nvm3_writeData(&handle, nvm3Key, aValue, aValueLength));
|
||||
break;
|
||||
}
|
||||
else if (err != OT_ERROR_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (needClose)
|
||||
{
|
||||
nvm3_close(&handle);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index)
|
||||
{
|
||||
return (OT_NVM3_SETTINGS_KEY_PREFIX | (otSettingsKey << 8) | (index & 0xFF));
|
||||
}
|
||||
|
||||
static otError mapNvm3Error(Ecode_t nvm3Res)
|
||||
{
|
||||
otError err;
|
||||
|
||||
switch (nvm3Res)
|
||||
{
|
||||
case ECODE_NVM3_OK:
|
||||
err = OT_ERROR_NONE;
|
||||
break;
|
||||
|
||||
case ECODE_NVM3_ERR_KEY_NOT_FOUND:
|
||||
err = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = OT_ERROR_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif // !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
* When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0
|
||||
|
||||
/**
|
||||
* @def RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM
|
||||
|
||||
Vendored
+4
@@ -90,6 +90,8 @@ COMMONCPPFLAGS =
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/ustimer/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/dmadrv/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/emdrv/nvm3/config \
|
||||
-I$(SDK_SRC_DIR)/platform/emlib/inc \
|
||||
-I$(SDK_SRC_DIR)/platform/halconfig/inc/hal-config \
|
||||
-I$(SDK_SRC_DIR)/platform/radio/rail_lib/chip/efr32 \
|
||||
@@ -134,6 +136,8 @@ SILABS_COMMON_SOURCES
|
||||
gecko_sdk_suite/v2.7/hardware/kit/common/bsp/bsp_stk_leds.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/dmadrv/src/dmadrv.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/gpiointerrupt/src/gpiointerrupt.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/nvm3/src/nvm3_hal_flash.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/nvm3/src/nvm3_lock.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/uartdrv/src/uartdrv.c \
|
||||
gecko_sdk_suite/v2.7/platform/emdrv/ustimer/src/ustimer.c \
|
||||
gecko_sdk_suite/v2.7/platform/emlib/src/em_adc.c \
|
||||
|
||||
Reference in New Issue
Block a user