Psoc4とGPSモジュール(U-blox NEO6M)を使った周波数カウンタ作成

Psoc4 の$4キット CY8CKIT-049-42XXとGPSモジュール U-blox NEO6-Mを使った周波数カウンタを試作しました。アマチュアレベルでは十分に使える精度のカウンタができましたので記載します。

■今回作成したカウンタの仕様
入力1:最大150MHzまで安定動作。(ぎりぎり200MHzまでは誤差が増えるけど反応していました)
入力2:MB506を使って1/64設定にて最大2.5GHzまで動作。
精度:GPSモジュールの1ppS出力を基準に計測時間1秒、8秒、64秒で計測。

●試作装置の全体写真
ユニバーサル基板で作成したので、少し配線が見苦しいのですが、このようなものをつくりました。
今回は他に、TCXO(12.8MHz)をつかったGPS無しのカウンタもできるように準備しているので、写真には青色の多回転VRも見えます。今回の記事ではつかっていません。
画像
















■Psoc4を選んだ理由
Psoc4はKITが比較的安価(今回は秋月にて購入)で、デジタル部分が自由に組み替え可能で、64個程度のFFとレジスタ、FIFOをもったUDBと、物理セル(シリアル、タイマ、その他)が1チップに入っており、外部回路を最低限で2入力のカウンタが簡単に作れそうなので選択しました。
また、実際に作ってみると、デジタルブロックを置くと、自動的に関数が作られるので、割り込みや、ポートの制御が容易にできる点もわかり、楽に制御ソフトがつくれることがわかりました。

■今回作成(上の写真)の全体ブロック図と説明。
画像



















カウンタ入力は2ついれています。
1つはダイレクトに高速バッファ(SN74LVC2GU04)を通してPsocに入力。もう1つはプリスケーラIC(MB506)を通して1/64分周してPsocに入力しました。

GPSはUbloxのNEO-6Mをつかい、1pps入力はGPSモジュールのLEDの近くのチップ抵抗のモジュール側から線を半田づけしてPsocに接続します。
NEO-6Mはヤフオクなどで比較的簡単に手に入るとおもいますが、秋月の1pps出力付のGPSモジュールならどれでも使えると思います。ただ、アンテナ内蔵の場合は1pps出力は延長ケーブルで伸ばして接続する必要があるので、アンテナ外付けの方が使いやすいと思います。
また、GPSの制御用にシリアルデータを接続しておきます。(今回はデフォルトのまま使用のため未使用)

PsocKITの青LEDと、タクトスイッチはそのままつかうこともできますが、今回は、写真のように並列で取り出しました。

あと、SC1602キャラクタLCDを接続しました。
Psoc CREATERでLCDを置くと自動的に配線案がつくられ、その通りに配線するとLCD表示ができてしまいます。また、LCDは4ビットパラレル、I2Cなど選べるので主要なキャラクタLCDならどれでも接続できると思います。これは便利で、お手軽です。

入力バッファにchip1stopでSN74LVC2GU04を購入しましたが、LVCU04ならSOP(1.27mmピッチ)もあるので、そちらにすべきでした。クロック周期は2nS程度(500MHz)までバッファできそうです。150MHz程度までカウントできるので、高速バッファは必須です。

■Psocの回路ブロックと説明
画像



















一見複雑ですが、1個のPsocでこれだけの回路が入ります。UDBブロック84%つかっていますので、余裕はあまりありません。Psoc4では少し工夫して高速化と37ビットのカウンタとしています。
動作説明しますと、GPSの1ppsは8ビットカウンタに入ってゲートタイム1秒と8秒、64秒をつくって、BASIC COUNTER1と2のイネーブルに接続します。
イネーブルが1の時にカウントし、0になると停止して、その時にisr1割り込みが発生します。割り込みが発生すると各カウンタ値をプログラムで読み込みます。読み込みが完了するとカウンタをリセットします。
そして次のゲートが開くタイミングを待つことになります。
BASIC COUNTERとCounter_1がわかれていますが、これは、動作速度と、UDBの使用セル数のトレードオフで分けました。BASICカウンタは8ビットまでは90MHz以上(Psoc4 実力は150MHz程度)で動作が可能ですが、Counter_1はマイコン内部のクロックの半分の速度でしかうごけません。したがってせいぜい24MHzまでとなります。しかしCounter_1は内部のメモリセル、レジスタセルもカウンタ動作でつかうので、32ビットカウンタでもUDBの消費が7セルしか使わないので効率的です。一方BASIC_COUNTERはそのビット数分のUDBセルを使います。Psoc4はUDBは64セルしかないので、今回のように分割しないと回路が組めません。
そして分割するとクロックが異なるので再同期させています。
あとは、入力を2チャネルつかっているのでそれを切り替えています。カウンタの切り替えも、速度を無視すれば簡単に入力で切り替えてしまえばよいのですが、今回は高速化のため、高速カウンタの部分を2つにわけて、32ビットの低速カウンタに入れています。
 BASIC COUNTERのデータシート(回路上でクリックしてデータシートを選択)では64MHz MAXですが、全温度、全設定なので、このようになっています。ビルド後のタイミングレポートを見ると、自分の環境では93MHzとなっていました。これも今回のフィッティングのMAX値なので、、常温だと150MHzでも動作しているのだとおもいます。後ろに実際に周波数を測定した結果を記載しました。

▼Counter_1の周期設定(回路上でCounter_1をダブルクリック)
 周期設定とTC設定は32bitのMAXとしてください。
 コンペアモードは使わないのでソフトウエアとする。
 クロックモードはアップカウントとする。
 割り込みはチェック不要。
 リロードはRESETのみチェックを入れます。

▼★重要  入力ピンの設定をTransparentにする。(回路上で入力ピンをダブルクリック)
 入力ピンはデフォルトでDOUBLEシンクのクロック同期となっています。ピンをダブルクリックするとCONFIGになりますが、そこのINPUTタブでSYNC MODEをTransparentにしてください。これを忘れるとCPUクロック以下の周波数しか測定できないので、重要な設定です。
ThresholdはCMOS(外部のバッファが5Vの場合。3VならLVTTLにする)、割り込みは周波数入力はNONEにします。pin3はfalling edgeです。

■ピン接続とクロック
今回のPsocのピン配線と、クロックを載せておきます。
画像


















画像

















クロックの説明を少し。
今回はつかっていませんが、12.8MHzのTCXOを接続しています。しかし、CPUクロックは40MHzとしています。これはBASIC COUNTERの出力をCOUNTER_1でカウントするので、200MHZをカウントすると(一応動作)5ビット1/32で6.25MHzとなります。もし、TCXOの12.8MHzでカウントするとCOUNTER_1は6.4MHzでカウントするので、半周期ずらしたタイミングで抜けてしまう可能性がある。40MHZなら20MHZなので数回たたけるので、再同期させても安定してカウントできるので、40MHZとしています。
テスト用に12.8MHZを出力して、GPS動作の確認をしています。


■メインルーチン(マイコンソフト部分)
少しコードはわかりにくい部分がありますが、以下に記載します。
今回は単純に標準で準備されているLCD表示関数を使っています。
おいおい、LCD表示の3桁づつのカンマ表示など別途対応したいと考えています。
回路は見た目複雑ですが、プログラムはそれほど行数無しで制御できてしまいます。
LCD部分とか標準の関数を使えてしまうので、お手軽に表示できますね。これは楽できました。


main.c 関数。
他の関数は回路にブロックを配置すると自動的に作成されます。
割り込み関数、LCD関数、カウンタ関数、PIN割り当てなど全部。
つけた名前で関数がつくられるので、注意。無いとコンパイルエラーになります。
ブロックの通りに回路を置けば問題ないはず。
/* ========================================
*
* Copyright YOUR COMPANY, THE YEAR
* All Rights Reserved
* UNPUBLISHED, LICENSED SOFTWARE.
*
* CONFIDENTIAL AND PROPRIETARY INFORMATION
* WHICH IS THE PROPERTY OF your company.
*
* ========================================
*/
#include
#include "LCD_Char_1.h"

unsigned long counter_flag=0,st=0,sw_int_flag=0;
unsigned long long count_data=0;
unsigned char count_mode=0;
unsigned char modename[7][16]={
"IN1:1 ","IN1:8 ","IN1:64 ","IN2:1 ","IN2:8 ","IN2:64 ","GPS "};

//isr_1割り込みルーチン
CY_ISR(isr1_handler)
{
/* Place your Interrupt code here. */
/* `#START isr_1_Interrupt` */
unsigned long long i,j;
counter_flag=1;
st=Counter_1_ReadStatusRegister();
i=Counter_1_ReadCounter()<<5;
if(count_mode<3){
j=FRQ_CNT_IN1_Read();
}else{
j=FRQ_CNT_IN2_Read();
}

count_data=i+j;
COUNTER_RESET_Write(1);
isr_1_ClearPending();
COUNTER_RESET_Write(0);
/* `#END` */
}
//isr_2割り込みルーチン
CY_ISR(isr2_handler)
{
sw_int_flag=1;
Pin_3_ClearInterrupt();
}

/*
モード
0: IN1 1S
1: IN1 8S(回路を変えて16Sでも可)
2: IN1 64S(回路を変えて128Sでも可)
3: IN2 1S
4: IN2 8S
5: IN2 64S
6: GPS MONITER 作りこみ未 GPSの衛星数、時間、緯度経度など表示予定
*/
int main()
{
unsigned short tt=0;
unsigned long long count_main,count_sub;

/* Place your initialization/startup code here (e.g. MyInst_Start()) */
LCD_Char_1_Start();
Counter_1_Start();
Counter_1_Stop();
Counter_1_WriteCounter((unsigned long)0);
Counter_1_Start();
isr_1_StartEx(isr1_handler) ;
//isr_1_Start();
isr_2_StartEx(isr2_handler) ;
//isr_2_Start();

count_mode=0;
LCD_Char_1_Position(1,0);
//1行0列に書く
LCD_Char_1_PrintString(modename[count_mode]);

CyGlobalIntEnable; /* Uncomment this line to enable global interrupts. */

for(;;)
{


if(counter_flag!=0){
counter_flag=0;
LCD_Char_1_Position(0,0);//1行0列に書く
tt=0;
switch(count_mode){ //count_mode bit0 入力ピン選択 bit1,bit2 GPSからの1pps信号の分周出力のセレクタ
case 0: //IN1 1S

tt=0;
count_main=count_data;
break;
case 1: //IN1 8S  ゲート時間が10Sでないので直読みできない。 ゲート時間を16Sに変えたら 8→16にする

tt=1;
count_main=count_data/8;
count_sub=((count_data-count_main*8)*10)/8;
break;
case 2: //IN1 64S ゲート時間が100秒でないので直読みできない。ゲート時間を128Sに変えたら64→128にする。

tt=2;
count_main=count_data/64;
count_sub=((count_data-count_main*64)*100)/64;
break;
case 3: //IN2 1S MB805プリスケーラは1/64なので64倍する。

tt=0;
count_main=count_data*64;
break;
case 4: //IN2 8S MB805プリスケーラは1/64でゲート時間8秒なので8倍する。

tt=0;
count_main=count_data*8;

break;
case 5: //IN2 64S MB805プリスケーラは1/64でゲート時間64秒なのでそのまま表示

tt=0;
count_main=count_data;
break;
case 6: //カウンタ割り込みが入ってきたときにGPSモードの処理が必要なら入れる。

break;

}

LCD_Char_1_Position(0,0);//1行0列に書く
LCD_Char_1_PrintU32Number((unsigned long)count_main);
if(tt==2){
LCD_Char_1_PrintString(".");
if(count_sub<10){
LCD_Char_1_PrintString("0");
}
LCD_Char_1_PrintU32Number((unsigned long)count_sub);
}
if(tt==1){
LCD_Char_1_PrintString(".");
LCD_Char_1_PrintU32Number((unsigned long)count_sub);
}

LCD_Char_1_PrintString("Hz ");
}
//スイッチを押してモードを切り替え割り込みがはいってフラグが立った後の処理。
if(sw_int_flag!=0){
CyDelay(300u); //チャタリング防止 300mSウエイト チャタ防止しないと多重に入力されてしまう。
sw_int_flag=0;
count_mode++;
if(count_mode>6)count_mode=0;
LCD_Char_1_Position(1,0);
//1行0列に書く
LCD_Char_1_PrintString(modename[count_mode]);
if(count_mode!=6){
COUNTER_RESET_Write(1); //MODEが切り替わったのでカウンタをリセットする。
COUNTER_RESET_Write(0);
}
switch(count_mode){ //count_mode bit0 入力ピン選択 bit1,bit2 GPSからの1pps信号の分周出力のセレクタ
case 0: //IN1 1S
INPUT_SEL_Write(0);
break;
case 1:
INPUT_SEL_Write(2); //IN1 8S
break;
case 2: //IN1 64S
INPUT_SEL_Write(4);
break;
case 3: //IN2 1S
INPUT_SEL_Write(1);
break;
case 4: //IN2 8S
INPUT_SEL_Write(3);

break;
case 5: //IN2 64S
INPUT_SEL_Write(5);
break;
case 6: //GPSモードの処理が必要なら入れる。 ステータス表示処理はここに入れる予定。とりあえず入力はIN1を選択
INPUT_SEL_Write(0);
break;

}

}

} //無限ループ
}

/* [] END OF FILE */

■手持ちのSGの周波数測定一覧表
NWT4000のSG出力の周波数を測定した。
デジタルなので±1のズレはやむを得ないが、高い周波数でズレが大きくなっている。ただし、12.8MHZのTCXOは問題ない。とりあえず200MHZまではカウントできているみたい。
画像












■メーカー製SG周波数測定結果
こちらはちゃんとしたメーカー製SG(横河)を本周波数カウンタで測定した結果です。出力は10dBmとしました。-5dBmでも測定できました。
SGの原振は10MHZで、若干ズレはみられますが、安定しています。
周波数が10倍の100MHZになるとちゃんと元の原振の10倍になっているので、周波数は信用できます。ただ、周波数ズレがでてきます。ジッタ成分のようですが、GPSなのか、回路要因なのか判別はできません。これは12.8MHZのTCXOで周波数を図りなおして、両方比較してみないとどちらの要因か微妙です。別の記事でGPSとTCXOを比較してみたいと思います。
Psocの利点で、自由にロジック部が組み替えできるので、1ppsの8ビットカウンタを16ビットのハードマクロの16ビットカウンタ(PWMモード)に変更して12.8MHZにすればTCXOによるカウンタになります。セル数的に両方いれられるかもう一度試してみようと思います。
ただ、GATE時間8秒で150MHZで±0.4HZ程度でアマチュア用途では充分かなっと思っています。
ジッタが回路要因とするとGPSの1ppsかカウント入力ピンかどこかでCPUクロック系でたたいてしまっている個所があるとジッタが出る可能性がありますが、チェックしたのですが、いずれも透過モードになっているので大丈夫そうです。
画像











■最後に
Psoc4をつかうとこのように簡単なソフトでカウンタが作れてしまい、かつ、複数入力の切り替えも簡単にできます。また、標準でキャラクタLCDの関数も豊富に用意されているので、お手軽に表示もできてしまう。周波数カウンタは他のマイコン(PIC)でも作れますが、プログラムの手間はPSOCが一番簡単に作れると思います。
Psocには今回はつかいませんでしたが、12ビットADコンバータ、8ビットDAコンバータ、オペアンプ、コンパレータのアナログブロックもあるので、いろいろ遊べそうです。
プログラマブルロジックの部分は、Psoc5(UDB 24個)と比べるとPSOC4はUDBの数が4個(64セル程度)なので今回のように工夫しないと配置ができないことがありますが、その分安いです。でも、高いけどPSOC5-KITを1つ持っておくと、MiniProc3相当になるので、便利だと思います。
今回の書き込みにはMiniProc3をつかいましたが、Psoc5 Kit (CY8CKIT-059 1500円)のUSB部分にMiniProc3と同じ機能があるので、今回のカウンタはPsoc4のKITでなくてもPsoc5-KITで作っても良いです。そうするとBASICCOUNTERのみでできます。そちらの方が回路はすっきりします。
 あと、Psoc4-KITはブートローダーがついているので、これを使えば書き込みはできますが、デバックができません。そのため、いろいろ遊ぶにはMiniProc3か、Psoc5 Kitが必要です。Posc4-KITのUSB側は切り離してUSBシリアル(CMOSレベル)で使えます。そのままGPSモジュールにつないでGPSの確認用に使えます。
 Psoc5 KitのUSB部分を切り離してヘッダコネクタをつけるとMiniProc3相当になります。どちらも無駄にはなりません。
※応用案
1)Psoc4KITのUSBシリアルの利用について
応用としてPsoc4-KITは切り離せるUSBシリアルがついていますが、シリアルを2chにして、USBに接続した方をそのままPCに接続するとPCで周波数がモニターできそうです。
2)TCXO対応(非GPS環境での周波数測定対応)
DAコンバータ精度は8ビットしかないので、外付けのSPI制御の16ビットDAコンバータ(DAC8552)などを増設してTCXOの自動高精度化もおもしろそう。アルゴリズムつくればGPSの1PPSと内部カウンタでつくった1ppsの時間差を比較してソフト制御のPLLがつくれるかも。これができれば、温度と電圧をパラメータにテーブルつくればGPS無しでも高精度カウンタ行けるかも。
3)Psoc5-kitに変更
Psoc5に変更することで、UDBが4→22に増強され、これにより、GPSとTCXO自動補正、GPSの1ppsの1/10 1/100分周回路、EEPROMエミュレータブロックをつかって温度補正値の記憶まですべて1つにいれられるので、ほぼ完ぺきな周波数カウンタが作れそうです。TCXOを恒温仕様にして、恒温内に温度センサーとシャントレギュレータ、DAコンバータを入れる必要がでてくるのはお約束ですが。
一応、Psoc4でもハードマクロの16ビットタイマーを使うことで、TCXOの周波数とGPSの1ppsの比較回路がぎりぎり入れられそうですが、16ビットのキャリーアウトは割り込みでカウントしないとUDBが足りないようです。

■TCXO 12.8MHZでカウントして、GPSの1ppsで12.8MHZをカウントし、12.8MHZとGPSのズレを表示する回路に変更しました。
 別記事に記載  

ブログ気持玉

クリックして気持ちを伝えよう!

ログインしてクリックすれば、自分のブログへのリンクが付きます。

→ログインへ

なるほど(納得、参考になった、ヘー)
驚いた
面白い
ナイス
ガッツ(がんばれ!)
かわいい

気持玉数 : 0

この記事へのコメント

この記事へのトラックバック