cancel
Showing results for 
Search instead for 
Did you mean: 

How to Feed Features and Get Predictions with X-CUBE-AI on STM32?

Stone_chan
Associate

Hi everyone,
I'm working on deploying an MLP model on STM32F746 using X-CUBE-AI. The model was converted from ONNX format, and I’m running into trouble feeding the input features and retrieving the prediction result

I want to run inference with the following flow:

float input_data[60] = { /* preprocessed features */ };
float output_data[1]; // expecting softmax probabilities
int output_label; // expecting predicted class label

My main confusion:

I'm unclear on how to actually use the interface generated by Cube.AI:

  • What are the correct steps to initialize and fill the ai_buffer structs?

  • Do I need to manually align my input/output arrays, or use the data_ins[] / data_outs[] generated by default?

  • What is the purpose of macros like AI_HANDLE_PTR(...) and AI_MNETWORK_IN?

  • I tried calling ai_mlp_run(...) like this:

     
    ai_mlp_run(network, ai_input, ai_output);

    but I get build errors or invalid pointer types

 



model information :

problem.png

app_X-cube-ai.h:
problem2.png

1 REPLY 1
Julian E.
ST Employee

Hello @Stone_chan,

 

When you create your project in CubeMX, select the last version of X Cube AI and the application Template.

 

Then in the generated code, you will find app_x-cube-ai.c in /X-Cube-AI-App.

The main functions here are the MX_X_CUBE_AI_Init and MX_X_CUBE_AI_Process.

 

In the MX_X_CUBE_AI_Process you will find 3 parts:

  • acquire_and_process_data(data_ins)
  • ai_run()
  • post_process(data_outs)

 

The way to pass data is through the function acquire_and_process_data(data_ins). By default, it looks like this:

int acquire_and_process_data(ai_i8* data[])
{
  /* fill the inputs of the c-model
  for (int idx=0; idx < AI_NETWORK_IN_NUM; idx++ )
  {
      data[idx] = ....
  }

  */
  return 0;
}

The for loop here is used if you have multiple input to give your model. In most case you have one, so you will only pass 1 time and fill data[0].

 

Same for the post_process(data_outs) function.

 

The data that you have to pass are 1D array of size of your input/output and be careful, by default the data_ins and data_outs are in int8 (ai_i8). So if you are using float32 for example, make sure to adapt the code.

 

For your board in particular, the MX_X_CUBE_AI_Process is not called in the main.c.

You can add it in the while(1) in the main function:

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* Enable the CPU Cache */

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Configure the peripherals common clocks */
  PeriphCommonClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC3_Init();
  MX_CRC_Init();
  MX_DCMI_Init();
  MX_DMA2D_Init();
  MX_ETH_Init();
  MX_FMC_Init();
  MX_I2C1_Init();
  MX_I2C3_Init();
  MX_LTDC_Init();
  MX_QUADSPI_Init();
  MX_RTC_Init();
  MX_SAI2_Init();
  MX_SDMMC1_SD_Init();
  MX_SPDIFRX_Init();
  MX_SPI2_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM5_Init();
  MX_TIM8_Init();
  MX_TIM12_Init();
  MX_USART1_UART_Init();
  MX_USART6_UART_Init();
  MX_FATFS_Init();
  MX_X_CUBE_AI_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 4096);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* Start scheduler */
  osKernelStart();

  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  MX_X_CUBE_AI_Process();
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

Have a good day,

Julian


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.