GPIOの通信状態を可視化する
I2C や SPI の絡む低レベルな通信階層の虫取りなどをやっていると、GPIOの変化を時系列で追いたいということはよくある。そういう時にはロジックアナライザーを持ち出すわけだが、ちゃんとしたのはそれなりに高価だし、USBドングル型の廉価品も専用アプリや各OS向けドライバーを準備するのは面倒だし、だったらその辺にある適当なマイコンで GPIOキャプチャして、シリアルコンソール表示できるだけでも用が足りるのではないか?と考えてサクッと書いてみたスケッチがこれだ。250kbps程度まで追えて、8KiBの SRAMで 1400ポイント程度のキャプチャができ、1/32 usec精度の表示ができるだけ、という原始的なものだが、それでも一応モノの役に立つ。
仕組みは単純。特定のポートグループを読み、時間情報と一緒にキャプチャテーブルへ格納するだけ。トリガーとキャプチャには BOTHEDGES 割込を用い、それにタイムアウト停止用のタイマーを加えている。
F_CPUをオーバークロック32MhzにセットしたAVR64DD32を観測器として、ISP書込器から ATtiny13A のシグニチャー(型番情報)を 125kbps で読み出す様子を可視化すると以下の通り。
<startup>
F_CPU=32000000
_AVR_IOXXX_H_=ioavr64dd32.h
CONSOLE_BAUD=500000
CAPTURE_MAX=1488
<capture wait>
<stop>
0: 0.000 0.000 00001111
1: 0.000 0.000 00000101
2: 1115.029 1115.029 00000001
3: 21144.013 20028.016 00001011
4: 21148.014 4.001 00000001
5: 21152.005 3.023 00000011
6: 21156.006 4.001 00001001
7: 21160.011 4.005 00001011
8: 21164.002 3.023 00000001
9: 21168.003 4.001 00000011
10: 21172.004 4.001 00001001
11: 21176.000 3.028 00001011
12: 21180.001 4.001 00001001
13: 21184.006 4.005 00001011
14: 21187.029 3.023 00000001
15: 21191.030 4.001 00000011
16: 21195.031 4.001 00000001
17: 21199.031 4.000 00000011
18: 21204.000 4.001 00000001
19: 21207.030 3.030 00000011
20: 21211.030 4.000 00001001
21: 21215.026 3.028 00001011
22: 21219.027 4.001 00000001
23: 21223.028 4.001 00000011
24: 21227.029 4.001 00001001
25: 21231.025 3.028 00001011
26: 21235.025 4.000 00000001
27: 21239.026 4.001 00000011
28: 21243.017 3.023 00000001
29: 21247.018 4.001 00000011
30: 21251.018 4.000 00001001
31: 21255.015 3.029 00001011
32: 21259.015 4.000 00001001
33: 21263.021 4.006 00001010
34: 21267.012 3.023 00001000
35: 21271.019 4.007 00000010
36: 21275.010 3.023 00000001
37: 21279.011 4.001 00000011
38: 21283.012 4.001 00000000
39: 21287.013 4.001 00000010
40: 21291.013 4.000 00000001
41: 21295.014 4.001 00000011
42: 21299.005 3.023 00000000
43: 21303.006 4.001 00000010
44: 21307.007 4.001 00000000
45: 21311.007 4.000 00000010
46: 21315.008 4.001 00000001
47: 21319.009 4.001 00000011
48: 21323.000 3.023 00000001
49: 21327.001 4.001 00000011
50: 21331.001 4.000 00000000
51: 21334.031 3.030 00000010
52: 21339.000 4.001 00000000
53: 21343.000 4.000 00000010
54: 21347.001 4.001 00000000
55: 21351.002 4.001 00000010
56: 21354.025 3.023 00000000
57: 21358.026 4.001 00000010
58: 21362.026 4.000 00000000
59: 21366.027 4.001 00000010
60: 21370.028 4.001 00000000
61: 21374.029 4.001 00000010
62: 21378.020 3.023 00000000
63: 21382.021 4.001 00000010
64: 21386.021 4.000 00000000
65: 21390.022 4.001 00000010
66: 21394.023 4.001 00000000
67: 38643.012 17248.021 00000010
68: 38647.013 4.001 00000000
69: 38651.004 3.023 00000010
70: 38655.004 4.000 00001000
71: 38659.010 4.006 00001010
72: 38663.001 3.023 00001000
73: 38667.007 4.006 00001010
74: 38671.007 4.000 00000000
75: 38674.030 3.023 00000010
76: 38678.031 4.001 00000000
77: 38683.000 4.001 00000010
78: 38687.001 4.001 00000000
79: 38691.001 4.000 00000010
80: 38695.002 4.001 00000000
81: 38698.025 3.023 00000010
82: 38702.026 4.001 00000000
83: 38706.023 3.029 00000010
84: 38710.024 4.001 00000000
85: 38714.025 4.001 00000010
86: 38718.025 4.000 00000001
87: 38722.026 4.001 00000011
88: 38726.027 4.001 00000001
89: 38730.018 3.023 00000011
90: 38734.019 4.001 00000000
91: 38738.019 4.000 00000010
92: 38742.020 4.001 00000000
93: 38746.021 4.001 00000010
94: 38750.022 4.001 00000000
95: 38754.013 3.023 00000010
96: 38758.013 4.000 00000000
97: 38762.014 4.001 00000010
98: 38766.015 4.001 00000000
99: 38770.012 3.029 00000010
100: 38774.013 4.001 00000000
101: 38778.014 4.001 00000010
102: 38782.014 4.000 00000000
103: 38786.006 3.024 00000010
104: 38790.006 4.000 00000000
105: 38794.007 4.001 00000010
106: 38798.008 4.001 00000000
107: 38802.008 4.000 00000010
108: 38806.009 4.001 00000000
109: 38810.000 3.023 00000010
110: 38814.001 4.001 00000000
111: 38818.002 4.001 00000010
112: 38822.002 4.000 00000000
113: 38826.003 4.001 00000010
114: 38830.004 4.001 00000000
115: 38834.001 3.029 00000010
116: 38838.002 4.001 00000000
117: 38841.025 3.023 00000010
118: 38845.026 4.001 00000000
119: 38849.027 4.001 00000010
120: 38853.027 4.000 00000001
121: 38857.028 4.001 00000011
122: 38861.029 4.001 00000001
123: 38865.020 3.023 00000011
124: 38869.020 4.000 00000001
125: 38873.021 4.001 00000011
126: 38877.022 4.001 00000001
127: 38881.023 4.001 00000011
128: 38885.023 4.000 00000000
129: 38889.014 3.023 00000010
130: 38893.015 4.001 00000000
131: 42653.028 3760.013 00000010
132: 42657.028 4.000 00000000
133: 42661.029 4.001 00000010
134: 42665.030 4.001 00001000
135: 42669.026 3.028 00001010
136: 42673.026 4.000 00001000
137: 42677.022 3.028 00001010
138: 42681.023 4.001 00000000
139: 42685.023 4.000 00000010
140: 42689.024 4.001 00000000
141: 42693.025 4.001 00000010
142: 42697.025 4.000 00000000
143: 42701.017 3.024 00000010
144: 42705.017 4.000 00000000
145: 42709.018 4.001 00000010
146: 42713.019 4.001 00000000
147: 42717.016 3.029 00000010
148: 42721.017 4.001 00000000
149: 42725.018 4.001 00000010
150: 42729.018 4.000 00000001
151: 42733.009 3.023 00000011
152: 42737.010 4.001 00000001
153: 42741.011 4.001 00000011
154: 42745.011 4.000 00000000
155: 42749.012 4.001 00000010
156: 42753.013 4.001 00000000
157: 42757.004 3.023 00000010
158: 42761.005 4.001 00000000
159: 42765.005 4.000 00000010
160: 42769.006 4.001 00000000
161: 42773.007 4.001 00000010
162: 42777.007 4.000 00000000
163: 42781.005 3.030 00000010
164: 42785.005 4.000 00000000
165: 42788.029 3.024 00000010
166: 42792.029 4.000 00000000
167: 42796.030 4.001 00000010
168: 42800.031 4.001 00000000
169: 42804.031 4.000 00000010
170: 42809.000 4.001 00000000
171: 42812.023 3.023 00000010
172: 42816.024 4.001 00000000
173: 42820.025 4.001 00000010
174: 42824.025 4.000 00000000
175: 42828.026 4.001 00000010
176: 42832.027 4.001 00001000
177: 42836.022 3.027 00001010
178: 42840.023 4.001 00001001
179: 42844.021 3.030 00000011
180: 42848.021 4.000 00000000
181: 42852.022 4.001 00000010
182: 42856.013 3.023 00000000
183: 42860.014 4.001 00000010
184: 42864.014 4.000 00000001
185: 42868.015 4.001 00000011
186: 42872.016 4.001 00000000
187: 42876.016 4.000 00000010
188: 42880.007 3.023 00000000
189: 42884.008 4.001 00000010
190: 42888.009 4.001 00000000
191: 42892.010 4.001 00000010
192: 42896.010 4.000 00000000
193: 42900.011 4.001 00000010
194: 42904.002 3.023 00000000
195: 46660.017 3756.015 00000010
196: 46664.017 4.000 00000000
197: 46668.018 4.001 00000010
198: 46672.019 4.001 00001000
199: 46676.015 3.028 00001010
200: 46680.015 4.000 00001000
201: 46684.011 3.028 00001010
202: 46688.012 4.001 00000000
203: 46692.013 4.001 00000010
204: 46696.013 4.000 00000000
205: 46700.014 4.001 00000010
206: 46704.005 3.023 00000000
207: 46708.006 4.001 00000010
208: 46712.007 4.001 00000000
209: 46716.007 4.000 00000010
210: 46720.008 4.001 00000000
211: 46724.006 3.030 00000010
212: 46728.006 4.000 00000000
213: 46732.007 4.001 00000010
214: 46735.030 3.023 00000001
215: 46739.031 4.001 00000011
216: 46743.031 4.000 00000001
217: 46748.000 4.001 00000011
218: 46752.001 4.001 00000000
219: 46756.001 4.000 00000010
220: 46759.025 3.024 00000000
221: 46763.025 4.000 00000010
222: 46767.026 4.001 00000000
223: 46771.027 4.001 00000010
224: 46775.027 4.000 00000000
225: 46779.028 4.001 00000010
226: 46783.019 3.023 00000000
227: 46787.026 4.007 00000010
228: 46791.017 3.023 00000000
229: 46795.018 4.001 00000010
230: 46799.019 4.001 00000000
231: 46803.020 4.001 00000010
232: 46807.020 4.000 00000000
233: 46811.021 4.001 00000010
234: 46815.012 3.023 00000000
235: 46819.013 4.001 00000010
236: 46823.014 4.001 00000000
237: 46827.014 4.000 00000010
238: 46831.015 4.001 00001000
239: 46835.011 3.028 00001010
240: 46839.012 4.001 00000000
241: 46843.012 4.000 00000010
242: 46847.013 4.001 00000000
243: 46851.011 3.030 00000010
244: 46855.011 4.000 00000000
245: 46859.003 3.024 00000010
246: 46863.003 4.000 00000000
247: 46867.004 4.001 00000010
248: 46871.005 4.001 00000000
249: 46875.005 4.000 00000010
250: 46879.006 4.001 00000000
251: 46882.029 3.023 00000010
252: 46886.030 4.001 00000001
253: 46890.031 4.001 00000011
254: 46894.031 4.000 00000001
255: 46899.000 4.001 00000011
256: 46903.001 4.001 00000001
257: 46906.024 3.023 00000011
258: 46910.025 4.001 00000000
259: 50333.001 3422.008 00001110
<Press the Enter key to the next capture>
ISP制御の実態は低電圧SPI通信で、キャプチャされた8ポート表示の左端4ビットが、MOSI、RESET(nSS)、CLK、MISO だ。うち RESET とCLKをトリガーに設定している。項番3から49の、SCK=1(昇端)に着目して読むと、MOSIにMLB先行でAC:53:00:00を送信していることがわかる。そして同時に MISOにはFF:FE:53:00が受信されている。この53の SPIエコーバックが、Attiny13Aが ISPプログラミング許可要求に対して承認を返した証跡だ。その後は黙々と ISPコマンドを送信し、応答を読み取り、最後は RESET=1 で終了(キャプチャタイムアウト)している。
観測器は 32MHzで動作させているが、32Mhz動作の32bitカウンターをSRAMのキャプチャテーブルに保存する割込ベクターが最大120クロック(約4us弱。レジスタページングやコンテキストスイッチ機構のない割込の重さは AVR最大の弱点)ほどかかるので、各項番間に1usのジッターが現れている。だが平均すれば4usなので、125kbps x 2倍のサンプリング周波数は一応確保されている。
tinyAVR-2以降の modernAVR世代では、2個の16bitカウンター、TCB0とTCB1を連結して、32bitのイベントキャプチャータイマーにする機能がある。このロジックアナライザー・スケッチはそれをそのまま使っている。当然普通の Arduino API互換 SDKではそういうことはできない(できなくはないが既定で有効になっている様々なAPI機能を殺しまくらないとならない)ので、素の avr-libcや XC8に対応した MPLAB Xなどの SDKが必要になる。しかし今時の モダンAVR は<avr/io.h>ヘッダーファイルがクラシック/レジェンドAVR世代より遥かに良くできているので、生のマシン語と変わらない可読性劣悪の呪文を唱える必要はない。肝心のペリフェラル・セットアップコードはこれだけだ。
/* TCB0の捕獲事象に接続 */
/* TCB0とTCB1の捕獲事象に接続 */
EVSYS_CHANNEL4 = EVSYS_CHANNEL_OFF_gc;
EVSYS_USERTCB0CAPT = EVSYS_USER_CHANNEL4_gc;
EVSYS_USERTCB1CAPT = EVSYS_USER_CHANNEL4_gc;
/* ch5=TCB0溢れ*/
/* TCB1の計数事象に接続 */
EVSYS_CHANNEL5 = EVSYS_CHANNEL_TCB0_OVF_gc;
EVSYS_USERTCB1COUNT = EVSYS_USER_CHANNEL5_gc;
/* TCB1は計数捕獲周波数測定動作かつ連結上位 */
TCB1_EVCTRL = TCB_CAPTEI_bm;
TCB1_CTRLB = TCB_CNTMODE_FRQ_gc;
TCB1_CTRLA = TCB_CASCADE_bm | TCB_CLKSEL_EVENT_gc | TCB_ENABLE_bm;
/* TCB0は計数捕獲周波数測定動作かつ連結下位 */
/* CLK元は主クロック(F_CPU)*/
TCB0_EVCTRL = TCB_CAPTEI_bm;
TCB0_CTRLB = TCB_CNTMODE_FRQ_gc;
TCB0_CTRLA = TCB_CLKSEL_DIV1_gc | TCB_ENABLE_bm;
/* キャプチャ実行方法;前回のキャプチャからの経過クロック数が読み出せる */
/* 上位カウンタを読むことで、下位ともども自動リセットされる */
EVSYS_SWEVENTA = EVSYS_SWEVENTA_4_bm;
uint32_t _timetick = TCB0_CCMP;
_timetick += TCB1_CCMP << 16;
まとめ
まあ所詮は 8-bit CPU の AVRであることに変わりはないので、出来たモノもこんなモンかなーというところ。本気出すなら動作周波数がもっと高くて、ネイティブな 32bitあるいは 64bitタイマー/カウンターを普通に備えている今時の RISC-Vや、ARM64チップなら 1us以下の分解能を持つロジックアナライザーは容易く作れるだろう。とはいえ思いついたものを雑に作れて、キャッシュせずともビルドが早くて、1分かからずアップロードできて、トライ&エラーサイクルが早いってのが AVR の利点、というか魅力だからね。それにしても、ESP32とかなんであんなにビルドもアップロードも珈琲沸かせるくらいに退屈なんでしょ…?
関連リンク
投稿者の人気記事
![[modernAVR] 簡易ロジックアナライザーを雑に作る](https://res.cloudinary.com/elchika/image/upload/t_elchika_article_cover/v1/user/060cd109-19e8-40f6-8046-7d4f29a6d7a6/article/22c04885-8c5e-4ce2-b26d-1c1677608e44/vemgbt2ldp1wvxxhrrjb.jpg)
![[modernAVR] AVR32LA32を使ってみる](https://res.cloudinary.com/elchika/image/upload/t_elchika_article_cover/v1/user/060cd109-19e8-40f6-8046-7d4f29a6d7a6/article/458fafd5-a755-4916-8eef-ff0c762fcfb0/fju7iiukzdlk3ujscgrl.jpg)
![[modernAVR] ひどいタクトスイッチのチャタリング除去と闘う](https://res.cloudinary.com/elchika/image/upload/t_elchika_article_cover/v1/user/060cd109-19e8-40f6-8046-7d4f29a6d7a6/article/221f78cf-4e6a-49c6-b6fe-ff14bd3bcaa8/mrbmeasnlgjs9fgtehgj.jpg)

-
askn
さんが
前の火曜日の22:33
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する