Hello, I am trying to follow this tutorial: https://docs.edgeimpulse.com/docs/using-cubeai using a STM32WL55JC1.
I directly pasted in raw features on my device and when monitoring the serial output the features array that is returned is changed. How is this possible if the raw features are directly pasted in? Here are a few of the output arrays I am seeing, they never seem to repeat.
Hi @jwcuddeb,
Any chance you could share your project or at least the main.cpp file?
Thanks,
Aurelien
Will not let me upload non-image files so here is a copy of main.cpp:
/* USER CODE BEGIN Header */ /** ****************************************************************************** * file : main.c * brief : Main program body ****************************************************************************** * attention * *© Copyright (c) 2021 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h"/* Private includes ----------------------------------------------------------/
/ USER CODE BEGIN Includes */
#include “edge-impulse-sdk/classifier/ei_run_classifier.h”using namespace ei;
// paste the raw features here
float features[] = {
61.7181, 9.5627, -42.6121…
};int get_feature_data(size_t offset, size_t length, float *out_ptr) {
memcpy(out_ptr, features + offset, length * sizeof(float));
return 0;
}/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart2;/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/ USER CODE BEGIN PFP *//* USER CODE END PFP */
/* Private user code ---------------------------------------------------------/
/ USER CODE BEGIN 0 */
#include <stdarg.h>
#include “edge-impulse-sdk/classifier/ei_run_classifier.h”void vprint(const char fmt, va_list argp)
{
char string[200];
if(0 < vsprintf(string, fmt, argp)) // build string
{
HAL_UART_Transmit(&huart2, (uint8_t)string, strlen(string), 0xffffff); // send message via UART
}
}void ei_printf(const char *format, …) {
va_list myargs;
va_start(myargs, format);
vprint(format, myargs);
va_end(myargs);
}/* USER CODE END 0 */
/**
- brief The application entry point.
- retval int
/
int main(void)
{
/ USER CODE BEGIN 1 *//* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();/* USER CODE BEGIN Init */
signal_t signal;
signal.total_length = sizeof(features) / sizeof(features[0]);
signal.get_data = &get_feature_data;/* 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_USART2_UART_Init();
/ USER CODE BEGIN 2 *//* USER CODE END 2 */
/* Infinite loop /
/ USER CODE BEGIN WHILE */
while (1)
{
ei_impulse_result_t result = { 0 };
EI_IMPULSE_ERROR res = run_classifier_continuous(&signal, &result, true);
ei_printf(“run_classifier returned: %d\n”, res);ei_printf("Predictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n", result.timing.dsp, result.timing.classification, result.timing.anomaly); // print the predictions ei_printf("["); for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { ei_printf_float(result.classification[ix].value);
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf(", “);
#else
if (ix != EI_CLASSIFIER_LABEL_COUNT - 1) {
ei_printf(”, “);
}
#endif
}
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf_float(result.anomaly);
#endif
ei_printf(”]\n\n\n");HAL_Delay(5000); /* 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};/** Configure LSE Drive Capability
/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/* Configure the main internal regulator output voltage
/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/* Initializes the CPU, AHB and APB busses clocks
/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK
|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}/**
- brief USART2 Initialization Function
- param None
- retval None
*/
static void MX_USART2_UART_Init(void)
{/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 /
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
{
Error_Handler();
}
/ USER CODE BEGIN USART2_Init 2 *//* USER CODE END USART2_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_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LED1_Pin|LED2_Pin|LED3_Pin, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, FE_CTRL3_Pin|FE_CTRL2_Pin|FE_CTRL1_Pin, GPIO_PIN_RESET);/*Configure GPIO pins : LED1_Pin LED2_Pin LED3_Pin */
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin|LED3_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 pins : FE_CTRL3_Pin FE_CTRL2_Pin FE_CTRL1_Pin */
GPIO_InitStruct.Pin = FE_CTRL3_Pin|FE_CTRL2_Pin|FE_CTRL1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pins : B1_Pin B2_Pin */
GPIO_InitStruct.Pin = B1_Pin|B2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : B3_Pin */
GPIO_InitStruct.Pin = B3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(B3_GPIO_Port, &GPIO_InitStruct);}
/* USER CODE BEGIN 4 */
/* 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 *//************************ © COPYRIGHT STMicroelectronics *END OF FILE/
It looks correct but I notice you use the run_classifier_continuous
function.
Can you try with the regular run_classifier
instead? I’m thinking the double buffering used for continuous audio is not performing as expected as your Prediction latency is over 2 sec.
If you also share your project ID, we could also try to reproduce and see why it is so slow.
Aurelien
Changing to run_classifier made the features consistent. However now the DSP/prediction is taking much much longer:
Project ID is 54230.
Performances are quite low because there’s no FPU on the M4. You can try a couple of things to tune your MFE block as mentioned in this post: Impulse performance on STM32WL55x extremely slow.
Especially the FFT size to 64, and setting your frame stride = frame length.
Aurelien
We are also running into a few additional issues with this project.
When I update the primary model with one generated by the EON tuner and deploy it via Cube.MX CMSIS-PACK, there seems to be a large amount of undefined references similar to the issue raised https://forum.edgeimpulse.com/t/cant-verify-stm32wl-project-successfully/3084 (which has since been fixed). I’m showing the existing errors in the screenshot below.
Also, is there an issue with the fact that we’re using a dual core project, and folder structure?
Thank you.
Hi @Markrubianes,
It looks more like the porting functions are not defined/found. Can you check whether EI_PORTING_STM32_CUBEAI
is defined (and set to 1)?
edge-impulse-sdk/porting/ei_classifier_porting.h:
#ifndef EI_PORTING_STM32_CUBEAI
#if defined(USE_HAL_DRIVER) && !defined(__MBED__) && EI_PORTING_ZEPHYR == 0
#define EI_PORTING_STM32_CUBEAI 1
#else
#define EI_PORTING_STM32_CUBEAI 0
#endif
#endif
Raul
Yes it is set to 1
#ifndef EI_PORTING_STM32_CUBEAI
#if defined(USE_HAL_DRIVER) && !defined(MBED) && EI_PORTING_ZEPHYR == 0
#define EI_PORTING_STM32_CUBEAI 1
#else
#define EI_PORTING_STM32_CUBEAI 0
#endif
#endif
Thanks for your reply.
This should mean that edge-impulse-sdk/porting/stm32-cubeai/ei_classifier_porting.cpp
can be found built and linked. Can you confirm? e.g. try putting some gibberrish like dfdffd;
in a function. The compilation should fail here. If it does fail, then the problem seems to be in the linking stage.