Beetle - The Smallest Arduino PWM周波数について 改訂版

BeetleはLeonardo互換ということなので，使えるかも...
1/4に一度投稿したのですが，あまりにひどい出来だったので，調べ直しました。

# 対象

| Pin Out | CPU |
|:-------:|:---:|
| D10 | 30pin = PB6|
| D9 | 29pin = PB5|

- D11 = 12pin = PB7 は，以下では除外する。
    - D11のPWMはデフォルト976.5625Hz，Duty精度は7ビット。
    - Timer0を使用するので，PWMの周波数を変更すると，`millis()`等にも影響を与えるため，この記事では周波数変更を考慮しない。

# duty:8ビット精度，周波数 = 490.2Hz で良い場合

```C++
  analogWrite(9,duty_9);   // uint8_t duty_9
  analogWrite(10,duty_10); // uint8_t duty_10
```

- 補足説明
    - 9ピン，10ピン 独立して設定可能。

# duty:8ビット精度，周波数を選択する

```C++
  // TCCR1B = (TCCR1B & 0b11111000) | 0x01; // 31372.55Hz           div:1
  // TCCR1B = (TCCR1B & 0b11111000) | 0x02; // 3921.16Hz            div:8
  // TCCR1B = (TCCR1B & 0b11111000) | 0x03; // 490.20Hz <- default  div:64
  // TCCR1B = (TCCR1B & 0b11111000) | 0x04; // 122.55Hz             div:256
  // TCCR1B = (TCCR1B & 0b11111000) | 0x05; // 30.64Hz              div:1024

  analogWrite(9,duty_9);   // uint8_t duty_9
  analogWrite(10,duty_10); // uint8_t duty_10
```

- コメントのうち，必要な行を有効にする。

- 補足説明
    - TCCR1Bレジスターの下位3ビットで，分周比が決められる。
    - このPWM周波数は，以下の式で決められる。
        - 16MHz / （分周比） / (255*2)
        - デフォルト値の例：16MHz/64/(255*2)≒490.2
    - 8ビットのカウンターで0->255->0->255を繰り返すため，(255*2)が周期となる。
    - phase-correct PWM mode（8ビット位相基準PWM動作）と呼ばれている。

- 参考URL
    - https://playground.arduino.cc/Main/TimerPWMCheatsheet/
    - http://usicolog.nomaki.jp/engineering/avr/avrPWM.html
    - http://garretlab.web.fc2.com/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_analog.c/analogWrite.html

# duty:16ビット未満，周波数を（ある程度任意に）設定する

10ピン限定。9ピンに出す方法がわからない。できなさそう？

以下の例は，4kHz 80％に設定している。

```C++
  TCCR1A = 0b00100001;
  TCCR1B = 0b00010000 | 0b001 ; // div = 1

  OCR1A=(uint16_t)(8000000 / 1 / 4000); // f=4kHz
  OCR1B=(uint16_t)(8000000 / 1 / 4000 * 80 / 100); // duty=80%
```

設定した`OCR1A`が，Duty精度となる。上記例では，8000000/4000=2000段階となる。（11ビット弱）

- 補足説明
    - 2行目の`0b001`が分周比設定で，基本周波数を決めている。以下のようになっている。

```C++
	// |CS12|CS11|CS10|=001    1分周 122Hz(=16MHz/(65535*2))
	// |CS12|CS11|CS10|=010    8分周 15.26Hz
	// |CS12|CS11|CS10|=011   64分周 1.91Hz
	// |CS12|CS11|CS10|=100  256分周 0.477Hz
	// |CS12|CS11|CS10|=101 1024分周 0.119Hz
```

- 122Hz未満の周波数にする場合，適当に分周を設定する。
    - たとえば100Hzなら，8分周にする。
    - `TCCR1B`の式の後半を書き換え，さらに`OCR1A`および`OCR1B`の`/ 1`の部分を変更する。

- 動作解説
    - 位相/周波数基準PWM動作というモードを使っている。
    - このPWMの**基本周波数**は，以下の式で決められる。
        - 16MHz / 分周比 / (65535*2) * 65535 = 8MHz / 分周比 / 65535
        - 上記の例：16MHz/1/(65535*2)≒122
    - 16ビットのカウンターで0->65535->0->65535を繰り返すため，(65535*2)が周期となる。
    - 16ビットレジスタ`OCR1A`にて，カウンターの上限値が決められる。
        - 65535の場合，基本周期そのものとなる。
        - 65535 >`OCR1A`の場合，カウンターが`OCR1A`に到達した時に，65535を待たずにリセットされる。すなわち，`OCR1A`により，基本周期が短くなる。
    - カウンターが16ビットレジスタ`OCR1B`にて設定した値よりも小さい時に，Hが出力される。
    - `OCR1A`は，基本周波数との比になる。具体的には，以下の式となる。

```
  OCR1A = 65535 * 基本周波数 / 設定周波数
        = 65535 * 16MHz / 分周比 / (65535*2) / 設定周波数
        = 8MHz / 分周比 / 設定周波数
```

- `OCR1B`も同様。

以下の図は，参考URLの図から加筆させてもらいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/970d67e5-8684-0660-ec91-7f0f5e7add2a.png)


-参考URL
    - http://blog.kts.jp.net/arduino-pwm-change-freq/
    - http://garretlab.web.fc2.com/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_analog.c/analogWrite.html