!ここは?
RakuChordではAVRを使って和音を鳴らしている、が、正直どうやって動いているかよくわかっていない
ということでまとめる

!初期設定

>> code cpp
  pinMode(9,OUTPUT);
<<
RakuChordではDigital9番を音声出力につないでいる。

これはatmega328でいうと 15ピン。このピンは PB5 OC1A PCINT1の機能がある

OC1Aが今回使いたいPWMの機能
13番ピンはTimer1を利用したPWMができる

Timer0,Timer2は8ビットだがTimer1は16bit

>> code cpp
  TCCR1A = _BV(COM1A1)| _BV(WGM10);
  TCCR1B = _BV(CS10);
<<

OC1AについてコンペアマッチでLOW
8bit位相基準PWM (topが0xff)
分周は無し

>> code cpp
  TIMSK1 = 1<<TOIE1;
<<

タイマー1を開始


ここまでで初期化はできた。

PWMの指定は次のように行う

>> code cpp
  OCR1A = 80; // for debug
<<
OCR1Aを設定することでPWMのduty比を変える

>> code cpp
  TCNT1 = timerLoadValue;
<<
現在のtimer1のカウンタの値を変更。


!タイマー割り込み

>> code cpp
ISR(TIMER1_OVF_vect)
<<
timer1のオーバーフローの時に呼び出される

>> code cpp
  dn[0] = dn[0] + d[0];
  dn[1] = dn[1] + d[1];
  dn[2] = dn[2] + d[2];
  dn[3] = dn[3] + d[3];
  dn[4] = dn[4] + d[4];
<<
5つある波形を進める

>> code cpp
  level = ((dn[0]&(1<<14))?vol[0]:0) +
          ((dn[1]&(1<<14))?vol[1]:0) +
          ((dn[2]&(1<<14))?vol[2]:0) +
          ((dn[3]&(1<<14))?vol[3]:0) +
          ((dn[4]&(1<<14))?vol[4]:0);
  OCR1A = level;
}
<<
現在の位相から出力レベルを取り出して5つ分を合計して、PWMの比率として突っ込む


!つまりどういうことか
Timer1をクロック分周なしで回す

これは16Mhzで動くRakuChordの場合はそのまま16Mhzでカウントアップが進むということ
今回は8bit PWMモードで動かしているので、タイマー1は0~0xffまでカウントアップすることとなる

OCR1Aの値より、大きいか、小さいかでPWMのduty比が決まる。

例えばOCR1Aが127の場合はちょうど半分半分のPWMとなる。

OCR1Aを更新するタイミングはtimer1のオーバーフローの時なので、

>>
<タイマーの天井がどっちか気になったので推測してみる。結果は書いてある通りなのでこの記載は見なくてよい>

(推測1)16bitタイマーの場合は2^16=65526までカウントアップしたときとなる?
(推測2)今回は8bit PWMモードで動かしているので256までカウントアップした時となる

(推測1の場合)
16Mhzで16bitタイマーだとしたら更新のタイミングは (1/16M) * (2^16) = 0.004096s = 244.140625Hz これでは和音は作れない 可聴域に入ってる

(推測2の場合)
16Mhzで8bitまでだとしたら更新タイミングは (1/16M) * (2^16) = 0.000016s = 62500Hz おそらく推測2だな
<<

今回は8bit PWMモードで動かしているので256までカウントアップした時となる。
CPU周波数は16MHzなので

>> math
\begin{equation}
(1/16\mathrm{M}) * (2^8) = 0.000016\mathrm{s} = 62500\mathrm{Hz}
\end{equation}
<<


この周期で、PWMのduty比を切り替える。 音質としては62.5KHzといったところ

d[0]を220にするとdnは62.5kHzで220加算されuintの限界である2^16をループするためには297回必要となる これは周波数にすると1/(297/62.5K) = 210.43Hzとなる

d[0]の値と周波数を並べるとこんな感じ

|220|1/(2^16/220/62.5K) =|210.437.. Hz
|440|1/(2^16/440/62.5K) =|422.297.. Hz
|880|1/(2^16/880/62.5K) =|844.594.. Hz

図らずともd[0]がほぼそのまま周波数となっている

62.5Kが出てきた経緯は
>> math
\begin{equation}
(1/16\mathrm{M}) * (2^8) = 0.000016\mathrm{s} = 62500\mathrm{Hz}
\end{equation}
<<
だからこれを数式に入れると

>> math
\begin{equation}
\frac{1}{\frac{2^{16}}{x} * \frac{1}{16\mathrm{M}} * 2^8}
\end{equation}
<<

となって

>> math
\begin{equation}
\frac{16\mathrm{M}}{2^{24}}x = 0.953674.. * x
\end{equation}
<<


となるから
f = d[0] * 0.95374...
ということか。d[0]で指定した定数の0.95374...倍の周波数の音が鳴るということのようだ。


今回の方式は8bit分のタイマーしか使っていないため、timer1ではないほかのタイマーでも利用できるはず。

5643382
wiki
1473953114