cancel
Showing results for 
Search instead for 
Did you mean: 

CubeMX LoraWAN support

Niclas Hedhman
Associate III

Is there any explanation to how to use production DevEUI, JoinEUI, AppKey and NetwKey, rather than the hardcoded se-identity.h?

I have searched all over, application notes, youtube and even studied examples and the actual code, but unable to find out how it is intended to be put together.

I tried to populate the LoRaMacNvmData_t passed in OnRestoreContextRequest in lora_app.c, but it is some "BackupContexts" being passed, that seems to be ignored (for this purpose).

Am I expected to rely on  

FLASH_IF_Read(nvm, LORAWAN_NVM_BASE_ADDRESS, nvm_size);

and flash from an external computer, rather than generate it internal to the MCU and report it to external system during test/calibration?

1 ACCEPTED SOLUTION

Accepted Solutions
Andrew Larkin
Associate III

Digging through all this to better understand what is going on...

When CONTEXT_MANAGEMENT_ENABLED == 1

There are four areas of memory that we care about:

1. seNvmInit [section(".USER_embedded_Keys") in Flash]
2. Nvm [section(".bss.LW_NVM_RAM") uninitialised in RAM]
3. NvmBackup [section(".bss.LW_NVM_BACKUP_RAM") uninitialised in RAM]
4. Nvm Context [(@0x0803f000) in Flash]

The DevEUI, JoinEUI, AppKey/NwkKey values (the "Keys") we care about for production programming of the device are located in seNvmInit.

If the linker script is "original" (as generated by the ioc file), the location in flash of the seNvmInit is undefined because the .USER_embedded_Keys memory section is not defined.

When the firmware first starts up, MX_LoRaWAN_Init() calls LoRaWAN_Init() calls LmHandlerConfigure() calls LoRaMacInitialization() calls SecureElementInit() which copies the keys from flash (seNvmInit) to uninitialised RAM (Nvm)

Nvm structure in ram is the working copy of the Keys.

On start up, it looks like a check is done to see if Nvm is valid. If a chip reset has happened, this preserves the context.

If Nvm is not valid, a copy is made from the NvmBackup RAM. This backup only seems to be updated as a part of LoRaMacHalt(). I am guessing this is like a "last known good" configuration.

If the NvmBackup is not valid, the firmware tries to restore from a context saved in flash. It seems the operation to store the Keys in Nvm context flash is a deliberate act by the application with a call to StoreContext().

If everything else has failed, then the Nvm is initialised from the seNvmInit original set of Keys.

All this seems to be pretty reasonable.

The problems though are in the management of the memory allocations.

1. The location of seNvmCtx is undefined so it is necessary to add an explicit allocation mapping in the linker script for .USER_embedded_Keys. Once this is done, precise memory locations for the keys can be determined to allow them to be overwritten during production.

2. The location of the application-stored context is improperly defined as an absolute memory location (0x0803f000) instead of being properly mapped via the linker script. This means there is no protection from conflicting use of the memory. The presumption that the last couple of pages of flash are "available" is inherently unsafe.

This conflict is NOT theoretical.

If the additional LoRaWAN packages functionality is enabled, then the Fragmented Data Block Transport package is enabled. This package also explicit uses the same region of flash (0x0803F000) (see frag_decoder_if.h)

Amending a previous comment I made about generating a CRC32 value, it is not necessary for the seNvmInit data as the CRC field is not used there - it only seems to be relevant in the ram Nvm copy, backup ram Nvm and saved context in flash as an integrity check.

View solution in original post

21 REPLIES 21
Issamos
Lead II

Hello @Niclas Hedhman 

My advice is to use the end_node exemple and try a deep debug on it to now how it exactly works.

Also this application note and this video may give some help.

Best regards.

II

Niclas Hedhman
Associate III

@Issamos, thanks but I am WAY beyond those stages. The endnode sample, all videos I have found and the application note all assume that you are experimenting and having the keys in se-identity.h. That is not a doable if you are planning of making thousands of devices to "other people".

My question is more along the lines of; "Has ST forgotten about how to make this commercially viable, with the LoraWAN CubeMX middleware?" and/or ignored the question all together. And since the structure is very different from the Semtech stack (which has no CubeMX at all, and its own device driver libraries and everything) it is not really that viable to try to merge Semtech on every revision, and therefor I have not dug too deep into Semtech's stuff.

From my PoV, hooks are either missing, deeply hidden and/or not documented. And I am at wit's end on how progress from "prototype" to "production".

Andrew Larkin
Associate III

I am hitting the same conundrum.

On a previous project (LoRaWAN 1.0.2), I reserved a page of flash to store DevEUI, keys, etc that could be programmed during production and just picked up the values.  This is a bit "hacky" but worked.

If KMS is not enabled, the keys from se-identity.h are placed in seNvmInit{}, which is then linked into memory section defined by 
SOFT_SE_PLACE_IN_NVM_START as __attribute__((section(".USER_embedded_Keys")))

However, this memory section isn't defined in the .ld file, so I can't predict where it will be placed.

A part of the solution is to modify the .ld file to reserve space for the USER_embedded_Keys section.

I am using the STM32WLE5CCUX_FLASH.ld file here.

I changed the /* Memories definition */ to reduce the FLASH section length and add a KEYS section

/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
RAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 252K
KEYS (rx) : ORIGIN = 0x0803F000, LENGTH = 4K
}

Then added thisto the end of the ld file, just before /DISCARD/
/* USER Embedded Keys data into "KEYS" Rom type memory */
.embeddedKeys :
{
. = ALIGN(4);
*(.USER_embedded_Keys)
. = ALIGN(4);
} >KEYS

This at least gets the seNvmInit structure (containing the keys) into a known location, but I have still to figure out which bytes are what.

One thing that bothers me though is prospect of being clobbered by the Context Management support. The default implementations of OnStoreContextRequest() and OnRestoreContextRequest() assume ownership of flash memory at LORAWAN_NVM_BASE_ADDRESS which is

/**
* @brief LoRaWAN NVM Flash address
* @note last 2 sector of a 128kBytes device
*/
#define LORAWAN_NVM_BASE_ADDRESS ((void *)0x0803F000UL)

This, to me, is bad coding behaviour as the address/memory allocation for LORAWAN_NVM_BASE_ADDRESS should also be defined within the ld file

I am dredding what all this might do to a future task which is to figure out how flash is managed for FUOTA.

I should also have mentioned that on the previous project we were using stm32cubeprogrammer to program the devices and using command line options to overwrite DevEUI and Key values directly into the target memory locations.

To solve the conflict temporarily, I have just reserved memory for the Context in the LD file:

MEMORY

{

RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K

RAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K

FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 248K

KEYS (rx) : ORIGIN = 0x0803E000, LENGTH = 4K

CONTEXT (rx) : ORIGIN = 0x0803F000, LENGTH = 4K

}

 

I think it is possible to have the Context Mgmt on the last 2K, if you need to. In AN5406, chapter 15, they write that 1484 bytes are used. and I think it is just the whole LoRaMacNvmData_t that is written out, so that's how to figure out which byte is what.

But is that really the best way to go about it? Having keys generated off-chip? 

So in soft-ce.c there is this little hint;

NiclasHedhman_0-1694431552084.png

Which seems to suggest that "Yes, you are supposed use external tools directly to populate Flash memory locations.", and that we would need to work out where the important bits will end, how to compute the CRC...

I think I am going to replace soft-ce.c with my own implementation, so I know what is going on.

I'm not actually seeing anything to indicate that the context in flash has a valid CRC - shows as zero.  As this data is being initialised by declaration in the source code, it would need the developer to compute a CRC and add it:

SOFT_SE_PLACE_IN_NVM_START
static const SecureElementNvmData_t seNvmInit =
{
    SOFT_SE_ID_LIST,
    .KeyList = SOFT_SE_KEY_LIST,
    .Crc32 = 0x11223344
};

With the USER_embedded_Keys mapped as I described before (0x0803e000), I get the following addresses for the keys of interest:

DevEUI[8]: 0x803e000
JoiEUI[8]: 0x803e008
APP_KEY[16]: 0x803e019
NWK_KEY[16]: 0x803e02a

 

Just a related observation, if the DevEUI is set to all zero's, then the LoRaWAN stack will make a call to GetUniqueId() in sys_app.c to provide one derived from the chip's unique ID.

You can read these values directly from the chip with STM32CubeProgrammer CLI