ロジックICとかで遊ぶときのチャタリングの話
みなさんお元気ですか?おいらは長距離通勤になって寝不足気味なのと電車の中で暇です。という訳で今回はスマホで適当にTips的な記事を書いてみた。ロジックICとかで遊ぶときのチャタリングの話。
そういや意外とチャタリングの波形ってまじまじと見た事がある人は少ない気がする。*1けど波形を録るのめんどくさいので初っ端から手書きでお茶をにごす。
こんな感じで数msもかけてONOFFを繰り返す波形*2を、例えばカウンタのクロックに入れると、当然カウンタ君はこの細いパルスもちゃんと数えてくれちゃう。
なんていうか「回路は思った通りには動かない。作った通りに動く。」な訳で、こういうのを知らないと例えば「スイッチが押された回数を数える回路」を作ろうと思いつつ「チャタリングも含めてONOFFした回数を数える回路」を作っちゃったりしがちな気がする。
前置きが長くなった。以下考えられる対策。
1.RCローパスフィルタとシュミットトリガインバータを入れる
よく初心者向けの本とかに出てくる気がする。チャタリングによるパルスを、RとCのローパスフィルタで小さくして、シュミットトリガのヒステリシス幅以下にすれば良い。真面目に考えるとこの条件から時定数が求められそう。まあ大抵いちいち真面目に設計しないで適当に長くしておく。定番。
2.ワンショットパルスに整形する
みんな大好き555とか単安定マルチバイブレータ*3とかで、トリガが入ったら一定期間Tのパルスを出すようにする。パルスの出力いくら入力がチャタリングしようと、出力には出てこないので安心。回路組むのちょっとめんどくさいのがこの方式の欠点だけど、利点としてはちょっといじると無安定マルチバイブレータにできるので、簡単にステップ実行と連続実行を切替できる。楽しい。
3.RS-FFをパタパタさせる
余ったゲートでなんとかしたいときとか、立ち上がりと立ち下がりで別な動作をするマニアックな回路をステップ実行させたいときとかは、NAND2つでRS-FFを組むといいと思う。あと何かの処理を始めるときにセットして、その処理が終わったらリセットするようにしとくと、ある処理の最中はその処理を再度呼ばないようにできる。例えるならファミレスで呼び鈴のボタンを素早く100連打しても、(2打目以降は無視されて)店員さんは1人しか来なくて、その店員さんが対応済みボタンを押すと、やっともう一度呼べるようになるみたいな。......何の話だっけ?
4.D-FFで打ち抜く
常に見てるからジタバタが気になる訳で決まったタイミングでしか見なければ0か1かはっきりする訳だ。例えば1Hzのクロックを入れたD-FFの入力にスイッチをつなげば出力は1秒毎にしか変化しない。え?その決まったタイミングで運悪く0と1の遷移中とかだったらどうなるのかって?君のような勘の良いガキは......嫌いじゃないよ。メタステーブルっていって真面目にやるなら気にしないといけない。*4
中身も無駄に長くなった。この記事は電車の中で適当に書いてみた。こんなのでも読みたいと思った変な人はいいねを押してくれると、この記事を書いた変な人がまた何か書くかもしれない。
FPGAで遊んでみた
みなさんお元気ですか?おいらは冬の寒さに負けて引きこもりがちです*1*2。引きこもると電子工作したくなるよね!という訳でちょっと前にFPGAで遊んでみたのを忘備録として書く*3。
回路とか
写真と回路図。回路図は書かずに作っちゃった*4ので実物を見て起こした。
使ったFPGAは秋月に600円で売ってるこれ↓。安いし外付け部品要らないし3.3V単電源で良いし*5手軽に始めるのに良いと思う。
書込みはJTAGを使うけど秋月のこれ↓とかで書き込める*6。FTDIのICの内のMPSSEってのに対応してるやつならJTAGが出せる*7ので行けるっぽい。
ちょっとだけ回路の工夫した点を書いておく。まずMachXO2に5Vをぶち込んじゃうのはかわいそうなので、AE-FT2232のVCCIOAに3.3Vを供給しておいた*8。
あとプルアップ/プルダウン抵抗は、MachXO2の中のデフォ設定と逆に引っ張らないといけないやつもあるらしくて、めんどいので全部2.2kΩと十分小さくした*9。
自分の場合はこれで普通に書き込めたので回路はこれで行くことにした。
ソフトとか
ここにインストールから書込みまで丁寧な解説があったので参考にした*10。
遊んでみる
とりあえず Hello World としてカウンタを書いてみた*11。動画*12とブロック図とソースコード。
わーい!FPGAでカウンタできた! pic.twitter.com/xffruaXSUv
— TEFSOM (@Si_SJ_MOSFET) 2020年11月9日
module Counter( input wire CLK, input wire RST, output wire[6:0] Qout ); reg[31:0] Count; always@(posedge RST, posedge CLK) begin if(RST) Count <= 32'h00000000; else Count <= Count + 32'h00000001; end //assign Qout[6:0] = Count[6:0]; //for test bench assign Qout[6:0] = Count[31:25]; //for blinking LEDs endmodule module top( input wire RST, output wire CLK, output wire[6:0] Qout ); defparam OSCH_1.NOM_FREQ = "133.00"; OSCH OSCH_1(1'b0,CLK,); Counter Counter_1(CLK,RST,Qout); endmodule
シミュとか
ところでHDLといえばシミュレーションしつついじりたい気がするのでその方法をメモしておく*13。
1.テストベンチを用意する
まず適当に書いて保存する。
`timescale 1ns/1ps module top_tb; reg RST; //input wire CLK; //output wire[6:0] Qout; //output top top_1(RST,CLK,Qout); task reset; begin RST = 1'b0; #10; RST = 1'b1; #10; RST = 1'b0; end endtask initial begin reset; #10000000; $finish; end endmodule
でSynthrsisには関係無いけどProjectとしては一緒にしておきたいので、File → Add → Existing File... でInput Filesに追加して、右クリックしてPropertiesからInclude for Simulation に設定した*14。
2.シミュの設定をウィズさんにしてもらう
最初に書いたtopのモジュールには、クロックとしてOSCHっていうMachXO2特有のモジュールも使っていて、全体をシミュレーションするにはそれのシミュ用ライブラリとかもちゃんと読み込まないといけないので、一旦おとなしく設定用ウィザードを使う。
図の赤丸部分を押下 → Next → Project name を適当につけてNext → Next → Source Files: に、1.で保存したテストベンチを、add simulation source file(s) してNext → Simulation Top Module: がテストベンチのモジュール*15になってることを確認してNext → Finish、で以下のように波形が見れるはず。
あと毎回この設定をしないといけないのかよめんどいなと一瞬思ったけど、Script Files ってとこにspfっていうファイルができているので、それをダブルクリックしてSkip to End すれば良いっぽい。めでたし、めでたし。
これでとりあえず一通り遊べるようになった。ちょいちょい遊んで更新したい*16。以上!
*1:寒さ以外にも最近流行りのアレとかもあるし
*2:てか前回の記事見たら暑いとか書いてて草。半年も放置しちゃった。月一くらいで書けたらいいな。
*3:というよりもう忘れちゃったので自分用に思い出しつつメモっておく
*4:UEWで一本ずつ配線してくと回路図書かなくても作れちゃうけど、しばらくして脳内から回路図が揮発すると「なんだこのもじゃもじゃは?」ってなるので、良い子は面倒くさがらずに回路図書きましょう
*5:水晶振動子とかコンフィグ用メモリとか色々載っててIOとコアで電圧が違ってて1万円以上するガチ評価ボードとかLチカだけして積むには高すぎるし使い倒す腕もまだ無い
*6:お高い謎の純正書込み器とか要らないのは良い
*7:JTAG以外も色々出せるらしいのでその内何か作ってみたい
*8:AE-FT2232のVCCIOAの電圧設定ジャンパがデフォで5V供給になってるので抜くのをお忘れなく
*9:これが詳しくて参考になった。
Macnica, Lattice-XO2基板設計時資料:
https://www.macnica.co.jp/business/semiconductor/articles/XO2_BoardDesign_rev06.pdf
*10:自分も前から気になっていたけどソフトめんどそうと思ってたところでこの記事を見つけてとても助かりました
*11:しょぼくても自分で書いたのが動くと楽しい
*12:まだピンヘッダを生やす前だ
*13:適当に我流でやったのを思い出しつつ書いた
*14:デフォでInclude for Synthrsis and Simulation になってるのをSimulation に変更した
*15:1.のテストベンチだとtop_tb
*16:PWMとかエンコーダとか既に遊んだのでその内記事書くかも
ロジックICでPWMしてみた(その2)
みなさんお元気ですか?おいらは夏の暑さに負けて夏バテ気味です*1。さて、前回の続きで、今回は同期設計で遊んでみる。
同期設計
前回と同様の回路を同期設計ぽく考えるとこんな感じになる*2。上に前回の、下に今回の。大きな違いはというと、コンパレータの出力が正しい所以外でじたばたしたときに、上のはアウトだけど下のは次のクロックまでに落ち着いてくれさえすればOKって事*3。あとは上はカウンタをクリアするのに細いパルスを使うけど下は使わなくて済むとか。
ところで図1を見るとしれっとビット数が半分になってる。一般的に同じ回路をつくるなら非同期の方が無駄がないと言われている*4けどただダウングレードしただけじゃつまらないのでもうちょっと同期設計なりに考えてみる。
こんな風に比較値用と周期用のレジスタをおくと、マイコンの中に入っていそうなまともっぽい回路になる*5。動画と回路図*6を置いておく。
周期とDuty比を可変できるPWMモジュール作ってみた。 pic.twitter.com/Fmg0GHXbpa
— TEFSOM (@Si_SJ_MOSFET) 2020年8月30日
感想
以上!
*1:今年暑くない?気のせい?
*2:そもそも同期設計ってどういう定義?って聞かれると困るんだけどこの記事では全て共通クロックのFFと組合せ回路だけでできてるって事にしておく
*3:例えるなら「ちょっとでもふざけてるの見つかると怒られる会社」と「毎回のミーティングにちゃんと結果持ってけばあとは何しててもいい会社」みたいな?後者の方が気楽でいいよね
*4:あとは74シリーズ自体が非同期設計ぽいのが多いのもある
*5:実は最初に図2を考えてから間引いて図1を作ったんだけど
*6:個人的には図3の回路図がロジックICだけできれいなので同期設計の方が好き
*7:最近回路とかプログラムとか全体を脳内でオンメモリにできなくなってきていて悲しいし更にちょっと間が空くと脳内メモリどころか脳内HDDからも揮発してしまうのでちまちま設計するには自分用の設計資料的なものをちゃんと残しておかないとなと思う
ロジックICでPWMしてみた(その1)
ロジックICで遊ぼうシリーズ!ということで前回はSPIしたけど今回はPWM。え?マイコンでよくね?仰る通りなんだけどそれじゃあつまんないし、オペアンプとコンパレータでアナログなPWMをして遊んでるのはまあまあ見るけど、意外とデジタルなPWMを自作して遊んでるのはあんまり見ない気がするので遊んでみる。
構想
まずは設計というほどじゃなくて妄想の整理というかコンセプト決めみたいなのをする。ここがぶれると回路の森で迷子になるので気を付けたい。コンセプトは「なるべく簡単にPWM波形を出す」ということにする。そうすると三角波は面倒なので鋸波でいいや*1、とか、ビット幅は4か8でいいや*2、とか、周期設定レジスタは無くてもいいや*3、とかどんどん決まってくる。
図1みたいなイメージ図が書けたら具体的な設計に移れる。 デジタル回路の本を読むと、非同期設計と同期設計てのがあって、非同期設計は回路規模は小さくて済むけどヒゲ(ハザード)とかに気を付けるのがめんどいから、大規模な回路を作るなら同期設計だよね的な事が書いてある。折角?なので両方作って遊んでみる。
非同期設計
とりあえず図1を見ていると、適当にカウンタで緑のカウント値を作って、紫の出力を作るためにラッチを置いておいて、カウント値が0のときにラッチをセットして、カウント値と赤の比較値をコンパレータで比較しておいて等しくなったらラッチをリセットすれば(とりあえずは)良さそうだと分かる。
という訳で適当に使うIC達を選びつつ*4ざっくりしたブロック図(図2)を書いて、実際の回路図(図3)にする。
一見謎なNOT(4040のRSTの直前の)とRCのローパスフィルタ(LPF)が入っている理由を一応説明しておく*5。非同期設計が面倒な理由でもある。
まずLPFがなぜ入っているかというとヒゲ除去のため。ヒゲってのはどういうときに生えてくるかというと、例えば、バイナリカウンタみたいに一度に複数のbitが変化する値を入力を使ったり、コンパレータみたいにカルノー図で1の塊が全部陸続きになってない組み合わせ回路を使ったり、とか。バリバリに該当するので74HC688の出力にはたまにヒゲが生えることが予想されて、実際にヒゲが生えること*6と、このLPFで除毛できること*7は確認した*8*9。
あと4040のRSTの直前のNOTは先にSRラッチをセットして後から4040をクリアするための時間差を作るという目論見。これを無しにして4040のQ9を直接RSTにつなぐと、試してないけどもしかしたらラッチがセットされるより先に4040がリセットされて出力ラッチが永遠にセットされないかも。
という訳で実際に作って遊んだのを貼っておく*10。
わーい!ロジックICで8bitのPWMできた! pic.twitter.com/Kh7FI8Qtck
— TEFSOM (@Si_SJ_MOSFET) 2020年8月15日
長くなったので同期設計でも遊んだんだけど次の記事に。
*1:三角波にしたいならアップダウンカウンタとT-FFがあれば作れるので74HC191と74HC73とかでできる
*2:ほんとは16か32くらい欲しいけど実用する訳ではなくて遊ぶだけなので要らない
*3:これも周波数を変えるには要るけど遊びなら不要
*4:とりあえず手抜きでいいから8bitは欲しいなと思って入手性が良さげな中から選んだ
*5:そういやNOTとLPFを入れて動くことは確かめたけど入れないと誤動作することは確かめてないのでもしかしたら無くても動くかもしれない
*6:https://twitter.com/Si_SJ_MOSFET/status/1294618247950524416
*7:https://twitter.com/Si_SJ_MOSFET/status/1294619785397800960
*8:どちらのオシロ画像も確か数秒間の波形を重ね書きしてて、最初は何か所か10nsくらいのヒゲが生えて戻る所があるけど、除毛後は波形がなまるけどヒゲが無いのがわかる
*9:LPFの定数は部品箱に転がってた小さいのという理由で勝手に決まった
*10:何をしてるかというと比較値を0x01→0x03→0x07...としてる訳だけど見せ方下手くそだな
ロジックICでマイコンとSPIしてみた
前書き
マイコンとかをいじっていて、内部の変数を見たいんだけどいっぱい線を引かずに済む方法は無いかなって思うこと無い?
個人的にはマイコンからSPIで吐いて74HC595でLEDを点けるのが好きでバーLEDとか7セグとかいくつか作った事がある。
今回は74HC165も使って読み書きの両方ができる回路を作って、忘備録としてここに多少書いておくことにした。
概要
百聞は何とかなのでとりあえず動画と概略図。マイコン(MCU)との8bitの入出力(スイッチ8個の状態を読んだり、LED8個を好きなパターンで点けたり)が、SPIの信号線4本だけ(と正確には絵に書いてないけど電源とGNDの合計6線)でできる。そんだけ。
わーい!ロジックICでSPI入出力デバイスできた! pic.twitter.com/qPRE7FlmYh
— TEFSOM (@Si_SJ_MOSFET) 2020年7月24日
部品
使ったロジックICは74HC595(LED点ける)、74HC165(SW読む)、74HC04(論理ひっくり返す)の3つだけ。意外と少なく済んだ。(実は最初に165じゃなくて595と対の597を使おうとしてたけど、入力をラッチするパルスを作るのが面倒なのと入手性が165よりも悪いので165にした。あと164はデータの書き換え中に出力を保持できないので595の方が好き。)
スイッチ(SW)は、秋葉原のaitendoの近くに遊舎工房ってお店ができたときに寄って買って部品箱に眠ってたキースイッチ。たしか以下の紫のやつ。別に普通のスイッチでも全く問題はないけど使ってみたかっただけ。LEDは普通に秋月の3mm砲弾型。
https://yushakobo.jp/shop/kailh-pro/
(雑談:そういや秋葉原に行ったときは秋月と千石に行くのは書くまでもないとして、aitendoで黒いプラスチックスペーサーセット(秋月のセットのよりクオリティ高いしばら売りのよりコスパ良いと思う)を買いつつ変なキットとか表示デバイスとかを見るのがルーチンだったな。またいつかぶらぶらしたい。)
回路図
こんな感じ。そんなに変な事はしていない。よく見るとあちこち負論理になってるのに気付くかもしれないけど、単なる好みの問題なので気にしないように。
そういやLEDの抵抗を何Ωにするかで年がばれる的なツイートを見たけど、自分は単に考えるのが面倒なので「とりあえず約1mA流れる抵抗値にして、暗すぎたり明るすぎてどうしようもなければ調整する」ことにしている。
あと真面目に考えると、MISOにスリーステートバッファを入れないと他のと衝突しないかとか気になるけど、今回は1つだけ使う想定として省略。(しばらくして発掘したときにこれを忘れて2つ使おうとしてヘンテコ波形で悩むとかありがちなのでメモとして残しておく。)
動作
今回の回路図だとSPIするときの波形はこうなる。SPIの波形ってクロックとデータの関係によって4通りあって更にSSが正論理か負論理かとかもあるからマイコンの設定には気を付けよう。読めないときは大抵設定を勘違いしている。(個人的にはこの設定はクロックより先にデータが出てきてクロックの立下り(ネガティブエッジ)でデータを読むので「先出しネガ読み」とか言ったりするけど当然誰にも通じないので注意)
説明
これで終わりでも良いけど図2の回路と図3の波形になる説明をちょっと書いてみる。
74HC165は図4に示すように、ロードモード(LD/SFがロー)の間に各入力(H~A)を読んで、シフトモード(LD/SFがハイ)にしてクロック(CLK)を入れると、クロックの立ち上がりでデータがシフトされて出力(QH)される。(上付きバーを打つのが面倒なので下線にした)
74HC595は図5に示すように、シフト用クロック(SCLK)の立ち上がりでシリアル入力(SI)を読んで、ラッチ用クロック(RCLK)の立ち上がりで各出力(QH~QA)が更新される。
もし仮に165と595に同じクロックを使うと図6みたいにSPIの違うモードが混ざった波形ができてしまって困る。なので色々手抜きで済むようにちょっと考えて各部の波形を図7みたいにすればいいやという結論に着地する。SSとかが負論理なのは好みの問題。
あとの書いてないピン等はデータシートで。データシート読まずに失敗するのはテストで問題文を全部読まずに回答して間違えるのとおんなじようなもんだって聖書にも書いてあるとかいないとか。そういえば聖書で思い出したけどロジックIC好きのバイブルといえば「CPUの創りかた」だと思うのでみんな読もう。あと几帳面な読者はこの記事中の記号が図と回路とデータシートとかで揃ってないことが気になるだろうけどこのピンだなと察してほしい。以上!
伝達関数の差分化の話(その3)
そろそろ終わりにしたい気もするけど、やっぱりグラフの比較くらいほしいのと、自分流+=戦法の話をもう少し書いておく。もうちっとだけ続くんじゃ。
3.1. 1次遅れ系の実装と波形の比較
さて、(1)の実装として、(2)と(3)を比較してみよう。
...... (1)
...... (2)
...... (3)
(、とおいた)
(2)のいい所はが出てこないところ。
タイマ「CPUさん、時間です!」
CPU「よし、を計算するか。ADCよ、はまだか?」
ADC「すいません!ただ今取ってきますので少々お待ちください!」
CPU「ちっ、これだからのろまなやつと組むのは嫌いなんだ。」
みたいな事にならずにCPUの手元に残ってる一個前のyとuの値で済む。一方で(3)のいい所は何にも考えずに実装できるわりにはそれなりに使えるところ。え?茶番よりグラフ?はい。
ΔTが細かい場合と粗い場合。双一次変換は一次遅れ系ならほぼ誤差は気にしなくてよさげ。+=戦法はΔT/Tが0.1くらい以下ならいいかなって感じ。
3.2. 2次遅れ系の実装と波形の比較
以上で良いかと思ったんだけどエクセルで遊んでたら色々思い出してきたのでもうちょっと書く。以下の二次遅れ系を実装してみる。
...... (4)
双一次変換は何も考えずに(4)に(5)をぶち込んでぐつぐつ煮て(6)を得ましょう。
...... (5)
...... (6)
(、とおいた)
頭は使わず手だけ動かせば良いのがいい所。
一方で+=戦法はそのまま代入しちゃいけない。なぜか?が2個以上出てくる式にそのまま入れるとの多項式になってとかが出てきてしまう。一個前のだけで書ける事だけが利点なのでちょっと頭を使おう。一言で書くと1元高次の方程式を多元1次の方程式にすればいい。
...... (4')
とりあえずyの時間微分をxとおく。
...... (4'')
...... (5)
できた。(5)の2行目の最後がじゃなくでなのはずるい気もするけど、2行目みたいに微分だけの時は1行目の結果が使えるからできる。当然お互いにお互いの行の結果を使うようなときは全部にするしかないけど。
どっちもΔTω=0.3くらいが限界ぽい。周波数の補正とかすれば使えなくもないけど。
添え字が全部のずる無し版+=戦法だとΔTω=0.03くらいが限界ぽい。そして周波数じゃなくて振幅がずれるのか。なるほど。
(ちなみに勘の良い読者は「(4'')って状態方程式ぽくね?」とか思ったかもしれない。実はその通りで伝達関数を状態方程式にして一階微分方程式にしちゃえば+=戦法以外もやりたい放題(4次ルンゲクッタとか)なんだけど余白が足りないので今回はここまで。もう飽きたけど需要があれば続くかも。)
伝達関数の離散化の話(その2)
前回は伝達関数の話と言いつつ伝達関数が出てこないタイトル詐欺だったので、今回は適当に例題として以下の伝達関数を離散化してみる。
...... (1)
どんな伝達関数かというと実は(その0)の図1に出てきた伝達関数を整理しただけ。一次遅れ系と呼ばれてて特性としてはローパスフィルタ。
2.1. 矩形近似の一次遅れ
とりあえず(その1)で出した以下の式を(1)にぶち込む。じゃなくてで記述しなくてもいいのか気になる人がいるかもしれないけど必要に応じて分母分子をで割ればいい。(を打つのがめんどいだけ)
...... (2)
できた。なお、とおいた。
...... (3)
これをどうやって実装するのかって?こうやってこうじゃ。
...... (4)
...... (5)
...... (6)
...... (7)
なんかデジタル信号処理の本とかで最初にでてきそうなフィルタになった。
...... (7')
ちなみに強引にこう書くと+=で実装できる。
2.2. 台形近似の一次遅れ
同様に以下の式を(1)にぶち込んで、
...... (8)
あらかじめ煮込んでおいたものがこちら。なお、とおいた。
...... (9)
ちなみに強引に以下のように書けばメモリに置いておく値は中括弧部分の1つで済む。
...... (9')
(そういえばを打つのを面倒がっていたら分母分子をで割り忘れて添え字が全部一個進んでしまった。まあ「『昨日の晩飯を基に今日の晩飯を決める』のと『今日の晩飯を基に明日の晩飯を決める』のは考え方としては同じこと」なのと同じことなので気にしないことにする。)
グラフ?はて何のことじゃ?