Skip to content
Draft
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
42 changes: 42 additions & 0 deletions samples/hello_ei/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# Copyright (c) 2026 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_ei)

# Add application source files
target_sources(app PRIVATE
src/main.c
)

# Add application include directories
target_include_directories(app PRIVATE
src/include
)

# Validate that Edge Impulse URI is specified
if(CONFIG_EDGE_IMPULSE_URI STREQUAL "")
message(FATAL_ERROR "CONFIG_EDGE_IMPULSE_URI must be specified")
endif()

include(${CMAKE_CURRENT_LIST_DIR}/edge_impulse/ei_sdk_utils.cmake)

# Process URI list from configuration (supports URLs and local paths)
process_edge_impulse_uri("${CONFIG_EDGE_IMPULSE_URI}" EI_URI_LIST)

# Get Edge Impulse API key header if specified
get_edge_impulse_api_key(EI_API_KEY_HEADER)

# Include Edge Impulse library integration
if(CONFIG_EDGE_IMPULSE_COMPILE_INTO_APP)
message(STATUS "Compiling Edge Impulse library into application binary")
include(${CMAKE_CURRENT_LIST_DIR}/edge_impulse/ei_compile_in_app.cmake)
else()
message(STATUS "Building Edge Impulse library as separate static library")
include(${CMAKE_CURRENT_LIST_DIR}/edge_impulse/ei_standalone_lib.cmake)
endif()
54 changes: 54 additions & 0 deletions samples/hello_ei/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# Copyright (c) 2026 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

mainmenu "Hello Edge Impulse sample application"

config EDGE_IMPULSE_URI
string "Edge Impulse library URI"
default ''
help
Specify URI used to access archive with Edge Impulse library.
The library will be downloaded into the build directory. You can specify
more than one URI separated by a semicolon.
Make sure to specify the HTTP API key header as EI_API_KEY_HEADER
variable during build if the HTTP server uses it.
You can also specify the absolute file path of a local file. In that
case, only one URI has to be defined.

config EDGE_IMPULSE_DEBUG_MODE
bool "Run Edge Impulse library in debug mode"
default n
imply NEWLIB_LIBC_FLOAT_PRINTF
help
Enables additional log information from Edge Impulse library.

config HELLO_EI_DATA_BUF_SIZE
int "Size of input data buffer"
default 512
help
The buffer is used to store input data for the Edge Impulse library.
Size of the buffer is expressed as number of floats.

config EDGE_IMPULSE_DOWNLOAD_ALWAYS
bool "Download Edge Impulse library on each build"
default n
help
Request the build system to download the Edge Impulse library on each
build. This results in the build target to always be considered out
of date.
If the re-downloaded zip has no code changes, then no re-building of
source is performed and only download of zip file will be done.

config EDGE_IMPULSE_COMPILE_INTO_APP
bool "Compile Edge Impulse library into application"
default y
help
If enabled, the Edge Impulse library will be compiled directly into
the application binary. If disabled, the library will be built as
a separate static library and linked to the application.

# This must be at the end to include Zephyr's Kconfig tree
source "Kconfig.zephyr"
79 changes: 79 additions & 0 deletions samples/hello_ei/edge_impulse/CMakeLists.ei.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# Copyright (c) 2026 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.13.1)
set(CMAKE_C_COMPILER_FORCED 1)
set(CMAKE_CXX_COMPILER_FORCED 1)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR "arm")

project(edge_impulse)
enable_language(ASM C CXX)

if(EI_COMPILE_DEFINITIONS)
add_compile_definitions(${EI_COMPILE_DEFINITIONS})
endif()

if(EI_INCLUDE_DIRECTORIES)
include_directories(${EI_INCLUDE_DIRECTORIES})
endif()

if(EI_SYSTEM_INCLUDE_DIRECTORIES)
include_directories(SYSTEM ${EI_SYSTEM_INCLUDE_DIRECTORIES})
endif()

include(${CMAKE_CURRENT_LIST_DIR}/../../compile_options.CXX.cmake OPTIONAL)
include(${CMAKE_CURRENT_LIST_DIR}/../../compile_options.C.cmake OPTIONAL)

set(EI_COMPILE_OPTIONS ${EI_C_COMPILE_OPTIONS})
list(REMOVE_ITEM EI_C_COMPILE_OPTIONS ${EI_CXX_COMPILE_OPTIONS} "")
list(REMOVE_ITEM EI_COMPILE_OPTIONS ${EI_C_COMPILE_OPTIONS})
list(REMOVE_ITEM EI_CXX_COMPILE_OPTIONS ${EI_COMPILE_OPTIONS} "")

# Skip warnings for the source files
set(SKIP_WARNINGS -Wall)
list(REMOVE_ITEM EI_COMPILE_OPTIONS ${SKIP_WARNINGS})
list(REMOVE_ITEM EI_C_COMPILE_OPTIONS ${SKIP_WARNINGS})
list(REMOVE_ITEM EI_CXX_COMPILE_OPTIONS ${SKIP_WARNINGS})

add_compile_options(${EI_COMPILE_OPTIONS})
foreach(option ${EI_C_COMPILE_OPTIONS})
add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
endforeach()

foreach(option ${EI_CXX_COMPILE_OPTIONS})
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:${option}>)
endforeach()

if(NOT TARGET app)
add_library(app STATIC)
endif()

if(EI_LIBRARY_NAME)
set_property(TARGET app PROPERTY OUTPUT_NAME ${EI_LIBRARY_NAME})
endif()

include(${CMAKE_CURRENT_LIST_DIR}/edge-impulse-sdk/cmake/utils.cmake)

add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/edge-impulse-sdk/cmake/zephyr)

target_include_directories(app PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)

# Find model source files
RECURSIVE_FIND_FILE(MODEL_FILES "${CMAKE_CURRENT_LIST_DIR}/tflite-model" "*.cpp")
list(APPEND SOURCE_FILES ${MODEL_FILES})

# Add all sources to the project
target_sources(app PRIVATE ${SOURCE_FILES})

# Suppress known build warnings for Edge Impulse source/header files.
target_compile_options(app
PRIVATE -Wno-double-promotion
PRIVATE -Wno-unused
PRIVATE -Wno-stringop-overread)
40 changes: 40 additions & 0 deletions samples/hello_ei/edge_impulse/ei_compile_in_app.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# Copyright (c) 2026 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
# Edge Impulse library integration - compilation into application binary
#

set(FETCH_CONTENT_NAME edge_impulse)

# Enable C linkage for Edge Impulse library (allows calling from C code)
target_compile_definitions(app PRIVATE
EI_C_LINKAGE=1
EIDSP_SIGNAL_C_FN_POINTER=1
)

include(FetchContent)

FetchContent_Declare(
${FETCH_CONTENT_NAME}
DOWNLOAD_EXTRACT_TIMESTAMP True
URL ${EI_URI_LIST}
HTTP_HEADER "Accept: application/zip"
${EI_API_KEY_HEADER}
)

FetchContent_MakeAvailable(${FETCH_CONTENT_NAME})

# Suppress specific compiler warnings for Edge Impulse SDK source files
set(EI_SUPPRESSED_WARNINGS_FLAGS "-Wno-double-promotion -Wno-unused -Wno-stringop-overread -Wno-sign-compare -Wno-maybe-uninitialized")

# Get all sources from app target and apply flags only to Edge Impulse files
get_target_property(ALL_SOURCES app SOURCES)
foreach(src ${ALL_SOURCES})
if(src MATCHES ${FETCHCONTENT_BASE_DIR}/${FETCH_CONTENT_NAME})
set_source_files_properties(${src} PROPERTIES
COMPILE_FLAGS "${EI_SUPPRESSED_WARNINGS_FLAGS}"
)
endif()
endforeach()
69 changes: 69 additions & 0 deletions samples/hello_ei/edge_impulse/ei_sdk_utils.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#
# Copyright (c) 2026 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
# Process Edge Impulse URI list from configuration

# Function to parse and process Edge Impulse URI(s)
# Supports multiple URIs separated by space, newline, or semicolon
# Converts relative paths to absolute paths
#
# Arguments:
# uri_input - Input URI string from CONFIG_EDGE_IMPULSE_URI
# output_var - Variable name to store the processed URI list
#
function(process_edge_impulse_uri uri_input output_var)
# Match first and any URI in the middle of input string
# URI can be separated by space, new line or semicolon
string(REGEX MATCHALL ".+[ \r\n;]" uri_prepare_list "${uri_input}")

# Match the last URI in input string
string(REGEX MATCH "[^ \n\r;].+$" uri_list_end "${uri_input}")

list(APPEND uri_prepare_list ${uri_list_end})

set(uri_list "")
foreach(uri IN LISTS uri_prepare_list)
# Remove trailing spaces
string(STRIP ${uri} uri_string)

# If URI is NOT a URL (http://, https://, file://), treat it as a local path
if(NOT ${uri_string} MATCHES "^[a-z]+://")
# Expand any ${VARIABLES} in the path
string(CONFIGURE ${uri_string} uri_string)

# Convert relative paths to absolute paths
if(NOT IS_ABSOLUTE ${uri_string})
# Using application source directory as base directory for relative path
set(uri_string ${APPLICATION_SOURCE_DIR}/${uri_string})
endif()
endif()

list(APPEND uri_list ${uri_string})
endforeach()

# Remove duplicated URIs from list
list(REMOVE_DUPLICATES uri_list)

# Return the processed list
set(${output_var} ${uri_list} PARENT_SCOPE)

endfunction()

# Get Edge Impulse API key header from sysbuild configuration
#
# Retrieves authentication header for downloading private Edge Impulse models
# Returns empty string if not configured or sysbuild not available
#
# Arguments:
# OUTPUT_VAR - Variable name to store API key header
function(get_edge_impulse_api_key OUTPUT_VAR)
if(COMMAND zephyr_get)
zephyr_get(EI_API_KEY_HEADER SYSBUILD GLOBAL)
else()
set(EI_API_KEY_HEADER "")
endif()

set(${OUTPUT_VAR} "${EI_API_KEY_HEADER}" PARENT_SCOPE)
endfunction()
Loading