編集履歴一覧に戻る
akira.keiのアイコン画像

akira.kei が 2025年02月10日00時31分35秒 に編集

初版

タイトルの変更

+

8ピンPICのPIC16F18313を使う(その12)NCOでシンセサイザ

タグの変更

+

PIC

+

PIC16F18313

記事種類の変更

+

セットアップや使用方法

ライセンスの変更

+

(GPL-3.0+) GNU General Public License, version 3

本文の変更

+

[<前の記事](url) : [次の記事>]() ## NCOでDCOにできないか PIC 16F18313に内蔵されてるNCOの出力周波数は20bitで指定できる。これだけ分解能があればシンセサイザーのオシレータ部分に使用できるかも。EXCELで0〜127のMIDIノート番号に対する周波数を計算して、NCOで得られるはずの周波数との誤差を求めてみた。 Foscが1MHzの場合だとノート番号77以降で誤差が0セントになる。実際には10セント程度は人の耳では識別できないし、これはこれで味があるとも言えるが、せっかくデジタルなんだからもう少し頑張りたい。 源振の1MHzを下げられれば周波数分解能が上がり、誤差が出にくくなるのだが、NCOへの入力は以下の3つしか選べない。 1. HFINTOSC 1. Fosc 1. LC1_out 実質的に上の2つはほぼ同じなので、LC1_outしか選択肢が無いが、鬼門のCLCモジュールを使わなくてはいけなくなるが、CLCモジュールにLFINTOSC(31kHz)が入力できればいい。 ## CLCモジュール CLCモジュールはとにかく意味がわからない。データシートを見ても機能がピンと来ないわけで、これはツールに頼るしかない!と、これも苦手なMCC(Classic)で設定してみた。 ![CLC](https://camo.elchika.com/4d32117bfc6b1c11be117266a8c838e0faf52de6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f64316434363666302d333730362d343538622d383262322d363763323632656162666131/) とにかく入力元はLFINTOSC(31kHz)に設定し、4-input ANDに突っ込んだ。RA5をPPS経由で出力モニタにすれば、LFINTOSCが本当は何Hzなのかが測れる。 ## pragma-config.h 将来的にUSARTからMIDI信号を受けたいので、動作周波数は速い方が通信エラーが少ない。今回はとりあえず1MHz駆動にしたが、32MHz駆動の方が妥当かもしれない。(いつもと同じなので省略) ##mainルーチン まずは冒頭はxc.hとpragma_config.hを忘れずにインクルードし、出力バッファ無効、アナログ無効にする。テンプレートのようなものだ。 ``` #include <xc.h> #include "pragma_config.h" void main(void) { TRISA=0xff; ANSELA=0; ``` CLCモジュールの設定はMCC classicに頼ったが、出来た中身を見てみるとなんとなく作法がわかってくる。4つのCLC1SELyには全部LFINOSCを指定、4つのCLC1GLSyもゲートを一つだけ選ぶことで、ここは単なるバッファになっている。最後にCLC1CONでモジュールを有効にして、RA5にPPS経由で出力するだけだ。 ``` // CLC1POL = 0x00; CLC1SEL0 = 0x1D; CLC1SEL1 = 0x1D; CLC1SEL2 = 0x1D; CLC1SEL3 = 0x1D; CLC1GLS0 = 0x02; CLC1GLS1 = 0x02; CLC1GLS2 = 0x02; CLC1GLS3 = 0x02; CLC1CON = 0x82; RA5PPSbits.RA5PPS=0b00100; // CLC1OUT TRISAbits.TRISA5=0; ``` あとはNCO1を設定すればいい。入力はCLCにしてRA2に出力する。インクリメントの0x07358はLFINTOSC周波数が31.25kHzの場合の440Hz出力のための値であり、測定するとかなりいいとこまでイケてるし、微調整も可能だろう。 今回は最後は空の無限ループだが、UARTからMIDIノートを受け取ってNCO 1INCに設定する割り込みルーチンを入れればある程度までは良さそうだ。実際はポルタメントとか変調をどう受け取るかが難しそうだが。 ``` // NCO1INC=0x07358; NCO1CLKbits.N1CKS=0b10; // CLC1OUT NCO1CONbits.N1PFM=0; NCO1CONbits.N1EN=1; RA2PPSbits.RA2PPS=0b11101; // NCO1 TRISAbits.TRISA2=0; while(1) { } } ``` ![キャプションを入力できます](https://camo.elchika.com/64b43f7505f342f634ed1b2f39b59c741a2f05f0/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f62383239643633302d366662622d346338382d626531632d393461643537643133353235/)