« PICでFFT (XC16でFFTにトライ) | メイン | dsPICでバンドスコープ 1  »

2021年10月25日 (月)

dsPIC33CH トラブル事例

<dsPIC33CH Trap Reset モジュロアドレッシング atpack>

New_sdr211025

左は、dsPIC33CH64MP202を使い、SDRを開発しているスナップですが、この開発中に遭遇したトラブル事例を紹介します。

①モジュロアドレッシングの為にワーキングレジスタを専用割り当てした時は、このレジスタをコンパイラーが勝手に使わないように処理する必要がある。

FIRフィルターを2種類設定しリングメモリーを構築する為に、モジュロアドレッシングの設定をおこないますが、ひとつのリングメモリーのコントロールの為に、ひとつのワーキングレジスタを専用に割り当てます。 このワーキングレジスタはW8とかW10が良く使われますが、一旦、この専用レジスタを割り当てた後、他の目的に同じレジスタを使用すると、トラップが発生し、RESETがかかってしまいます。 コンパイラーの説明によると、このように専用レジスタを設定した後は、コンパイラーがこのレジスタを使わない様にユーザー側で設定する必要があると説明されております。

その方法は、MPLAB X XC16 GCCのオプション欄に以下のように記述します。 この例では、W8とW11をコンパイラーは使用しなくなります。

-ffixed-w8  -ffixed-w11    

全て小文字で記述する事。  最初wを大文字にした為、全く効果がなく焦りました。

 

②割り込みにて、トラップが発生し、RESETされる。特に、32bitや64bitの演算のとき、16bit単位の演算途中に割り込みが発生した場合、直前のデータの回復ができなくなる事があり、演算結果に誤りが発生したり、ひどい時はトラップが発生するもの。

特に、C言語で複数の演算式を1行の命令文として記述した時に発生しやすい。演算式をひとつづつに分解して、かつ途中に中継用の変数をおけば、かなり改善される。 それでも、10usecに1回くらいの頻度で割り込みがかかるような場合、かなりの頻度でトラップが発生する。

対策としては、割り込みの周期を変えても良い場合、トラップの発生する演算の期間中、割り込みを遅延させる。 割り込みを遅延させる方法で一番簡単な方法は、該当する演算命令の直前に割り込みの優先順位を0にして、演算が終わったら優先順位を元にもどせば良い。

ただし、ADCのタイミングなどのように周期をずらせない場合、対応不可なので、あきらめる事になります。

この現象はdsPICに限らず、PIC24FJでもFFT処理時、発生していました。その場合、一旦周期的な割り込みを禁止して、FFTの計算をやらせていました。

これらの事が理解できるまで1か月以上かかりました。結局 dsPIC33CHの場合、10usecの割り込みはスレーブ側だけにし、浮動小数点の計算やlong intを扱う演算などは、定期割り込みがかからないマスター側のみで行う事にします。 実際に実現できるかトライした結果OKとなりました。

 

③ レジスタ変数の禁止

古い資料には、ワーキングレジスタを16bitの変数に指定すると、そのワーキングレジスタはコンパイラーが専用と認識し、他の用途には使用されないと説明されていますが、これは当時から非推奨となっていました。 そして、現在は、そのような記述をするとエラーになります。

 

④ Slaveという文字の非推奨

XC16 V1.50で、エラーに近いワーニングが出て、コンパイラをアップデートしろと怒られます。 そこで、V1.70に変更しましたら、今後 Slave という文字は secondary に変えろとコメントが付きます。 この変更を実施したら、コンパイラの出力から赤文字がなくなりました。

 

⑤ 発振回路とPLL設定

SDRとして使う為に、クリスタルによる発振をベースとしたクロック回路を構築しようとしましたが、なぜか、Foscが生成されません。 通常、以下のようにコンフィギファイルを設定しますが、クリスタル発振回路は正常に動作しているのに、PLL回路への信号が途中で途絶えているみたいで、動作しません。 

#pragma config FNOSC = PRIPLL     //プライマリ-オシレーター、PLLモード     
#pragma config POSCMD = HS    //8MHz以上のクリスタル発振

何日も原因が判らず、先へ進めなくなりましたので、クリスタル発振を外部発振回路に変え、コンフィギファイルを以下のように書き換え、OSCの出力にFosc/2が出てくるようにしましたが、信号は有りませんでした。

#pragma config POSCMD = EC           // 外部クロック
#pragma config OSCIOFNC = OFF     //

結局解決できず、再度マニュアルを読み直すと、どの説明も、最初FRCモードで立ち上げ、その後で、外部発振やクリスタル発振モードへ移行する例しか書いてありません。 そこで、そのサンプル通りに設定すると、晴れて、正常にFosc/2が出力され、プロブラムが実行されるようになりました。 このFosc/2がFRCによるものか、外部クリスタル発振器によるものかは、接続した周波数カウンターで簡単に見分けがつきます。 FRCの場合、周波数が1000Hz以上ばらつきますが、クリスタルの場合、バラツキは1Hz以内です。 以前、dsPIC33FJにて、SSBジェネレーターを作った時は、従来のやり方で問題無かったのに、と焦りましたが、動き出しましたので、とりあえず、納得です。

最終的に、コンフィギファイルを以下のように設定した上で

#pragma config FNOSC = FRC           // Oscillator Source Selection (Fast RC Oscillator with PLL module (FRCPLL) )
#pragma config IESO = ON               // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)

// FOSC
#pragma config POSCMD = EC     

Mainプログラムの中で、以下のように記述することで、動作OKとなりました。

 // POSCとPLLの設定 FRCで起動して、外部clockのPLLモードへ切り替える

 PLLFBDbits.PLLFBDIV = 100 ; // M FPLL=819.2 Fosc=204.8
 CLKDIVbits.PLLPRE = 3;  // N1 1/3 Xtal=24.576MHz
 PLLDIVbits.POST1DIV = 2; // N2
 PLLDIVbits.POST2DIV = 1; // N3
   
 // Initiate Clock Switch to FRC with PLL (NOSC=0b001)
    __builtin_write_OSCCONH(0x3);
    __builtin_write_OSCCONL(OSCCON | 0x01);
 // Wait for Clock switch to occur
 while (OSCCONbits.OSWEN != 0);//Clock SW 切り替え完了
 while (OSCCONbits.LOCK != 1); //PLL Rock 完了

 

 ⑥CCP3の怪

周期割り込み用のタイミングを取る為に、CCP1 CCP2と単純なタイマー仕様で利用していましたが、さらに割り込みが必要になり、同じようにCCP3を設定しました。 設定した割り込みタイミングは約6KHz程度の周期でしたが、出てきたタイミングは、周期が乱れた約850KHzくらいの異常周期でした。 設定が間違ったかと、何度もチェックしましたが、間違っていません。 試しにCCP3の3の数字をすべて4に変えたら、設定通り6.25KHzの周期で割り込みが発生します。

CCP3の異常の原因はわかりませんでしたが、とりあえずCCP4で正常に動作していますので、そのままです。

<半年後に追記>この原因は多分Timer3をADコンバーターのサンプリングレート設定に使っている事が原因かも知れません。

 

⑦DACがsigned intで動かない。 unsigned intオンリーです。

どこかに設定があるかもと、日本語、英語、類似dsPIcの資料を読みあさりましたが、結局、極性付整数によるドライブが出来るという説明は見つかりませんでした。 多分、極性付整数は扱えないのでしょう。 FIRフィルターなどをデジタル処理する上で極性付きはマストですから、DSPの計算部分は極性付きで実行させ、DACに出力する直前にsignedからunsignedへ変換すれば良いようです。

Singned_int

Unsingned_int

左上は、signed intのデータをそのままDACに出力したものです。 右は、DACに出力する前に、データに2048を加算したものです。 12bitのDACですから、その半分のオフセットを加えてやれば、データが全部正の値になりますので、正常に出力出来ています。 ただし、この状態を作る為には、DSP内のデータは整数で有る事が必要で、TAP係数もADCの設定もすべて、signed intにしておくことが必要でした。

  

⑧配列変数の要素数が確保した要素数をオーバーしてもコンパイルエラーがでず、ハングアップする。

通常、配列変数の宣言を要素数を指定して行いますが、誤って、その要素数をオーバーしても、コンパイラはエラーをはかずに、そのままリンク完了してしまいます。 その為、いざRUNさせると、ハングアップを起こし、動かなくなります。 どこでハングアップしているのかを、LED点灯を目印に調べていくと、その原因が要素数のオーバーらしいという事がわかりました。 エラーなしでコンパイル完了したのに、プログラムが止まった場合、最初に疑えば、解決がはやくなりそうです。 XC8では、ちゃんとエラーが出たような記憶でしたが。

 

⑨2021年12月の時点でXC16 V1.70がインストールされている状態で新規にプロジェクトを作ると、Configの記述が変更されており、XC16 v1.50の記述のままではエラーになる。

I/OポートをMasterが使うかSlaveが使うかを記述するときの記号が変更されている。

MSTR → MAIN            SLV1 → SEC1

どうやら、マスターとかスレーブという語句を全て禁止したみたい。 なにもエラーにしなくても、ワーニングにして変更を開示すれば良いのに。   この変更を加えた事により、エラー表示は無くなり、コンパイルが成功するのですが、マスター側は正常に動作しているのに、スレーブ側がランしていません。 まだ、何か変更事項があるらしい。

Microchip.dsPIC33CH-MP_DFP.1.10.223.atpackというファイルをMicrochip(US)のホームページで見つけ、これを下記のようにインストールしたら、スレーブも動き出しました。

Atpack_install ターゲットファイルは、USBメモリーの中にダウンロードしてありましたので、そのファイルを選択するだけです。

Atpack_tgt

 後で判ったのですが、MPLAB Xのupdateリストを調べたら、このatpackもリストの中に含まれていました。 updateファイルは自動的にインストールされる事はなく、MPLAB Xのバージョンアップ時、それまでのatpackはアップデートされるみたい。 このatpackがリリースされたのが2021年11月3日だったようで、マニュアルによるインストールが必要なようです。 このatpackをインストールした後、プロジェクトのプロパティを開き、以下のようにPacksをセレクトすると、このupdateが適用されます。 MainもSecondも両方設定必要です。

After_atpack

これらの設定で、一応スレーブは起動できたのですが、IQミキサーを構成して、IとQの信号を引き算して、DACへ通すと、出力はゼロになります。 これは、IQ信号に90度の位相差が無い事を意味し、以前と同じ状態で、正常に動作していない事を示しています。 さらに、この対応する前はFIRフィルターは機能していましたが、今回の設定でハングアップするようになりました。 これらのソースプログラムは、すべてdsPIC33FJ用として作成され、このdsPIC上では正常に動作し、トランシーバーを実用しているものですが、このdsPIC33CH上では正常に動かないようです。

MicrochipのXC16のバージョン履歴を見ますと、V1.61というのが存在し、これはV1.60のバグフィックス版と説明されていますので、XC16 V1.70またはdsPIC33CHのファームウェアにバグがあるのかも知れません。 しばらく、このICを使うのは延期した方が良さそうです。

一方、かろうじてミキシング動作だけはOKのIQミキサーですが、DACからの出力をオシロで観察すると、無歪で取り出せるレベルは0.18Vppくらいで、スプリアスレベルが-50dBくらいしか確保できません。 実際の送信機の基準レベルは、この限界値より3dBくらい低い値に設定し、これ以上レベルが上がらないようにALCをかけますので、スプリアスは良くても-47dBくらいにしかならず、不適合となります。 これは、12bitのDACによる基本性能によるもので、16bit DACを備えたdsPIC33FJより24dBも悪化しており、受信機に利用出来ても、送信機には使えないという事がはっきりしました。

バンドスコープから始めたこのマイコンの検討でしたが、最終的に、400KHzくらいのキャリアをもつSSBジェネレーターを目標としていましたので、これできっぱりと諦めがつきました。 このマイコンによるSDRの開発は中止する事にします。

 

INDEXに戻る