---
# System prepended metadata

title: PWM

---

# PWM

## PWM Output
![image](https://hackmd.io/_uploads/rkwZBVDTT.png =x160)

### Project Settings
1. In **System Core → RCC**, set **High Speed Clock (HSE)** as **Crystal/Ceramic Resonator**
    ![image](https://hackmd.io/_uploads/B1h4H4DpT.png =x250)
   
2. On the Nucleo board, check the frequency written on this metal chip, in this case it is **8.000mHz**
    ![image](https://hackmd.io/_uploads/SyODHVw66.png =x200)

    Then, in **Clock Configuration**, set **Input Frequency** as the value on the chip
    ![image](https://hackmd.io/_uploads/H1cYr4vp6.png =x200)

3. Set **PLL Source Mux** as **HSE**, **System Clock Mux** as **PLLCLK** and **HCLK** value as you wanted, in this case, we use 80 MHz
    ![image](https://hackmd.io/_uploads/BJFsBNP6T.png)

4. Choose a Timer and a channel and its corresponding pin. In this case, we choose **Timer 1** and **Channel 1** which uses the **PA8** pin
    ![image](https://hackmd.io/_uploads/ry96rNDTT.png =x200)

    In **Timers → TIM1** settings, set **Clock Source** as **Internal Clock**
    ![image](https://hackmd.io/_uploads/BJDk8NPp6.png =x200)

    In **TIM1** settings, set **Channel1** as **PWM Generation CH1**
    ![image](https://hackmd.io/_uploads/S1g-LEw6a.png =x200)

5. Look up **Block Diagram** in the [datasheet](https://www.st.com/resource/en/datasheet/stm32f401re.pdf) of your board and check the timer belongs to which peripheral
    In this case, **Timer 1** is connectec to **APB2**
    ![image](https://hackmd.io/_uploads/H1jGIEPpa.png =x300)

6. Back to **Clock Settings**, check the timer frequency of the peripheral
    In this case, the timer frequency of **APB2** is 80 MHz
    ![image](https://hackmd.io/_uploads/rkVEI4wap.png =x250)

7. Now we need to focus on three important parameters of PWM settings such as **Timer clock**, **PWM frequency**, and **Duty cycle**
    - **Timer clock** $=\frac{Original\ timer\ clocks}{Prescaler+1}$
    - **PWM frequency** $=\frac{Timer\ clock}{Counter\ period+1}$
    - **Duty cycle** $=\frac{CCRX}{Counter\ period}\times 100\%$

    In our case, we set:
    - **Timer clock** $=1\ MHz=\frac{80\ MHz}{80}\Rightarrow Prescaler=(80-1)$
    - **PWM frequency** $=10 kHz=\frac{1\ MHz}{100}\Rightarrow Counter\ period=(100-1)$
    
    Set the parameters in **TIM1 → Parameters setting**
    ![image](https://hackmd.io/_uploads/HyVI84Dpa.png =x200)

    We will control the **Duty cycle** later in the programming part 

8. (Optional) Add a new **DMA Request** (Direct Memory Access) and Choose the 
    ![image](https://hackmd.io/_uploads/Hk6D8Nv66.png =x200)

    And set the **direction** to **Memory to Peripheral**
    ![image](https://hackmd.io/_uploads/SkrF8NvTT.png =x200)


9. Save and generate the project

---
### Programming
In this section, we also use **TIM1 Channel 1** for example
1. To set the **Duty Cycle**, use:
    ```cpp
    TIM1->CCR1 = 50 // timer 1, channel 1, duty cycle 50%
    ```
2. To start the PWM mode, use:
    ```cpp
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    ```
    (Optional) Use DMA (Direct Memory Access) to start the PWM mode, use the following code instead
    ```cpp
    uint16_t pwmData[3];
    pwmData[0] = 0; pwmData[1] = 50; pwmData[2] = 100;
    HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)pwmData, 3);
    ```
    
## PWM Input
(Fill this up later)

## Reference
- [It takes two minutes to generate PWM signal in STM32](https://www.youtube.com/watch?v=9bpMReVEVzM&ab_channel=SteppeSchool)
- [STM32 TIMERS #1. PWM Output || DMA](https://www.youtube.com/watch?v=OwlfFp8fPN0&list=PLfIJKC1ud8gjLZBzjE3kKBMDEH_lUc428)
- [STM32 TIMERS #2. PWM Input](https://www.youtube.com/watch?v=P6211ic2N_s&list=PLfIJKC1ud8gjLZBzjE3kKBMDEH_lUc428&index=4&pp=iAQB)