前回までに完成させた、可変周波数クロック発振器を更に一歩先へ進めるため、SSCG機能を追加してみたいと思います。
本HPでは、何度か登場しています。以下記事がまとまっていそうです。
「#9-7 内蔵RC発振器を校正する」より、こちらを参照。
簡単に説明しておくと、特定の周波数に於ける消費電力(電流)が増えると、その周波数の電波雑音が発生するのです。その雑音をEMI(Electro Magnetic Interference)ノイズと呼びます。同期設計された論理回路(LSI)は、クロックの立ち上がりエッジ付近で大半の電力(電流)が消費されるので、クロック周波数に相当するEMIノイズが大きくなる傾向があります。
電子機器にはEMIノイズを規定する規格があって、EMIノイズを低く抑えるために様々な技術が使われます。その一つが、SSCG(Spread Spectrum Clock Generator)です。LSIを駆動するクロック周波数を、目標周波数を中心として上下に分散させる技術です。
何が嬉しいか?と言うと、下図で説明します。

クロック周波数を上下に幅広く分散させることによって、目標周波数付近に集中していた消費電力(電流)が分散して、EMIノイズのピークが低下します。
※実際のSSCGでは、分散後の分布が水色の三角形ではなく、長方形に近いのではないか?と推測します。その方が、更にピークを低下できますから。上図は原理を解説するための模式図だとご理解ください。
SSCGには、短所もあります。それは、通信規格やモータ駆動用のPWM等で顕現します。クロック周波数が変動する事で、通信を失敗したり、モータが円滑に回らなくなったりするのです。
同期設計に於ける神様とも言うべきクロックが変動する事で、正確な実時間の計測も困難となります。
LSI内部で、SSCGが適用されたブロック(CPU等)と、非適用のブロック(通信ユニットや、モータ制御ユニット等)が混在する場合、2つのブロック間の信号線は非同期であることを前提として設計しなければなりません。これは、論理設計を手間取らせる大きな原因となります。慣れない設計者が迂闊に手を出すと、バグの温床となることもあります。
こうして見ると、マイコンなどで作る組み込み制御用途では、SSCGによる長所より短所の方が大きくて、中々使いこなすのは難しそうです。
周波数の変動アルゴリズムについて考察を進めるため、身近で適用可能なSSCGを参考にしようと思います。最近使ったSSCGと言えば、Cmod A7ボードのFPGA(Xilinx社製)に搭載されたSSCG(PLLマクロ)がありました。こちらの記事を参照して見てください。
VivadoのPLLマクロ設定ウインドウを以下図に示します。

上のウインドウで、
インターネットで調べてみたところ、一般的なSSCGの変動幅は、目標周波数の0.2〜数[%]程度らしいと判りました。
以上で、一般的なSSCGに関する調査が終了しました。次節から具体的にSSCGを設計する検討に入ります。
基本方針としては、ATtiny85のソフトウェアにより、OSCCALレジスタを定期的に書き換える事で内蔵RC発振器の周波数を変動させ、SSCG機能を実現しようと考えています。
ATtiny85を使って作った可変周波数クロック発振器に、SSCG機能を追加する検討を進めて行きます。
まず、目標周波数に対して、どのような形式で周波数を変動させるか検討して見ましょう。
発振器などのアナログ電子回路が、周囲からの影響を受けて特性変動する現象は一般に正規分布になります。ところがSSCGを作る事に関して言うと、周波数分布が正規分布になることは好ましくありません。正規分布では、分布の中央付近にエネルギが集中してしまう事が主な理由です。
EMIノイズ低下を目的とするSSCGの場合、周波数分布は広く満遍なく分散してくれた方が嬉しいのです。

今回追加するSSCG機能については、上図の様に鋸歯状(直線的)に周波数を変化させることにしました。
※論文などによると、直線的に変化させるより、少し歪ませた方が良い結果を得られるみたいです。追求したい方は、各自調査願います。
変動幅(Frequency deviation)は、一般に0.2〜数[%]だと言う事なので、これに従うと、ATtiny85内蔵RC発振器の周波数8MHzに対しては、16(0.2%)〜160(2%)[kHz]に相当します。
そもそも、周波数−OSCCAL変換表の解像度が1MHz÷16=62.5kHzでしたので、変動幅を160kHzと仮定すると、2〜3[タップ]程に相当します。これでは変動幅が小さすぎます。
ここで一考:
UARTが通信を失敗しない範囲と言う条件なら、最大12.8タップ(=800kHz÷62.5kHz)程度の変動幅が確保できると判りました。
※8N1形式よりも長いフレームである9E2形式や9O2形式だと、12[ビット/フレーム]なので、K<<1.042(変動幅±4.2%)となって、許容範囲が狭まる事に留意のこと。
変動周期(Modulation period)は、FPGAのSSCGでは25〜250[kHz]でした。最低の25kHzでも周期40μsですから、この変動周期は速すぎます。
ATtiny85のソフトウェアによってSSCGを実現しようとしているので、変動周期をもっと長くしなければ実現不可能です。そこで、「こうあるべき」から開始するのではなく、どの程度の周期が実現できるのか、と言う視点から検討を進めます。
基本方針として、定期的にOSCCALレジスタを書き換える必要があります。定期的な処理は割り込みを使うのが基本です。
定期的割り込みに使用可能なATtiny85のタイマは2本です。
と言う事で、タイマに空きがありませんでした。ガックシ……😔。
と、思ったら、Arduino IDEのメニュー項目の中に、「millis()/micros():Enabled」という項目が有る事を思い出しました(下図)。

この項目で「Disabled」を選択すると、TC0タイマをユーザリソースとして使用可能になります。代償として、millis()関数とmicros()関数は使えなくなりますが……。
※ちなみに、delay()関数は使えました。ただし、タイマではなくCPU命令の実行時間で遅延させる方式に実装が切り替わる(#ifdef)記述になっていました。
TC0の割り込みISR内でOSCCALレジスタを書き換え、こちらの図の様な周波数変動を起こすことにしました。
予備実験として、ISR内の処理時間を計測しながら、なるべくISR内の処理を最小化して、割り込み負荷率を下げたのですが、それでも、割り込み周期256サイクルが「やっと」な感じでした。どうも、TC0割り込み以外にも割り込みが発生(※)していて、そちらの処理が終わるまでTC0割り込みが保留される場合がある様です。
※恐らく、Wireライブラリの割り込みだと想像していますが、詳細は不明です。
fCPU=8MHzだと、256サイクル÷fCPU=32μsが割り込み周期です。割り込み周期(256サイクル)を固定して、その整数倍(ユーザが設定可能)をSSCGの変動周期とします。
可変周波数クロック発振器のI2C通信で設定可能なI/OレジスタへSSCG関連のレジスタを追加します。以下に、追加するレジスタの目標仕様を示します。
追加レジスタ目標仕様:
こちらのI/Oレジスタ仕様を更新しておきました。併せてご確認ください。
フゥ……。一つ壁を打ち壊したところで、お時間となりました。次回、完成させます。


