/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 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 "generic_macros.h" #include "lcd.h" #include "DNI.h" #include "PCA9685.h" #include "24AA02E48.h" #include "CS43L22.h" #include "SST25VF016B.h" #include "LIS302DL.h" #include "MP45DT02.h" #include "LSM9DS1.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define WAIT_UNTIL_CB_PRESSED while (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) && HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8)) #define WAIT_UNTIL_CB_RELEASED while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) || !HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8)) #define UB (GPIOA->IDR & GPIO_PIN_0) #define SWT1 !(GPIOC->IDR & GPIO_PIN_11) #define SWT2 !(GPIOA->IDR & GPIO_PIN_15) #define SWT3 !(GPIOC->IDR & GPIO_PIN_9) #define SWT4 !(GPIOC->IDR & GPIO_PIN_6) #define SWT5 !(GPIOC->IDR & GPIO_PIN_8) #define WAIT_UNTIL_ALL_BUTTONS_RELEASED do {} while ( UB || SWT1 || SWT2 || SWT3 || SWT4 || SWT5 ) #define LEN(x) ( sizeof(x) / sizeof((x)[0]) ) /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc1; I2C_HandleTypeDef hi2c1; I2S_HandleTypeDef hi2s2; SPI_HandleTypeDef hspi1; TIM_HandleTypeDef htim2; extern size_t display_current_frame; /* USER CODE BEGIN PV */ const int ((*executors[])(void)) = { DNI_show_celsius, PCA9685_run_test, EEPROM_24AA02E48_run_test, CS43L22_run_test, SST25VF016B_run_test, LIS302DL_run_test, MP45DT02_run_test, LSM9DS1_test_accel, LSM9DS1_test_magnet }; const void ((*cleanup_functions[])(void)) = { NULL, PCA9685_cleanup, NULL, CS43L22_cleanup, NULL, NULL, NULL, LSM9DS1_cleanup_accel, NULL }; size_t current_executor_id = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); static void MX_I2C1_Init(void); static void MX_SPI1_Init(void); static void MX_TIM2_Init(void); static void MX_I2S2_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void button_init_and_test(void) { // letting the buttons be tested display_write_data_seq("Fill any bar:"); DISPLAY_SET_CURSOR(1, 5); display_write_data_seq("[-] [-----]"); size_t pressed_elements; uint32_t sw_button_locations[5][2] = { {(uint32_t) GPIOC, (uint32_t) GPIO_PIN_11}, {(uint32_t) GPIOA, (uint32_t) GPIO_PIN_15}, {(uint32_t) GPIOC, (uint32_t) GPIO_PIN_9}, {(uint32_t) GPIOC, (uint32_t) GPIO_PIN_6}, {(uint32_t) GPIOC, (uint32_t) GPIO_PIN_8} }; do { HAL_Delay(100); pressed_elements = 0; DISPLAY_SET_CURSOR(1, 6); if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)) { pressed_elements |= 0x20; display_write_data_byte('*'); } else { display_write_data_byte('-'); } DISPLAY_SET_CURSOR(1, 10); for (size_t i = 0; i < 5; i++) { pressed_elements >>= 1; size_t input = !HAL_GPIO_ReadPin((GPIO_TypeDef *) sw_button_locations[i][0], sw_button_locations[i][1]); if (input) { pressed_elements |= 0x20; display_write_data_byte('*'); } else { display_write_data_byte('-'); } } } while (!(((pressed_elements & 0x1) == 0x1) || ((pressed_elements & 0x3E) == 0x3E))); // visual reaction to bar fill DISPLAY_SET_CURSOR(0, 0); display_write_data_seq("Release buttons"); GPIOD->ODR = 0x1000; HAL_Delay(300); GPIOD->ODR = 0x2000; HAL_Delay(300); GPIOD->ODR = 0x4000; HAL_Delay(300); GPIOD->ODR = 0x8000; HAL_Delay(300); // waiting for all buttons to be released WAIT_UNTIL_ALL_BUTTONS_RELEASED; GPIOD->ODR = 0x0000; HAL_Delay(200); } /* 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 */ /* 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_ADC1_Init(); MX_I2C1_Init(); MX_SPI1_Init(); MX_TIM2_Init(); MX_I2S2_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start(&htim2); TIM2->CNT = 0; HAL_TIM_Base_Stop(&htim2); GPIOD->ODR = 0x1000; display_init(); GPIOD->ODR = 0xF000; button_init_and_test(); // perform all tests size_t successful_tests = 0; size_t failed_tests = 0; for (display_current_frame = 1; display_current_frame < LEN(executors)+1; display_current_frame++) { DISPLAY_CLEAR; display_write_data_seq("Testing..."); DISPLAY_SET_CURSOR(1, 2); display_write_data_seq("P:"); display_write_data_byte('0' + (successful_tests / 10) % 10); display_write_data_byte('0' + (successful_tests) % 10); DISPLAY_SET_CURSOR(1, 10); display_write_data_seq("F:"); display_write_data_byte('0' + (failed_tests / 10) % 10); display_write_data_byte('0' + (failed_tests) % 10); display_to_framebuffer(); // test if (executors[display_current_frame-1]()) failed_tests++; else successful_tests++; // cleanup (if required) if (cleanup_functions[display_current_frame-1]) cleanup_functions[display_current_frame-1](); display_to_direct(); } // render final result to first framebuffer display_to_framebuffer(); display_current_frame = 0; DISPLAY_CLEAR; display_write_data_seq("All tests done!"); DISPLAY_SET_CURSOR(1, 2); display_write_data_seq("P:"); display_write_data_byte('0' + (successful_tests / 10) % 10); display_write_data_byte('0' + (successful_tests) % 10); DISPLAY_SET_CURSOR(1, 10); display_write_data_seq("F:"); display_write_data_byte('0' + (failed_tests / 10) % 10); display_write_data_byte('0' + (failed_tests) % 10); display_to_direct(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { WAIT_UNTIL_ALL_BUTTONS_RELEASED; display_load(display_current_frame); while (1) { // go to next report if ( (GPIOA->IDR & GPIO_PIN_0) || !(GPIOC->IDR & GPIO_PIN_11) || !(GPIOC->IDR & GPIO_PIN_8) ) { display_current_frame += 1; display_current_frame %= LEN(executors)+1; break; } // go to previous report else if ( !(GPIOC->IDR & GPIO_PIN_9) || !(GPIOC->IDR & GPIO_PIN_6) ) { display_current_frame -= 1; if (display_current_frame == 0xFFFFFFFFU) display_current_frame = LEN(executors); break; } // return to summary frame else if ( !(GPIOA->IDR & GPIO_PIN_15) ) { display_current_frame = 0; break; } } /* 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}; /** Macro to configure the PLL multiplication factor */ __HAL_RCC_PLL_PLLM_CONFIG(16); /** Macro to configure the PLL clock source */ __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI); /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; 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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /** * @brief ADC1 Initialization Function * @param None * @retval None */ static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_9; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /** * @brief I2C1 Initialization Function * @param None * @retval None */ static void MX_I2C1_Init(void) { /* USER CODE BEGIN I2C1_Init 0 */ /* USER CODE END I2C1_Init 0 */ /* USER CODE BEGIN I2C1_Init 1 */ /* USER CODE END I2C1_Init 1 */ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2C1_Init 2 */ /* USER CODE END I2C1_Init 2 */ } /** * @brief I2S2 Initialization Function * @param None * @retval None */ static void MX_I2S2_Init(void) { /* USER CODE BEGIN I2S2_Init 0 */ /* USER CODE END I2S2_Init 0 */ /* USER CODE BEGIN I2S2_Init 1 */ /* USER CODE END I2S2_Init 1 */ hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_RX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_48K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2S2_Init 2 */ /* USER CODE END I2S2_Init 2 */ } /** * @brief SPI1 Initialization Function * @param None * @retval None */ static void MX_SPI1_Init(void) { /* USER CODE BEGIN SPI1_Init 0 */ /* USER CODE END SPI1_Init 0 */ /* USER CODE BEGIN SPI1_Init 1 */ /* USER CODE END SPI1_Init 1 */ /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN SPI1_Init 2 */ /* USER CODE END SPI1_Init 2 */ } /** * @brief TIM2 Initialization Function * @param None * @retval None */ static void MX_TIM2_Init(void) { /* USER CODE BEGIN TIM2_Init 0 */ /* USER CODE END TIM2_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xffffffff; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ } /** * @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_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12 |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_7, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); /*Configure GPIO pins : PA0 PA15 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : PE7 PE10 PE11 PE12 PE13 PE14 PE15 */ GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12 |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /*Configure GPIO pins : PD11 PD12 PD13 PD14 PD15 PD4 PD7 */ GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PC6 PC8 PC9 PC11 */ GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pin : PB7 */ GPIO_InitStruct.Pin = GPIO_PIN_7; 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); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* 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 */