akira.kei が 2025年02月10日00時35分02秒 に編集
コメント無し
本文の変更
[<前の記事](https://elchika.com/article/452b0d11-20a9-4da8-bf27-b104d9693917/) : [次の記事>]() ## 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)が入力できればいい。
実質的に上の2つはほぼ同じなので、LC1_outしか選択肢が無いが、鬼門のCLCモジュールを使わなくてはいけなくなる。ここでCLCモジュールにLFINTOSC(31kHz)が入力できればいい。
## CLCモジュール CLCモジュールはとにかく意味がわからない。データシートを見ても機能がピンと来ないわけで、これはツールに頼るしかない!と、これも苦手なMCC(Classic)で設定してみた。  とにかく入力元は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) { } } ``` 