## [STM32 TIMER PWM & Input Capture] - Fan Speed Control and Monitoring **GitHub:** https://github.com/CarterWu-M/STM32_FAN_CTRL **Board:** NUCLEO-F072RB **IDE:** STM32CubeIDE **FAN:** ADDA AB0505LB-GBB ![imgpsh_fullsize_anim](https://hackmd.io/_uploads/r1q7pPm1Jx.png) --- ### Introduction --- This article introduces how to use Timer PWM to adjust the fan's speed and how to use Timer input capture to measure the fan's speed. During the operation, a scope is used to observe the PWM duty cycle and the fan's speed feedback signal. --- ### Fan Wiring --- ![fan](https://hackmd.io/_uploads/SJtvCw7k1g.png) **Black:** Ground **Red:** 5V **White:** Outputs a pulse signal based on fan rotation speed **Blue:** Takes a PWM signal to adjust fan speed --- ### STM32CubeMX settings --- ![image](https://hackmd.io/_uploads/Skb_Uum1ye.png) **PC13:** Configure GPIO EXTI for a button **PA8:** TIM PWM to control the fan speed **PA0:** TIM Input Capture to monitor the fan speed ![image](https://hackmd.io/_uploads/SyS0KdXJ1e.png) Configure the APB1 Timer clocks to 48MHz --- ### Timer - PWM --- ![image](https://hackmd.io/_uploads/rybZt_Xyye.png) Configure TIM1 CH1 for PWM generation Configure TIM1 Presaler to 48-1 Configure TIM1 Auto-Reload Register(ARR) to 100-1 --- #### Formula --- TIM CLOCK = $\dfrac{APB\ \ TIM\ \ CLOCK}{PRESCALAR}$ \ FREQUENCY = $\dfrac{TIM\ \ CLOCK}{ARR}$ \ DUTY % = $\dfrac{CCRx}{ARR}$ X 100% **Example:** TIM CLOCK = $\dfrac{APB\ \ TIM\ \ CLOCK = 48MHz}{PRESCALAR = 48}$ = 1MHz \ FREQUENCY = $\dfrac{TIM\ \ CLOCK\ \ = 1MHz}{ARR = 100}$ = 100KHz \ DUTY % = $\dfrac{CCRx=10}{ARR = 100}$ X 100% = 10% ```c= /* USER CODE BEGIN 0 */ static uint8_t duty = 0; void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_PIN_13 == GPIO_Pin) { if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_Pin)) { //When the user button is pressed, increase the duty cycle by 10%. //If the duty cycle exceeds 100, reset the duty cycle to 0. if (100 < (duty += 10)) { duty = 0; } TIM1->CCR1 = duty; } } } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 2 */ TIM1->CCR1 = 100;//Set the duty cycle to 100% HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);//Start the PWM generation /* USER CODE END 2 */ while (1) { } } ``` --- #### Scope --- ![NewFile4](https://hackmd.io/_uploads/B10TX3Qykl.png) ![image](https://hackmd.io/_uploads/HysmDaNyJe.png) * PWM Duty = 0% * Freq = 0 Hz ![NewFile1](https://hackmd.io/_uploads/By32m271yx.png) ![image](https://hackmd.io/_uploads/Sk38vT41kg.png) * PWM Duty = 20% * Freq = 10k Hz ![NewFile2](https://hackmd.io/_uploads/ryUa7h7kyg.png) ![image](https://hackmd.io/_uploads/Sk2Fv64yyl.png) * PWM Duty = 70% * Freq = 10k Hz ![NewFile3](https://hackmd.io/_uploads/B15T7nQ1Jg.png) ![image](https://hackmd.io/_uploads/r1_sva4Jkx.png) * PWM Duty = 100% * Freq = 0 Hz --- #### Youtube Vedio --- {%youtube rUN6wgfiBok %} --- ### Timer - Input Capture --- ![image](https://hackmd.io/_uploads/SJIsd3Qkyg.png) Configure TIM2 CH1 as Input Capture direct mode Configure TIM2 Prescaler to 48-1 Configure TIM2 Auto-Reload Register(ARR) to 0xffffffff-1 ![image](https://hackmd.io/_uploads/r1TvlaXkkg.png) Remember to configure the GPIO as pull-up because the fan speed signal is open-drain. If you don't configure this, the signal will appear as shown in the picture below. ![NewFile1](https://hackmd.io/_uploads/rJFfGa7Jyx.png) You can see that the maximum voltage is 80mV, which is very samll ```c= /* USER CODE BEGIN 0 */ #define REF_FREQ (48000000 / 48) static bool isFirstCap = true; static uint32_t ic1 = 0; static uint32_t ic2 = 0; static float icFreq = 0; void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (HAL_TIM_ACTIVE_CHANNEL_1 == htim->Channel) { if (true == isFirstCap) { ic1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); isFirstCap = false; } else { uint32_t diff; ic2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); if (ic2 >= ic1) { diff = ic2 - ic1; } else { diff = (0xffffffff - ic1) + ic2; } ic1 = ic2; icFreq = REF_FREQ / diff; } } } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 2 */ HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); /* USER CODE END 2 */ while (1) { } } ``` --- #### Scope --- ![NewFile1](https://hackmd.io/_uploads/HyrxH1E11e.png) When the PWM output duty cycle is 0%, the measured fan speed frequency is: - Scope: 0 Hz (no rising or falling signal) - Input Capture: 0 Hz (no rising or falling signal) ![NewFile1](https://hackmd.io/_uploads/H1_dTnEy1x.png) ![image](https://hackmd.io/_uploads/Sk66ph4ykg.png) When the PWM output duty cycle is 10%, the measured fan speed frequency is: - scope: 12 Hz - Input Capture: 11 Hz ![NewFile2](https://hackmd.io/_uploads/BkMC0h4J1e.png) ![image](https://hackmd.io/_uploads/ByoZ0n4yJx.png) When the PWM output duty cycle is 50%, the measured fan speed frequency is: - scope: 85.5 Hz - Input Capture: 87 Hz ![NewFile4](https://hackmd.io/_uploads/SJ3WHkV1kx.png) ![image](https://hackmd.io/_uploads/BkNFCnNkyg.png) When the PWM output duty cycle is 100%, the measured fan speed frequency is: - scope: 147 Hz - Input Capture: 145 Hz --- #### Youtube Vedio --- {%youtube mxPrWlIAvi4 %} --- ### References --- - https://controllerstech.com/pwm-in-stm32/ - https://controllerstech.com/input-capture-in-stm32/