From 1d63b3a478b9f3cdd22b877d8c98e3011fd07081 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 24 Jun 2021 15:50:25 +0200 Subject: [PATCH] Initial commit --- fancontroller.ioc | 157 ++++++++++++ fancontroller.pdf | Bin 0 -> 37012 bytes fancontroller.sch | 631 ++++++++++++++++++++++++++++++++++++++++++++++ main.c | 467 ++++++++++++++++++++++++++++++++++ main.h | 87 +++++++ 5 files changed, 1342 insertions(+) create mode 100644 fancontroller.ioc create mode 100644 fancontroller.pdf create mode 100644 fancontroller.sch create mode 100644 main.c create mode 100644 main.h diff --git a/fancontroller.ioc b/fancontroller.ioc new file mode 100644 index 0000000..a20eec6 --- /dev/null +++ b/fancontroller.ioc @@ -0,0 +1,157 @@ +#MicroXplorer Configuration settings - do not modify +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=false +Mcu.Family=STM32G0 +Mcu.IP0=NVIC +Mcu.IP1=RCC +Mcu.IP2=SYS +Mcu.IP3=TIM2 +Mcu.IP4=USART2 +Mcu.IPNb=5 +Mcu.Name=STM32G031F(4-6-8)Px +Mcu.Package=TSSOP20 +Mcu.Pin0=PA0 +Mcu.Pin1=PA1 +Mcu.Pin10=PB6 +Mcu.Pin11=VP_SYS_VS_Systick +Mcu.Pin12=VP_TIM2_VS_ClockSourceINT +Mcu.Pin2=PA2 +Mcu.Pin3=PA3 +Mcu.Pin4=PA4 +Mcu.Pin5=PA5 +Mcu.Pin6=PA6 +Mcu.Pin7=PA7 +Mcu.Pin8=PA13 +Mcu.Pin9=PA14-BOOT0 +Mcu.PinsNb=13 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32G031F8Px +MxCube.Version=6.1.1 +MxDb.Version=DB.6.0.10 +NVIC.EXTI4_15_IRQn=true\:0\:0\:false\:false\:true\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.SVC_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true +PA0.Locked=true +PA0.Signal=S_TIM2_CH1 +PA1.Signal=S_TIM2_CH2 +PA13.Mode=Serial_Wire +PA13.Signal=SYS_SWDIO +PA14-BOOT0.Mode=Serial_Wire +PA14-BOOT0.Signal=SYS_SWCLK +PA2.Mode=Asynchronous +PA2.Signal=USART2_TX +PA3.Mode=Asynchronous +PA3.Signal=USART2_RX +PA4.GPIOParameters=GPIO_Label +PA4.GPIO_Label=Case1 +PA4.Locked=true +PA4.Signal=GPXTI4 +PA5.GPIOParameters=GPIO_Label +PA5.GPIO_Label=Case2 +PA5.Locked=true +PA5.Signal=GPXTI5 +PA6.GPIOParameters=GPIO_Label +PA6.GPIO_Label=CPU +PA6.Locked=true +PA6.Signal=GPXTI6 +PA7.GPIOParameters=GPIO_Label +PA7.GPIO_Label=GPU +PA7.Locked=true +PA7.Signal=GPXTI7 +PB6.GPIOParameters=GPIO_PuPd,GPIO_Label +PB6.GPIO_Label=Switch +PB6.GPIO_PuPd=GPIO_PULLDOWN +PB6.Locked=true +PB6.Signal=GPIO_Input +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=false +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32G031F8Px +ProjectManager.FirmwarePackage=STM32Cube FW_G0 V1.4.1 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=1 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=fans.ioc +ProjectManager.ProjectName=fans +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=STM32CubeIDE +ProjectManager.ToolChainLocation= +ProjectManager.UnderRoot=true +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_TIM2_Init-TIM2-false-HAL-true,4-MX_USART2_UART_Init-USART2-false-HAL-true +RCC.ADCFreq_Value=16000000 +RCC.AHBFreq_Value=16000000 +RCC.APBFreq_Value=16000000 +RCC.APBTimFreq_Value=16000000 +RCC.CortexFreq_Value=16000000 +RCC.EXTERNAL_CLOCK_VALUE=12288000 +RCC.FCLKCortexFreq_Value=16000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=16000000 +RCC.HSE_VALUE=8000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=16000000 +RCC.I2S1Freq_Value=16000000 +RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APBFreq_Value,APBTimFreq_Value,CortexFreq_Value,EXTERNAL_CLOCK_VALUE,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2C1Freq_Value,I2S1Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PWRFreq_Value,SYSCLKFreq_VALUE,TIM1Freq_Value,USART1Freq_Value,VCOInputFreq_Value,VCOOutputFreq_Value +RCC.LPTIM1Freq_Value=16000000 +RCC.LPTIM2Freq_Value=16000000 +RCC.LPUART1Freq_Value=16000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO1PinFreq_Value=16000000 +RCC.PLLPoutputFreq_Value=64000000 +RCC.PLLQoutputFreq_Value=64000000 +RCC.PLLRCLKFreq_Value=64000000 +RCC.PWRFreq_Value=16000000 +RCC.SYSCLKFreq_VALUE=16000000 +RCC.TIM1Freq_Value=16000000 +RCC.USART1Freq_Value=16000000 +RCC.VCOInputFreq_Value=16000000 +RCC.VCOOutputFreq_Value=128000000 +SH.GPXTI4.0=GPIO_EXTI4 +SH.GPXTI4.ConfNb=1 +SH.GPXTI5.0=GPIO_EXTI5 +SH.GPXTI5.ConfNb=1 +SH.GPXTI6.0=GPIO_EXTI6 +SH.GPXTI6.ConfNb=1 +SH.GPXTI7.0=GPIO_EXTI7 +SH.GPXTI7.ConfNb=1 +SH.S_TIM2_CH1.0=TIM2_CH1,PWM Generation1 CH1 +SH.S_TIM2_CH1.ConfNb=1 +SH.S_TIM2_CH2.0=TIM2_CH2,PWM Generation2 CH2 +SH.S_TIM2_CH2.ConfNb=1 +TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE +TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM2.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM2.ClockDivision=TIM_CLOCKDIVISION_DIV1 +TIM2.IPParameters=Channel-PWM Generation1 CH1,Period,AutoReloadPreload,ClockDivision,Channel-PWM Generation2 CH2 +TIM2.Period=640 +USART2.IPParameters=VirtualMode-Asynchronous,Mode +USART2.Mode=MODE_TX +USART2.VirtualMode-Asynchronous=VM_ASYNC +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM2_VS_ClockSourceINT.Mode=Internal +VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT +board=custom +isbadioc=false diff --git a/fancontroller.pdf b/fancontroller.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1a0c8f540fa0fab40989ba810397865285416b12 GIT binary patch literal 37012 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
© 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 "string.h" +#include "stdio.h" + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ +#define TIMEBASE 1000 +#define PWM_MINIMUM 20 +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +TIM_HandleTypeDef htim2; + +UART_HandleTypeDef huart2; + +/* USER CODE BEGIN PV */ +const uint16_t GPU_STAGES[] = {900, 1400, 1800, 2200}; +const uint16_t CPU_STAGES[] = {850, 900, 1000, 1200}; + +uint32_t freq_count_gpu; +uint32_t freq_count_cpu; +uint32_t freq_count_case1; +uint32_t freq_count_case2; +uint32_t last_gpu; +uint32_t last_cpu; +uint32_t last_case1; +uint32_t last_case2; +uint16_t rpm_gpu; +uint16_t rpm_cpu; +uint16_t rpm_case1; +uint16_t rpm_case2; +uint32_t pwm_fan1; +uint32_t pwm_fan2; +uint8_t gpu_stage; +uint8_t cpu_stage; +uint8_t current_stage; +char msg[256]; + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +static void MX_GPIO_Init(void); +static void MX_TIM2_Init(void); +static void MX_USART2_UART_Init(void); +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +int max(uint8_t a, uint8_t b) { + if (a > b) { + return a; + } + return b; +} + + +/* 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_TIM2_Init(); + MX_USART2_UART_Init(); + /* USER CODE BEGIN 2 */ + HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); + HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); + + /* USER CODE END 2 */ + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + + if (HAL_GPIO_ReadPin(Switch_GPIO_Port, Switch_Pin) == GPIO_PIN_SET) { + // do stuff + } + + if (rpm_gpu < GPU_STAGES[0]) { + gpu_stage = 1; + } else if (rpm_gpu < GPU_STAGES[1]) { + gpu_stage = 2; + } else if (rpm_gpu < GPU_STAGES[2]) { + gpu_stage = 3; + } else if (rpm_gpu < GPU_STAGES[3]) { + gpu_stage = 4; + } else { + gpu_stage = 5; + } + + if (rpm_cpu < CPU_STAGES[0]) { + cpu_stage = 1; + } else if (rpm_cpu < CPU_STAGES[1]) { + cpu_stage = 2; + } else if (rpm_cpu < CPU_STAGES[2]) { + cpu_stage = 3; + } else if (rpm_cpu < CPU_STAGES[3]) { + cpu_stage = 4; + } else { + cpu_stage = 5; + } + + + current_stage = max(gpu_stage, cpu_stage); + if (current_stage == 1) { + pwm_fan1 = PWM_MINIMUM; + } else if (current_stage == 2) { + pwm_fan1 = 35; + } else if (current_stage == 3) { + pwm_fan1 = 50; + } else if (current_stage == 4) { + pwm_fan1 = 80; + } else { + pwm_fan1 = 100; + } + + // For now + pwm_fan2 = pwm_fan1; + + + // Write the value after converting from duty cycle to raw value. + TIM2->CCR1 = htim2.Init.Period * pwm_fan1 / 100; + TIM2->CCR2 = htim2.Init.Period * pwm_fan2 / 100; + + + // If the fans don't spin, the rpm won't be updated as no + // interrupts are called. This resets those values every two seconds. + if (HAL_GetTick() - last_gpu >= TIMEBASE * 2) { + rpm_gpu = 0; + freq_count_gpu = 0; + } + if (HAL_GetTick() - last_cpu >= TIMEBASE * 2) { + rpm_cpu = 0; + freq_count_cpu = 0; + } + if (HAL_GetTick() - last_case1 >= TIMEBASE * 2) { + rpm_case1 = 0; + freq_count_case1 = 0; + } + if (HAL_GetTick() - last_case2 >= TIMEBASE * 2) { + rpm_case2 = 0; + freq_count_case2 = 0; + } + + sprintf(msg, "GPU: %u RPM\nCPU: %u RPM\nCase 1: %u RPM\nCase2: %u RPM\n", rpm_gpu, rpm_cpu, rpm_case1, rpm_case2); + HAL_UART_Transmit(&huart2, (uint8_t *) msg, strlen(msg), 100); + sprintf(msg, "PWM Case 1: %lu %%\nPWM Case 2: %lu %%\n\n", pwm_fan1, pwm_fan2); + HAL_UART_Transmit(&huart2, (uint8_t *) msg, strlen(msg), 100); + + HAL_Delay(1000); + /* 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 the main internal regulator output voltage + */ + HAL_PWREx_ControlVoltageScaling(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.HSIDiv = RCC_HSI_DIV1; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + 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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) + { + Error_Handler(); + } +} + +/** + * @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}; + TIM_OC_InitTypeDef sConfigOC = {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 = 640; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + 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(); + } + if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM2_Init 2 */ + + /* USER CODE END TIM2_Init 2 */ + HAL_TIM_MspPostInit(&htim2); + +} + +/** + * @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; + 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(); + } + /* 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(); + + /*Configure GPIO pins : Case1_Pin Case2_Pin CPU_Pin GPU_Pin */ + GPIO_InitStruct.Pin = Case1_Pin|Case2_Pin|CPU_Pin|GPU_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /*Configure GPIO pin : Switch_Pin */ + GPIO_InitStruct.Pin = Switch_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(Switch_GPIO_Port, &GPIO_InitStruct); + + /* EXTI interrupt init*/ + HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); + +} + +/* USER CODE BEGIN 4 */ +void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin) { + if (GPIO_Pin == GPU_Pin) { + if ((HAL_GetTick() - last_gpu) <= TIMEBASE) { + freq_count_gpu++; + } else { + rpm_gpu = freq_count_gpu * 60 / 2; + last_gpu = HAL_GetTick(); + freq_count_gpu = 0; + } + } + + if (GPIO_Pin == CPU_Pin) { + if ((HAL_GetTick() - last_cpu) <= TIMEBASE) { + freq_count_cpu++; + } else { + rpm_cpu = freq_count_cpu * 60 / 2; + last_cpu = HAL_GetTick(); + freq_count_cpu = 0; + } + } + + + if (GPIO_Pin == Case1_Pin) { + if ((HAL_GetTick() - last_case1) <= TIMEBASE) { + freq_count_case1++; + } else { + rpm_case1 = freq_count_case1 * 60 / 2; + last_case1 = HAL_GetTick(); + freq_count_case1 = 0; + } + } + if (GPIO_Pin == Case2_Pin) { + if ((HAL_GetTick() - last_case2) <= TIMEBASE) { + freq_count_case2++; + } else { + rpm_case2 = freq_count_case2 * 60 / 2; + last_case2 = HAL_GetTick(); + freq_count_case2 = 0; + } + } +} + +/* 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 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/main.h b/main.h new file mode 100644 index 0000000..f075157 --- /dev/null +++ b/main.h @@ -0,0 +1,87 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @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 */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32g0xx_hal.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define Case1_Pin GPIO_PIN_4 +#define Case1_GPIO_Port GPIOA +#define Case1_EXTI_IRQn EXTI4_15_IRQn +#define Case2_Pin GPIO_PIN_5 +#define Case2_GPIO_Port GPIOA +#define Case2_EXTI_IRQn EXTI4_15_IRQn +#define CPU_Pin GPIO_PIN_6 +#define CPU_GPIO_Port GPIOA +#define CPU_EXTI_IRQn EXTI4_15_IRQn +#define GPU_Pin GPIO_PIN_7 +#define GPU_GPIO_Port GPIOA +#define GPU_EXTI_IRQn EXTI4_15_IRQn +#define Switch_Pin GPIO_PIN_6 +#define Switch_GPIO_Port GPIOB +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/