PythonだけでRaspberry piのGPIOピンをALT0に設定するための話
raspberry Pi2を最近いじっているのですが、GPIOピンからクロックをチップに供給したいことがありました。
そのためには、例えばGPIOピン5を通常の入出力ではなく、ALT0 (alternative function 0)に設定する必要があります。
他にもクロック出力を設定できるピンがありますが、詳しくはraspiに搭載されているARMプロセッサであるBCM2835のデータシートを参照してみてください(102pくらい)。↓
https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
結局色々調べたのですが、Pythonだけで完結できず、こちらのページ↓を参考にしてcプログラムでクロックを出力することに成功。(感謝!)
しかし、データ取得・解析にはPythonを使っていたので、できれば動いているコードはPythonだけで統一したいなあと思い、必要なライブラリを実装しました。
そのために、RPIOライブラリのカスタマイズを行います。
ただし、私が使っているのはraspberry Pi2なのですが、現在RPIOはraspberry Piに対応していない模様。raspberry Pi2でも使えるようカスタマイズされた
を改造し、ALT0への対応を行います。
■成果物
できました。フォーク元にプルリクエストを投げましたが、どうなることやら無事速攻でマージされました、感謝。
■インストール、つかいかた
raspberry Piターミナル上で
git clone https://github.com/fukatani/RPIO.git
git clone https://github.com/tylerwowen/RPIO.git
cd RPIO
python setup.py install
とうち、ここで完了と思いきや、なぜか私の環境では
dist-packagesに未解凍のファイルが置かれます(左下)。シュール。
なんででしょうね。前世の行いでしょうかね。知ってる人、教えてくださいね。
しょうがないので、手作業で解凍してやりインストール完了です。
import RPIO
RPIO.setup(5, RPIO.ALT0)
とすると、5ピンからGPCLK1(大体20MHz)がでます。嬉しいです。
ちなみにGPCLKは波形がグチャグチャでそれなりに高周波ノイズが激しいので、クロックの波形を直で突っ込むとSPIなどの波形がゆがむことがあります。最悪、通信が失敗し、かえって来たデータが信用できなくなるかもしれません。
そういう場合はクロックの後ろに抵抗(100ohmくらい?)つけてみましょう。
高周波成分が除去されて、通信が成功するようになるはずです。
なんか今ハードウェアエンジニアっぽいこといってしまった、、、
■追伸
うーん、RPIOの一部テストが通りません。フォーク元も。Pi2はピン配変わったからかしら。
raspberry Pi用のTravis CIがあったらいろいろはかどるのになー。
やる気があるひと修正してみましょう(人まかせ)。
雑記:IDE使用時にPythonで標準出力をリダイレクトした時のちょっとしたトラブルシューティング
Pythonでは標準出力(いわゆるprint関数の中に入れると文字がコンソールに出ちゃう奴)の出力先をファイルに変える(=リダイレクトする)のも簡単だ。
↑このへんを参考にしつつ
>>> import sys
>>> sys.stdout = open('out.txt', 'w')
>>> print('uwaaaaa')
と書くだけで、コンソールにuwaaaaaと表示される代わりに、out.txtと言うファイルが実行ディレクトリで作成され、その中にuwaaaaaというメッセージが書き込まれるのである。
標準出力をコンソールに戻すのも基本的には簡単でsys.stdoutにsys.__stdout__を代入してやればよい。すなわち、
>>> import sys >>> sys.stdout = open('out.txt', 'w') >>> print('uwaaaaa') >>> sys.stdout = sys.__stdout__ >>> print('yamerooooo')
と実行するとuwaaaaaはout.txtに表示されるが、yameroooはコンソールに表示されるのである。
ところが、コマンドプロンプトなどからPythonを実行していない場合、例えば、PyscripterなどのIDE上でPythonを実行していると、uwaaaaaはout.txtに表示されるが、yameroooはどこにも表示されないことに気づいた。
これについて調べてみるとどうもPyscripterではsys.__stdout__ではなく別の標準出力を最初から使っている事が原因のようだ↓
https://groups.google.com/forum/#!topic/pyscripter/rhtXtinfmGM
Pyscripter固有の解決法を施して、他の環境では動かないコードが入るのは避けたいしな、、と悩んでいたが、シンプルにsys.stdoutの初期の実体が何であれ、それを一時的に確保して後で用が済んだら戻してやればよいと言うことに気づいた。
すなわち、
>>> import sys
>>> temp_sysout = sys.stdout >>> sys.stdout = open('out.txt', 'w') >>> print('uwaaaaa') >>> sys.stdout = temp_sysout >>> print('yamerooooo')
としてやればよい。これで「yamerooooo」はコンソールに表示されるのである。勿論IDEだけでなく、コマンドプロンプトでも動作する。
Veriloggenを使ってみた、そしてVerilogメタプログラミングの新地平を見た
以前から気になっていたshtaxxx氏作Veriloggenを実際に使ってみた。
これは…熱い!
私が書いてみたコード↓
for文の中でクロック分周を繰り返しているのが肝。
生成されたverilog↓
うは!意図通りできてる!!!
for文に入れるだけで三回クロックが分周できてる!!!
これは、楽しいです。
私が考えたveriloggenのメリットとしては、
・verilogのダサい文法が回避できる(begin - endとか)
・柔軟にメタプログラミング的なことが出来る。genvarでもある程度できるが、規則的にレジスタ名を生成するようなことはできない。
・抽象レベルでの回路定義。なんかちょっとパラメータ入れたらおっきいコード吐くみたいな。
今後機能がたくさん追加されるようなので、おっかけとくことにします。
verilog向けコードメトリクス算出機能をリリース
pyverilog_toolboxにverilog向けコードメトリクス算出機能をリリースしました。
モジュール/ファンクション/レジスタレベルで全インスタンスについてメトリクスを算出し、それぞれのメトリクスの合計スコアと上位メンバを表示します。スコアが大きいほど複雑なやつです。。
使い方
例によってテストコードで。
コマンドプロンプト上で
(Pyverilog_toolboxをインストールしたディレクトリ)/verify_tool
に移動し、
$ Python metrics_calculator.py ../testcode/metrics_func.v
と入力します。適宜、.vファイルは測定対象に変更してください。
出力は
module metrics
total: 19
average: 19
each score:
TOP: 19
Number of input ports: 4
Number of output ports: 0
Number of registers: 1
Number of clocks: 1
Number of resets: 1
register metrics
total: 1
average: 1
each score:
('TOP', 0): 1
Number of branch: 0
Max nest: 1
function metrics
total: 9
average: 9
each score:
('TOP.md_always0.al_block0.al_functioncall0', 0): 9
Number of branch: 1
Max nest: 2
Number of variables: 2
てなような感じでプロファイルが出てきます。
モジュール/レジスタ/ファンクションが複数ある場合は上位から表示されます。
沢山あると大変なので、表示数上限を設定しており、設定ファイルにより上限を変更することができます。(設定ファイル記述法の詳細はgithubにて)
メトリクス判断基準の詳細
モジュールレベル
・input portの数
・output portの数
・regの数
・clkの種類(=非同期ドメイン数)
・rstの種類
デフォルトではただレジスタが増えるよりもポートの増加に対して厳しい判定をします。
(ポートが多い=疎結合の原則に反する。)
またクロックドメインの数によっても大きく上昇するので、非同期ドメインが存在するモジュールはなるべく小さく作りスコアを抑えるべき、ということになります。
レジスタレベル
・条件分岐(if,else if, else)の数
・ネストの数
デフォルトでは条件分岐が増える以上にネストの数に厳しいです。どんな言語でも過剰なネストは悪だと思うので。
ファンクションレベル
・条件分岐(if,else if, else)の数
・ネストの数
・読み込み変数の数
こちらもデフォルトでは条件分岐が増える以上にネストの数に厳しいです。
また、変数が多いと読み込み順を誤りやすくなるなど、
可読性が下がると推定します。
考え中のことと活用法
メトリクスの指標としてよく使われる行数カウントは現在のところ未実装です。
実装がめんどくさかった、というのと、
数えりゃいーじゃん、というのと、
verilogの行数はregの数×if文の分岐数で大体決まってくるので、
そこまで重要ではないかなと。要望があれば足すかもしれません。
また正直パラメータは適当です。私の感覚で決めました。
納得いかん!という型は設定ファイルによって書き換えることが出来ます。
詳細はgithubにて。
またスコアが高いとか低いとか絶対値それ自体には大きな意味はありません。
機能の大きさに伴ってスコアが増えるのは当たり前ですし、
ポートがない空のモジュールを作ればそれがスコアゼロで最高のVerilogコードと言うことになってしまいます。
むしろリファクタリング前と後でどれだけ減ったかとか、
あるいは他のモジュール/レジスタと比べて突出して複雑なものがあるから、
リファクタリングしたほうがよいサインなのかもという風に、
相対値に着目したほうが有意義かと思います。
また、pyverilog_toolboxに実装されているcodeclone_finder(同一レジスタの発見器)や、
unreferenced_finder(未使用変数の発見器)を使ってメトリクススコアを減らすのもよいでしょう。
追伸:
そういえばpyverilogのissueにsympyによる論理最適化なんてのが追加されております。熱い。
メトリクス測定→スコア高い奴をオートでリファクタリング→メトリクス現象なんてできたらワクワクですなあ。
他のissuesも気になります。pyverilogの更なる進化に期待。
pyverilog_toolboxをpipにうpるまでの熱い戦い&トラブル時のための備忘録
というわけで、pyveriog_toolboxをpip経由でラクチンインストールするための準備を整えた。
なんかpyverilogもいつのまにか(前から?)pipに対応していたので、私も時代に追いつくべく。
もちろんpipアップロードは初体験です。
基本的に参考にしたのは
こちらの素晴らしきブログである。
といいつつ少しつまづいたので備忘録を。
事件その1、認証失敗
まず、上記ブログにおいてpypiのアカウント作成後、
$ python setup.py register
を試したところ、
$ Server(401) basic auth failed
みたいなエラーが出てしまった。なんやねんなんやねんと大騒ぎつつ色々試していたが、サイトに情報を登録するだけではアカウント登録できていなかったのである。
pypiでアカウント作成後、登録しているメールに
To complete your registration of the user "(ユーザー名)" with the python module
index, please visit the following URL:
という内容のメールが来るので、慌てず深呼吸をしつつリンクをクリックしてアカウント登録を完了しましょう。
それ以外には.pypircファイルのユーザー名やパスワードのミスが考えられます。ホームディレクトリに作成した.pypircの内容を確認しましょう。
もう一度registerを試したところ
$ Server(200): OK
を無事確認。
事件その2、アップロードできない事件
上記事件1を解決後、どや顔で
$ python setup.py upload
叩いたところ
$ error: No dist file created in earlier command
となってしまた。これもね、全然分からないのでエラーメッセージをググリマス。
Adding a Package to PyPi For the 1st Time. - Jamie Curle
そしたらこちらのブログに「特に明確な理由はねーがこっちのコマンドを試した」
$ python setup.py sdist upload
と書いてあったので私も特に理由はねーが試した。
すると、
$ Server(200): OK
を確認。よくわかんないけどできてそうだからいっか、
事件その3、ダウンロードできない事件
アップロードに成功したので今度はpip installを試してみる。
$ pip install pyverilog_toolbox
すると、
$ Could not find any downloads that satisfy the requirements pyverilog_toolbox
あばばばば、と奇声をあげながら色々叫んでいるうちに、よくよく調べてみると\pyverilog_tool_box.egg-infoなるディレクトリができていることに気づく。
あれなんでtoolとboxの間に"_"が入っているんだっけ?と思いsetup.pyを見てみると、
from setuptools import setup, find_packages
import re
import os
version = '0.0.0'
def read(filename):
return open(os.path.join(os.path.dirname(__file__), filename)).read()
try:
import pypandoc
read_md = lambda f: pypandoc.convert(f, 'rst')
except ImportError:
print("warning: pypandoc module not found, could not convert Markdown to RST")
read_md = lambda f: open(f, 'r').read()
setup(name='pyverilog_tool_box',
version=version,
description='Pyverilog-based verification/design tools',
keywords = 'Verilog, Register Map, code clone',
author='Ryosuke Fukatani',
author_email='nannyakannya@gmail.com',
url='https://github.com/fukatani/Pyverilog_toolbox',
license="Apache License 2.0",
packages=find_packages(),
package_data={ 'pyverilog_toolbox' : ['testcode/*'], },
)
となっているのである。nameがまちがっとるやん。
【誤】
name='pyverilog_tool_box'
【正】
name='pyverilog_toolbox'
とまあしょぼいミスをなおして、パッケージ作成、登録、アップロードを行うと、
$ pip install pyverilog_toolbox
を叩くと無事インストールが出来た。ふう。
テストも動いた。と見せかけて1個動かなかった。どうやらテストに不備があるようなので近日修整予定。
というわけで、pyverilog_toolboxもpipでのインストールに対応しました。色々とドキュメントを直さないと。
コードクローンファインダー for verilog
(上記サイトより引用)
コードクローンとは
コードクローンとはソースコード中での類似または一致した部分を表します. コードクローンは,「コピーとペースト」によるプログラミングや,意図的に同一処理を繰り返して書くことにより,プログラムテキスト中に作りこまれます.
コードクローンの弊害
一般的に,コードクローンはソフトウェアの保守を困難にする要因の一つである,といわれています. 例えば,あるコードクローン上にフォールトが発見された場合に,開発者はそれと対応する全てのコードクローンを確認して,必要があれば全てのコードクローンに同様の修正を行う必要があるからです. 特に大規模システムでは,チームによる開発が通常行われており,上述したように一人の開発者がサブシステムを確認し,全てのコードクローンに対して一貫した修正を行うことはきわめて困難な作業であるといえます.
そのような事態を例えばCなどの言語ではコードクローンファインダーとして、
CCFinderのようなソフトが発表されている。
verilogでもこういうのあったら便利だけどニッチな言語だから見当たらないので、
Pyverilogを利用して作ってみました。実はPyverilog作者のshtaxxx氏が発案者だったりします。感謝。
開発指針
私が感じているCなどのソフトウェア言語とverilogの違い。
C
・ほとんどのコードはメソッド(関数orプロシージャ)の中に存在する。
Verilog
・ほとんどのコードはalways文(そしてそのほとんどはFFに代表されるレジスタ)の中に存在
verilogにもfunction文はあるが、使用頻度は多くない。
また参照はmoduleの中でのみ行われるため、クローンを探す需要はあまりない。
というわけでalways文で記述されるレジスタのクローンを探すことにしました。
verilogにおいてクローンを減らすということは回路面積を減らすことにもつながります。
機能説明
現在codeclone_finderで発見することができるクローンは以下の二つ。
・論理的に全く同一なレジスタ
例えばこのようなこーど。
always @(posedge CLK or negedge RST) begin
if(RST) begin
reg1 <= 1'b0;
end else begin
reg1 <= IN;
end
end
assign in1 = IN;
always @(posedge CLK or negedge RST) begin
if(RST) begin
reg2 <= 1'b0;
end else begin
reg2 <= in1;
end
end
in1とIN1の実体は同じであるためreg1とreg2は毎クロック必ず同じ値を保持します。
reg2の記述を消し、reg1を使いまわすべきです。
・論理的に全く反転しているレジスタ
always @(posedge CLK or negedge RST) begin
if(RST) begin
reg2 <= 1'b0;
end else begin
reg2 <= in1;
end
end
always @(posedge CLK or negedge RST) begin
if(RST) begin
reg3 <= 1'b1;
end else begin
reg3 <= !in1;
end
end
上記のコードでは、reg2とreg3は毎クロック必ず同じ値を保持します。
遅延のために後ろにインバータを使いたくないというような非常に稀な状況を除いて、このようなリファクタリングが有効です。
always @(posedge CLK or negedge RST) begin
if(RST) begin
reg2 <= 1'b0;
end else begin
reg2 <= in1;
end
end
assign reg3 = !reg2;
これで保守性が上がるとともにレジスタが1個減ります。
codeclone_finderの使い方
まずは
を参考に、Pyverilog_toolboxをインストールしてください。
そして
コマンドプロンプト上で
(Pyverilog_toolboxをインストールしたディレクトリ)/verify_tool
に移動し、
$ Python codeclone_finder xxxx.v
と入力します。(xxxx.vは自分で用意したverilogコード)
試しにPyverilog_toolboxに梱包されているテストコードで動かすと
$ Python codeclone_finder ../testcode/reg_clone.v
Invert reg pairs: *1, *2, *3
Clone reg pairs: *4, *5
のようにコードクローンを指摘してくれます。
最後に
将来的には類似していてリファクタリングが可能なレジスタを見つけたり、
リファクタリングまで児童でしてくれるブラウザが作れればいいかなーと思いつつ。