↑PICキット 14ピンCPU基板
 PIC16F18326が挿入
 8MHZ水晶発振モジュールも挿入
PIC16F18326内蔵NCOモジュールを弄ってみる

16F18326には16F1705には無い、数値制御オシレータモジュールなるものがあります。
データシートをざっと見てみると、詳細は不明ですが・・・ (^_^;)
割と正確な周波数でパルスを発生させる事が出来るような感じです。

ちょっと実験するのには 既存のPICキット基板で大丈夫そうですし、
何かアマチュア無線家にも便利そうなモジュールなので、まずは実験がてらお気軽に弄ってみる事にしました。

参考文献
 PIC16F18326データシート MicroChip
 電子工作のためのPIC16F1ファミリ活用ガイドブック 後閑哲也著 技術評論社


↑ NO-11
 インクリメンタルタイプ
 ロータリーエンコーダー基板



↑ NO-14
 I2C接続LCDモジュール

NCOモジュールの実験は14ピンのPICキット各基板を使用

NO-01 14ピンCPUモジュール
NO-06 8MHZ水晶発振モジュール
NO-11 ロータリーエンコーダモジュール
NO-14 I2C接続LCDモジュール(NO-12でも可)

出力モニターにオシロスコープ&周波数カウンタ

以上の構成で実験を行いました。






↑ 回路図





↑ 全体接続
PIC16F18326内蔵NCOモジュールの下調べ

当局にとっては初めて弄るモジュールで、使い勝手も何も分からないので適当です。
とりあえず動けば良いや、と言う事で最低限の事をマニュアルから読んでみました。
今後大幅に変更して行く事になると思われます。

1.NCOモジュールの基本的な構成
(1)アキュムレータ
   20ビットのレジスタで、読み書き可能ですが、
   加算器の演算結果がここに反映されます。
   NCOxACCL 下位8ビット
   NCOxACCH 中位8ビット
   NCOxACCU 上位8ビットだが、その内下位4ビットを使用
            このレジスタ上位4ビットの読み出し値は常に0です。
   以上の3レジスタで構成されます。
   アキュムレータからはオーバーフロービットが出力されます。
   これはNCOクロックの1クロックの間’H’となります。
   例えば、NCOが32MHZで動作していたなら、
   31.25nsの間’H’となり、その後’L’となります。
   このフラグビットがその後各ロジックを通り、各種データビットとなり、
   ピン出力や割り込み等を発生させます。

(2)加算器
   CPUのインストラクションクロックから独立して動作する様です。
   システムクロック(Fosc)で高速に20ビット加算動作します。
   前回の加算結果値(ACC値)とインクリメント値を加算します。
   その値を20bitアキュムレータレジスタに上書きします。
   タイミング表から1クロックで上記演算動作終了しています。

(3)インクリメントレジスタ
   20ビットのレジスタで、読み書き可能
   NCOxINCL 下位8ビット
   NCOxINCH 中位8ビット
   NCOxINCU 上位8ビットだが、その内下位4ビットを使用
   以上の3レジスタで構成されます。
   設定された全値はNCOxINCLレジスタに書き込んだ刹那、
   インクリメント・バッファに転送されます。
   加算器は、そのバッファのインクリメント値を演算に使用します。
   通常動作時、バッファの値は再度書き込みされない限り保持されます。

2.NCOモジュール制御レジスタ
(1)NCOx 制御レジスタ
 bit7 NxCOx:NCOxイネーブルビット
      1=NCOxモジュールを有効にする
      0=NCOxモジュールを無効にする(初期値)
 bit6 未実装:読み出し=0
 bit5 NxOUT:NCOx出力ビット
      1=NCOx出力がHigh
      0=NCOx出力がLow(初期値)
 bit4 NxPOL:NCOx極性ビット
      1=NCOx出力信号をアクティブLowにする(反転)
      0=NCOx出力信号をアクティブHighにする(非反転)
 bit3-1 未実装
 bit0 NxPFM:NCOxパルス周波数モードビット
      1=NCOxをパルス周波数モードで動作させる
      0=NCOxを固定ディーティサイクルモードで動作させる

(2)NCOxCLK:NCOxクロック制御レジスタ
   一見、出力デバイダの様に感じますが、まるで違うので注意
 bit7-5 NxPWS<2:0>:出力パルス幅選択ビット
        111=NCOxクロック128周期
        110=NCOxクロック64周期
        101=NCOxクロック32周期
        100=NCOxクロック16周期
        011=NCOxクロック8周期
        110=NCOxクロック4周期
        001=NCOxクロック2周期
        000=NCOxクロック1周期
 bit4-2 未実装 read as '0'
 bit1-0 NxCKS<1:0>:NCOクロック源選択ビット
        11=予約済み
        10=CLC1_OUT
        01=Fosc
        00=HFINTOSC(16MHZ)

3.動作モード
 今回は固定ディーティサイクルモード(FDCモード)で動作させます。
 よって、50%デューティーでパルスを出力します。(注1)

(1)FDCモード(固定デューティサイクルモード)
  NCO出力ビットはオーバーフローフラグが立ち下がった時から、
  次の立下りまでの間、NCO出力ビットを’H’にします。
  その後次のOFフラグ立下りまで’L’となります。
  つまり、NCO出力パルスはOFフラグ2回で1周期となります。

(2)PFモード(パルス周波数モード)
  OFフラグ立下りからNCO出力ビットを’H’にします。
  NCOクロックの、指定の数の間だけNCO出力’H’を維持します。
  次のOFフラグが発生するよりも長く指定すると、結果は不定となります。
  どのくらいの間’H’にするかはNxPWSビットで指定します。


4.NCO出力周波数
 FDCモードにおいて、NCO出力パルスの1周期の時間はタイミング表より、
 OFフラグ2周期分の時間となります。
 よって、出力パルス周波数(Fnco)は、

 2×Fnco=NCOクロック×(INC値÷(2の20乗))
   Fnco=(NCOクロック×(INC値÷1048576))÷2

 計算例
  NCOクロック 32MHZ
  INC値 8000H=32768
  Fnco=32000000×(32768÷2097152)
      =32000000÷64
      =500(KHZ)

 設定例(NCOクロック32MHZ)
  Fnco=107HZ   INC値 7H
  Fnco=1KHZ    INC値 42H
  Fnco=10KHZ   INC値 028FH
  Fnco=100KHZ  INC値 199AH
  Fnco=1MHZ    INC値 10000H
 因みに、INC値=1で15HZ~16HZ位です。

さて・・・ 机上の空論(計算)はこの位にしといて、プログラミングおよび実験に入りたいと思います。
何か久々に・・・ワクワクしてきますね (^^♪

注1)
 NCO動作イメージについては、マニュアルのブロック図およびタイミング表を参照すると、解り易いと思います。
アキュムレータには、ひたすらインクリメント値の加算結果が入る。
オーバーフローする度に、オーバーフローフラグビットがNCOクロックの1クロックの間だけアクティブとなる。
FDCモードの場合、オーバーフロービットが0→1→0の立下りでNCO出力が0→1となり、次のオーバーフローフラグが同様に立下りでNCO出力が1→0となる。
すなわち、2回のオーバーフローでNCO出力パルスが1サイクル分構築される。
計算上ではNCOクロックの1/2~1/2097152まで、
つまり32MHZクロックで15HZ程度から16MHZ程度までパルスを発生できる事が可能と言う事になる。
それも、NCOクロックが高精度ならばNCO出力パルスも高精度となります。

PIC16F18326
PPSレジスタの設定

 RC0:I2Cクロック入出力
  SSP1CLKPPS=10H
  RC0PPS=18H

 RC1:I2Cデータ入出力
  SSP1DATPPS=11H
  RC1PPS=19H

 RC2:NCO1出力
  RC2PPS=1DH

実験用NCO制御プログラム構想

NCO制御は速度や微妙なタイミング等を要求しませんし、実数演算も行います。
よって、XC8でプログラムする事にします。
ロータリーエンコーダでNCOインクリメント値をグルグルと可変設定
I2C接続LCDモニターに設定したNCOインクリメント値を表示、および
想定出力パルス周波数値を演算して、LCD表示
もちろん、NCO出力はオシロ+周波数カウンタでモニターします。
これで、NCOの基本的な能力を見る事が出来ると思います。

一言で言えば、可変周波数パルス発生器ですね・・・
出力が矩形波なので、バンバン高調波が出ますなこりゃ・・・
まあ取り合えず、プログラミングを楽しむとしよう (^O^)/

メインプログラムの他にI2C制御ライブラリが必要です
ロータリーエンコーダ制御関数は当局版のXC8版Ver1.0を使用します。
NCOモジュールに対しては、その専用レジスタに数値設定するだけなので、今の段階では単純な作業です。
応用する時は設定する数値を用意する事が主な作業となりそうです。

ヘッダーファイルの置き場所
MPLAB X IDE Ver5.5

「Projects」ウインドウの、
「Header Files」を右クリック、
「Add Existing Item・・・」
 ここで「MSSP02b.h」を登録
 「AQM1602v1.h」を登録
 「R_ENCODERv1.h」を登録


同様に、
「Source Files」に
 ここで「MSSP02b.c」を登録
 「AQM1602v1.c」を登録
 「R_ENCODERv1.c」を登録
この場所にはメインプログラムも登録


インクルードファイル

 MSSP02b.h
 
 AQM1602v1.h
 
 R_ENCODERv1.h

 MSSP02b.c
 
 AQM1602v1.c
 
 R_ENCODERv1.c


メインソースファイル

 16F18326_NCO_TEST01a.c


実験用プログラム用に作成した関数およびインクルード関数

NCOモジュール用関数

1)unsigned long int NCO_CALC(
  unsigned long int 引数1、unsigned long int 引数2)

   NCO INC値とNCOクロックから生成周波数を演算
   小数点第1位を四捨五入して、整数(HZ)で返します。
   関数内部では実数計算をしています。

   引数1:NCOインクリメント値で32bit符号無し整数
   引数2:NCOクロック周波数(HZ)で32bit符号無し整数
   戻値:NCO出力パルス周波数(HZ)で32bit符号無し整数

2)void NCO1_INI_FDC(void)
   NCO1モジュールをFDCモードで初期設定します。
   NCOクロックはFoscとします。
   最初に1回呼び出します。

   引数1:無し
   引数2:無し
   戻値:無し

3)void NCO1_SETINC(unsigned long int 引数1)
   NCOインクリメント値をNCOモジュールに設定

   引数1:NCOインクリメント値で32bit符号無し整数
   戻値:無し

ロータリーエンコーダ制御関数 Ver1

4)unsigned long int RE_DATA(
  unsigned long int 引数1、unsiged long int 引数2)

   REを右回転した場合、引数1に引数2を加算します
   キャリー発生時は最大値のままです。
   REを左回転した場合、引数1から引数2を減算します
   ボロー発生時は’0’のままでマイナス数値にはなりません。

   引数1:元となるカウンタ数値で32bit符号無し整数
   引数2:加減算する1ステップ数値で32bit符号無し整数
   戻値:加減算された32bit符号無し整数
      REが回転してなかった場合、元の数値をそのまま返します。


MSSPおよびAQM1602関連は省きます
過去ページをご参照下さい・・・  <m(__)m>
生成波形のオシロ画像各種
10:1プローブを使用しています。




↑ 波形① 100HZ



↑ 波形② 1KHZ




↑ 波形③ 10KHZ




↑ 波形④ 100KHZ




↑ 波形⑤ 500KHZ




↑ 波形⑥ 1MHZ




↑ 波形⑦ 2MHZ




↑ 波形⑧ 5MHZ
 波形の「ブレ」が目立ってきました





↑ 波形⑨ 7.1MHZ
 波形はブレまくりです・・・






実験用プログラム実行結果

意外やあっさりと目的の動作をしてくれました (^^♪
もっとハマるかと思っていたのに・・・ 1回目の驚き。
ロータリーエンコーダをグルグル回すと、パルスを低周波から高周波まで広範囲に発生してくれます・・・ 2回目の驚き
変化ステップは01Hと100Hの2種類のみの設定だったので、周波数変化量が小さくて、REのつまみを回すのが疲れました。
生成周波数演算も、周波数カウンタの実周波数値とほぼ同値で驚いています。
これが3回目の驚き
PICをX’TALで動作させると、生成周波数も結構安定しています。

う~む、これって意外と使えるかも (^_^)

ただし、オシロで生成波形を見ている限り、7.8MHZ程度以上は波形がよく解らなくなるし、周波数カウンタに切り替えても、周波数カウントもしなくなります。
まあ、CPU基板のピンにプローブを当てて出力パルスを取得していますので、当局のオシロの扱いが素人過ぎるのが原因でしょう。 (^_^;)
因みに、100MHZまで対応のプローブを使用してはいますが・・・
ただの同軸ケーブル+ワニ口クリップのコードでは、高周波領域では波形がかなり鈍ります。
画像に関しては、オシロのフォーカスがイマイチ合わなくなってきました・・・
ちょっと見ずらいと思います。

各局様はこれらの記述をサラッと読んで、もしかしてPICはDDSとして使える?
と思われるかも知れませんが、少々厳しいです。
第一にNCO出力はガチガチのデジタル波形、矩形波です。
次に最高速の32MHZクロックで、INC値が1変化で15~16HZ変化となりますが、HF帯の周波数を直接生成できます。
計算上、8bitPICが10HZ/INC値や1HZ/INC値を実現するには、クリスタル発振クロック周波数を下げれば良いのですがが、Foscがそれぞれ約21MHZや約2MHZとなり、当然生成上限周波数ががっくりと下がります。
(変に思うかの知れませんが、NCOクロックが上がれば、1インクリメント当たりの周波数解像度が荒くなり、クロックが低くなれば、1インクリメント当たりの周波数解像度が細かくなるのです)
ヘテロダインすればHF帯のVFOが実現できそうですが、もはやDDSではありません。(もどき?)
でも、色々妥協すれば(アマチュア発想で走れば)何かできそうです (^^♪

兎に角、色々実験してみない事には何とも言えません、
まず、今回はNCO最初の実験と言う事で、今後の楽しみを沢山残しながら、これにて締めくくりたいと思います。  (^O^)/


JULY/2019/JA0QON

↑SPI機器開発用基板

PIC16F18346を挿入
8MHZ水晶発振モジュールも挿入
これにて追加実験をしています






↑ LPF 回路図






↑ ローパスフィルタ基板

この基板出力をオシロで観察しました。






↑ 8MHZ水晶モジュール

これは2列ピン用で、いままでの1列用の水晶モジュールはこの基板には使用できません。
回路はどちらも同じです。






↑ 基板に水晶モジュールを差し込み






↑ 500KHZ出力

 垂直 500mV/DIV
 以下全て同じ
 水平軸は見やすい様に変えています





↑ 約700KHZ







↑ 1MHZ







↑ 約1.2MHZ








↑ 1.5MHZ







↑ 約1.7MHZ







↑ 2MHZ







↑ 約 2.2MHZ








↑ 2.5MHZ







↑ 約2.8MHZ








↑ 約2.8MHZ







↑ 3MHZ






不要かなとは思いましたが、この実験に使用したプログラムソースを記します。
XC8で記述されています。


「SPI機器開発用基板」用プログラム


 インクルードファイル

 SC1602v1_SPIB.h

 R_ENCORDERv1_RC23.h


 プログラムファイル

 XC8_16F18346_NCO_SPIB_TEST01.c

 SC1602v1_SPIB.c

 R_ENCORDERv1_RC23.c
その後の実験による追記

※その後の実験はPICキット上のPIC16F18326では無く、「SPI機器開発用基板」上のPIC16F18346のNCOで行っています。
8MHZの水晶モジュールを差し込んでいます。

1)オシロによる観測波形のブレについての考察
 これについては何度か実験しましたが、概ね考察と実験が合致してきました。
 実験では、
 a)発振周波数が高くなると波形のブレが大きくなってくる
 b)ブレが大きい周波数でも、ある周波数ではブレが止まる

この2点の実験結果についての考察ですが、これについてはNCOのパルス発生機構そのものに原因があるのではと、当局は思い始めています。
と言うのは、
 c)アキュムレータでは、ひたすらINC値を演算している
   そしてオーバーフロー発生でOFビットを1サイクルのみHとします。
 d)OFした演算結果はアキュムレータに残るが20bit以内の数値が残る。
   結果的にOFビットはキャリーフラグみたいなもん?
 e)次のINC値は桁上がりした下位20bitに加算される
   つまり演算サイクルにINC値以外の数値が加わる事となる

机上の計算をしてみましょう
INC値=45000Hとする
00:ACC=00000H(初期値)
01:ACC=45000H
02:ACC=8AOO0H
03:ACC=CF000H
04:ACC=14000H OF=1(4演算サイクル)
05:ACC=59000H
06:ACC=9E000H
07:ACC=E3000H
08:ACC=28000H OF=1(4演算サイクル)
09:ACC=6D000H
10:ACC=B2000H
11:ACC=F7000H
12:ACC=3C000H OF=1(4演算サイクル)
13:ACC=81000H
14:ACC=C6000H
15:ACC=0B000H OF=1(3演算サイクル)
16:ACC=50000H

 f)OF(オーバーフロー)の間隔は直接生成周波数の周期となっている
   上記例では生成周波数周期が短くなる時がある事が分かる
   これがオシロで見える波形の「ブレ」となっていると思われる
   何か周波数変調?を掛けている感じになってしまう・・・

 g)OF時「余り?」の出ない演算数値もある
   これがオシロ波形で条件発生する「ブレの無い」波形と思われる
   ACC(アキュムレータ)が2の20乗なので、20個存在する
   計算上の「ぶれない」周波数はオシロ波形でも一致・確認できました。


NCO出力をローパスフィルタに通してみた

フィルタ基板回路図は左記の通りで、単なるLCローパスフィルタです。
当局の貧弱な技術力では複雑なフィルタ設計は出来ないのでシンプルです。
回路図におけるNCO入力直後の抵抗(1KΩ)はPIC保護用で、波形も少し丸まるので一石二鳥です。
出力はオシロを接続するので、TR1石のバッファを入れてます。
このバッファアンプの入力インピーダンスは低くした方が出力波形が良くなります。
LCフィルタ部分は1段では話にならないので多段にしてみた
計算上は2.25MHZのカットオフですが、実際オシロで見ると2.7MHZ位から急速に減衰し始めます。
この実験用フィルタ基板はランド法で製作しています。
画像のように1MHZあたりから出力波形が、そこそこまともになってきました。
とは言え、波形を拡大すると微妙にブレています。
2.5MHZ程度以上はNCO出力波形のブレが目に見えて酷くなりますし、周波数カウンタも誤作動し始めます。
この辺が使用限界な気がします。

さてと・・・前半と比較してテンションが駄々下がりの当局ですが・・・
何に応用できるか思案中です・・・

2020年04月29日 JA0QON


戻る  実験・製作の記録TOPへ戻る