Skip to main content
Visitor II
September 11, 2026
Question

STM32N6 NPU: STEdgeAI tool generated code fails at initialization, when weight read APIs are called in Zephyr RTOS environment

  • September 11, 2026
  • 0 replies
  • 53 views

Tool versions (let me know if more details are needed on this):

Zephyr RTOS  v4.4.0

STEdgeAI Core V4.0.0

ST Edge AI Core v4.0.0-20500 359356bb0
STM32CubeAI 12.0.0-RC4

Board: Nucleo N657X0 Q (nucelo_n657x0_q from Zephyr RTOS boards configuration)

 

I generated NPU deployable code from the int8 quantized CNN model using this command:

stedgeai analyze -m ./CNN_int8.onnx --type onnx --target stm32n6 --st-neural-art

 

I tried to integrate the generated code in the zephyr environment for deployment. But the application fails when the calls to read the weight from external flash is requested using the APIs.

The application is such that there are certain things running in the MCU after which the NN code is called using teh generated code from STEdgeAI Core tool and quantized CNN model.

 

Succeeded calls (successful calls from the network code):

LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE

LL_ATON_RT_Reset_Network

LL_ATON_Input_Buffers_Info_network

LL_ATON_Output_Buffers_Info_network

LL_Buffer_addr_start

 

 

Failed calls:

LL_ATON_RT_RunEpochBlock → This is where the model is stuck

 

NPU functions I have created for the zephyr integration:

#include "npu_inference.h"

#include <errno.h>
#include <stdbool.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <string.h>

#include "ll_aton.h"
#include "ll_aton_NN_interface.h"
#include "ll_aton_runtime.h"
#include "network.h"

LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE(network);

static bool initialized;

static int probe_xspi_constants(void)
{
const struct device *flash_dev;
const struct flash_parameters *params;

flash_dev = DEVICE_DT_GET(DT_CHOSEN(spi_flash0));
if (!device_is_ready(flash_dev)) {
printk("NPU: spi-flash0 device not ready\n");
return -ENODEV;
}

params = flash_get_parameters(flash_dev);
if (params == NULL) {
printk("NPU: flash parameters unavailable\n");
return -EIO;
}

printk("NPU: flash ready erase=0x%02x write_block=%u\n",
(unsigned int)params->erase_value,
(unsigned int)params->write_block_size);

return 0;
}

int npu_inference_init(void)
{
const LL_Buffer_InfoTypeDef *input_buffers;
const LL_Buffer_InfoTypeDef *output_buffers;

printk("NPU: init begin\n");
input_buffers = LL_ATON_Input_Buffers_Info_network();
output_buffers = LL_ATON_Output_Buffers_Info_network();

printk("NPU: buffer metadata resolved\n");

if (input_buffers == NULL || output_buffers == NULL ||
LL_Buffer_len(&input_buffers[0]) != LL_ATON_NETWORK_IN_1_SIZE_BYTES ||
LL_Buffer_len(&output_buffers[0]) != LL_ATON_NETWORK_OUT_1_SIZE_BYTES) {
printk("NPU: buffer metadata mismatch\n");
return -EINVAL;
}

if (probe_xspi_constants() != 0) {
printk("NPU: xSPI probe failed (continuing anyway to observe runtime behavior)\n");
}

printk("NPU: runtime init start\n");
LL_ATON_RT_RuntimeInit();
printk("NPU: runtime init done\n");

printk("NPU: network init start\n");
LL_ATON_RT_Init_Network(&NN_Instance_network);
printk("NPU: network init done\n");

initialized = true;
return 0;
}

int npu_infer(const float features[60], int8_t output[2])
{
const LL_Buffer_InfoTypeDef *input_buffers;
const LL_Buffer_InfoTypeDef *output_buffers;
static bool printed_run_markers;

if (!initialized || features == NULL || output == NULL) {
return -EINVAL;
}

if (!printed_run_markers) {
printk("NPU: infer entry\n");
}

LL_ATON_RT_Reset_Network(&NN_Instance_network);

input_buffers = LL_ATON_Input_Buffers_Info_network();
output_buffers = LL_ATON_Output_Buffers_Info_network();

if (!printed_run_markers) {
printk("NPU: buffers resolved\n");
}

memcpy(LL_Buffer_addr_start(&input_buffers[0]), features,
LL_ATON_NETWORK_IN_1_SIZE_BYTES);

if (!printed_run_markers) {
printk("NPU: input copied\n");
}

for (;;) {
LL_ATON_RT_RetValues_t rt_ret = LL_ATON_RT_RunEpochBlock(&NN_Instance_network);
if (!printed_run_markers) {
printk("NPU: run ret=%d\n", (int)rt_ret);
}

if (rt_ret == LL_ATON_RT_DONE) {
break;
}

if (rt_ret == LL_ATON_RT_WFE) {
k_yield();
}
}

if (!printed_run_markers) {
printk("NPU: runtime done\n");
}

memcpy(output, LL_Buffer_addr_start(&output_buffers[0]),
LL_ATON_NETWORK_OUT_1_SIZE_BYTES);
if (!printed_run_markers) {
printk("NPU: output copied\n");
printed_run_markers = true;
}
return 0;
}

 

npu_inference_init is successful but it fails for npu_infer() function.

Error received:

[00:00:11.267,000] <err> os: ***** HARD FAULT *****
[00:00:11.273,000] <err> os: Bus fault on vector table read
[00:00:11.279,000] <err> os: r0/a1: 0xfefa125a r1/a2: 0x00000000 r2/a3: 0x710003d0
[00:00:11.288,000] <err> os: r3/a4: 0x342e0010 r12/ip: 0x0000003c r14/lr: 0x342e00f0
[00:00:11.297,000] <err> os: xpsr: 0x341b1000
[00:00:11.302,000] <err> os: s[ 0]: 0x341a1e01 s[ 1]: 0x341b10c0 s[ 2]: 0x342e00f0 s[ 3]: 0x342e0000
[00:00:11.313,000] <err> os: s[ 4]: 0x710003d0 s[ 5]: 0x342e01e0 s[ 6]: 0x342e00f0 s[ 7]: 0x0000000f
[00:00:11.323,000] <err> os: s[ 8]: 0x341a1e5c s[ 9]: 0x01100000 s[10]: 0x00000000 s[11]: 0x00000000
[00:00:11.334,000] <err> os: s[12]: 0x00000000 s[13]: 0x00000000 s[14]: 0x00000000 s[15]: 0x00000000
[00:00:11.344,000] <err> os: fpscr: 0x00000000
[00:00:11.349,000] <err> os: Faulting instruction address (r15/pc): 0x341b10a0
[00:00:11.357,000] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
[00:00:11.365,000] <err> os: Current thread: 0x341ae530 (unknown)
FATAL: reason=0
FATAL: HFSR=0x00000002 CFSR=0x00008200 BFAR=0x710003d0 MMFAR=0x00000000

Initial level memory access fails at initialization, error:

[00:00:00.000,000] <dbg> flash_stm32_xspi: flash_stm32_xspi_init: XSPI Init'd
[00:00:00.107,000] <dbg> flash_stm32_xspi: flash_stm32_xspi_init: Reset Mem (SPI/STR)
[00:00:05.115,000] <err> flash_stm32_xspi: XSPI AutoPoll wait failed
[00:00:10.123,000] <err> flash_stm32_xspi: XSPI abort failed
[00:00:10.129,000] <err> flash_stm32_xspi: XSPI memory not ready

 

I have check for RFI attributes that is not an issue, ARMv8-M TrustZone ITNS interrupt routing is also not an issue I believe. *mem_ready() fails after 5sec wait time which leaves the external flash region (0x71000000) never truly memory-mapped and I believe it is creating the hard fault at NPU inference.

 

 

app.overlay:

/ {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;

npu_activations: npu_activations@342e0000 {
reg = <0x342e0000 0x1e0>;
no-map;
};
};
};

/*
* Added for bugfixing
*/
&xspim {
status = "disabled";
};

/* Enable additional SRAM banks (4 × 448 KB = 1.75 MB extra RAM) */
&axisram3 {
status = "okay";
};
&axisram4 {
status = "okay";
};
&axisram5 {
status = "okay";
};
&axisram6 {
status = "okay";
};

&npu {
status = "okay";
};

&npu_cache {
status = "okay";
};

&gpiob {
status = "okay";
};

&gpiog {
status = "okay";
};

&pinctrl {
usart3_tx_pc10: usart3_tx_pc10 {
pinmux = <STM32_PINMUX('C', 10, AF7)>; /* Alternate Function 7 for USART3_TX */
bias-pull-up;
};
usart3_rx_pc11: usart3_rx_pc11 {
pinmux = <STM32_PINMUX('C', 11, AF7)>; /* Alternate Function 7 for USART3_RX */
bias-pull-up;
};
};
&usart3 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&usart3_tx_pc10 &usart3_rx_pc11>;
pinctrl-names = "default";
};
&spi1 {
status = "okay";
pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pg3 &spi1_mosi_pg4>;
pinctrl-names = "default";
};

&pinctrl {
spi1_sck_pa5: spi1_sck_pa5 {
pinmux = <STM32_PINMUX('A', 5, AF5)>; /* Alternate Function 5 for SPI1_SCK */
bias-pull-up;
};
spi1_miso_pg3: spi1_miso_pg3 {
pinmux = <STM32_PINMUX('G', 3, AF5)>; /* Alternate Function 5 for SPI1_MISO */
bias-pull-up;
};
spi1_mosi_pg4: spi1_mosi_pg4 {
pinmux = <STM32_PINMUX('G', 4, AF5)>; /* Alternate Function 5 for SPI1_MOSI */
bias-pull-up;
};
};

 

prj.conf:

# Console
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_UART_CONSOLE=y
CONFIG_CONSOLE=y
CONFIG_SERIAL=y

# Performance
CONFIG_SPEED_OPTIMIZATIONS=y
CONFIG_FPU=y
CONFIG_CMSIS_DSP=y
CONFIG_CMSIS_DSP_BASICMATH=y
CONFIG_CMSIS_DSP_FASTMATH=y
CONFIG_CMSIS_DSP_STATISTICS=y
CONFIG_CMSIS_DSP_TRANSFORM=y

# Neural-ART runtime requirements
CONFIG_CACHE_MANAGEMENT=y
CONFIG_DYNAMIC_INTERRUPTS=y

# Stacks
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1024
CONFIG_ISR_STACK_SIZE=2048
CONFIG_IDLE_STACK_SIZE=320

CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_FLASH_LOG_LEVEL_DBG=y
CONFIG_SHELL=n
CONFIG_NETWORKING=n
CONFIG_BT=n
CONFIG_FILE_SYSTEM=n
CONFIG_TEST=n
CONFIG_PM=n

# Basic drivers
CONFIG_FLASH=y
CONFIG_GPIO=y
CONFIG_GPIO_STM32=y

# So that Neural-ART constants at 0x71000000 are CPU-readable.
CONFIG_STM32_MEMMAP=y

 

CMakeLists.txt (excluded certain content from source file):

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

# Define the project
project(STM32N6withNPU)

set(STEDGEAI_CORE_DIR "C:/ST/STEdgeAI/4.0" CACHE PATH
"Root directory of the ST Edge AI Core installation")
set(STEDGEAI_NPU_DIR "${STEDGEAI_CORE_DIR}/Middlewares/ST/AI/Npu/ll_aton")
set(STEDGEAI_NPU_DEVICE_DIR "${STEDGEAI_CORE_DIR}/Middlewares/ST/AI/Npu/Devices/STM32N6xx")
set(STEDGEAI_AI_INC_DIR "${STEDGEAI_CORE_DIR}/Middlewares/ST/AI/Inc")
set(STEDGEAI_RUNTIME_LIB
"${STEDGEAI_CORE_DIR}/Middlewares/ST/AI/Lib/GCC/ARMCortexM55/NetworkRuntime1200_CM55_GCC.a")

if(NOT EXISTS "${STEDGEAI_NPU_DIR}/ll_aton.h")
message(FATAL_ERROR "ST Edge AI Neural-ART runtime not found. Set STEDGEAI_CORE_DIR to the ST Edge AI 4.0 installation.")
endif()

if(NOT EXISTS "${STEDGEAI_RUNTIME_LIB}")
message(FATAL_ERROR "ST Edge AI Cortex-M55 runtime library not found: ${STEDGEAI_RUNTIME_LIB}")
endif()

if(NOT EXISTS "${STEDGEAI_NPU_DEVICE_DIR}/ATON.h")
message(FATAL_ERROR "STM32N6 NPU device header not found: ${STEDGEAI_NPU_DEVICE_DIR}/ATON.h")
endif()

if(NOT EXISTS "${STEDGEAI_AI_INC_DIR}/ai_datatypes_internal.h")
message(FATAL_ERROR "ST AI common headers not found: ${STEDGEAI_AI_INC_DIR}/ai_datatypes_internal.h")
endif()

# Add application sources
target_sources(app PRIVATE
Core/<MCU configured source files>
Core/main.c
npu_inference.c
xspi_irq_monitor.c
xspim_check.c
npu_model/network.c
${STEDGEAI_NPU_DIR}/ecloader.c
${STEDGEAI_NPU_DIR}/ll_aton.c
${STEDGEAI_NPU_DIR}/ll_aton_cipher.c
${STEDGEAI_NPU_DIR}/ll_aton_dbgtrc.c
${STEDGEAI_NPU_DIR}/ll_aton_debug.c
${STEDGEAI_NPU_DIR}/ll_aton_lib.c
${STEDGEAI_NPU_DIR}/ll_aton_lib_sw_operators.c
${STEDGEAI_NPU_DIR}/ll_aton_osal_zephyr.c
${STEDGEAI_NPU_DIR}/ll_aton_profiler.c
${STEDGEAI_NPU_DIR}/ll_aton_reloc_callbacks.c
${STEDGEAI_NPU_DIR}/ll_aton_reloc_network.c
${STEDGEAI_NPU_DIR}/ll_aton_rt_main.c
${STEDGEAI_NPU_DIR}/ll_aton_runtime.c
${STEDGEAI_NPU_DIR}/ll_aton_util.c
${STEDGEAI_NPU_DIR}/ll_sw_float.c
${STEDGEAI_NPU_DIR}/ll_sw_integer.c
${STEDGEAI_NPU_DEVICE_DIR}/mcu_cache.c
${STEDGEAI_NPU_DEVICE_DIR}/npu_cache.c
)

target_include_directories(app PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
Core
npu_model
${STEDGEAI_NPU_DIR}
${STEDGEAI_NPU_DEVICE_DIR}
${STEDGEAI_AI_INC_DIR}
)

target_compile_definitions(app PRIVATE
NDEBUG
LL_ATON_PLATFORM=LL_ATON_PLAT_STM32N6
LL_ATON_OSAL=LL_ATON_OSAL_ZEPHYR
LL_ATON_SW_FALLBACK=1
APP_HAS_PARALLEL_NETWORKS=0
)

target_link_libraries(app PRIVATE ${STEDGEAI_RUNTIME_LIB})

# Cortex-M55 Helium/MVE
target_compile_options(app PRIVATE
-mfloat-abi=hard
-mfpu=fpv5-d16
-ffast-math
-funroll-loops
)

 

Requesting help on this as I just started working on NPU and I need urgent help in resolving this issue.

I have shared all the possible details I believe will be necessary to find my error or configuration I have missed, but do let me know if any more details are necessary from my side to debug the issue).