- PCM/WAVE: dsPIC33FJ64GP802の16bit DACでWAVE再生 2015/01
PCM/WAVE: dsPIC33FJ64GP802の16bit DACでWAVE再生 2015/01
はじまり
dsPIC33FJ64GP802というマイコンがあって、
480円(税込)だった。
実はこのマイコン、オーディオ専用の16bitDACを積んでいるんです。
- DAC部:
- 256倍オーバーサンプリングDAC搭載。
- 差動電圧出力。 1.15Vpp (中点電位1.65V)
- fs=100KHz まで可能。
- MCUは40MIPSで動く。
- DMAもある。
- 他にも盛りだくさん。:D
と、なかなか良い感じ。
年末に購入しておいたのでこの機会にChaNさんのFatFsを使ってSDカードから、 WAVE/PCMの音楽データを再生してみました。
参考:
- 後閑さんが本をだしている様です。(未購入)xD
- 「フルート吹きのMIDI工房」さんのページ
● 実験テーマ57
DAC出力は非常に簡単だった
configとクロック周りの設定をしたら、データシートのDAC設定通りに設定すれば、
あっという間にDACから信号が出ちゃいました。
実質、DAC割込みを始動させるだけで動きます。
PWMとかタイマー設定とか無関係です。
PWMで音出す方がよっぽど手間がかかります。:D
ソフト
PIC24FとdsPIC33Fは基本的な部分は結構同じなので、
(イヤ、微妙に違うと言えば違うんだけど。。。オイ)
以前、PIC24FでPWM再生した時のソフトで、PWMの周期割込みをDAC割込みに
変えるだけでOKでした。 楽ちんだった。(^^)/
PIC24F: 8bit PWMの音 / PCM/WAVE再生
SPI:
PIC24FJ64GA002はDMAがないせいか、SPIに8段のFIFOがあって(^^)/だったけど、
dsPIC33FはDMAがあるせいで、SPIに多段FIFO積んでない orz。
なくても大丈夫だったけど。オイ
ハード
ひとまずブレッドボードを使って部品箱にある様な部品だけで音だし実験してみたい
という方針。
オペアンプは1個で作る
http://ww1.microchip.com/downloads/en/DeviceDoc/21685d.pdf
差動合成用のオペアンプは、後閑さんの作品だとMCP6022を2個使いだけど、
(MCP6022はオペアンプ2個入りなので1個でできます)
そんなオペアンプ部品箱にないっ!
ブレッドボードだとスペースもないので、2回路入りで単電源で、3V〜5Vの
「レールtoレール」とか 「フルスイング」と 言われる
部品箱にある以下の品種を使ってみた。
OPアンプ | 価格 | 動作電圧 | SR | リンク |
---|---|---|---|---|
LM358N | @20円 | 3V〜32V | SR=0.5V/u | http://akizukidenshi.com/download/LM358N_NS.pdfs |
LMC662 | @80円 | 5V〜15V | SR= 1.1V/us | http://www.tij.co.jp/jp/lit/ds/jajsbe5/jajsbe5.pdf |
OPA2340 | @? | 2.7V〜5V | SR= 6V/us | http://www.ti.com/lit/ds/symlink/opa340.pdf |
OPA2350 | @? | 2.7V〜5.5V | SR= 22V/us | http://www.ti.com/lit/ds/symlink/opa350.pdf |
オペアンプは最終的に5V駆動にして使える品種を増やした。(^^)/
後述。
サンプリング周波数問題
別に問題というほどではないけど、後閑さんの作品だとサンプリング周波数(fs)は
44.1KHzに固定なのです。
べつに固定でもいいんだけど、何とかfs=48KHzのWAVEファイルも再生したいのだった。
水晶発振子問題
別に問題じゃ。。。オイ
fs=44.1KHzと48KHzのWAVEファイルを再生しようとすると、外部に二つの水晶発振子を付けて切り換える j
様なハードが必要で、ちょっとめんどくさい。:D
そもそも部品箱に「11.2896MHz」や「12.288MHz」とかの水晶発振子はないのだった。xD
ということで、
精度(誤差)が2%のマイコン内蔵発振器でなんとかならないか考えたのが以下のメモ。
内蔵発振は2%の精度だけど、最大誤差が2%なので実際はもっといいはず。
実測してみると大体**0.2%**だった。(^^)/ (安定度は今ひとつだけど)
これ売ってない。 orz
AK8138MV
大げさ過ぎる気もする。:D
内蔵発振器だけで、fs=44.1KHzと48KHzを再生可能にする
そこで表計算ソフトでいろいろ探ってみると多少の周波数誤差はあるものの、
内蔵発振器7.3728MHzを元にfs=44.1KHzと48KHzのWAVEファイルを再生できることが分った (^^)/
オーバークロック
丁度いい周波数がFOSCをオーバークロックしたものと、ちょっとFOSCが小さめの時と
2種類あった。FOSCが小さいとちょっともったいないので
オーバークロック版で最初は試した。
DACへはFOSCクロックを供給します。
FOSC PLLとDAC周波数設定
細かいことは表計算ソフトに任せて :D 結果だけメモしておきます。 もっといい組合わせがあるかもしれませんが現時点では不明です。
オーバークロックしない版
FRC = 7.3728MHz (内蔵クロック)
FRCDIV:
分周比 = 1/1 設定値=0
FRCDIV後出力周波数: 7.3721MHz
PLLPRE:
分周比 = 1/3 設定値=1
PLLPRE後出力周波数: 2.4576MHz
APSTSCLR:
分周比 = 1/8 設定値=4
fs=44.1KHz:
M (PLL multiple) = 37
PLLDIV: 設定値 = 35
PLLPOST:
分周比 = 1/2 設定値=0
PLLPOST後出力周波数: 45.4656MHz (=FOSC)
fsに対する誤差: -0.6757%
FOSC = 45.4656MHz
FCY = 22.7328MHz
MCU処理能力 約23MIPS
fs=48KHz:
M (PLL multiple) = 40
PLLDIV: 設定値 = 38
PLLPOST:
分周比 = 1/2 設定値=0
PLLPOST後出力周波数: 49.1520MHz (=FOSC)
fsに対する誤差: 0%
FOSC = 49.1520MHz
FCY = 24.5760MHz
MCU処理能力 約25MIPS
オーバークロック版
FRC = 7.3728MHz (内蔵クロック)
FRCDIV:
分周比 = 1/1 設定値=0
FRCDIV後出力周波数: 7.3721MHz
PLLPRE:
分周比 = 1/2 設定値=0
PLLPRE後出力周波数: 3.6864MHz
APSTSCLR:
分周比 = 1/16 設定値=3
fs=44.1KHz:
M (PLL multiple) = 49
PLLDIV: 設定値 = 47
PLLPOST:
分周比 = 1/2 設定値=0
PLLPOST後出力周波数: 90.3168MHz (=FOSC)
fsに対する誤差: 0%
FOSC = 90.3168MHz
FCY = 45.1584MHz
MCU処理能力 約45MIPS
fs=48KHz:
M (PLL multiple) = 53
PLLDIV: 設定値 = 51
PLLPOST:
分周比 = 1/2 設定値=0
PLLPOST後出力周波数: 97.6896MHz (=FOSC)
fsに対する誤差: 0.6289%
FOSC = 97.6896MHz
FCY = 48.8448MHz
MCU処理能力 約49MIPS
49MIPS !! xD って オイ
fs依存でFOSCを切り換える
再生するWAVEファイルのfsによって、PLLやDACクロックの設定を
上記の値に切り換えます。
FOSCはマイコンシステムの基本クロックなので、関連する周辺I/OでFOSC依存なものは、
クロックの再計算が必要です。
といっても今のところ、Timer,UARTとSPI,FatFsくらい。
今のところ、usecオーダの「delay()ベタ待ち系」は放置してあります。:D
これで、
通常再生時にfsを自動切り替えできるので、かなりうれしい感じになりました。(^^)/
Config設定値
PICの場合、これをちゃんと書かないとうまく動かないのだ。
下で出てくる8MHz水晶発振子の設定も入っています。
#include "sys.h"
_FBS( BWRP_WRPROTECT_OFF
& BSS_NO_BOOT_CODE
& RBS_NO_BOOT_RAM);
_FSS( SWRP_WRPROTECT_OFF
& SSS_NO_SEC_CODE
& RSS_NO_SEC_RAM);
_FGS( GWRP_OFF & GSS_OFF );
_FWDT( FWDTEN_OFF);
_FPOR( FPWRT_PWR2);
_FICD( ICS_PGD1 & JTAGEN_OFF );
#ifdef IRC_7_3728MHZ
_FOSCSEL( FNOSC_FRCPLL &IESO_ON );
_FOSC( POSCMD_NONE
& OSCIOFNC_OFF
& IOL1WAY_OFF
& FCKSM_CSDCMD);
#elif defined(EXT_OSC_8MHZ)
_FOSCSEL( FNOSC_PRIPLL &IESO_ON );
_FOSC( POSCMD_HS
& OSCIOFNC_ON
& IOL1WAY_OFF
& FCKSM_CSDCMD);
#else
#error
#endif
DAC出力の差動合成とオペアンプの電源電圧
差動合成前のマイコンの出力Lch(左チャンネル)の場合、
DAC1LP = (+)1.15Vpp
DAC1LN = (-)1.15Vpp
( Typ. 1.15Vpp = VDACH - VDACL, Max 2Vpp オイ)
これを外部オペアンプ(以下オペアンプ)を通して差動合成すると、
DAC1L = (+)1.15Vpp - (-)1.15Vpp = 2.3Vpp の信号となる。 (= ±1.15Vp)
オペアンプ電源 3.3Vの場合
Vcc/2=1.65V を中点電圧とするので、オペアンプ出力振幅の最大(max)、最小値(min)は、
Vout = 1.65V ±1.15Vp = 0.5V (min) 〜 2.8V (max)
となる。
- 最悪値
DAC部のバラツキが最大値だった場合、
Vout = 1.65V ±2.0Vp = -0.35V (min) 〜 3.65V (max)
となり、3.3V電源では破綻する。
音が悪い感じに聞こえる。
オペアンプ電源 5Vの場合
Vcc/2=2.5V を中点電圧とするので、オペアンプ出力振幅の最大、最小値は、
Vout = 2.5V ±1.15Vp = 1.35V (min) 〜 3.65V (max)
となる。
- 最悪値
バラツキの最大値だった場合、
Vout = 2.5V ±2.0Vp = 0.5V (min) 〜 4.5V (max)
となり、5V電源なら全く問題ない。
結論
オペアンプの電源を5Vにした方がより良いのと、使えるオペアンプの種類も増えるので
可能なら5Vが良いのだ。
もし音が変な場合は、DAC出力の値が上に書いた様に「ハズれな物に当たった :D 」可能性もあるので、
オペアンプの電源を5Vにしてみるのも一つの手かも。
2つの水晶発振子でfs=44,1KHzと48KHzを切り換える一つの方法
多少の誤差を許容すればDACにクロックを供給する方法は結構たくさんある。
上の方法で内蔵クロックを使った部分を「例えば8MHzの水晶発振子」にすれば同様に多少のfs誤差で
2種類のfsを切り換える事は可能だ。
でもやっぱり、
fsの誤差0ゼロで使いたいといった場合、
- 方法
- プライマリクロック端子(OSC1/OSC2)に12.2880MHzの水晶発振子を付ける。
(諸設定値は変える必要あり) - DAC用のAuxiliary OSCとして(SOSCO/SOSCI)端子に11.2896MHzの水晶発振子を付ける。
fs=48KHzはFOSCを分周した物を使い、fs=44.1KHzはそのまま11.2896MHzを使えば、
誤差ゼロシステムとなる。
- プライマリクロック端子(OSC1/OSC2)に12.2880MHzの水晶発振子を付ける。
- メリット
- システムクロックを固定化できる。
- 水晶発振子を2つ付けるだけなので回路が簡単。
- デメリット
I/Oピンを水晶発振子で4つも使ってしまう。
中点電位の低インピーダンス化
オペアンプの中点電位の絶対値については、そんなに意味はなくて、(なくはないんだけど :D)
上に書いた様にレールtoレールの上限、下限値からある程度の余裕が確保できるポイントに設定できれば良い。
それよりも、中点電位の変動を少なくする方が重要と考える。
従って、中点電位生成にボルテージフォロア等を使った方が良いし、
当然、オペアンプの電源は定電圧化し、微動だにしない様にしておくのが良い。
音質はどう?
そもそもブレッドボードなので、xD
xD
なんだけど、
さらに、内蔵クロックベースだからさらに、
xD
なんだけど、
そういう話を知らないで聴けばけっこういい音だと思います。
十分合格圏だと思います。
オペアンプは、泣く子も黙る :D
バーブラウンのOPA2350を5V駆動、出力のカップリングコンデンサは3.3uFのフィルムコンデンサ
です。
ここに電解コンデンサを使うのは断固拒否した方がいいと思います。xD
LME49721MAというオペアンプも結構良いらしいのでそのうち聴いてみる。
オペアンプなしでひとまず音を出す方法
「部品箱に単電源用のオペアンプなんてないっ!」
って言う場合。 xD
とりあえず、
DAC1LP とDAC1RP端子に2.2uF〜10uFのコンデンサ(電解可 xD)をつなげて、
その先をGNDとあわせてヘッドホンアンプやPCの入力端子に入れれば実験的な音は出る。
試してないけど。:D
8MHzの水晶発振子で音を出す (^^)/ fs=44.1KHz, 48KHz対応
8MHzの水晶発振子なら部品箱にあるので、これで音だししてみた。
(^^)/
やっぱり、こっちのほうがいい音します。:D
水晶の精度は必須だ。xD
ブレッドボードでよくここまで出るね。
合格 !
(ただ、よく聴くと電源に起因すると思われる微小ノイズがわかる)
クロック設定
-
オーバークロックしない版
FRC = 8.0000MHz (水晶発振子) FRCDIV: 分周比 = 1/1 設定値=0 FRCDIV後出力周波数: 8.0000MHz PLLPRE: 分周比 = 1/3 設定値=1 PLLPRE後出力周波数: 2.6667MHz APSTSCLR: 分周比 = 1/8 設定値=4 fs=44.1KHz: M (PLL multiple) = 34 PLLDIV: 設定値 = 32 PLLPOST: 分周比 = 1/2 設定値=0 PLLPOST後出力周波数: 45.3333 (=FOSC) fsに対する誤差: -0.3859% FOSC = 45.3333MHz FCY = 22.6667MHz MCU処理能力 約23MIPS fs=48KHz: M (PLL multiple) = 37 PLLDIV: 設定値 = 35 PLLPOST: 分周比 = 1/2 設定値=0 PLLPOST後出力周波数: 49.3333 (=FOSC) fsに対する誤差: -0.3676% FOSC = 49.3333MHz FCY = 24.6667MHz MCU処理能力 約25MIPS
追記 (2016/01)
実は書き忘れていたことがありました。
DACのクロックは上述の様に設定すると
再生速度が2倍速くなってしまいました。
従ってDACモジュール内の分周器で適当に1/2してつじつまを合わせています。
何度も見直しましたが,理由が不明だったので
最終的につじつまを合わせて正しく再生できたのでそこで終了としました。