### Network I/O Buffers Setup Source: https://stm32ai-cs.st.com/assets/embedded-docs/embedded_client_stai_api_migration.html This section details the process of allocating and setting network input and output buffers using both Legacy Client APIs and ST Edge AI Embedded Client APIs. ```APIDOC ## Network I/O Buffers Setup ### Description This endpoint details the process of allocating and setting network input and output buffers. ### Method N/A (Code Snippet Comparison) ### Endpoint N/A (Code Snippet Comparison) ### Parameters N/A ### Request Example **Legacy Client APIs:** ```c /* Inputs Buffer Setup */ /* Retrieve pointers to the model's input tensors */ ai_buffer* ai_input = ai_network_inputs_get(network, NULL); if (ai_input) { ai_input[0].data = AI_HANDLE_PTR(input1) /* defined in network_inputs.h */ } /* Outputs Buffers Setup */ /* Allocate and declare output buffer #1 */ AI_ALIGNED(4) float output1[AI_NETWORK_OUT_1_SIZE]; /* Retrieve pointers to the model's output tensors */ ai_buffer* ai_output = ai_network_outputs_get(network, NULL); if (ai_output) { ai_output[0].data = AI_HANDLE_PTR(output1); } /* No specific I/O setters since ai_input and ai_output as passed as argument of the ai_network_run() */ ``` **ST Edge AI Embedded Client APIs:** ```c /* Inputs Buffer Setup */ /* C-Table declaring inputs buffer pointers array and set inputs addresses */ stai_ptr input_buffers[STAI_NETWORK_IN_NUM] = { (stai_ptr)input1 /* defined in network_inputs.h */ }; /* !New!: Set network inputs buffers */ return_code = stai_network_set_inputs(network, input_buffers, STAI_NETWORK_IN_NUM); if (return_code != STAI_SUCCESS) { LOG_PRINT(" ## Test Failed executing stai set inputs: 0x%x.\n\n", return_code) return -1; } /* Outputs Buffers Setup */ /* Allocate and declare output buffer #1 */ STAI_ALIGNED(STAI_NETWORK_OUT_1_ALIGNMENT) float output1[STAI_NETWORK_OUT_1_SIZE]; /* Declare outputs buffer pointers array and set outputs addresses */ stai_ptr output_buffers[STAI_NETWORK_OUT_NUM] = { (stai_ptr)output1 }; /* Set network outputs buffers */ return_code = stai_network_set_outputs(network, output_buffers, STAI_NETWORK_OUT_NUM); if (return_code != STAI_SUCCESS) { LOG_PRINT(" ## Test Failed executing stai set outputs: 0x%x.\n\n", return_code) return -1; } ``` ### Response N/A ``` -------------------------------- ### Install Runtime Loadable Model Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html The ll_aton_reloc_install function acts as a dynamic loader to initialize a memory-mapped neural network model. It requires a pointer to the model image, configuration parameters, and an instance structure to perform relocation and setup. ```C int ll_aton_reloc_install(const uintptr_t file_ptr, const ll_aton_reloc_config *config, NN_Instance_TypeDef *nn_instance); ``` -------------------------------- ### Install and Run Bare Metal AI Model (C) Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html Illustrates installing and running a runtime loadable AI model in a bare-metal environment. This function initializes the model, handles input/output buffer management, and executes the inference. It requires the `ll_aton_reloc_network.h` header and assumes memory allocation functions like `reserve_exec_memory_region` are available. ```c #include "ll_aton_reloc_network.h" static NN_Instance_TypeDef nn_instance; /* LL ATON handle */ uint8_t *input_0, *prediction_0; uint32_t input_size_0, prediction_size_0; int ai_init(const uintptr_t file_ptr, const uintptr_t file_params_ptr) { const LL_Buffer_InfoTypeDef *ll_buffer; ll_aton_reloc_info rt; int res; /* Retrieve the requested RAM size to install the model */ res = ll_aton_reloc_get_info(file_ptr, &rt); /* Reserve executable memory region to install the model */ uintptr_t exec_ram_addr = reserve_exec_memory_region(rt.rt_ram_copy); /* Reserve external read/write memory region for external RAM region */ uintptr_t ext_ram_addr = NULL; if (rt.ext_ram_sz > 0) ext_ram_addr = reserve_ext_memory_region(rt.ext_ram_sz); /* Create and install an instance of the relocatable model */ ll_aton_reloc_config config; config.exec_ram_addr = exec_ram_addr; config.exec_ram_size = rt.rt_ram_copy; config.ext_ram_addr = ext_ram_addr; config.ext_ram_size = rt.ext_ram_sz; config.ext_param_addr = NULL; /* or @ of the weights/params if split mode is used */ config.mode = AI_RELOC_RT_LOAD_MODE_COPY; // | AI_RELOC_RT_LOAD_MODE_CLEAR; res = ll_aton_reloc_install(file_ptr, &config, &nn_instance); if (res != 0) { /* Retrieve the addresses of the input/output buffers */ ll_buffer = ll_aton_reloc_get_input_buffers_info(&nn_instance, 0); input_0 = LL_Buffer_addr_start(ll_buffer); input_size_0 = LL_Buffer_len(ll_buffer); ll_buffer = ll_aton_reloc_get_output_buffers_info(&nn_instance, 0); prediction_0 = LL_Buffer_addr_start(ll_buffer); prediction_size_0 = LL_Buffer_len(ll_buffer); /* Init the LL ATON stack and the instantiated model */ LL_ATON_RT_RuntimeInit(); LL_ATON_RT_Init_Network(&nn_instance); } return res; } void ai_deinit(void) { LL_ATON_RT_DeInit_Network(&NN_Instance_Default); LL_ATON_RT_RuntimeDeInit(); } void ai_run(void) { LL_ATON_RT_RetValues_t ll_aton_ret; LL_ATON_RT_Reset_Network(&nn_instance); do { ll_aton_ret = LL_ATON_RT_RunEpochBlock(&nn_instance); if (ll_aton_ret == LL_ATON_RT_WFE) { LL_ATON_OSAL_WFE(); } } while (ll_aton_ret != LL_ATON_RT_DONE); } void main(void) { uintptr_t file_ptr, file_params_ptr; user_system_init(); /* HAL, clocks, NPU sub-system... */ user_model_mgr(&file_ptr, &file_params_ptr); if (ai_init(file_ptr, file_params_ptr)) { /*... installation issue ..*/ } while (user_app_not_finished()) { /* Fill input buffers */ user_fill_inputs(input_0); /* If requested, perform the NPU/MCU cache operations to guarantee the coherency of the memory. */ // LL_ATON_Cache_MCU_Clean_Invalidate_Range(input_0, input_size_0); // LL_ATON_Cache_MCU_Invalidate_Range(prediction_0, prediction_size_0); /* Perform a complete inference */ ai_run(); /* Post-process the predictions */ user_post_process(prediction_0); } ai_deinit(); //... } ``` -------------------------------- ### POST /ll_aton_reloc_install Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html Installs and initializes a runtime loadable neural network model using the LL ATON runtime extension. ```APIDOC ## POST /ll_aton_reloc_install ### Description The `ll_aton_reloc_install()` function acts as a runtime dynamic loader. It is used to install and to create an instance of a memory-mapped runtime loadable module. The function performs compatibility checks, initializes memory pools, and installs/relocates code and data sections as needed. ### Method POST ### Endpoint ll_aton_reloc_install(const uintptr_t file_ptr, const ll_aton_reloc_config *config, NN_Instance_TypeDef *nn_instance) ### Parameters #### Path Parameters - **file_ptr** (uintptr_t) - Required - Pointer to the image of the runtime loadable model. - **config** (ll_aton_reloc_config*) - Required - Configuration details for installation, including memory addresses and sizes. - **nn_instance** (NN_Instance_TypeDef*) - Required - Pointer to the neural network instance structure to be initialized. ### Request Example { "file_ptr": "0x08001000", "config": { "base_addr": "0x24000000", "size": 2048 }, "nn_instance": "instance_ptr" } ### Response #### Success Response (200) - **status** (int) - Returns 0 on success, nonzero on error. #### Response Example { "status": 0 } ``` -------------------------------- ### Initialize and Run Inference with Embedded C-API Source: https://stm32ai-cs.st.com/assets/embedded-docs/embedded_client_api_legacy.html Demonstrates the minimal setup for an AI model, including memory allocation for activations and IO buffers, model initialization, and the inference execution loop. This example assumes a 32-bit floating-point model generated with no-allocation options. ```C #include #include "network.h" #include "network_data.h" /* Global handle to reference the instantiated C-model */ static ai_handle network = AI_HANDLE_NULL; /* Global c-array to handle the activations buffer */ AI_ALIGNED(32) static ai_u8 activations[AI_NETWORK_DATA_ACTIVATIONS_SIZE]; /* Array to store the data of the input tensor */ AI_ALIGNED(32) static ai_float in_data[AI_NETWORK_IN_1_SIZE]; /* c-array to store the data of the output tensor */ AI_ALIGNED(32) static ai_float out_data[AI_NETWORK_OUT_1_SIZE]; /* Array of pointer to manage the model's input/output tensors */ static ai_buffer *ai_input; static ai_buffer *ai_output; /* * Bootstrap */ int aiInit(void) { ai_error err; /* Create and initialize the c-model */ const ai_handle acts[] = { activations }; err = ai_network_create_and_init(&network, acts, NULL); if (err.type != AI_ERROR_NONE) { /* Handle error */ }; /* Reteive pointers to the model's input/output tensors */ ai_input = ai_network_inputs_get(network, NULL); ai_output = ai_network_outputs_get(network, NULL); return 0; } /* * Run inference */ int aiRun(const void *in_data, void *out_data) { ai_i32 n_batch; ai_error err; /* 1 - Update IO handlers with the data payload */ ai_input[0].data = AI_HANDLE_PTR(in_data); ai_output[0].data = AI_HANDLE_PTR(out_data); /* 2 - Perform the inference */ n_batch = ai_network_run(network, &ai_input[0], &ai_output[0]); if (n_batch != 1) { err = ai_network_get_error(network); /* Handle error */ }; return 0; } /* * Example of main loop function */ void main_loop() { aiInit(); while (1) { /* 1 - Acquire, pre-process and fill the input buffers */ acquire_and_process_data(in_data); /* 2 - Call inference engine */ aiRun(in_data, out_data); /* 3 - Post-process the predictions */ post_process(out_data); } } ``` -------------------------------- ### Full Inference Lifecycle Implementation Source: https://stm32ai-cs.st.com/assets/embedded-docs/embedded_client_api_legacy.html A complete example demonstrating initialization of a network, configuration of input/output buffers, and the main inference loop. ```C #include #include "network.h" static ai_float *in_data[AI_NETWORK_IN_NUM]; static ai_buffer *ai_inputs; static ai_buffer *ai_outputs; static ai_float out_1_data[AI_NETWORK_OUT_1_SIZE]; static ai_float out_2_data[AI_NETWORK_OUT_2_SIZE]; static ai_float* out_data[AI_NETWORK_OUT_NUM] = { &out_1_data[0], &out_2_data[0] }; int aiInit(void) { ai_inputs = ai_network_inputs_get(network); ai_outputs = ai_network_outputs_get(network); for (int i=0; i < AI_NETWORK_IN_NUM; i++) { in_data[i] = (ai_u8 *)(ai_inputs[i].data); } for (int i=0; i < AI_NETWORK_OUT_NUM; i++) { ai_outputs[i].data = AI_HANDLE_PTR(&out_data[i]); } } void main_loop() { while (1) { acquire_and_process_data(in_data); ai_network_run(network, &ai_inputs[0], &ai_outputs[0]); post_process(out_data); } } ``` -------------------------------- ### Define a Quantized Model with QKeras Source: https://stm32ai-cs.st.com/assets/embedded-docs/dqnn_support.html Demonstrates how to use QKeras drop-in replacements for Keras layers to create a quantized network. It includes examples of QActivation and QConv2D with specific quantizer configurations. ```python import tensorflow as tf import qkeras x = tf.keras.Input(shape=(28, 28, 1)) y = qkeras.QActivation(qkeras.quantized_relu(bits=8, alpha=1))(x) y = qkeras.QConv2D(16, (3, 3), kernel_quantizer=qkeras.binary(alpha=1), bias_quantizer=qkeras.binary(alpha=1), use_bias=False, name="conv2d_0")(y) y = tf.keras.layers.MaxPooling2D(pool_size=(2,2))(y) y = tf.keras.layers.BatchNormalization()(y) y = qkeras.QActivation(qkeras.binary(alpha=1))(y) model = tf.keras.Model(inputs=x, outputs=y) ``` -------------------------------- ### Configure serial connection parameters Source: https://stm32ai-cs.st.com/assets/embedded-docs/ai_runner_python_module.html Examples of configuring the serial driver for the stedgeai CLI, including specifying baud rates and COM ports for different operating systems. ```bash # Set baud rate $ stedgeai ... -d serial:921600 # Set COM port (Windows/Linux) $ stedgeai ... -d serial:COM4 $ stedgeai ... -d /dev/ttyACM0 # Set both $ stedgeai ... -d serial:COM4:921600 ``` -------------------------------- ### Connect Input Buffer to Network Instance Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_api_and_stack.html Example implementation showing how to declare a network instance and associate a user-allocated buffer with the network's first input. ```C LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE(network) // Define buffers for Inputs (the input is an RGB image, 256 x 256 x 3 x 8 bits) uint8_t input_buff[256 * 256 * 3]; // Connect buffer to the network first input. res = LL_ATON_Set_User_Input_Buffer(&NN_Instance_network, 0, input_buff, 256 * 256 * 3); assert (res == LL_ATON_User_IO_NOERROR); ``` -------------------------------- ### Fill First Input Tensor Example Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_api_and_stack.html Demonstrates how to fill the first input tensor of a neural network with a specific value. It utilizes the LL_ATON_Input_Buffers_Info function to get buffer details and LL_Buffer_addr_start and LL_Buffer_len for memory manipulation. ```c #define INPUT_NR 0 #define INPUT_VAL 0xFF LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE(network) LL_Buffer_InfoTypeDef* inputs_ptr = LL_ATON_Input_Buffers_Info(&NN_Instance_network); // Get a pointer to all input buffers info LL_Buffer_InfoTypeDef* first_input_ptr = &(inputs_ptr[INPUT_NR]); // Get a pointer to the first buffer info memset((void*)LL_Buffer_addr_start(first_input_ptr), INPUT_VAL, LL_Buffer_len(first_input_ptr)); ``` -------------------------------- ### Build and Load Test Application with n6_loader.py Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_getting_started.html This command prepares the compiler environment, updates the C-project, converts raw memory files to Intel-hex, builds the C-project, and loads the application onto the board. It requires the board to be configured in 'dev mode'. ```bash > python $STEDGEAI_CORE_DIR/scripts/N6_scripts/n6_loader.py ``` -------------------------------- ### Build and Load Test Application with USB Support Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_getting_started.html This command is similar to the default build and load process but enables USB support for higher data transfer speeds. It requires an additional USB cable to connect the board. ```bash > python $STEDGEAI_CORE_DIR/scripts/N6_scripts/n6_loader.py --build-config N6-DK-USB ``` -------------------------------- ### Sequential Quantized Dense Layers with Binary Weights (Python) Source: https://stm32ai-cs.st.com/assets/embedded-docs/dqnn_support.html This example showcases two sequential QDense layers. The first layer processes an 8-bit quantized input with binary weights to produce a binary output. The second layer takes this binary output and computes an f32 output using binary weights. The operation analysis highlights the mix of smul_s8_s1 and sxor_s1_s1 operations. ```python x = tf.keras.Input(shape=shape_in) y = tf.keras.layers.Flatten()(x) y = qkeras.QActivation(qkeras.quantized_bits(bits=8, integer=7))(y) y = qkeras.QDense(64, kernel_quantizer=qkeras.binary(alpha=1), bias_quantizer=qkeras.binary(alpha=1), use_bias=True, name="dense_0")(y) y = tf.keras.layers.BatchNormalization()(y) y = qkeras.QActivation(qkeras.binary(alpha=1))(y) y = qkeras.QDense(10, kernel_quantizer=qkeras.binary(alpha=1), bias_quantizer=qkeras.binary(alpha=1), use_bias=True, name="dense_1")(y) y = tf.keras.layers.Activation("softmax")(y) ``` -------------------------------- ### Run Inference with ll_aton Runtime API (C) Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_api_and_stack.html Provides a basic inference loop using the ll_aton runtime API. This example initializes the runtime and network, retrieves I/O buffer information, and enters a continuous loop to get features, pre-process, execute inference, and post-process. It includes cache management for NPU and MCU. ```c #include "ll_aton_caches_interface.h" // Network instance declaration LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE ( network ) ; NN_Interface_TypeDef *NN_InterfacePnt ; NN_Instance_TypeDef *NN_InstancePnt ; void* input_start_address ; void* input_end_address ; void* output_start_address ; void* output_end_address ; void main ( void ) { applicationSetup() ; // system initialization networkSetup() ; // Enter inference loop while ( 1 ) { getFeature ( input_start_address ) ; // Wait for input data from somewhere featurePreProcess ( input_start_address ) ; // Feature pre-processing (if any) inferenceExecute ( NN_InstancePnt ) ; inferencePostProcess ( output_start_address ) ; // Inference post-processing (if any) } /* endwhile */ } void networkSetup ( void ) { LL_ATON_RT_RuntimeInit() ; // Initialize runtime // Set references to the network "network" NN_InterfacePnt = (NN_Interface_TypeDef *) &NN_Interface_network ; NN_InstancePnt = (NN_Instance_TypeDef *) &NN_Instance_network ; // Initialize network LL_ATON_RT_Init_Network ( NN_InstancePnt ) ; // Set call back (if any) //LL_ATON_RT_SetEpochCallback ( EpochBlock_TraceCallBack , NN_InstancePnt ) ; // deprecated in future releases LL_ATON_RT_SetNetworkCallback ( NN_InstancePnt, EpochBlock_TraceCallBack) ; // Get I/O buffers addresses const LL_Buffer_InfoTypeDef * buffersInfos = NN_InterfacePnt -> input_buffers_info(); input_start_address = LL_Buffer_addr_start(&buffersInfos[0]); input_end_address = LL_Buffer_addr_end(&buffersInfos[0]); buffersInfos = NN_InterfacePnt -> output_buffers_info(); output_start_address = LL_Buffer_addr_start(&buffersInfos[0]); output_end_address = LL_Buffer_addr_end(&buffersInfos[0]); } int inferenceExecute ( NN_Instance_TypeDef *networkInstancePnt ) { LL_ATON_RT_RetValues_t ll_aton_rt_ret; if ( networkInstancePnt == NULL ) { return ( -1 ) ; } /* endif */ LL_ATON_Cache_NPU_Invalidate(); /* if NPU cache is used */ LL_ATON_Cache_MCU_Clean_Invalidate_Range(input_start_address, input_end_address - input_start_address); LL_ATON_Cache_MCU_Invalidate_Range(output_start_address, output_end_address - output_start_address); LL_ATON_RT_Reset_Network(networkInstancePnt); // Reset the network instance object do { /* Execute first/next step of Cube.AI/ATON runtime */ ll_aton_rt_ret = LL_ATON_RT_RunEpochBlock(networkInstancePnt); /* Wait for next event */ if (ll_aton_rt_ret == LL_ATON_RT_WFE) { /*** subject to change to fit also user code requirements ***/ LL_ATON_OSAL_WFE(); } } while (ll_aton_rt_ret != LL_ATON_RT_DONE); } ``` -------------------------------- ### Quantized Dense Layer with 8-bit Input and Binary Weights (Python) Source: https://stm32ai-cs.st.com/assets/embedded-docs/dqnn_support.html This example demonstrates a QDense layer with 8-bit quantized input and binary weights. It includes an optional BatchNormalization layer and outputs in f32 format. The analysis shows the number of operations and their types, highlighting the efficiency of the smul_s8_s1 operation. ```python import qkeras import tensorflow as tf shape_in = (128, 128) x = tf.keras.Input(shape=shape_in) y = qkeras.QActivation(qkeras.quantized_bits(bits=8, integer=7))(x) y = tf.keras.layers.Flatten()(y) y = qkeras.QDense(16, kernel_quantizer=qkeras.binary(alpha=1), bias_quantizer=qkeras.binary(alpha=1), use_bias=True, name="dense_0")(y) y = tf.keras.layers.BatchNormalization()(y) y = tf.keras.layers.Activation("softmax")(y) model = tf.keras.Model(inputs=x, outputs=y) ``` -------------------------------- ### Initialize and Start Free Running Counter Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_profiler.html Code snippet to initialize and start a free-running counter for measuring epoch durations. It configures counter properties like signal, event type, and wrap-around behavior. ```c LL_Dbgtrc_Counter_InitTypdef counter_init; counter_init.signal = DBGTRC_VDD; counter_init.evt_type = DBGTRC_EVT_HI; counter_init.wrap = 0; counter_init.countdown = 0; counter_init.int_disable = 1; counter_init.counter = 0; LL_Dbgtrc_Counter_Init(0, _COUNTER_ID, &counter_init); LL_Dbgtrc_Counter_Start(0, _COUNTER_ID); ``` -------------------------------- ### Configure and Start Stream Engine Activity Counters Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_profiler.html Configures and starts counters to measure the active cycles of stream engines during epoch execution. It utilizes helper functions like LL_Dbgtrc_Count_StrengActive_Config and LL_Dbgtrc_Count_StrengActive_Start. Input masks determine which stream engines are monitored. ```c int LL_Dbgtrc_Count_StrengActive_Config(uint32_t istreng, uint32_t ostreng, unsigned int counter); int LL_Dbgtrc_Count_StrengActive_Start(uint32_t istreng, uint32_t ostreng, unsigned int counter); void _configure_counters(const LL_ATON_RT_EpochBlockItem_t *epoch_block) { LL_Dbgtrc_Count_StrengActive_Config( epoch_block->in_streng_mask, epoch_block->out_streng_mask, _COUNTER_BASE_IDX); LL_Dbgtrc_Count_StrengActive_Start( epoch_block->in_streng_mask, epoch_block->out_streng_mask, _COUNTER_BASE_IDX); } ``` -------------------------------- ### Running N6 Loader Script with Configuration Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_getting_started.html This command demonstrates how to execute the `n6_loader.py` script using a specified configuration file. The `--n6-loader-config` argument points to the JSON file containing all necessary settings for the script's operation. ```bash python n6_loader.py --n6-loader-config ./config_n6l.json ``` -------------------------------- ### Display Memory Pool C-Descriptors (C Example) Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html An example demonstrating how to iterate through and display memory pool descriptors for a given model image. It uses `ll_aton_reloc_get_mem_pool_desc` in a loop to fetch each descriptor and prints its flags, file offset, destination address, and size. ```c ll_aton_reloc_mem_pool_desc *mem_c_desc; int index = 0; while ((mem_c_desc = ll_aton_reloc_get_mem_pool_desc((uintptr_t)bin, index))) { printf(" %d: flags=%x foff=%d dst=%x s=%d\n", index, mem_c_desc->flags, mem_c_desc->foff, mem_c_desc->dst, mem_c_desc->size); index++; } ``` -------------------------------- ### Configure and Start Memory Burst Counters Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_profiler.html Configures and starts counters to measure read/write memory burst lengths. It uses functions like LL_Dbgtrc_Count_BurstsLen to set up counters for different bus interfaces and burst sizes. This allows evaluation of memory traffic during epoch execution. ```c int LL_Dbgtrc_Count_BurstsLen(unsigned int counter, unsigned char busif, unsigned char readwrite); int LL_Dbgtrc_BurstLenBenchStart(unsigned int counter_id); void _configure_counters(const LL_ATON_RT_EpochBlockItem_t *epoch_block) { /* equivalent to LL_Dbgtrc_BurstLenBenchStart(0); */ const int counter_id = 0; LL_Dbgtrc_Count_BurstsLen(counter_id, 0, 0); /* Busif 0 writes */ LL_Dbgtrc_Count_BurstsLen(counter_id + 4, 0, 1); /* Busif 0 reads */ LL_Dbgtrc_Count_BurstsLen(counter_id + 8, 1, 0); /* Busif 1 writes */ LL_Dbgtrc_Count_BurstsLen(counter_id + 12, 1, 1); /* Busif 1 reads */ } ``` -------------------------------- ### Deploy Relocatable Model using st_load_and_run.py Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html This script deploys a relocatable AI model to the STM32 target. It takes the path to the model binary as input and outputs detailed information about the model, board, and deployment process, including inference performance metrics. ```bash $STEDGEAI_CORE_DIR/Utilities/windows/python $STEDGEAI_CORE_DIR/scripts/N6_reloc/st_load_and_run.py -i \network_rel.bin ``` ```text NPU Utility - ST Load and run (dev environment) (version 2.0) Creating date : ... model info : st_ai_output\network_rel.bin: size=55,832 cpuid=0xd22 c_name='network' 'Embedded ARM GCC' ll_aton=1.1.3.3 acts/params=57,087/22,065 xip/copy=632/13,312 ext_ram=0 split=False secure=True board : 'stm32n6570-dk' mode : ['copy'] board info : 'stm32n6570-dk' baudrate=921600 eflash_loader='MX66UW1G45G_STM32N6570-DK.stldr' eflash[sec/pg]=64.0KB/4.0KB exec_ram[int/ext]=655,360/4,194,304 ext_ram=28,311,552 addrs=0x70FFF000,0x71000000,0x71800000 use clang : False install mode : 'copy' total (1) : overlay bin=65,536 xip=640 [copy=13,312] 'installed in int exec_ram' ext_ram=0 flash@ : 0x71000000 flash_params@ : 0x00000000 Resetting the board. Flashing 'header (nb_entries=1)' at address 0x70FFF000 (size=20).. Flashing 'st_ai_output\network_rel.bin' at address 0x71000000 (size=55832).. Loading & start the validation application 'stm32n6570-dk-validation-reloc'.. Deployed model is started and ready to be used. Executing the deployed model (desc=serial:921600).. ... Inference time per node ------------------------------------------------------------------------------------------------------------------- c_id m_id type dur (ms) % cumul CPU cycles name ------------------------------------------------------------------------------------------------------------------- 0 - epoch (EC) 0.210 96.6% 96.6% [ 896 166,877 573 ] EpochBlock_1 -> 14 1 - epoch (SW) 0.007 3.4% 100.0% [ 110 40 5,704 ] EpochBlock_15 ------------------------------------------------------------------------------------------------------------------- total 0.218 [ 1,006 166,917 6,277 ] 4592.41 inf/s [ 0.6% 95.8% 3.6% ] ------------------------------------------------------------------------------------------------------------------- ``` -------------------------------- ### Get Input/Output Buffer Information Functions in C Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_api_and_stack.html Functions to retrieve information about input, output, and internal buffers for a given NN_Instance_TypeDef in STM32AI. These functions return pointers to LL_Buffer_InfoTypeDef structures, which can then be used with utility functions to get buffer addresses and lengths. ```c const LL_Buffer_InfoTypeDef *LL_ATON_Output_Buffers_Info(const NN_Instance_TypeDef *nn_instance); const LL_Buffer_InfoTypeDef *LL_ATON_Input_Buffers_Info(const NN_Instance_TypeDef *nn_instance); const LL_Buffer_InfoTypeDef *LL_ATON_Internal_Buffers_Info(const NN_Instance_TypeDef *nn_instance); // And utilities: unsigned char *LL_Buffer_addr_start(const LL_Buffer_InfoTypeDef *buf); unsigned char *LL_Buffer_addr_end(const LL_Buffer_InfoTypeDef *buf); uint32_t LL_Buffer_len(const LL_Buffer_InfoTypeDef *buf); ``` -------------------------------- ### Perform Static Quantization with ONNX Runtime Source: https://stm32ai-cs.st.com/assets/embedded-docs/quantization.html This script demonstrates how to quantize an ONNX model using the StaticQuantConfig. It includes a custom CalibrationDataReader implementation to preprocess images into the NCHW format required by ONNX Runtime. ```python import numpy import onnxruntime from onnxruntime.quantization import QuantFormat, QuantType, StaticQuantConfig, quantize, CalibrationMethod from onnxruntime.quantization import CalibrationDataReader from PIL import Image input_model_path = 'my_model.onnx' output_model_path = 'my_model_quantized.onnx' calibration_dataset_path = '/path/to/data/for/calibration' def _preprocess_images(images_folder: str, height: int, width: int): image_names = os.listdir(images_folder) batch_filenames = image_names unconcatenated_batch_data = [] for image_name in batch_filenames: image_filepath = images_folder + "/" + image_name pillow_img = Image.new("RGB", (width, height)) pillow_img.paste(Image.open(image_filepath).resize((width, height))) input_data = numpy.float32(pillow_img) - numpy.array( [123.68, 116.78, 103.94], dtype=numpy.float32 ) nhwc_data = numpy.expand_dims(input_data, axis=0) nchw_data = nhwc_data.transpose(0, 3, 1, 2) unconcatenated_batch_data.append(nchw_data) batch_data = numpy.concatenate( numpy.expand_dims(unconcatenated_batch_data, axis=0), axis=0 ) return batch_data class XXXDataReader(CalibrationDataReader): def __init__(self, calibration_image_folder: str, model_path: str): self.enum_data = None session = onnxruntime.InferenceSession(model_path, None) (_, _, height, width) = session.get_inputs()[0].shape self.nhwc_data_list = _preprocess_images(calibration_image_folder, height, width) self.input_name = session.get_inputs()[0].name self.datasize = len(self.nhwc_data_list) def get_next(self): if self.enum_data is None: self.enum_data = iter([{self.input_name: nhwc_data} for nhwc_data in self.nhwc_data_list]) return next(self.enum_data, None) def rewind(self): self.enum_data = None dr = XXXDataReader(calibration_dataset_path, input_model_path) conf = StaticQuantConfig( calibration_data_reader=dr, quant_format=QuantFormat.QDQ, calibrate_method=CalibrationMethod.MinMax, optimize_model=True, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, per_channel=True) quantize(infer_model, output_model_path, conf) ``` -------------------------------- ### Epoch Callback Implementation Example in C Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_api_and_stack.html An example implementation of an epoch callback function in C for STM32AI. This function handles different callback types such as pre-start, post-end, and network initialization, allowing for actions like toggling trace pins or capturing timing information. ```c void EpochBlock_TraceCallBack ( LL_ATON_RT_Callbacktype_t ctype , const NN_Instance_TypeDef *nn_instance , const EpochBlock_ItemTypeDef *eb ) { switch ( ctype ) { case LL_ATON_RT_Callbacktype_PRE_START : TOGGLE_EPOCH_PIN ; // Trace epoch pin for oscilloscope break ; case LL_ATON_RT_Callbacktype_POST_END : // If needed dump intermediate activations checkEpochOutputs ( eb -> epoch_num ) ; break ; case LL_ATON_RT_Callbacktype_NN_Init : // Capture network start time inferenceBaseTime = dwtGetCycles() ; break ; default : return ; break ; } /* endswitch */ } // end of EpochBlock_TraceCallBack() function ``` -------------------------------- ### Analyze Neural Network Models with stedgeai Source: https://stm32ai-cs.st.com/assets/embedded-docs/command_line_interface.html Demonstrates the use of the stedgeai command-line tool to analyze deep learning models for STM32 targets. Includes examples for compressed floating-point models and quantized TFLite models with specific memory allocation flags. ```bash $ stedgeai analyze -m dnn.h5 -c low --target stm32 ``` ```bash $ stedgeai analyze -m .tflite --allocate-inputs --target stm32 ``` -------------------------------- ### Generate Relocatable Binary Model using npu_driver.py Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html Demonstrates how to invoke the npu_driver.py script to convert network C files into loadable binary models. It shows the default behavior and how to override the output filename using the --name/-n flag. ```bash # Default behavior using network.c python npu_driver.py -i /network.c # Using a custom model file python npu_driver.py -i /my_model.c # Specifying a custom output name python npu_driver.py -i /network.c -n toto ``` -------------------------------- ### Retrieve Tensor Information from Buffer Descriptor (C) Source: https://stm32ai-cs.st.com/assets/embedded-docs/embedded_client_api_legacy.html Demonstrates how to access and extract information about input tensors from a network descriptor. It shows how to get the buffer descriptor, extract its format using `AI_BUFFER_FORMAT`, and retrieve dimensions like height, width, and channels using `AI_BUFFER_SHAPE_ELEM`. It also shows how to get the total size and size in bytes. ```c #include "network.h" { /* Use the generated macro to set the buffer input descriptors */ const ai_buffer *ai_input = ai_network_inputs_get(network, NULL); /* Extract format of the first input tensor (index 0) */ const ai_buffer *ai_input_1 = &ai_input[0]; /* Extract format of the tensor */ const ai_buffer_format fmt_1 = AI_BUFFER_FORMAT(ai_input_1); /* Extract height, width and channels of the first input tensor */ const ai_u16 height_1 = AI_BUFFER_SHAPE_ELEM(ai_input_1, AI_SHAPE_HEIGHT); const ai_u16 width_1 = AI_BUFFER_SHAPE_ELEM(ai_input_1, AI_SHAPE_WIDTH); const ai_u16 ch_1 = AI_BUFFER_SHAPE_ELEM(ai_input_1, AI_SHAPE_CHANNEL); const ai_u16 size_1 = AI_BUFFER_SIZE(ai_input_1); /* number of item*/ const ai_u32 size_in_bytes_1 = AI_BUFFER_BYTE_SIZE(size_1, fmt_1); ... } ``` -------------------------------- ### Configure Model Buffers and Initialize Source: https://stm32ai-cs.st.com/assets/embedded-docs/stm32_relocatable_mode.html Sets up the activation and weights buffers for the model instance and initializes the network handle for inference. ```C ai_handle weights_addr; ai_bool res; uint8_t *act_addr = malloc(rt_info.acts_sz); if (rt_info.weights) weights_addr = rt_info.weights; else weights_addr = WEIGHTS_ADDRESS; res = ai_rel_network_init(net, &weights_addr, &act_addr); ``` -------------------------------- ### Generate Specialized C-files Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_getting_started.html Command to generate C-files using a custom profile and an example of the resulting EC blob constant section in the generated header file. ```bash stedgeai generate -m mobilenet_v2_0.35_224_fft_int8.tflite --target stm32n6 --st-neural-art allmems--O3-ec@neural_art.json ``` ```c ECBLOB_CONST_SECTION static const uint64_t _ec_blob_1 [] = { 0x000094edca057a7aUL, 0x0000005d0000003dUL, 0x5c00004200802241UL, 0x1500006008000000UL, 0x000700005c027c00UL, 0x000040005c070043UL, 0x5c0c00430000ffe0UL, 0x1041204200000000UL }; ``` -------------------------------- ### Initialize and execute AI model inference in C Source: https://stm32ai-cs.st.com/assets/embedded-docs/stm32_how_to_run_a_model_locally.html Demonstrates the complete lifecycle of an AI model inference, including static buffer allocation, network initialization, input data preparation, and execution. It uses the standard ai_network API to process data and retrieve results. ```c #include #include #include #include #include "network.h" #include "network_data.h" ai_u8 activations[AI_NETWORK_DATA_ACTIVATIONS_SIZE]; ai_u8 in_data[AI_NETWORK_IN_1_SIZE_BYTES]; ai_u8 out_data[AI_NETWORK_OUT_1_SIZE_BYTES]; ai_buffer *ai_input; ai_buffer *ai_output; int main(int argc, char const *argv[]) { ai_handle network = AI_HANDLE_NULL; ai_error err; ai_network_report report; const ai_handle acts[] = { activations }; err = ai_network_create_and_init(&network, acts, NULL); if (err.type != AI_ERROR_NONE) { printf("ai init_and_create error\n"); return -1; } if (ai_network_get_report(network, &report) != true) { printf("ai get report error\n"); return -1; } ai_input = &report.inputs[0]; ai_output = &report.outputs[0]; srand(1); for (int i = 0; i < AI_NETWORK_IN_1_SIZE; i++) { in_data[i] = rand() % 0xFFFF; } ai_input = ai_network_inputs_get(network, NULL); ai_output = ai_network_outputs_get(network, NULL); ai_input[0].data = AI_HANDLE_PTR(in_data); ai_output[0].data = AI_HANDLE_PTR(out_data); ai_i32 n_batch = ai_network_run(network, &ai_input[0], &ai_output[0]); if (n_batch != 1) { err = ai_network_get_error(network); printf("ai run error %d, %d\n", err.type, err.code); return -1; } for (int i = 0; i < AI_NETWORK_OUT_1_SIZE; i++) { printf("%d,", out_data[i]); } return 0; } ``` -------------------------------- ### Enable LL ATON Runtime Relocation Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html The LL_ATON_RT_RELOC macro must be defined during compilation to enable the necessary code paths for managing and installing runtime loadable models. ```C #define LL_ATON_RT_RELOC ``` -------------------------------- ### Deploy Multiple Relocatable Models using st_load_and_run.py Source: https://stm32ai-cs.st.com/assets/embedded-docs/stneuralart_reloc_mode.html This script deploys multiple relocatable AI models to the STM32 target by listing their respective binary paths. Each model must have a unique c-name for proper identification and deployment. ```bash $STEDGEAI_CORE_DIR/Utilities/windows/python $STEDGEAI_CORE_DIR/scripts/N6_reloc/st_load_and_run.py -i \model1_rel.bin \model2_rel.bin ``` -------------------------------- ### Configure Environment for stm_ai_runner Source: https://stm32ai-cs.st.com/assets/embedded-docs/ai_runner_python_module.html Commands to install necessary Python dependencies and set the PYTHONPATH environment variable to enable the stm_ai_runner package. ```bash pip install protobuf<3.21 tqdm colorama pyserial numpy export PYTHONPATH=$STEDGEAI_CORE_DIR/scripts/ai_runner:$PYTHONPATH export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python ```