# `PWM` Module API Manual

## Overview

The K230 contains two PWM hardware modules internally, each with three output channels. The output frequency of each module is adjustable, but the three channels share the same clock, while the duty cycle can be adjusted independently. Therefore, channels 0, 1, and 2 have the same output frequency, and channels 3, 4, and 5 also have the same output frequency. For the I/O configuration of channel output, please refer to the IOMUX module.

## API Introduction

The PWM class is located in the `machine` module.

### Example Code

```python
import time
from machine import PWM, FPIOA

CONSTRUCT_WITH_FPIOA = False

PWM_CHANNEL = 0

PWM_PIN = 42
TEST_FREQ = 1000  # Hz


# Initialize PWM with 50% duty
try:
    if CONSTRUCT_WITH_FPIOA:
        # 使用FPIOA 配置引脚复用为PWM, 构造时传入 channel
        fpioa = FPIOA()
        fpioa.set_function(PWM_PIN, fpioa.PWM0 + PWM_CHANNEL)
        pwm = PWM(PWM_CHANNEL, freq=TEST_FREQ, duty=50)
    else:
        # 直接传入引脚
        pwm = PWM(PWM_PIN, freq=TEST_FREQ, duty=50)
except Exception:
    print("FPIOA setup skipped or failed")

print("[INIT] freq: {}Hz, duty: {}%".format(pwm.freq(), pwm.duty()))
time.sleep(0.5)

# duty() getter and setter
print("[TEST] duty()")
pwm.duty(25)
print("Set duty to 25%, got:", pwm.duty(), "→ duty_u16:", pwm.duty_u16(), "→ duty_ns:", pwm.duty_ns())
time.sleep(0.2)

# duty_u16()
print("[TEST] duty_u16()")
pwm.duty_u16(32768)  # 50%
print("Set duty_u16 to 32768, got:", pwm.duty_u16(), "→ duty():", pwm.duty(), "→ duty_ns():", pwm.duty_ns())
time.sleep(0.2)

# duty_ns()
print("[TEST] duty_ns()")
period_ns = 1000000000 // pwm.freq()
duty_ns_val = (period_ns * 75) // 100  # 75%
pwm.duty_ns(duty_ns_val)
print("Set duty_ns to", duty_ns_val, "ns (≈75%), got:", pwm.duty_ns(), "→ duty():", pwm.duty(), "→ duty_u16():", pwm.duty_u16())
time.sleep(0.2)

# Change frequency and re-check duty values
print("[TEST] Change frequency to 500Hz")
pwm.freq(500)
print("New freq:", pwm.freq())
print("Duty after freq change → duty():", pwm.duty(), "→ duty_u16():", pwm.duty_u16(), "→ duty_ns():", pwm.duty_ns())
time.sleep(0.2)

# Clean up
pwm.deinit()
print("[DONE] PWM test completed")
```

<a id="pwm-constructor"> </a>

### Constructor

```python
pwm = PWM(pin, freq = -1, duty = -1, duty_u16 = -1, duty_ns = -1)
```

**Parameters**

- `pin`: Pin object, or pin number. The driver automatically sets the pin to PWM alternate function. For the correspondence between specific pins and PWM, please refer to [Pin Multiplexing](#pwm-pinmux)
- `freq`: PWM channel output frequency
- `duty`: PWM channel output duty cycle, representing the percentage of high level in the entire period, with a value range of [0, 100]
- `duty_ns`: The time of high level output from the PWM channel, in `ns`
- `duty_u16`: The time of high level output from the PWM channel, with a value range of [0, 65535]

> Only one of `duty`, `duty_ns`, and `duty_u16` can be set.

### `init` Method

```python
PWM.init(freq = -1, duty = -1, duty_u16 = -1, duty_ns = -1)
```

**Parameters**

Refer to [Constructor](#pwm-constructor)

### `deinit` Method

```python
PWM.deinit()
```

Release the resources of the PWM channel.

**Parameters**

None

**Return Value**

None

### `freq` Method

```python
PWM.freq([freq])
```

Get or set the output frequency of the PWM channel.

**Parameters**

- `freq`: PWM channel output frequency, optional parameter. If no parameter is passed in, the current frequency is returned.

**Return Value**

Returns the output frequency of the current PWM channel or empty.

### `duty` Method

```python
PWM.duty([duty])
```

Get or set the output duty cycle of the PWM channel.

**Parameters**

- `duty`: PWM channel output duty cycle, optional parameter. If no parameter is passed in, the current duty cycle is returned.

**Return Value**

Returns the output duty cycle of the current PWM channel or empty.

**Return Value**

None

### `duty_u16` Method

```python
PWM.duty_u16([duty_u16])
```

Get or set the output duty cycle of the PWM channel.

**Parameters**

- `duty_u16`: PWM channel output duty cycle, optional parameter. If no parameter is passed in, the current duty cycle is returned.

**Return Value**

Returns the output duty cycle of the current PWM channel or empty.

**Return Value**

None

### `duty_ns` Method

```python
PWM.duty_ns([duty_ns])
```

Get or set the output duty cycle of the PWM channel.

**Parameters**

- `duty_ns`: PWM channel output duty cycle, optional parameter. If no parameter is passed in, the current duty cycle is returned.

**Return Value**

Returns the output duty cycle of the current PWM channel or empty.

**Return Value**

None

<a id="pwm-pinmux"></a>

## PWM Pin Multiplexing

| PWM | Alternative Pins |
|-----|---------------------|
| PWM0 | GPIO42, GPIO54, GPIO60 |
| PWM1 | GPIO43, GPIO55, GPIO61 |
| PWM2 | GPIO7, GPIO46, GPIO56 |
| PWM3 | GPIO8, GPIO47, GPIO57 |
| PWM4 | GPIO9, GPIO52, GPIO58 |
| PWM5 | GPIO25, GPIO53, GPIO59 |
