2020年11月3日火曜日

おしゃべり時計withUSB開発日誌(12)、SOSC VT-200-Fクリスタルの所定数について。

 おしゃべり時計withUSBは、(株)秋月電子通商で売っている VT-200-Fクリスタルを RTCC用の発振子として使っています。 許容偏差±20ppm(±1.7秒/1日)の誤差で¥30-(20201028)のリーズナブルなクリスタルなのですが、PICで使っているとたまに壊れる事があります。

VT-200-Fの仕様を確認すると、水晶励振レベル(DL)が0.1μW、最大1μWと非常に低いドライブレベルです。その為PICに直接接続するとドライブレベル(DL)が大きすぎて壊れてしまうようです。



このドライブレベルを下げるためには、SOSCOピンに直列に抵抗(Rd)を入れて調整する必要があります。 この直列抵抗の値の選定については、PIC32MXのセカンダリオシレータ (SOSC) 水晶振動子回路の設計における注意点(AN2351)に詳しく書かれています。 この資料に記載がありますがPIC32MXのSOSCを確実に発信させる為には、A点の電圧が400mV必要です。 AN2351の資料では、調整時のRdのポテンションメータとオシロスコーププローブの影響を考慮して600~900mVのレンジ内になるよう、直列抵抗Rdの値を調整するように記載されています。 また残念ながらこの方法で求めた直列抵抗Rdの値が、VT-200-Fの仕様を満たす最大励振レベルとなるかどうかは分かりません。 


またAN2351の資料に、C1,C2の求め方も記載されていますが、コンデンサの値をいくつか試して最も安定している値にするよう記載されています。 実際の所C1,C2の値が小さくなれると周波数が高くなり、C1,C2の値が大きくなると周波数が低くなります。 またC1,C2の値が小さいと発信が不安定になり、C1,C2の値が大きいと発信が安定します。

手持ちのVT-200-Fとコンデンサで調べたところ、15pFで+10ppmほど周波数が高くなり、33pFで-10ppmほど周波数が低くなるようです。その為おしゃべり時計withUSBではC1,C2を22pFとしました。 これについても水晶振動子やコンデンサの個々の状態によって変動するものであり目安でしかありません。


さて直列抵抗の値についてですが、PIC32MX250F128B,VT-200-F,C1/C2=22pf,気温20°C,電源電圧3.3Vでいくつか試した所、以下ようになりました。
  • 2.6MΩ - 100mV
  • 1.6MΩ - 200mV
  • 1.0MΩ - 300mV
  • 620KΩ - 400mV
  • 510KΩ - 480mV

2.6MΩ - 100mV

1.6MΩ - 200mV

1.0MΩ - 300mV

620KΩ - 400mV
 
510KΩ - 480mV



注意点としては、A点の電圧が下がると水晶発振が始まるまでの時間が延びます。計測では300mVで約2秒、200mVで約8秒かかり、100mV以下では数十秒たっても起動しなくなりました。


1.0MΩ - 300mV




1.6MΩ - 200mV



以上を踏まえ、おしゃべり時計withUSBでは、C1,C2=22pF Rd=510KΩ としました。





水晶のドライブレベルを確認するため水晶振動子に流れるドライブ電流を計るには、トランジスタ技術2020年11月号に表面実装typeの水晶振動子を使った発信回路の設計&測定技術の記事に詳しく書かれています。 しかしながら自分は電流プローブもスペクトラムアナライザも持っていない為、記事の方法では残念ながらドライブ電流を計る事ができませんでした。


※20210723追記

新しいPICでは、RTCCの設定がLow Power Modeがデフォルトとなっており、この場合上記の設定ではRTCCが動かない現象に遭遇しました。RTCCがLow Power Modeの場合は、C1,C2=15pF Rd=0Ωとしています。

⇒https://planetxgear.blogspot.com/2021/05/vfdld8035eclock-15.html


参考文献




2020年9月22日火曜日

おしゃべり時計withUSB開発日誌(11)、Sleep時の消費電流。

 1.Sleep時の消費電流、またはバックアップコンデンサの有効時間。

以前Sleep時の消費電流が1mA程度であったが、これの原因の一つがCDSで明るさを検知してPIC32MXのコンパレータへの入力回路にあった。

問題の回路は+5VをCDSと100KΩの抵抗で分圧してコンパレータの入力としていた。 周囲が明るいとき、CDSの抵抗値は数10KΩ以下となり、コンパレータの入力がCPUの電源電圧+3.3V以上となり、漏れ電流が流れてしまっていたようである。


以前の回路


この部分を下記のように追加で100KΩの抵抗を入れる事により、コンパレータへの入力を+2.5V以下にすることにより、Sleep時の消費電流を600uA程度に抑える事ができた。


修正した回路

CMP1, CMP2両方とも100KΩづつ追加した理由は、CMP1,2のリファレンス電圧が一つしか指定できす閾値を揃える為である。 またCMP1に100KΩを3っつ直列に並べたのは、抵抗の在庫を増やしたくなかったのと、同じロット内の抵抗ならばそれぞれの誤差の偏りが同様なので、1/3の分割がより誤差が少なくなる為としておく。

その他あちこち弄ってSLEEP時の消費電流を下げようと悪戦苦闘したのだが、結局520μAまでしか下がらなかった。

20200922(+20hぐらい?)



2020年9月17日木曜日

おしゃべり時計withUSB開発日誌(10)、チャイム時間チェックのロジック、RTCCキャリブレーションロジックの再検討。

 4.チャイムが時々ならなくなる。チャイム時間チェックロジックの再検討。

これは、次のチャイム時間を取得するロジックvRTCC_getNextChimeTimeもしくはvRTCC_TimeCheckが動かず、pbFFF_get_nextTimeで次の時間を取得できていないのだろう。 

各保持している時間、bNextHHMM、bNextHHMM、bCurrentHHMM は文字列型だが、割り込み処理中では、xsprintf関数が上手く動かない為、1分ごとの割り込みでは、チャイム時間やアラーム時間のチェックが出来ずこの割り込み処理の修正が必要である。 なので1分毎の割り込み処理中に数字⇒文字列変換の必要がないように、これらの変数を文字列からinteger型に替える。 

※問題の関数=>xsprintf(bCurrentHHMM, "%02d%02d", currentTime.tm_hour, currentTime.tm_min);


各保持している時間、bNextHHMM、bNextHHMM、bCurrentHHMMをまず数字型に変更する。合わせて、RTCCobjをstruct型で定義してそこに変数を全て入れる。

そもそも、これらbNextHHMM、bNextHHMM、bCurrentHHMMの変数が文字列型を使っていた理由は、その文字列でchime.txtの一覧をサーチする為だったので、このサーチ関数pbFFF_get_nextTimeを使う時だけ時間を数値⇒文字列変換して対応する事にする。 

サーチ関数pbFFF_get_nextTimeの返り値も文字列な為、文字列⇒数値に変換する必要がある。 これには当初 xatoi関数を使っていたのだが、思うように変換できない場合があり1時間ほど悩んだ挙句、atoi関数を使う事にし解決した。 (※xatoiには変換エラー時のリターンがあったため当初こちらを利用していた。)



5.RTCCキャリブレーションロジックの再検討

RTCCの進み遅れ具合を設定する、キャリブレーション値は時刻を合わせるごとに512⇒128⇒64⇒32⇒16⇒8⇒4⇒2⇒1⇒1、、と半分づつ、最後は1づつ変化するようにしている。 しかしなが最初の時刻設定を間違えてしまった場合、その間違え分を取り返すまでに相当数の回数を時刻合わせいなければならなくなる。 そこでキャリブレーション値の変化を1/2ではなく2/3づつとなるように修正する。

また、時計用に使用しているクリスタルVT200の誤差が±20ppmとなっている。

PIC32MXのRTCCのキャリブレーションの範囲が±260ppmであり、これを10ビット(±512)で設定可能であるため、20ppm = 20/260*512 = 39.38 となる。 3で割り切れる42をスタートとして、42⇒28⇒19⇒13⇒9⇒6⇒4⇒3⇒2⇒1、、と変化するように修正する。

20200913(+3.0h)


2020年9月14日月曜日

おしゃべり時計withUSB開発日誌(9)、現在の課題

 おおむね対応するべき課題は以下の通り。

1.Sleep時の消費電流。

2.Sleepから復帰した時のボタンの効き。

3.曜日の実装。

4.チャイムが時々ならなくなる。

5.RTCCキャリブレーションロジックの再検討

6.スイッチメニューで、日付・時間設定で発声しない。



1.Sleep時の消費電流。

今の所Sleep時に1mAを消費しているが、100μA程度には抑えたい。


2.Sleepから復帰した時のボタンの効き。

ボタンを押してSleepから復帰しても、USBメモリのエニュメレーションが終わらないと、メニュー動作に入らない。 Sleep起動時の押されたボタンでメニュー動作に入るようにしたい。


3.曜日の実装。

今まで”何曜日”と発声していなかったが、これを実装する。


4.チャイムが時々ならなくなる。

これは、次のチャイム時間を取得するロジックvRTCC_getNextChimeTimeもしくはvRTCC_TimeCheckが的確に動いて、pbFFF_get_nextTimeで次の時間を取得できていないのだろう。 

各保持している時間、bNextHHMM、bNextHHMM、bCurrentHHMM は文字列型だが、割り込み処理中では、xsprintf関数が上手く動かない為、これらの変数を文字列からinteger型に替える必要がある。 

※問題の関数=>xsprintf(bCurrentHHMM, "%02d%02d", currentTime.tm_hour, currentTime.tm_min);


5.RTCCキャリブレーションロジックの再検討

RTCCの進み遅れ具合を設定する、キャリブレーション値は時刻を合わせるごとに512⇒128⇒64⇒32⇒16⇒8⇒4⇒2⇒1⇒1、、と半分づつ、最後は1づつ変化するようにしている。 しかしなが最初の時刻設定を間違えてしまった場合、その間違え分を取り返すまでに相当数の回数を時刻合わせいなければならなくなる。 そこでキャリブレーション値の変化を1/2ではなく2/3づつとなるように修正する。


6.スイッチメニューで日付・時間設定している時に、設定日付・時間を発声しない。

これは、設定日付・時間の値が変更された事が、発声部の検知対象外となっている為と思われるので、該当部分のコーディングを追加する。

20200912(+1.0h)



2020年9月1日火曜日

おしゃべり時計withUSB開発日誌(8)、USBメモリ エニュメレーションの遅延

時計回りの機能を、色々とデバッグ中。
省電力の為、通常はPICはSleepしてUSBの電源も落としておいて、スイッチが押されたら、もしくは1分経過したら、SLEEPから復帰しUSBメモリの電源を入れて、時間を喋る事になる。

しかしながら、USBメモリは電源を入れたら直ぐに使えるわけではなく、アドレスを割り振るなどのエニュメレーションをして、Configuredのステータスにならないとメモリの内容を読み出せない。 これに1~2秒、USBメモリによっては数秒かかるのだ。

なので、USBのエニュメレーションが終わってから、USBメモリから音声データを読み出して音声を再生する必要がある。 そうしないとエラーとなる。悪くすれば処理が帰ってこず、プログラムが暴走するなんて事もある。 つまりUSBメモリのステータスを見て処理を進めていかなければならず、地味にめんどくさかったりする。

しかしながらここは肝の処理なので、注意してデバッグしていく必要がある。

20200829(+4.0)


おしゃべり時計のメインの機能にチャイムがある。 これはchime.txtに列記した時間になると”何時何分です。”と時間を喋る機能である。 これ自体は、以前のプログラムを踏まえて問題なく実装する事が出来た。

おしゃべり時計のもう一つのメインの機能が音楽ファイルを順番に再生していく機能がある。これも順番に再生するだけならば問題なく実装する事が出来た。


音楽を順番に再生しているときに、チャイムの時間が来たらどうするかというと、一旦音楽を中断して時間を発話させたい。だって、時計なのであって、音楽の再生はおまけの機能なのだから。 これを実現する為の処理の流れは下記のようになる。

1.音楽を再生中

2.チャイム発生時間の到来を検知。

3.再生中の音楽をストップ

4.chime.txtのファイルをサーチして該当した時間の音声データファイル名を取得する。

5.時間の音声データファイルを再生する。※複数ある場合、複数回再生する。

5.次のチャイムの時間を、chime.txtをサーチして取得する。

6.上記3.でストップした音楽をはじめから再生する。

といった具合になる。 今回作成している”おしゃべり時計withUSB”は、ファイルオブジェクトは一つしか実装していない。バッファを8Kbyteも使う為、メモリを圧迫してしまうからだ。

なので一つのファイルオブジェクトを使い回すことになる。上記1~6を実現するのに5つ以上のファイルをとっかえひっかえ読み出す必要がある。 これの切り替えがなかなか上手く出来ずに何日か悩みつつデバッグしていたが、本日ようやく何とかスムーズに切り替える事が出来るようになった。

まだまだ、スイッチメニューの切り替えが上手くいかなかったりするので、今しばらくはこのあたりのデバッグに時間がかかりそうである。

20200901(+8.0h)




2020年8月16日日曜日

おしゃべり時計withUSB開発日誌(7)、NVM

 残念ながらPIC32MXにはEEPROMが無いので、ちょっとしたパラメータを格納する為にプログラムメモリに書き込む事にする。その為に使う機能がNVMだ。今回初めて使うことになるのでちょっとテストしてみた。 


参考資料は下記となる。

  1. 組み込みエンジニア向け MPLAB® XC32 ユーザガイド
  2. セクション 5. フラッシュ プログラミング


NVMは迂闊にプログラムエリアを書き換え出来ないように、フラグを設定したりキーワードを設定したりといろいろ手順が複雑で、またPIC32MX250の場合、消去の単位が1KBytes、書き込む単位が128bytesだったりするのでちょっと面倒くさい。

しかしながら面倒な書き込み手順についてはMCCがコードを出力してくれるのでこれを使えば大丈夫だ。


MCCを使ったNVMの設定は下記の通り。Media Start Addressはデフォルトのままとし、割り込みもチェックしない。


レジスタの設定は、上記1.の資料を参考に赤枠の部分を修正した。



次にデータを書き込むプログラムエリアだが、仮想メモリKSEG0の0x9D000000~0x9D01FFFFに1KBytesを確保しなければならない。当初0x9D01E000あたりを使いたかったのだが、アセンブルリストを確認した所、何やら別の事に使っているようだったので、0x9D018000あたりを使うことにした。


これについて、下記のようにコーディングしてみた。 

-------------------------------------------------------------------------------------------

volatile const BYTE __attribute__((address(0x9D000000 + 0x18000))) NVM_ProgramPage[1024] = {

    "aaa\n"   

};

-------------------------------------------------------------------------------------------

+0x18000についてだが、プログラムが0x14624だったので、そのちょっと後ろのキリの良いあたりにしている。

またMVN_ProgramPageの変数についてだが、当初typedefで型を作って割り当てたのだが、voidのポインターに型変換が出来なかったので、実際にコーディングする時にもう一工夫必要だ。


それで初めて使う機能はやはり躓く部分があるもので、下記のようなコーディングをして試したのだがなぜか上手く動かない。vVNM_Test1, vVNM_Test2 をそれぞれ動かせば、NVM_ProgramPageのエリアが更新されるはずが更新されないのだ。


さんざん悩んだ挙句にはたと思いついて修正したコーディングが下記の通り。


つまり、Program area⇒Program area では上手く機能しないという事。ちょっとテストするつもりの迂闊なコーディングではまってしまい、これで半日つぶしました。


最終的にテストのプログラムは下記の通り。 

-------------------------------------------------------------------------------------------

volatile const BYTE __attribute__((address(0x9D000000 + 0x18000))) NVM_ProgramPage[1024] = {

    "aaa\n"   

};


//******************************************************************************

/**

 * @brief   NVM TEST .

 * @param[in,out]   

 * @return          

 * @details

 *

 */


void vNVM_Test0 (

)

{

    // Erase second page of Program Flash

    NVM_ErasePage((void*)NVM_ProgramPage);

}


void vNVM_Test1 (

)

{

    BYTE bMsg_NVM1[128] = {

        "Hello World!\r\n"   

    };

    // Erase second page of Program Flash

    NVM_ErasePage((void*)NVM_ProgramPage);

    // Write 128 words starting at Row Address NVM_ProgramPage

    NVM_WriteRow((void*)NVM_ProgramPage, (void*)bMsg_NVM1);

}


void vNVM_Test2 (

)

{

    BYTE bMsg_NVM2[128] = {

        "Check NVM feature\r\n"   

    };

    // Erase second page of Program Flash

    NVM_ErasePage((void*)NVM_ProgramPage);

    // Write 128 words starting at Row Address NVM_ProgramPage

    NVM_WriteRow((void*)NVM_ProgramPage, (void*)bMsg_NVM2);

}

-------------------------------------------------------------------------------------------


20200814(+6.0h)



2020年8月14日金曜日

おしゃべり時計withUSB開発日誌(6)、printfで2進数表示。

 RTCCのキャリブレーションの設定についてコーディングしたので、デバッグでコンソールに値を2進数で表示したい。

しかしながら、c言語のprintfには、2進数の出力フォーマット指定が無い。

そこでネットでいろいろ調べて下記のよにコーディングを追加して2進数で表示するようにした。

---------------------------------------------------------------------------------------------

void printb(unsigned int val) 

{

    unsigned int mask = (int)1 << (sizeof(int) * 8 - 1);

    do 

    {

        if ( val & mask ){

            xputs("1");

        }

        else{

            xputs("0");

      }

    }

    while (mask >>= 1);

  

}


void putb(unsigned int v) 

{

  xputs("0b"), printb(v), xputs("\n");

}

---------------------------------------------------------------------------------------------


これで、次のようにコーディングすれば、下記のように出力される。
xputs("Cal Value = "); 
putb(RTCCONbits.CAL);



20200730(+2.0)




UTC7642_AMラジオ Ver.2.0 (2Tr+1IC) スーパーヘテロダイン(1)

 UTC7642を使用したヘテロダイン方式のAMラジオをブレッドボードで試しています。 アンテナとバリコンは、 電子ウサギさんの記事 を参考にスーパー用にしています。 Q2(2SC1815)は他励式の局部発信(OSC)で放送周波数+455kHzの信号を作成し、Q1(2SC1815...