STM32 Microcontroller

To work with AI models in STM32 Microcontrollers the following versions of CubeIDE, CubeMX, X-CUBE-AI packages are suitable to work.

Working versions of STM32 tools to work with AI/ Machine Learning models

###################################################

CubeMX version = 6.6.1

STM32Cube MCU Packages of H7 series = 1.10.0 and 1.9.1

CubeIDE vesion = 1.10.1

X-CUBE-AI package = 7.2.0

STM32 DSP Library inclusion to CUBE IDE that worked for me:
Follow this video: https://youtu.be/vCcALaGNlyw

Also you may include the library from https://youtu.be/jqCpaleqfls


AI Deprecated Issue:
Solution here: https://community.st.com/s/question/0D53W00001mHuYGSA0/invalid-initializer-error-with-autogenerated-code-xcubeai

My problem solved when I modified the error occurrences in sin_model.h from this:


to this:


Latest AI model code for STM32 microcontroller is given below:

Link

https://wiki.st.com/stm32mcu/wiki/AI:How_to_perform_motion_sensing_on_STM32L4_IoTnode#Real-time_scheduling_considerations

New way of writing AI code in STM32 which worked for my case:


/* USER CODE BEGIN Header */

/**

  ******************************************************************************

  * @file           : main.c

  * @brief          : Main program body

  ******************************************************************************

  * @attention

  *

  * Copyright (c) 2023 STMicroelectronics.

  * All rights reserved.

  *

  * This software is licensed under terms that can be found in the LICENSE file

  * in the root directory of this software component.

  * If no LICENSE file comes with this software, it is provided AS-IS.

  *

  ******************************************************************************

  */

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"


/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include "stdio.h"

#include "string.h"

#include "sine_model.h"

#include "sine_model_data.h"

#include <inttypes.h>

#include <stdlib.h>

#include "ai_platform.h"

#include "ai_datatypes_defines.h"


/* USER CODE END Includes */


/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */


/* USER CODE END PTD */


/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

/* USER CODE END PD */


/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */


/* USER CODE END PM */


/* Private variables ---------------------------------------------------------*/


CRC_HandleTypeDef hcrc;


TIM_HandleTypeDef htim1;


UART_HandleTypeDef huart3;


/* USER CODE BEGIN PV */

volatile uint32_t dataRdyIntReceived;

ai_handle sine_model;

float aiInData[AI_SINE_MODEL_IN_1_SIZE];

float aiOutData[AI_SINE_MODEL_OUT_1_SIZE];

ai_u8 activations[AI_SINE_MODEL_DATA_ACTIVATIONS_SIZE];


//const char* activities[AI_SINE_MODEL_OUT_1_SIZE] = {

//  "stationary", "walking", "running"

//};

ai_buffer * ai_input;

ai_buffer * ai_output;


char buf[100];

int buf_len = 0;

float y_val;

/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_USART3_UART_Init(void);

static void MX_CRC_Init(void);

static void MX_TIM1_Init(void);

/* USER CODE BEGIN PFP */


static void AI_Init(void);

static void AI_Run(float *pIn, float *pOut);

//static uint32_t argmax(const float * values, uint32_t len);


/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */


/* USER CODE END 0 */


/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */


  /* 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();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_USART3_UART_Init();

  MX_CRC_Init();

  MX_TIM1_Init();

  /* USER CODE BEGIN 2 */

  dataRdyIntReceived = 0;

//  MEMS_Init();

// Greetings!

buf_len = sprintf(buf, "\r\n\r\nSine Model inference NEW WAY\r\n");

HAL_UART_Transmit(&huart3, (uint8_t*) buf, buf_len, 100);

AI_Init();

  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  uint32_t write_index = 0;

  while (1)

  {

  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14);  // Turn off Green LED after inference


  aiInData[write_index] = (float) 1.0f;

//   if (write_index == AI_SINE_MODEL_IN_1_SIZE) {

// write_index = 0;


// printf("Running inference\r\n");

AI_Run(aiInData, aiOutData);


/* Output results */

for (uint32_t i = 0; i < AI_SINE_MODEL_OUT_1_SIZE; i++) {

printf("%8.6f ", aiOutData[i]);

y_val = aiOutData[i];

// Greetings!

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);  // Turn off Green LED after inference


// Print output of neural network along with inference time (microseconds)

buf_len = sprintf(buf, "predicted value sin(x)= %f\r\n",y_val);

HAL_UART_Transmit(&huart3, (uint8_t*) buf, buf_len, 100);

HAL_Delay(100);

// }

// uint32_t class = argmax(aiOutData, AI_NETWORK_OUT_1_SIZE);

// printf(": %d - %s\r\n", (int) class, activities[class]);

  }

    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


/**

  * @brief System Clock Configuration

  * @retval None

  */

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  /** Supply configuration update enable

  */

  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);


  /** Configure the main internal regulator output voltage

  */

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);


  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}


  __HAL_RCC_SYSCFG_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);


  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}


  /** Initializes the RCC Oscillators according to the specified parameters

  * in the RCC_OscInitTypeDef structure.

  */

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

  RCC_OscInitStruct.PLL.PLLM = 4;

  RCC_OscInitStruct.PLL.PLLN = 480;

  RCC_OscInitStruct.PLL.PLLP = 2;

  RCC_OscInitStruct.PLL.PLLQ = 20;

  RCC_OscInitStruct.PLL.PLLR = 2;

  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;

  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;

  RCC_OscInitStruct.PLL.PLLFRACN = 0;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  {

    Error_Handler();

  }


  /** Initializes the CPU, AHB and APB buses clocks

  */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2

                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;

  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;

  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;

  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;

  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;

  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;


  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)

  {

    Error_Handler();

  }

}


/**

  * @brief CRC Initialization Function

  * @param None

  * @retval None

  */

static void MX_CRC_Init(void)

{


  /* USER CODE BEGIN CRC_Init 0 */


  /* USER CODE END CRC_Init 0 */


  /* USER CODE BEGIN CRC_Init 1 */


  /* USER CODE END CRC_Init 1 */

  hcrc.Instance = CRC;

  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;

  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;

  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;

  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;

  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;

  if (HAL_CRC_Init(&hcrc) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN CRC_Init 2 */


  /* USER CODE END CRC_Init 2 */


}


/**

  * @brief TIM1 Initialization Function

  * @param None

  * @retval None

  */

static void MX_TIM1_Init(void)

{


  /* USER CODE BEGIN TIM1_Init 0 */


  /* USER CODE END TIM1_Init 0 */


  TIM_ClockConfigTypeDef sClockSourceConfig = {0};

  TIM_MasterConfigTypeDef sMasterConfig = {0};


  /* USER CODE BEGIN TIM1_Init 1 */


  /* USER CODE END TIM1_Init 1 */

  htim1.Instance = TIM1;

  htim1.Init.Prescaler = 240-1;

  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim1.Init.Period = 1;

  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  htim1.Init.RepetitionCounter = 0;

  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)

  {

    Error_Handler();

  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)

  {

    Error_Handler();

  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN TIM1_Init 2 */


  /* USER CODE END TIM1_Init 2 */


}


/**

  * @brief USART3 Initialization Function

  * @param None

  * @retval None

  */

static void MX_USART3_UART_Init(void)

{


  /* USER CODE BEGIN USART3_Init 0 */


  /* USER CODE END USART3_Init 0 */


  /* USER CODE BEGIN USART3_Init 1 */


  /* USER CODE END USART3_Init 1 */

  huart3.Instance = USART3;

  huart3.Init.BaudRate = 115200;

  huart3.Init.WordLength = UART_WORDLENGTH_8B;

  huart3.Init.StopBits = UART_STOPBITS_1;

  huart3.Init.Parity = UART_PARITY_NONE;

  huart3.Init.Mode = UART_MODE_TX_RX;

  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart3.Init.OverSampling = UART_OVERSAMPLING_16;

  huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

  huart3.Init.ClockPrescaler = UART_PRESCALER_DIV1;

  huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

  if (HAL_UART_Init(&huart3) != HAL_OK)

  {

    Error_Handler();

  }

  if (HAL_UARTEx_SetTxFifoThreshold(&huart3, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)

  {

    Error_Handler();

  }

  if (HAL_UARTEx_SetRxFifoThreshold(&huart3, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)

  {

    Error_Handler();

  }

  if (HAL_UARTEx_DisableFifoMode(&huart3) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN USART3_Init 2 */


  /* USER CODE END USART3_Init 2 */


}


/**

  * @brief GPIO Initialization Function

  * @param None

  * @retval None

  */

static void MX_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};


  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOC_CLK_ENABLE();

  __HAL_RCC_GPIOH_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();

  __HAL_RCC_GPIOD_CLK_ENABLE();

  __HAL_RCC_GPIOG_CLK_ENABLE();

  __HAL_RCC_GPIOE_CLK_ENABLE();


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin, GPIO_PIN_RESET);


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);


  /*Configure GPIO pin : B1_Pin */

  GPIO_InitStruct.Pin = B1_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);


  /*Configure GPIO pins : LD1_Pin LD3_Pin */

  GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


  /*Configure GPIO pin : USB_OTG_FS_OVCR_Pin */

  GPIO_InitStruct.Pin = USB_OTG_FS_OVCR_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  HAL_GPIO_Init(USB_OTG_FS_OVCR_GPIO_Port, &GPIO_InitStruct);


  /*Configure GPIO pin : LD2_Pin */

  GPIO_InitStruct.Pin = LD2_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);


}


/* USER CODE BEGIN 4 */

static void AI_Init(void)

{

  ai_error err;


  /* Create a local array with the addresses of the activations buffers */

  const ai_handle act_addr[] = { activations };

  /* Create an instance of the model */

  err = ai_sine_model_create_and_init(&sine_model, act_addr, NULL);

  if (err.type != AI_ERROR_NONE) {

    printf("ai_sine_model_create error - type=%d code=%d\r\n", err.type, err.code);

    Error_Handler();

  }

  ai_input = ai_sine_model_inputs_get(sine_model, NULL);

  ai_output = ai_sine_model_outputs_get(sine_model, NULL);

}


static void AI_Run(float *pIn, float *pOut)

{

  ai_i32 batch;

  ai_error err;


  /* Update IO handlers with the data payload */

  ai_input[0].data = AI_HANDLE_PTR(pIn);

  ai_output[0].data = AI_HANDLE_PTR(pOut);


  batch = ai_sine_model_run(sine_model, ai_input, ai_output);

  if (batch != 1) {

    err = ai_sine_model_get_error(sine_model);

    printf("AI ai_sine_model_run error - type=%d code=%d\r\n", err.type, err.code);

    Error_Handler();

  }

}


/* USER CODE END 4 */


/**

  * @brief  This function is executed in case of error occurrence.

  * @retval None

  */

void Error_Handler(void)

{

  /* USER CODE BEGIN Error_Handler_Debug */

  /* User can add his own implementation to report the HAL error return state */

  __disable_irq();

  while (1)

  {

  }

  /* USER CODE END Error_Handler_Debug */

}


#ifdef  USE_FULL_ASSERT

/**

  * @brief  Reports the name of the source file and the source line number

  *         where the assert_param error has occurred.

  * @param  file: pointer to the source file name

  * @param  line: assert_param error line source number

  * @retval None

  */

void assert_failed(uint8_t *file, uint32_t line)

{

  /* USER CODE BEGIN 6 */

  /* User can add his own implementation to report the file name and line number,

     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */