Important update: Arm Announces End of Life Timeline for Mbed. This site will be archived in July 2026. Read the full announcement.
This is an example application based on Mbed-OS LoRaWAN protocol APIs. The Mbed-OS LoRaWAN stack implementation is compliant with LoRaWAN v1.0.2 specification.
Dependents: Projet_de_bachelor_code Projet_de_bachelor_code
Issue: Out of memory failures
I have been trying to port this example to an ST Nucleo L073RZ with a SX1276MB1LAS LoRa WAN radio. It has 20KB of SRAM, 10KB of which are being taken by uninitialized data.
After setting the main stack size to 1024 and disabling memory debug I can get the example to a point where it will join but will then later fail on the next uplink with an error code of -1014 which indicates that the crypto library failed. The failure is a result of the crypto library unable to allocate memory.
I have tried the default, develop, and release profile; all with the same result.
Any thoughts on what else I can disable to free up more SRAM would be helpful.
Thank you, Parker MacKenzie
- Compiler GCC - mbed compile -m nucleo_l073rz -t GCC_ARM
- Changes to mbed_app.json (beyond setting the device eui, app key, and app eui): "lora.phy": 8,
"main_stack_size": { "value": 1024 },
"lora-spi-mosi": { "value": "D11" }, "lora-spi-miso": { "value": "D12" }, "lora-spi-sclk": { "value": "D13" }, "lora-cs": { "value": "D10" }, "lora-reset": { "value": "A0" }, "lora-dio0": { "value": "D2" }, "lora-dio1": { "value": "D3" }, "lora-dio2": { "value": "D4" }, "lora-dio3": { "value": "D5" }, "lora-dio4": { "value": "D8" }, "lora-dio5": { "value": "D9" }, "lora-rf-switch-ctl1": { "value": "NC" }, "lora-rf-switch-ctl2": { "value": "NC" }, "lora-txctl": { "value": "NC" }, "lora-rxctl": { "value": "NC" }, "lora-ant-switch": { "value": "NC" }, "lora-pwr-amp-ctl": { "value": "NC" }, "lora-tcxo": { "value": "NC" }
4 comments:
...continued A little more analysis shows 2.5KBytes of the heap are in use as determined using the MBED_HEAP_STATS_ENABLED function. Note that when turning on the debug of the heap (MBED_HEAP_STATS_ENABLED) will cause the program to fail to allocate memory for encryption at the join instead of what is seen here at the ::send() function.
Also to note the stacks are within their limits and the heap is not too incredibly large.
Adaptive data rate (ADR) - Enabled [ 143] cur:2568 max:2568 [ 146] cur:2568 max:2568 Connection error, code = -1014
Heap debugged disabled and stack debug enabled:
Dummy Sensor Value = 2.1 Thread: 0x20002D3C, Stack size: 1024, Max stack: 880 Thread: 0x200024BC, Stack size: 512, Max stack: 104 Thread: 0x20002474, Stack size: 768, Max stack: 120 Thread: 0x20002068, Stack size: 1024, Max stack: 376 send() - Error code -1014
...continued The following shows the straw (280 Bytes) which is breaking the camels (heap) back.
#0 0x0800a69e in aes_ctx_alloc () at ./mbed-os/features/mbedtls/src/cipher_wrap.c:169 #1 0x0800a5f2 in mbedtls_cipher_setup () at ./mbed-os/features/mbedtls/src/cipher.c:159 #2 0x08007c16 in LoRaMacCrypto::compute_mic () at ./mbed-os/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp:71 #3 0x08005e4a in LoRaMac::prepare_frame () at ./mbed-os/features/lorawan/lorastack/mac/LoRaMac.cpp:1591 #4 0x080072e4 in LoRaMac::send () at ./mbed-os/features/lorawan/lorastack/mac/LoRaMac.cpp:999 #5 0x080073b0 in LoRaMac::send_ongoing_tx () at ./mbed-os/features/lorawan/lorastack/mac/LoRaMac.cpp:1308 #6 0x080043ca in LoRaWANStack::process_scheduling_state () at ./mbed-os/features/lorawan/LoRaWANStack.cpp:1083 #7 0x08004858 in LoRaWANStack::state_controller () at ./mbed-os/features/lorawan/LoRaWANStack.cpp:998 #8 0x08004930 in LoRaWANStack::handle_tx () at ./mbed-os/features/lorawan/LoRaWANStack.cpp:330 #9 0x08003ba4 in LoRaWANInterface::send () at ./mbed-os/features/lorawan/LoRaWANInterface.cpp:122 #10 0x080003f6 in send_message () at ./main.cpp:198 #11 0x080004b2 in lora_event_handler () at ./main.cpp:266 #12 0x08000188 in mbed::Callback<void (lora_events)>::function_call<void (*)(lora_events)>(void const*, lora_events) () at ./mbed-os/platform/Callback.h:1178 #13 0x08003d94 in mbed::Callback<void (lora_events)>::call(lora_events) const () at ./mbed-os/platform/Callback.h:1103 #14 mbed::Callback<void (lora_events)>::operator()(lora_events) const () at ./mbed-os/platform/Callback.h:1109 #15 events::EventQueue::context10<mbed::Callback<void (lora_events)>, lora_events>::operator()() () at ./mbed-os/events/EventQueue.h:2344 #16 events::EventQueue::function_call<events::EventQueue::context10<mbed::Callback<void (lora_events)>, lora_events> >(void*) () at ./mbed-os/events/EventQueue.h:2315 #17 0x08003748 in equeue_dispatch () at ./mbed-os/events/equeue/equeue.c:410 #18 0x08003298 in events::EventQueue::dispatch () at ./mbed-os/events/EventQueue.cpp:35 #19 0x0800036c in events::EventQueue::dispatch_forever () at ./mbed-os/events/EventQueue.h:92 #20 main () at ./main.cpp:170
...continued...
The following disassembly shows the first attempt of the LoRaMAC::send() to allocated an AES context of 280 (r1) Bytes failing (returning 0) (r0).
(gdb) disassemble Dump of assembler code for function aes_ctx_alloc: 0x0800a692 <+0>: movs r1, #140 ; 0x8c 0x0800a694 <+2>: push {r4, lr} 0x0800a696 <+4>: lsls r1, r1, #1 0x0800a698 <+6>: movs r0, #1 => 0x0800a69a <+8>: bl 0x8012388 <calloc> 0x0800a69e <+12>: subs r4, r0, #0 0x0800a6a0 <+14>: beq.n 0x800a6a6 <aes_ctx_alloc+20> 0x0800a6a2 <+16>: bl 0x8009838 <mbedtls_aes_init> 0x0800a6a6 <+20>: movs r0, r4 0x0800a6a8 <+22>: pop {r4, pc} End of assembler dump. (gdb) info registers r0 0x1 1 r1 0x118 280 r2 0x3 3 r3 0x800a693 134260371 r4 0x20001314 536875796 r5 0x801e0f8 134340856 r6 0x20001314 536875796 r7 0x22 34 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20002f68 0x20002f68 <_main_stack+480> lr 0x800a5f3 134260211 pc 0x800a69a 0x800a69a <aes_ctx_alloc+8> xPSR 0x1000000 16777216 (gdb) ni 0x0800a69e 169 mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); (gdb) disassemble Dump of assembler code for function aes_ctx_alloc: 0x0800a692 <+0>: movs r1, #140 ; 0x8c 0x0800a694 <+2>: push {r4, lr} 0x0800a696 <+4>: lsls r1, r1, #1 0x0800a698 <+6>: movs r0, #1 0x0800a69a <+8>: bl 0x8012388 <calloc> => 0x0800a69e <+12>: subs r4, r0, #0 End of assembler dump. (gdb) info registers r0 0x0 0 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x20001314 536875796
Digging a bit deeper with a little more debugging.
Summary
Long story short, after the uninitialized variables are allocated in the RAM there is not a lot of space for the heap. Finding a way to significantly cut these back should help. The example definitely runs out of memory, likely there is some heap left when it fails but it is likely too fragmented to carve off a 280 Byte chunk. Any thoughts or suggestions would be welcome.
Here are the details
As mentioned in the last post the device is running out of memory. With the main stack size set to 1024 the device will run out of dynamic memory (heap) attempting to send a packet in the aes_ctx_alloc() called by the mbedtls_cipher_setup attempting to allocate 1 block of 280 Bytes through calloc.
First here is the static analysis of the image which shows that 13K of the 20K of SRAM is being used for data and bss (should leave 7K +- for heap)...
Of the remaining 7K Bytes of static ram almost 6K of it is being allocated to heap: