A PC fan controller that doesn't (completely) suck.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

main.c 12 KiB

il y a 3 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. /* Private includes ----------------------------------------------------------*/
  23. /* USER CODE BEGIN Includes */
  24. #include "string.h"
  25. #include "stdio.h"
  26. /* USER CODE END Includes */
  27. /* Private typedef -----------------------------------------------------------*/
  28. /* USER CODE BEGIN PTD */
  29. /* USER CODE END PTD */
  30. /* Private define ------------------------------------------------------------*/
  31. /* USER CODE BEGIN PD */
  32. #define TIMEBASE 1000
  33. #define PWM_MINIMUM 20
  34. /* USER CODE END PD */
  35. /* Private macro -------------------------------------------------------------*/
  36. /* USER CODE BEGIN PM */
  37. /* USER CODE END PM */
  38. /* Private variables ---------------------------------------------------------*/
  39. TIM_HandleTypeDef htim2;
  40. UART_HandleTypeDef huart2;
  41. /* USER CODE BEGIN PV */
  42. const uint16_t GPU_STAGES[] = {900, 1400, 1800, 2200};
  43. const uint16_t CPU_STAGES[] = {850, 900, 1000, 1200};
  44. uint32_t freq_count_gpu;
  45. uint32_t freq_count_cpu;
  46. uint32_t freq_count_case1;
  47. uint32_t freq_count_case2;
  48. uint32_t last_gpu;
  49. uint32_t last_cpu;
  50. uint32_t last_case1;
  51. uint32_t last_case2;
  52. uint16_t rpm_gpu;
  53. uint16_t rpm_cpu;
  54. uint16_t rpm_case1;
  55. uint16_t rpm_case2;
  56. uint32_t pwm_fan1;
  57. uint32_t pwm_fan2;
  58. uint8_t gpu_stage;
  59. uint8_t cpu_stage;
  60. uint8_t current_stage;
  61. char msg[256];
  62. /* USER CODE END PV */
  63. /* Private function prototypes -----------------------------------------------*/
  64. void SystemClock_Config(void);
  65. static void MX_GPIO_Init(void);
  66. static void MX_TIM2_Init(void);
  67. static void MX_USART2_UART_Init(void);
  68. /* USER CODE BEGIN PFP */
  69. /* USER CODE END PFP */
  70. /* Private user code ---------------------------------------------------------*/
  71. /* USER CODE BEGIN 0 */
  72. int max(uint8_t a, uint8_t b) {
  73. if (a > b) {
  74. return a;
  75. }
  76. return b;
  77. }
  78. /* USER CODE END 0 */
  79. /**
  80. * @brief The application entry point.
  81. * @retval int
  82. */
  83. int main(void)
  84. {
  85. /* USER CODE BEGIN 1 */
  86. /* USER CODE END 1 */
  87. /* MCU Configuration--------------------------------------------------------*/
  88. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  89. HAL_Init();
  90. /* USER CODE BEGIN Init */
  91. /* USER CODE END Init */
  92. /* Configure the system clock */
  93. SystemClock_Config();
  94. /* USER CODE BEGIN SysInit */
  95. /* USER CODE END SysInit */
  96. /* Initialize all configured peripherals */
  97. MX_GPIO_Init();
  98. MX_TIM2_Init();
  99. MX_USART2_UART_Init();
  100. /* USER CODE BEGIN 2 */
  101. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  102. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  103. /* USER CODE END 2 */
  104. /* Infinite loop */
  105. /* USER CODE BEGIN WHILE */
  106. while (1)
  107. {
  108. if (HAL_GPIO_ReadPin(Switch_GPIO_Port, Switch_Pin) == GPIO_PIN_SET) {
  109. // do stuff
  110. }
  111. if (rpm_gpu < GPU_STAGES[0]) {
  112. gpu_stage = 1;
  113. } else if (rpm_gpu < GPU_STAGES[1]) {
  114. gpu_stage = 2;
  115. } else if (rpm_gpu < GPU_STAGES[2]) {
  116. gpu_stage = 3;
  117. } else if (rpm_gpu < GPU_STAGES[3]) {
  118. gpu_stage = 4;
  119. } else {
  120. gpu_stage = 5;
  121. }
  122. if (rpm_cpu < CPU_STAGES[0]) {
  123. cpu_stage = 1;
  124. } else if (rpm_cpu < CPU_STAGES[1]) {
  125. cpu_stage = 2;
  126. } else if (rpm_cpu < CPU_STAGES[2]) {
  127. cpu_stage = 3;
  128. } else if (rpm_cpu < CPU_STAGES[3]) {
  129. cpu_stage = 4;
  130. } else {
  131. cpu_stage = 5;
  132. }
  133. current_stage = max(gpu_stage, cpu_stage);
  134. if (current_stage == 1) {
  135. pwm_fan1 = PWM_MINIMUM;
  136. } else if (current_stage == 2) {
  137. pwm_fan1 = 35;
  138. } else if (current_stage == 3) {
  139. pwm_fan1 = 50;
  140. } else if (current_stage == 4) {
  141. pwm_fan1 = 80;
  142. } else {
  143. pwm_fan1 = 100;
  144. }
  145. // For now
  146. pwm_fan2 = pwm_fan1;
  147. // Write the value after converting from duty cycle to raw value.
  148. TIM2->CCR1 = htim2.Init.Period * pwm_fan1 / 100;
  149. TIM2->CCR2 = htim2.Init.Period * pwm_fan2 / 100;
  150. // If the fans don't spin, the rpm won't be updated as no
  151. // interrupts are called. This resets those values every two seconds.
  152. if (HAL_GetTick() - last_gpu >= TIMEBASE * 2) {
  153. rpm_gpu = 0;
  154. freq_count_gpu = 0;
  155. }
  156. if (HAL_GetTick() - last_cpu >= TIMEBASE * 2) {
  157. rpm_cpu = 0;
  158. freq_count_cpu = 0;
  159. }
  160. if (HAL_GetTick() - last_case1 >= TIMEBASE * 2) {
  161. rpm_case1 = 0;
  162. freq_count_case1 = 0;
  163. }
  164. if (HAL_GetTick() - last_case2 >= TIMEBASE * 2) {
  165. rpm_case2 = 0;
  166. freq_count_case2 = 0;
  167. }
  168. sprintf(msg, "GPU: %u RPM\nCPU: %u RPM\nCase 1: %u RPM\nCase2: %u RPM\n", rpm_gpu, rpm_cpu, rpm_case1, rpm_case2);
  169. HAL_UART_Transmit(&huart2, (uint8_t *) msg, strlen(msg), 100);
  170. sprintf(msg, "PWM Case 1: %lu %%\nPWM Case 2: %lu %%\n\n", pwm_fan1, pwm_fan2);
  171. HAL_UART_Transmit(&huart2, (uint8_t *) msg, strlen(msg), 100);
  172. HAL_Delay(1000);
  173. /* USER CODE END WHILE */
  174. /* USER CODE BEGIN 3 */
  175. }
  176. /* USER CODE END 3 */
  177. }
  178. /**
  179. * @brief System Clock Configuration
  180. * @retval None
  181. */
  182. void SystemClock_Config(void)
  183. {
  184. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  185. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  186. /** Configure the main internal regulator output voltage
  187. */
  188. HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  189. /** Initializes the RCC Oscillators according to the specified parameters
  190. * in the RCC_OscInitTypeDef structure.
  191. */
  192. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  193. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  194. RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  195. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  196. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  197. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  198. {
  199. Error_Handler();
  200. }
  201. /** Initializes the CPU, AHB and APB buses clocks
  202. */
  203. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  204. |RCC_CLOCKTYPE_PCLK1;
  205. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  206. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  207. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  208. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  209. {
  210. Error_Handler();
  211. }
  212. }
  213. /**
  214. * @brief TIM2 Initialization Function
  215. * @param None
  216. * @retval None
  217. */
  218. static void MX_TIM2_Init(void)
  219. {
  220. /* USER CODE BEGIN TIM2_Init 0 */
  221. /* USER CODE END TIM2_Init 0 */
  222. TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  223. TIM_MasterConfigTypeDef sMasterConfig = {0};
  224. TIM_OC_InitTypeDef sConfigOC = {0};
  225. /* USER CODE BEGIN TIM2_Init 1 */
  226. /* USER CODE END TIM2_Init 1 */
  227. htim2.Instance = TIM2;
  228. htim2.Init.Prescaler = 0;
  229. htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  230. htim2.Init.Period = 640;
  231. htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  232. htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  233. if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  234. {
  235. Error_Handler();
  236. }
  237. sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  238. if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  239. {
  240. Error_Handler();
  241. }
  242. if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  243. {
  244. Error_Handler();
  245. }
  246. sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  247. sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  248. if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  249. {
  250. Error_Handler();
  251. }
  252. sConfigOC.OCMode = TIM_OCMODE_PWM1;
  253. sConfigOC.Pulse = 0;
  254. sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  255. sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  256. if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  257. {
  258. Error_Handler();
  259. }
  260. if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  261. {
  262. Error_Handler();
  263. }
  264. /* USER CODE BEGIN TIM2_Init 2 */
  265. /* USER CODE END TIM2_Init 2 */
  266. HAL_TIM_MspPostInit(&htim2);
  267. }
  268. /**
  269. * @brief USART2 Initialization Function
  270. * @param None
  271. * @retval None
  272. */
  273. static void MX_USART2_UART_Init(void)
  274. {
  275. /* USER CODE BEGIN USART2_Init 0 */
  276. /* USER CODE END USART2_Init 0 */
  277. /* USER CODE BEGIN USART2_Init 1 */
  278. /* USER CODE END USART2_Init 1 */
  279. huart2.Instance = USART2;
  280. huart2.Init.BaudRate = 115200;
  281. huart2.Init.WordLength = UART_WORDLENGTH_8B;
  282. huart2.Init.StopBits = UART_STOPBITS_1;
  283. huart2.Init.Parity = UART_PARITY_NONE;
  284. huart2.Init.Mode = UART_MODE_TX;
  285. huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  286. huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  287. huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  288. huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  289. huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  290. if (HAL_UART_Init(&huart2) != HAL_OK)
  291. {
  292. Error_Handler();
  293. }
  294. /* USER CODE BEGIN USART2_Init 2 */
  295. /* USER CODE END USART2_Init 2 */
  296. }
  297. /**
  298. * @brief GPIO Initialization Function
  299. * @param None
  300. * @retval None
  301. */
  302. static void MX_GPIO_Init(void)
  303. {
  304. GPIO_InitTypeDef GPIO_InitStruct = {0};
  305. /* GPIO Ports Clock Enable */
  306. __HAL_RCC_GPIOA_CLK_ENABLE();
  307. __HAL_RCC_GPIOB_CLK_ENABLE();
  308. /*Configure GPIO pins : Case1_Pin Case2_Pin CPU_Pin GPU_Pin */
  309. GPIO_InitStruct.Pin = Case1_Pin|Case2_Pin|CPU_Pin|GPU_Pin;
  310. GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  311. GPIO_InitStruct.Pull = GPIO_NOPULL;
  312. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  313. /*Configure GPIO pin : Switch_Pin */
  314. GPIO_InitStruct.Pin = Switch_Pin;
  315. GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  316. GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  317. HAL_GPIO_Init(Switch_GPIO_Port, &GPIO_InitStruct);
  318. /* EXTI interrupt init*/
  319. HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
  320. HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
  321. }
  322. /* USER CODE BEGIN 4 */
  323. void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin) {
  324. if (GPIO_Pin == GPU_Pin) {
  325. if ((HAL_GetTick() - last_gpu) <= TIMEBASE) {
  326. freq_count_gpu++;
  327. } else {
  328. rpm_gpu = freq_count_gpu * 60 / 2;
  329. last_gpu = HAL_GetTick();
  330. freq_count_gpu = 0;
  331. }
  332. }
  333. if (GPIO_Pin == CPU_Pin) {
  334. if ((HAL_GetTick() - last_cpu) <= TIMEBASE) {
  335. freq_count_cpu++;
  336. } else {
  337. rpm_cpu = freq_count_cpu * 60 / 2;
  338. last_cpu = HAL_GetTick();
  339. freq_count_cpu = 0;
  340. }
  341. }
  342. if (GPIO_Pin == Case1_Pin) {
  343. if ((HAL_GetTick() - last_case1) <= TIMEBASE) {
  344. freq_count_case1++;
  345. } else {
  346. rpm_case1 = freq_count_case1 * 60 / 2;
  347. last_case1 = HAL_GetTick();
  348. freq_count_case1 = 0;
  349. }
  350. }
  351. if (GPIO_Pin == Case2_Pin) {
  352. if ((HAL_GetTick() - last_case2) <= TIMEBASE) {
  353. freq_count_case2++;
  354. } else {
  355. rpm_case2 = freq_count_case2 * 60 / 2;
  356. last_case2 = HAL_GetTick();
  357. freq_count_case2 = 0;
  358. }
  359. }
  360. }
  361. /* USER CODE END 4 */
  362. /**
  363. * @brief This function is executed in case of error occurrence.
  364. * @retval None
  365. */
  366. void Error_Handler(void)
  367. {
  368. /* USER CODE BEGIN Error_Handler_Debug */
  369. /* User can add his own implementation to report the HAL error return state */
  370. __disable_irq();
  371. while (1)
  372. {
  373. }
  374. /* USER CODE END Error_Handler_Debug */
  375. }
  376. #ifdef USE_FULL_ASSERT
  377. /**
  378. * @brief Reports the name of the source file and the source line number
  379. * where the assert_param error has occurred.
  380. * @param file: pointer to the source file name
  381. * @param line: assert_param error line source number
  382. * @retval None
  383. */
  384. void assert_failed(uint8_t *file, uint32_t line)
  385. {
  386. /* USER CODE BEGIN 6 */
  387. /* User can add his own implementation to report the file name and line number,
  388. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  389. /* USER CODE END 6 */
  390. }
  391. #endif /* USE_FULL_ASSERT */
  392. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/