/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 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" #include "openamp.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include // to use sprintf #include "math.h" #include "string.h" #include "ai_platform.h" #include "emotion_model.h" #include "emotion_model_data.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 ---------------------------------------------------------*/ ADC_HandleTypeDef hadc2; DMA_HandleTypeDef hdma_adc2; CRC_HandleTypeDef hcrc2; IPCC_HandleTypeDef hipcc; UART_HandleTypeDef huart4; /* USER CODE BEGIN PV */ ai_handle emotion_model; float aiInData[AI_EMOTION_MODEL_IN_1_SIZE]; float aiOutData[AI_EMOTION_MODEL_OUT_1_SIZE]; ai_u8 activations[AI_EMOTION_MODEL_DATA_ACTIVATIONS_SIZE]; const char* emotions[AI_EMOTION_MODEL_OUT_1_SIZE] = { "non-stress", "stress" }; ai_buffer * ai_input; ai_buffer * ai_output; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void PeriphCommonClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_IPCC_Init(void); static void MX_CRC2_Init(void); static void MX_UART4_Init(void); static void MX_ADC2_Init(void); int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb); /* 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 */ char buf[50]; // buffer for serial output string int buf_len = 0; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ if(IS_ENGINEERING_BOOT_MODE()) { /* Configure the system clock */ SystemClock_Config(); } if(IS_ENGINEERING_BOOT_MODE()) { /* Configure the peripherals common clocks */ PeriphCommonClock_Config(); } else { /* IPCC initialisation */ MX_IPCC_Init(); /* OpenAmp initialisation ---------------------------------*/ MX_OPENAMP_Init(RPMSG_REMOTE, NULL); } /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_CRC2_Init(); MX_UART4_Init(); MX_ADC2_Init(); /* USER CODE BEGIN 2 */ AI_Init(); // start timer/counter // HAL_TIM_Base_Start(&htim16); // test print output buf_len = sprintf(buf, "\r\n\r\nSTM32 X-Cube-AI test\r\n"); HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ // uint32_t write_index = 0; while (1) { for (int i = 0; i < AI_EMOTION_MODEL_IN_1_SIZE+1; ++i) { HAL_ADC_Start(&hadc2); HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY); aiInData[i] = HAL_ADC_GetValue(&hadc2); HAL_Delay(1); if (i == AI_EMOTION_MODEL_IN_1_SIZE) { buf_len = sprintf(buf, "Running inference\r\n"); HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); AI_Run(aiInData, aiOutData); /* Output results */ for (uint32_t i = 0; i < AI_EMOTION_MODEL_OUT_1_SIZE; i++) { buf_len = sprintf(buf, "%8.6f ", aiOutData[i]); HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); } uint32_t class = argmax(aiOutData, AI_EMOTION_MODEL_OUT_1_SIZE); buf_len = sprintf(buf, ": %d - %s\r\n", (int) class, emotions[class]); HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); } } // Wait before doing it again HAL_Delay(500); /* 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_MEDIUMHIGH); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_CSI|RCC_OSCILLATORTYPE_HSI |RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS_DIG; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1; RCC_OscInitStruct.CSIState = RCC_CSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL2.PLLSource = RCC_PLL12SOURCE_HSE; RCC_OscInitStruct.PLL2.PLLM = 3; RCC_OscInitStruct.PLL2.PLLN = 66; RCC_OscInitStruct.PLL2.PLLP = 2; RCC_OscInitStruct.PLL2.PLLQ = 1; RCC_OscInitStruct.PLL2.PLLR = 1; RCC_OscInitStruct.PLL2.PLLFRACV = 0x1400; RCC_OscInitStruct.PLL2.PLLMODE = RCC_PLL_FRACTIONAL; RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL3.PLLSource = RCC_PLL3SOURCE_HSE; RCC_OscInitStruct.PLL3.PLLM = 2; RCC_OscInitStruct.PLL3.PLLN = 34; RCC_OscInitStruct.PLL3.PLLP = 2; RCC_OscInitStruct.PLL3.PLLQ = 17; RCC_OscInitStruct.PLL3.PLLR = 37; RCC_OscInitStruct.PLL3.PLLRGE = RCC_PLL3IFRANGE_1; RCC_OscInitStruct.PLL3.PLLFRACV = 6660; RCC_OscInitStruct.PLL3.PLLMODE = RCC_PLL_FRACTIONAL; RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL4.PLLSource = RCC_PLL4SOURCE_HSE; RCC_OscInitStruct.PLL4.PLLM = 4; RCC_OscInitStruct.PLL4.PLLN = 99; RCC_OscInitStruct.PLL4.PLLP = 6; RCC_OscInitStruct.PLL4.PLLQ = 8; RCC_OscInitStruct.PLL4.PLLR = 8; RCC_OscInitStruct.PLL4.PLLRGE = RCC_PLL4IFRANGE_0; RCC_OscInitStruct.PLL4.PLLFRACV = 0; RCC_OscInitStruct.PLL4.PLLMODE = RCC_PLL_INTEGER; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** RCC Clock Config */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_ACLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 |RCC_CLOCKTYPE_PCLK3|RCC_CLOCKTYPE_PCLK4 |RCC_CLOCKTYPE_PCLK5; RCC_ClkInitStruct.AXISSInit.AXI_Clock = RCC_AXISSOURCE_PLL2; RCC_ClkInitStruct.AXISSInit.AXI_Div = RCC_AXI_DIV1; RCC_ClkInitStruct.MCUInit.MCU_Clock = RCC_MCUSSOURCE_PLL3; RCC_ClkInitStruct.MCUInit.MCU_Div = RCC_MCU_DIV1; RCC_ClkInitStruct.APB4_Div = RCC_APB4_DIV2; RCC_ClkInitStruct.APB5_Div = RCC_APB5_DIV4; RCC_ClkInitStruct.APB1_Div = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2_Div = RCC_APB2_DIV2; RCC_ClkInitStruct.APB3_Div = RCC_APB3_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK) { Error_Handler(); } /** Set the HSE division factor for RTC clock */ __HAL_RCC_RTC_HSEDIV(24); } /** * @brief Peripherals Common Clock Configuration * @retval None */ void PeriphCommonClock_Config(void) { RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the common periph clock */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_CKPER; PeriphClkInit.CkperClockSelection = RCC_CKPERCLKSOURCE_HSE; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /** * @brief ADC2 Initialization Function * @param None * @retval None */ static void MX_ADC2_Init(void) { /* USER CODE BEGIN ADC2_Init 0 */ /* USER CODE END ADC2_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC2_Init 1 */ /* USER CODE END ADC2_Init 1 */ /** Common config */ hadc2.Instance = ADC2; hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV256; hadc2.Init.Resolution = ADC_RESOLUTION_16B; hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc2.Init.LowPowerAutoWait = DISABLE; hadc2.Init.ContinuousConvMode = DISABLE; hadc2.Init.NbrOfConversion = 1; hadc2.Init.DiscontinuousConvMode = DISABLE; hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; hadc2.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_6; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC2_Init 2 */ __HAL_RCC_VREF_CLK_ENABLE(); // Enable the VREF clock HAL_SYSCFG_VREFBUF_HighImpedanceConfig(SYSCFG_VREFBUF_HIGH_IMPEDANCE_DISABLE); // Disable the high impedance mode which is the default one read page 1694 of refman HAL_SYSCFG_VREFBUF_VoltageScalingConfig(SYSCFG_VREFBUF_VOLTAGE_SCALE1); // To set the volage to 2.5v HAL_SYSCFG_EnableVREFBUF(); // To enable VREFBUF if(HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) != HAL_OK) { /* Calibration Error */ Error_Handler(); } /* USER CODE END ADC2_Init 2 */ } /** * @brief CRC2 Initialization Function * @param None * @retval None */ static void MX_CRC2_Init(void) { /* USER CODE BEGIN CRC2_Init 0 */ /* USER CODE END CRC2_Init 0 */ /* USER CODE BEGIN CRC2_Init 1 */ /* USER CODE END CRC2_Init 1 */ hcrc2.Instance = CRC2; hcrc2.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; hcrc2.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; hcrc2.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; hcrc2.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; hcrc2.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; if (HAL_CRC_Init(&hcrc2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN CRC2_Init 2 */ /* USER CODE END CRC2_Init 2 */ } /** * @brief IPCC Initialization Function * @param None * @retval None */ static void MX_IPCC_Init(void) { /* USER CODE BEGIN IPCC_Init 0 */ /* USER CODE END IPCC_Init 0 */ /* USER CODE BEGIN IPCC_Init 1 */ /* USER CODE END IPCC_Init 1 */ hipcc.Instance = IPCC; if (HAL_IPCC_Init(&hipcc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN IPCC_Init 2 */ /* USER CODE END IPCC_Init 2 */ } /** * @brief UART4 Initialization Function * @param None * @retval None */ static void MX_UART4_Init(void) { /* USER CODE BEGIN UART4_Init 0 */ /* USER CODE END UART4_Init 0 */ /* USER CODE BEGIN UART4_Init 1 */ /* USER CODE END UART4_Init 1 */ huart4.Instance = UART4; huart4.Init.BaudRate = 115200; huart4.Init.WordLength = UART_WORDLENGTH_8B; huart4.Init.StopBits = UART_STOPBITS_1; huart4.Init.Parity = UART_PARITY_NONE; huart4.Init.Mode = UART_MODE_TX_RX; huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart4.Init.OverSampling = UART_OVERSAMPLING_16; huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1; huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart4) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_DisableFifoMode(&huart4) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN UART4_Init 2 */ /* USER CODE END UART4_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMAMUX_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); /*Configure GPIO pins : USB_PWR_CC2_Pin USB_PWR_CC1_Pin */ GPIO_InitStruct.Pin = USB_PWR_CC2_Pin|USB_PWR_CC1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ static void AI_Init(void) { ai_error err; // char buf[50]; // buffer for serial output string // int buf_len = 0; /* 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_emotion_model_create_and_init(&emotion_model, act_addr, NULL); if (err.type != AI_ERROR_NONE) { // buf_len = sprintf(buf, "ai_emotion_model_create error - type=%d code=%d\r\n", err.type, err.code); // HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); printf("ai_emotion_model_create error - type=%d code=%d\r\n", err.type, err.code); Error_Handler(); } ai_input = ai_emotion_model_inputs_get(emotion_model, NULL); ai_output = ai_emotion_model_outputs_get(emotion_model, NULL); } static void AI_Run(float *pIn, float *pOut) { ai_i32 batch; ai_error err; // char buf[50]; // buffer for serial output string // int buf_len = 0; /* 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_emotion_model_run(emotion_model, ai_input, ai_output); if (batch != 1) { err = ai_emotion_model_get_error(emotion_model); // buf_len = sprintf(buf, "AI ai_emotion_model_run error - type=%d code=%d\r\n", err.type, err.code); // HAL_UART_Transmit(&huart4, (uint8_t *)buf, buf_len, 100); printf("AI ai_emotion_model_run error - type=%d code=%d\r\n", err.type, err.code); Error_Handler(); } } static uint32_t argmax(const float * values, uint32_t len) { float max_value = values[0]; uint32_t max_index = 0; for (uint32_t i = 1; i < len; i++) { if (values[i] > max_value) { max_value = values[i]; max_index = i; } } return max_index; } void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) { // HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { // HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); } /* 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 */