Hello,
I am working on an Alif Ensemble E7 (Cortex-M55 + Ethos-U55) running Zephyr RTOS, and I am trying to deploy an Edge Impulse model that should run on the Ethos-U55 NPU.
My goal is to offload the inference to the Ethos-U NPU. I was able to build and flash the firmware, and the boot log correctly shows:
- “Starting EI realtime classifier…”
- “Ethos-U device is ready”
- and then just before inference:
=== start inference ===
But after that, the program never continues: I never see the “after run_classifier” log (=== end inference ===). It doesn’t reboot and doesn’t appear to crash, but no more printf/ei_printf output appears after the call to run_classifier().
main.cpp :
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <stdio.h>
#include "edge-impulse-sdk/classifier/ei_run_classifier.h"
// LED
#define RED_LED_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(RED_LED_NODE, gpios);
// Accéléromètre
static const struct device *sensor = DEVICE_DT_GET(DT_NODELABEL(lis2dux12_body));
static float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = {0};
static size_t feat_index = 0;
static int get_feature_callback(size_t offset, size_t length, float *out_ptr)
{
static uint32_t n = 0;
if ((n++ % 50) == 0)
{
ei_printf("[cb] off=%u len=%u\n", (unsigned)offset, (unsigned)length);
}
memcpy(out_ptr, features + offset, length * sizeof(float));
return 0;
}
static ei_impulse_result_t g_result;
K_THREAD_STACK_DEFINE(hb_stack, 1024);
static struct k_thread hb_thread;
static void hb_fn(void *, void *, void *)
{
while (1)
{
ei_printf("[hb] t=%llu\n", ei_read_timer_ms());
k_msleep(1000);
}
}
auto main() -> int
{
printf("Starting EI realtime classifier...\n");
if (!device_is_ready(sensor))
{
printf("Accelerometer NOT READY\n");
return 0;
}
// --- LED ---
if (gpio_is_ready_dt(&led))
{
gpio_pin_configure_dt(&led, GPIO_OUTPUT);
}
const size_t frame_size = EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE;
// --- Vérif Ethos-U ---
const struct device *ethosu = DEVICE_DT_GET(DT_NODELABEL(ethosu0));
if (!device_is_ready(ethosu))
{
printf("Ethos-U device not ready\n");
}
else
{
printf("Ethos-U device is ready\n");
}
while (true)
{
gpio_pin_toggle_dt(&led);
struct sensor_value accel[3];
int rc = sensor_sample_fetch_chan(sensor, SENSOR_CHAN_ACCEL_XYZ);
if (rc != 0)
{
printf("sensor_sample_fetch_chan error: %d\n", rc);
k_msleep(10);
continue;
}
rc = sensor_channel_get(sensor, SENSOR_CHAN_ACCEL_XYZ, accel);
if (rc != 0)
{
printf("sensor_channel_get error: %d\n", rc);
k_msleep(10);
continue;
}
float ax = sensor_value_to_double(&accel[0]);
float ay = sensor_value_to_double(&accel[1]);
float az = sensor_value_to_double(&accel[2]);
// printf("%.3f,%.3f,%.3f\n", ax, ay, az);
features[feat_index++] = ax;
features[feat_index++] = ay;
features[feat_index++] = az;
if (feat_index >= frame_size)
{
feat_index = 0;
signal_t signal;
signal.total_length = frame_size;
signal.get_data = get_feature_callback;
// uint64_t start = k_uptime_get();
// ei_printf("Running inference...\n");
ei_printf("\n=== start inference ===\n");
EI_IMPULSE_ERROR ei_status = run_classifier(&signal, &g_result, false);
ei_printf("\n=== end inference ===\n");
// uint64_t end = k_uptime_get();
// printf("Inference time: %llu ms\n", end - start);
if (ei_status != EI_IMPULSE_OK)
{
printf("EI classifier error: %d\n", ei_status);
}
else
{
printf("\n=== PREDICTION ===\n");
for (size_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++)
{
printf("%s : %.3f\n",
g_result.classification[i].label,
g_result.classification[i].value);
}
float best_value = -1.0f;
const char *best_label = "unknown";
for (size_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++)
{
if (g_result.classification[i].value > best_value)
{
best_value = g_result.classification[i].value;
best_label = g_result.classification[i].label;
}
}
printf("**Detected state : %s (%.3f)\n", best_label, best_value);
// ei_printf("Arena size: %d bytes\n", EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE);
}
}
k_msleep(EI_CLASSIFIER_INTERVAL_MS);
// k_msleep(5); // 200 Hz
}
return 0;
}
prj.conf :
# --- SYSTEM ---
CONFIG_CPP=y
CONFIG_STD_CPP17=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
CONFIG_REQUIRES_FULL_LIBC=y
CONFIG_REQUIRES_FULL_LIBCPP=y
CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192
# --- MEMORY ---
CONFIG_MAIN_STACK_SIZE=65536
CONFIG_ISR_STACK_SIZE=8192
CONFIG_HEAP_MEM_POOL_SIZE=131072
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192
# --- LOGGING ---
CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y
# --- UART ---
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
# --- SENSORS ---
CONFIG_GPIO=y
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_LIS2DUX12=y
# --- ETHOS-U55 (NPU) ---
CONFIG_ARM_ETHOS_U=y
CONFIG_ARM_ETHOS_U55_256=y
CONFIG_CMSIS_DSP=y
# CONFIG_CMSIS_NN=y
CONFIG_FPU=y
CONFIG_FPU_SHARING=y
CONFIG_CMSIS_DSP_STATISTICS=y
CONFIG_CMSIS_DSP_TRANSFORM=y
CONFIG_CMSIS_DSP_MATRIX=y
CONFIG_CMSIS_DSP_FILTERING=y
CONFIG_CMSIS_DSP_DISTANCE=y
CONFIG_ASSERT=y
CONFIG_INIT_STACKS=y
CONFIG_STACK_SENTINEL=y
CONFIG_THREAD_STACK_INFO=y
CONFIG_EXCEPTION_STACK_TRACE=y
CONFIG_FAULT_DUMP=2
CmakeLists.txt :
cmake_minimum_required(VERSION 3.13.1)
set(EXTRA_CONF_FILE ../../base.conf)
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
list(APPEND ZEPHYR_EXTRA_MODULES ${PROJECT_DIR}/drivers)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hp_app)
add_compile_definitions(EI_CLASSIFIER_ALLOCATION_STATIC=1)
# --- CONFIGURATION ETHOS-U55 ---
if(ETHOSU_TARGET_NPU_CONFIG MATCHES "^ethos-(u[0-9]+)-([0-9]+)$")
set(ETHOSU_ARCH "${CMAKE_MATCH_1}")
set(ETHOSU_MACS "${CMAKE_MATCH_2}")
add_compile_definitions(ETHOSU_ARCH_U55=1)
add_compile_definitions(EI_CLASSIFIER_TFLITE_ENABLE_ETHOS_U55=1)
if(ETHOSU_MACS STREQUAL "256")
set(CONFIG_ARM_ETHOS_U55_256 y CACHE BOOL "" FORCE)
elseif(ETHOSU_MACS STREQUAL "128")
set(CONFIG_ARM_ETHOS_U55_128 y CACHE BOOL "" FORCE)
endif()
else()
message(FATAL_ERROR "Missing -DETHOSU_TARGET_NPU_CONFIG=ethos-u55-256")
endif()
# --- DEFINITIONS ---
target_compile_definitions(app PRIVATE
TF_LITE_STATIC_MEMORY
EI_CLASSIFIER_SENSOR=EI_CLASSIFIER_SENSOR_UNKNOWN
EIDSP_USE_CMSIS_DSP=1
EI_CLASSIFIER_TFLITE_ENABLE_CMSIS_NN=0
EIDSP_LOAD_CMSIS_DSP_SOURCES=0
ARM_MATH_CM55
ARM_MATH_LOOPUNROLL
)
# --- INCLUSIONS ---
zephyr_include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk
${CMAKE_CURRENT_SOURCE_DIR}/model-parameters
${CMAKE_CURRENT_SOURCE_DIR}/tflite-model
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/dsp
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/classifier
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/flatbuffers/include
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/gemmlowp
${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/ruy
)
# --- SOURCES ---
target_sources(app PRIVATE main.cpp)
# Edge Impulse Core
file(GLOB_RECURSE EI_DSP "${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/dsp/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/dsp/*.c")
file(GLOB_RECURSE EI_CLASSIFIER "${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/classifier/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/classifier/*.c")
# Third Party
file(GLOB_RECURSE EI_THIRD_PARTY
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/third_party/*.cc"
)
# TensorFlow Lite Micro
file(GLOB_RECURSE EI_TENSORFLOW
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/tensorflow/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/tensorflow/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/tensorflow/*.cc"
)
# Model
file(GLOB_RECURSE EI_MODEL
"${CMAKE_CURRENT_SOURCE_DIR}/tflite-model/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/tflite-model/*.cc"
)
file(GLOB_RECURSE EI_PARAMS
"${CMAKE_CURRENT_SOURCE_DIR}/model-parameters/*.cpp"
)
# Porting Layer
target_sources(app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/edge-impulse-sdk/porting/zephyr/ei_classifier_porting.cpp")
# Assemblage
target_sources(app PRIVATE
${EI_DSP}
${EI_CLASSIFIER}
${EI_THIRD_PARTY}
${EI_TENSORFLOW}
${EI_MODEL}
${EI_PARAMS}
)
# --- OPTIONS ---
target_compile_options(app PRIVATE
-flax-vector-conversions
-Wno-strict-aliasing
-Wno-unused-parameter
-Wno-deprecated-declarations
-Wno-format
)
set_property(TARGET app PROPERTY CXX_STANDARD 17)
target_link_libraries(app PRIVATE -lm)
Thank you in advance for your help.
Best regards,
Rizelaine
