!ここは?
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