## [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

---
### 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
---

**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
---

**PC13:** Configure GPIO EXTI for a button
**PA8:** TIM PWM to control the fan speed
**PA0:** TIM Input Capture to monitor the fan speed

Configure the APB1 Timer clocks to 48MHz
---
### Timer - PWM
---

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
---


* PWM Duty = 0%
* Freq = 0 Hz


* PWM Duty = 20%
* Freq = 10k Hz


* PWM Duty = 70%
* Freq = 10k Hz


* PWM Duty = 100%
* Freq = 0 Hz
---
#### Youtube Vedio
---
{%youtube rUN6wgfiBok %}
---
### Timer - Input Capture
---

Configure TIM2 CH1 as Input Capture direct mode
Configure TIM2 Prescaler to 48-1
Configure TIM2 Auto-Reload Register(ARR) to 0xffffffff-1

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.

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
---

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)


When the PWM output duty cycle is 10%, the measured fan speed frequency is:
- scope: 12 Hz
- Input Capture: 11 Hz


When the PWM output duty cycle is 50%, the measured fan speed frequency is:
- scope: 85.5 Hz
- Input Capture: 87 Hz


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/