アナログシンセの VCO ブロック (50) -- ATtiny13 版プログラム (3)

ATtiny13 を含む多くの AVR マイコンと、ATtiny10 とでは、入力ポートのプルアップの設定に関する設定方法に差があり、それに対応して ATtiny13 用プログラムではディスチャージ用の 3 ステート出力操作を変更する必要があります。
また、ATtiny10 用のプログラムの時から気になっていた「誤動作」の原因を特定し、解決することができました。
まず、ATtiny13 を含む多くの AVR マイコンでは、入力ポートのプルアップの設定に独立したレジスタを使用せず、出力ポート (PORTxn) に設定されている値が「1」 であればプルアップあり、「0」であればプルアップなし (ハイインピーダンス) という仕様になっています。
PUD ビットにより、全ポートの全ピットのプルアップを一律に禁止することはできますが、個々のポート/ビットごとの設定はできません。
データ方向レジスタ (DDxn) とポート出力レジスタ (PORTxn) とに設定される値によって決まるポートの状態の表を下に示します。

PORTxn = 0 PORTxn = 1
DDxn = 0 Hi-Z pullup
DDxn = 1 "0" (Lo-Z) "1" (Lo-Z)

GND 側に対する放電、つまり、低インピーダンスの「0」とハイインピーダンス状態を切り換える場合は、表の左側の列に相当し、ポート出力値を「0」に保ったままデータ方向レジスタ (DDxn) の設定で入力/出力を切り換えれば実現できます。
問題は VCC 側に対する放電、つまり、低インピーダンスの「1」とハイインピーダンス状態の切り換えです。
上の表で行方向、列方向は、それぞれ別のレジスタのビットの操作なので、表の左上の「Hi-Z」から右下の「1」までの斜め方向の移動を、一回の操作で到達することはできません。
斜め方向の移動は、左右方向の移動一回と、上下方向の移動一回を組み合わせて、計 2 回の操作で実現する必要があります。
つまり、「Hi-Z」から「1」までの斜め方向の移動は、

  • Hi-Z → pullup → "1" (Lo-Z)
  • Hi-Z → "0" (Lo-Z) → "1" (Lo-Z)

のどちらかの方法をとる必要があります。
目的の低インピーダンス「1」を出力する前に、たとえ 1 命令実行の期間とはいえ低インピーダンスの「0」が出力されるのは好ましくないので、ATtiny13 用プログラムでは

  • Hi-Z → pullup → "1" (Lo-Z)

のシーケンスで行うようにしています。
次は、ATtiny10 用のプログラムの時から気になっていた「誤動作」の問題です。
リワインド式 VCO の構成での (正常動作時の) 波形写真を下に示します。 リワインド・パルス幅は約 25 μs に設定してあります。

上側のトレースが SYNC パルス出力で、「L」になっている期間「リワインド」されます。
下側のトレースが積分器出力で見た、のこぎり波出力波形です。
低い周波数で発振させているので、リワインド期間ではない部分の波形がほぼ水平線に見えています。
これが「誤動作」の状態では下の写真のようになります。

本来、一発だけ出るべきリワインド・パルスが連続して出力されています。
のこぎり波波形は、いったんリワインドから回復した直後に、またリワインドされるので、「段」がついたような形になっています。
2 回目のリワインドの途中で GND レベルまで到達し、それ以降は本来は電圧が下がり続けるはずですが負電圧を出力できないので、その時点から GND レベルにクランプされたままとなっています。
この誤動作は、周波数の低い場合に発生する確率が大きくなり、下の写真のような高い周波数に対しては、ほとんど発生しません。

この原因として、

  • コンパレータにヒステリシスを設定できないために、
  • 周波数が低い、つまり、積分器出力の変化がゆるやかな場合に、
  • コンパレータでしきい値を超えてコンパレータ出力が反転し、
  • 本来のコンパレータ割り込みが発生して、
  • プログラムの制御が割り込みルーチンに移り、
  • 割り込みフラグがハードウェア的にクリアされたあと、
  • 入力ノイズなどの影響でコンパレータ出力がバタつき、
  • 余分なコンパレータ割り込みが発生し、
  • 割り込みサービス・ルーチンの実行が終了したあとに、
  • 再びコンパレータ割り込みサービス・ルーチンが起動される

ものと考えました。
AVR の内蔵コンパレータは、出力をハード的にピン出力することができないので、コンパレータ出力信号がバタつくのを外部から直接観察することはできません。
ソフトウェアでコンパレータ・レジスタACO (Analog Comparator Output) ビットを読み取り、ポートに出力するようにしてみましたが、7 クロックに 1 回のレートでしかサンプリングできず、コンパレータ出力が「バタつく」様子は観測できませんでした。
それでも、ACI (Analog Comparator Interrupt flag) をポートに出力してみると、誤動作する場合に「余計」なコンパレータ割り込みが発生していることは確認できました。
この誤動作の対策としては、アナログ・コンパレータ割り込みサービス・ルーチンの最後の部分に ACI をクリアする命令を追加しました。
リセット/リワインド・パルスの時間幅は割り込みサービス・ルーチン内でソフトウェア的なディレイで実現しているので、割り込みサービス・ルーチンの終わりに達するころには、すでにのこぎり波のリセット/リワインドは終了し、コンパレータ出力がバタつく可能性はありません。
したがって、もしコンパレータ出力のバタつきにより、余計なコンパレータ割り込みが発生していても、ACI をクリアする命令のおかげで割り込みルーチンの再起動は防止されます。