Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions classifier/inferencing_engines/tflite_micro.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "edge-impulse-sdk/classifier/ei_aligned_malloc.h"
#include "edge-impulse-sdk/classifier/ei_model_types.h"
#include "edge-impulse-sdk/classifier/inferencing_engines/tflite_helper.h"
#include "edge-impulse-sdk/porting/ei_classifier_porting.h"

#if defined(EI_CLASSIFIER_HAS_TFLITE_OPS_RESOLVER) && EI_CLASSIFIER_HAS_TFLITE_OPS_RESOLVER == 1
#include "tflite-model/tflite-resolver.h"
Expand Down Expand Up @@ -88,6 +89,33 @@
#define DEFINE_SECTION(x) __attribute__((section(x)))
#endif

#ifdef EI_CLASSIFIER_ALLOCATION_STATIC
#ifndef EI_WEAK_FN
#define EI_WEAK_FN __attribute__((weak))
#endif

/**
* @brief Get the static tensor arena memory and its actual size.
*
* @param[out] actual_size Pointer to a size_t variable where the actual size of the
* provided static arena (in bytes) will be stored.
* @return ei_unique_ptr_t A smart pointer holding the memory address of the static arena,
* bound with a no-op deleter to protect static lifespans.
*/
EI_WEAK_FN ei_unique_ptr_t ei_get_static_tensor_arena(size_t *actual_size)
{
#if defined (EI_TENSOR_ARENA_LOCATION)
static uint8_t tensor_arena[EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE] ALIGN(16) DEFINE_SECTION(STRINGIZE_VALUE_OF(EI_TENSOR_ARENA_LOCATION));
#else
static uint8_t tensor_arena[EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE] ALIGN(16);
#endif
if (actual_size != nullptr)
*actual_size = EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE;
// Assign a no-op lambda to the "free" function in case of static arena
return ei_unique_ptr_t(tensor_arena, [](void *){});
}
#endif

/**
* Setup the TFLite runtime
*
Expand All @@ -111,15 +139,14 @@ static EI_IMPULSE_ERROR inference_tflite_setup(
*ctx_start_us = ei_read_timer_us();

ei_config_tflite_graph_t *graph_config = (ei_config_tflite_graph_t*)block_config->graph_config;
size_t actual_arena_size = graph_config->arena_size;

#ifdef EI_CLASSIFIER_ALLOCATION_STATIC
// Assign a no-op lambda to the "free" function in case of static arena
#if defined (EI_TENSOR_ARENA_LOCATION)
static uint8_t tensor_arena[EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE] ALIGN(16) DEFINE_SECTION(STRINGIZE_VALUE_OF(EI_TENSOR_ARENA_LOCATION));
#else
static uint8_t tensor_arena[EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE] ALIGN(16);
#endif
p_tensor_arena = ei_unique_ptr_t(tensor_arena, [](void*){});
p_tensor_arena = ei_get_static_tensor_arena(&actual_arena_size);
if (actual_arena_size < graph_config->arena_size) {
ei_printf("Static TFLite arena is smaller then (%zu bytes)\n", graph_config->arena_size);
return EI_IMPULSE_TFLITE_ARENA_ALLOC_FAILED;
}
#else
// Create an area of memory to use for input, output, and intermediate arrays.
uint8_t *tensor_arena = (uint8_t*)ei_aligned_calloc(16, graph_config->arena_size);
Expand Down Expand Up @@ -171,12 +198,12 @@ static EI_IMPULSE_ERROR inference_tflite_setup(
tflite::MicroProfiler *profiler = new tflite::MicroProfiler;

tflite::MicroInterpreter *interpreter = new tflite::MicroInterpreter(
model, resolver, tensor_arena, graph_config->arena_size, nullptr, profiler);
model, resolver, (uint8_t *)p_tensor_arena.get(), actual_arena_size, nullptr, profiler);

*micro_profiler = (void*)profiler;
#else
tflite::MicroInterpreter *interpreter = new tflite::MicroInterpreter(
model, resolver, tensor_arena, graph_config->arena_size, nullptr, nullptr);
model, resolver, (uint8_t *)p_tensor_arena.get(), actual_arena_size, nullptr, nullptr);

micro_profiler = nullptr;
#endif
Expand Down
30 changes: 30 additions & 0 deletions porting/ei_classifier_porting.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "edge-impulse-sdk/dsp/returntypes.h"
#include "edge-impulse-sdk/dsp/memory.hpp"

#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C" {
Expand Down Expand Up @@ -257,6 +258,35 @@ void *ei_calloc(size_t nitems, size_t size);
*/
void ei_free(void *ptr);

/**
* @brief Get the user-defined static tensor arena memory and its actual size.
*
* This weak interface allows application designers or hardware vendors to override
* the default tensor arena location. It provides a clean dependency injection pattern
* to host the arena in specialized memory regions (e.g., CCMRAM, non-cacheable SRAM)
* or to align the buffer boundary for MPU (Memory Protection Unit) configurations.
*
* @note After overriding this function, you can freely apply hardware-specific configurations
* (such as disabling/enabling D-Cache or setting MPU regions) directly to your
* custom static buffer in the application layer.
*
* @code
* #define SO_BIG_SIZE (1024 * 1024 * 5)
* static uint8_t my_tensor_arena[SO_BIG_SIZE];
* ei_unique_ptr_t ei_get_static_tensor_arena(uint32_t *actual_size)
* {
* if (actual_size != nullptr)
* *actual_size = SO_BIG_SIZE;
* return ei_unique_ptr_t(my_tensor_arena, [](void*){});
* }
* @endcode
*
* @param[out] actual_size Pointer to a size_t variable where the actual size of the
* provided static arena (in bytes) will be stored.
* @return ei_unique_ptr_t A smart pointer holding the memory address of the static arena.
*/
ei_unique_ptr_t ei_get_static_tensor_arena(size_t *actual_size);

/** @} */

#if defined(__cplusplus) && EI_C_LINKAGE == 1
Expand Down