今回はRaspberryPiで工作をしてみました。
見ての通り、RS Componentsのケースを木の板にネジ止めして、そこにRaspberryPiをはめ込んだだけです。放熱とLEDが見えるようにするためRSのケースのふたの部分は使わないことにしました。設置場所がないので、写真の通りラックに吊り下げる形での設置にしました。
電源を供給するACアダプタがそこそこ暖かくなるので今の時点では長期連続運転は心配ですが、より余裕のある高容量のACアダプタに交換した後は連続稼働させようと思っています。

趣味の電子工作などの記録。時にLinuxへ行ったり、ガジェットに浮気したりするので、なかなかまとまらない。
調子に乗ってPIC18F14K50の他のサンプルを秋月の800円ボードで動かしてみました。
動作環境はLinuxMint13 + PicKit3です。「MPLAB-X」「MPLAB C18ツールチェーン」「Microchip Library for Applications」はすでにインストールされているものとします。(といっても、ダウンロードして、スーパーユーザー権限でスクリプトを走らせるだけでインストールできますが)
まず、サンプルプロジェクトを開いて初期設定を行います。ここではUSBキーボードのサンプルプロジェクトを動かしてみます。
次にビルド&書き込みを行います。
本来は評価ボードにはスイッチがついているので、そのスイッチを押すと文字が入力されるようなのですが、800円ボードにはそんなものはありませんので、勝手にキー入力されていってしまいます。
何のキーが入力されるかは、keyboard.c の907行目で HID REPORT にキーのコードに相当するusageを設定しています。usageはUSBの仕様書のうち、HID Usage Tableの53頁からの一覧表に乗っていて、4が「A」のキーに相当します。その後の926行目付近ではキーを話した場合のREPORTを送っています。
この辺を読んでソースを弄っていけば、変なキーボード(CTRL + ALT + DEL専用キーボードとか)も作れるはずです。(^^;
しばらく前に秋月で安価な高精度気圧センサLPS331のモジュールが出ていたので購入してあったのですが、これを電池駆動の気圧センサとして仕立ててみました。
おもなキーパーツは、
といったところです。
小型軽量かつ長時間駆動を目指すため、単4電池1本からスイッチングレギュレータを使って電源を生成しています。
当初はHT7733Aを使用し、LCフィルタでノイズを低減して使用していたのですが、どうも動作が安定しないのでノイズが原因かと疑って、一旦5Vにしてから3.3VのCMOSリニアレギュレータで電源を生成しています。(根本原因は他にあったので、結局これがどのくらい影響しているかはわかりません)
センサにはLEDが搭載されていますが、電池での動作時間を伸ばすため、その右上の電流制限抵抗を除去することでLEDへの電流をカットしています。
背面は試行錯誤の繰り返しで汚くなってしまいました。
ソフトウェアはMPLAB-X+XC8で作成していますが、このLPS331というデバイスは結構くせがあり苦労しました。(XC8にもいろいろ癖があって苦労しました)
当初は自動モードで勝手に連続変換させて、変換終了時に割り込みにてPICに通知、値を読み取って表示させようとしていました。しかしこちらの記事にあるように連続モードで変換すると、変換の処理自体?が抜けていることがあるのです。そこで、約1秒周期でワンショットの変換コマンドを発行することにしたのですが、それでも表示の変動が起こります。「レジスタは初期値に関わらず全部書き込まないとダメ」など、いろいろWebで見かけた情報を取り込みながら、最終的には約2秒周期での変換とすると変換値の暴れが収まるようですので、約2秒周期での変換&表示としています。それでも時折温度については±1℃程度の範囲で暴れることがあるようですが、妥協しました。
以前作ったArduinoベースの温度・湿度・気圧計との比較です。
気圧についてはLPS331APの方がごくわずか・・・0.2hPa程度ですが、低めに出る傾向があるようです。
温度の方はLPS331APの方が0.7℃程度ですが低めに出ています。
値の安定性については気圧・温度ともにSCP1000の方が明らかに安定しています。
LPS331のほうはドキュメントもよく読むとおかしな所が結構あって(ドキュメントの)出来がよくありません。ドキュメントの出来が悪いデバイスは概してデバイス自体にもいろいろ問題を抱えている場合が多いように経験しています。
#原因切り分け用に買い足したLPS331APがあるのだけど、どうしようかな・・・(^^;
それと消費電流ですが、電池のところで測定すると、センサが動作していないタイミングでは1.8mAくらいで、センサが動作すると4mA程度に上がります。ただ、デジタルテスタで測定しているので、どのくらいが本当のピークなのかはわかりません。センサの動作時間自体は100msにも満たないようなので、平均でも2mA以下くらいなのでしょうか。2mAとすると、単4アルカリ乾電池の容量は700~800mAh程度のようですので、電池1本で350~400時間程度(電圧が下がってくるので、もうちょっと短いか)=約2週間程度の動作時間というところでしょうか。
現状では消費電流を下げて駆動時間を伸ばすためにPICの動作周波数は内蔵オシレータ使用で125kHzとしてあります。さらに消費電流を下げるために表示更新の待ち時間でのPIC自体のスリープも考えたのですが、内部の31kHzのLFINTOSCでスリープ動作させる方法が見つかりませんでした。どうやら外付けの32kHzのクリスタルで動作させないといけないようで、そこまで部品追加するのは面倒なので止めました。
ソースも置いておこうかな・・・と思ったのですが、コメントが古い(試行錯誤する前)ので、とりあえずやめておきます。(コメントを整理したら置くかも・・)
製作したUSB LCDモジュールですが、Twitterのtweetを表示させてみました。
Streaming API で指定したキーワードが含まれているTweetを表示させてみます。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, json, tweepy, re, os
# Account
consumer_key= ' '
consumer_secret= ' '
access_token= ' '
access_token_secret= ' '
class Listener(tweepy.streaming.StreamListener):
def on_status(self, status):
message = status.user.name.encode("utf-8") + ":" + \
re.sub(r'\n',r' ',status.text.encode("utf-8"))
print status.id,":", \
status.lang,":", \
status.user.screen_name.encode("utf-8"),":", \
status.user.name.encode("utf-8"),":", \
re.sub(r'\n',r' ',status.text.encode("utf-8"))
os.system('./usblcd.py "'+message+'"')
return True
def on_error(self, status):
print status
if __name__ == '__main__':
l = Listener()
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
stream = tweepy.Stream(auth, l)
stream.filter(languages=['ja'],track=['tbs','fujitv','ntv','tvasahi','tvtokyo'])
今回はキーワードを’tbs’,’fujitv’,’ntv’,’tvasahi’,’tvtokyo’として、テレビ局に関するTweetを拾ってみます。
Pythonスクリプトを動かすとこんな感じで表示されました。
どんどん表示される感じがわかるように動画ファイルも上げておきます。
PIC18F14K50を使ってUSBで接続・制御するグラフィックLCDモジュールを作ってみました。
LCDモジュールは手持ちの秋月の128×64のグラフィック液晶です。
PIC18F14K50では端子が不足するので、74HC273(Dラッチ)を使って制御信号をラッチしてからLCDモジュールのデータ線に信号を与えています。
この74HC273はパーツ箱に眠っていたもので、デートコードは8820でした。つまり1988年の第20週ですから25年以上前の1988年5月下旬頃に製造されたものということになります。無事に動くか少し不安ではありましたが・・・。
裏側はこんな感じでぐちゃぐちゃになってしまいました。本当はLCDは180度回した形で取り付けたかったのですが、このLCD、図面の右側から端子が振ってあって、思いっきり間違えてしまいました。それで急遽LCDの方を回して、コネクタをもう一つつける形にしてしまいました。
ファームウェアは例によって /dev/ttyACM0 としてUSBシリアルとして認識されるようになっていて、液晶モジュールへの制御信号とデータの繰り返しで垂れ流すとそのままLCDモジュールをPICが制御するようになっています。PC側はPythonで記述してあって、一旦GDライブラリを使ってビットマップ上にTrueType(のビットマップフォント)を展開した後、LCD用のコマンド列を生成するようになっています。LCDにはnaga10フォントで半角24文字×6行の表示ができるようになっています。
またHACK A DAYの記事からですが、インテルアーキテクチャのArduinoに続いて、またArduino関連で新しい話がでてきました。
どうも、BeagleBone.orgとArduinoのコラボレーション・・・ということらしいのですが、Arduino Treというのが2014年4月に登場するみたいです。
(写真はArduino.ccからの借用です)
内容はArduino+BeagleBoneBlackのようで見たまんまみたいです。
Arduino側はATmega32u4 16MHz、BeagleBone側はAM3359(Cortex-A8) 1GHz+DDR3 512MBとのこと。
ネットワーク通信と負荷のかかる演算処理はCortex-A8側で、リアルタイム性の要求される制御や現存のArduinoのシールド資産を使った制御はArduino側で、ということでしょうね。
気になるのはお値段です。Arduinoはハードウェアとしては大した回路ではなく、両面基板でも実現容易な部類なのですが、BeagleBoneBlackの方は(電子工作向けとしては)かなりの高スペックな基板・・・確か6層の微小スルーホール仕様だったと思います。BeagleBoneBlackはサイズを徹底的に切り詰めている感じでしたが、こちらではそれを結構大きなサイズで使うのでお値段も安くなさそうな気がします。
あとは、BeagleBoneBlackの方は、もうちょっとOSの方がなんとかならないかと・・・(^^;
HACK A DAYのこの記事で知ったのですが、インテルがローマのMaker FaireでArduinoとハードウェア(シールド)およびソフトウェアコンパチブルの開発ボードを発表したようです。その名も「ガリレオ(Galileo)」。
本家arduino.ccの記事によると、ボードとしてのハードウェアスペックはこんな感じみたいです。
Arduinoとしては、
というところで、Arduinoっぽいものを目指しているのではなく、Arduinoとの高い互換性を狙っているように見えます。
インテルはこのボード(Galileo)を大学向けに5000枚ほどバラ撒くようです。(参考記事)
今ある情報だけではソフトウェアの構成がいまいちわかりませんが、単なるArduinoの領域に400MHzのPentiumはオーバースペック過ぎるように思えます。当然インテルもわかっているでしょうが。ただ、ロボット関連などでは結構な演算性能が求められるはずなので、必要な分野もあるだろう、ということでテストマーケティングに投入する(寄付する)のでしょう。
そして興味深い(期待したい)のは、今後、どの分野に展開していくかです。
今時、ネットワークおよびネットワークに関連する機能(http,smtp,ftp,cifs,…)は様々な機器(お遊び含む)で求められるので、それをお気楽お手軽に実現するための基盤としてLinuxをみんな使う(使いたい)わけです。だから安価で環境の整っているRaspberryPiやBeagleBoneに興味を示す人が多いわけです。
となると、Galileoボードは安価に市販されるのか、Linuxは動作するのか、というところが注目したいところです。Pentium 400MHzクラスであれば、GUIは別にしてLinuxでもBSDでも問題なく載るはずです。そこに膨大なArduinoシールドの資産を使うと、いろんなものが作れる(作る人がいる)のではないか、と思うのは自分だけではないはずです。
BeagleBoneBlackが49ドル、RaspberryPiが35ドルで販売されていることを考えると、60ドル以下、できれば50ドルを割る価格で販売してくれないかな~、と思うんですが、どうでしょう、インテルさん。70ドル以上ではAndroidとRaspberryPiで爆進するARM版Linux・・・このままではいずれ(すでに?)組込み分野で席巻することになるでしょう・・・の勢いは止められないと思いますので。
いずれにせよ、今後に注目です。
CDCで動くようになった秋月800円PIC18F14K50ボードですが、これに秋月I2C小型液晶(他でも売ってますが・・・)をつけてみました。
まあ、日本語データシートに沿ってI2Cの初期化と、液晶の説明書に沿って液晶の初期化をして、CDCでの入力された文字を(エコーバックに加えて)液晶にも表示させているだけです。
実験風景はこんな感じです。
1枚目の写真は全景で、ttyACM0として認識した後、GtkTermで入力した文字が表示された様子です。2枚目はPIC周辺の拡大写真です。
PICkit3でプログラムを書き込んだ後PGC/PGDは抜いておかないと、これらがUSBのD+/D-になっているためUSBで認識できませんので、2本だけ線が外してあります。ブレッドボード上でピロンと2本伸びたジャンパ線がI2Cの信号線です。I2Cバスのプルアップ抵抗(2.7kΩ)は液晶の下にあります。最初は液晶モジュールのピッチ変換基板に載っているのと同じ10kΩを使っていたら動作が安定せず、2時間くらい悩んでしまいました。やっぱり規格はちゃんと調べて値を決めないとダメですね。
縦に実装している小さな基板にはSOT23パッケージの5V→3.3Vレギュレータ(TAR5S33)が見えていない面に載っています。液晶モジュールの電源電圧が3.3Vなので入れていて、この基板の裏側にはチップ部品を載せるパッドがあるのでそこにパスコンを載せています。
ソフトウェアの方ですが、液晶の制御はI2Cで行いますが、シングルマスタモードでの動作前提なので簡単でした。
PIC18F14K50はPIOはもちろんのこと、今回使ったI2Cの他に、ADC、コンパレータ、PWM、タイマ、UARTなどがある上に、Linuxでバッチリ認識できるUSB付きでボードで800円、チップ単体だと150円(SSOP)とか170円(DIP、SOP)で手に入ります。そもそもPICというのがプログラミングする上で多少ナニではありますが・・・、周辺コントローラ(Peripheral Interface Controller = PIC)なのでそう割り切ればまあいいでしょう。
ここまでの作業はすべてLinuxMint13上で実施しているのですが、このやり方だとPICおよび周辺回路のプログラミング・デバッグはx86のLinuxでしっかりやっつけてほぼ完成したところでRaspberryPiに持っていく、ということが非常に容易になります。実際に今回作ったものを持っていってみました。
残念ながら、RaspberryPiではGtkTermは動かないようなのですが、上記の通りしっかり認識できています。
削除していない評価ボードのプログラムが悪さしているものの、他のターミナルプログラム(cutecom)でも液晶に表示ができています。
複数の同じUSBデバイスを識別する方法として、シリアルナンバーで区別する方法がありますが、MicrochipのCDCサンプルプログラムでは以下の通り、シリアルナンバーはサポートされていません。
$ sudo lsusb -d 04d8:000a -v
Bus 001 Device 004: ID 04d8:000a Microchip Technology, Inc. CDC RS-232 Emulation Demo
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x04d8 Microchip Technology, Inc.
idProduct 0x000a CDC RS-232 Emulation Demo
bcdDevice 1.00
iManufacturer 1 Microchip Technology Inc.
iProduct 2 CDC RS-232 Emulation Demo
iSerial 0 ←ここ
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
(以下略)
そこで、シリアルナンバー対応してみました。
usb_descripters.c の 166行目付近の device_dsc を以下のように修正します。
/* Device Descriptor */
ROM USB_DEVICE_DESCRIPTOR device_dsc=
{
0x12, // Size of this descriptor in bytes
USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type
0x0200, // USB Spec Release Number in BCD format
CDC_DEVICE, // Class Code
0x00, // Subclass code
0x00, // Protocol code
USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h
0x04D8, // Vendor ID
0x000A, // Product ID: CDC RS-232 Emulation Demo
0x0100, // Device release number in BCD format
0x01, // Manufacturer string index
0x02, // Product string index
0x03, // Device serial number string index
0x01 // Number of possible configurations
};
修正したのは下から2つめの「// Device serial number string index」で、0x00だったのを0x03にして、string indexの3がシリアルナンバーであることを指定します。
さらに同じファイルのもっと後の方にstring descriptorの定義があるので、ここも修正します。
//Language code string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[1];}sd000={
sizeof(sd000),USB_DESCRIPTOR_STRING,{0x0409}};
//Manufacturer string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[25];}sd001={
sizeof(sd001),USB_DESCRIPTOR_STRING,
{'M','i','c','r','o','c','h','i','p',' ',
'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'
}};
//Product string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[25];}sd002={
sizeof(sd002),USB_DESCRIPTOR_STRING,
{'C','D','C',' ','R','S','-','2','3','2',' ',
'E','m','u','l','a','t','i','o','n',' ','D','e','m','o'}
};
//Serial string descriptor これを追加
ROM struct{BYTE bLength;BYTE bDscType;WORD string[8];}sd003={
sizeof(sd003),USB_DESCRIPTOR_STRING,
{'S','N','0','0','0','0','0','1'}
};
//Array of configuration descriptors
ROM BYTE *ROM USB_CD_Ptr[]=
{
(ROM BYTE *ROM)&configDescriptor1
};
//Array of string descriptors
ROM BYTE *ROM USB_SD_Ptr[USB_NUM_STRING_DESCRIPTORS]=
{
(ROM BYTE *ROM)&sd000,
(ROM BYTE *ROM)&sd001,
(ROM BYTE *ROM)&sd002,
(ROM BYTE *ROM)&sd003 // これを追加
};
追加箇所は2箇所、sd003に関するところです。
この修正だけだとUSB_NUM_STRING_DESCRIPTORSの定義が変わらないため、コンパイルでエラーが出ますので、usb_config.h も修正します。144行目に
#define USB_NUM_STRING_DESCRIPTORS 3
というのがあるので、これを
#define USB_NUM_STRING_DESCRIPTORS 4
に修正します。
これでコンパイルしてFlashに書き込んで、USBコネクタに挿入すると、
$ sudo lsusb -d 04d8:000a -v
Bus 001 Device 005: ID 04d8:000a Microchip Technology, Inc. CDC RS-232 Emulation Demo
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x04d8 Microchip Technology, Inc.
idProduct 0x000a CDC RS-232 Emulation Demo
bcdDevice 1.00
iManufacturer 1 Microchip Technology Inc.
iProduct 2 CDC RS-232 Emulation Demo
iSerial 3 SN000001
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
bConfigurationValue 1
:
:
以下略
となって、無事にシリアルナンバーがつきました。
日経Linuxの9月号にPIC18F14K50をLinuxで使う、という趣旨の記事が載っています。
要はLinux上のMPLABX環境でPIC18F14K50のCDC(Communication Device Class)のサンプルプログラムをコンパイルして、PICkit3で書き込んで、CDCとして認識させて動かす、というものです。このサンプル自体はずーっと昔にWindows上のMPLABでコンパイルして動かしたことがあるのですが、Linuxではうまく動かず放ってありました。
手持ちに秋月のPIC18F14K50の800円ボードもPICkit3もあるし、ちょっとやってみたいこともあるので試してみました。環境は LinuxMint13 32bit です。
大きな流れとしては、
というところです。
で、書き込んだ後、ボードをUSBケーブルでホストPC(Mint13)と接続するのですが、接続後に見えるデバイスは「/dev/ttyACM0」ではなく「/dev/ttyUSB0」と「/dev/ttyUSB1」になってしまいます。ロードされるドライバも cdc_acm ではなく、ftdi_sioがロードされてしまい、正しく動作しません。
この原因は ftdi_sio ドライバにUSBデバイスID「04d8:000a」が記述されていて、そちらがロードされてしまうためのようです。とりあえず回避するには、
$ sudo rmmod ftdi_sio
として、ftdi_sio ドライバを外してやり、その後でUSBケーブルを差し直すと正しく /dev/ttyACM0 として見えて、ちゃんと動作するようになります。恒久的には ftdi_sio ドライバを /etc/modprobe.d の下の blacklist に入れてやればおそらく解決するのでしょうが、当然本物のFTDIチップが動かなくなります。
なんでこんなことになっているかというと、この件のパッチが投げられている
https://patchwork.kernel.org/patch/1464661/
によると、FTDIチップをエミュレーションするファームウェアでこのMicrochipの評価ボードのベンダID/デバイスIDをそのまま使っているハードウェアベンダがいるため・・・・ということのようです。(うー、勘弁して・・・・)
ドライバに直接手を入れれば修正できるようなのですが、ちょっと面倒臭いですね・・・。何かいい方法(ベンダID/デバイスIDを指定して blacklist するなど)があればいいのですが・・・。
で、何とかならないかと、試しに /etc/udev/rules.d/10-cdcacm.rules として以下の内容のファイルを作ります。
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", GROUP="adm", MODE="0666", SYMLINK+="cdc_acm"
udevをリスタートしてルールを読み込ませます。
$ sudo service udev restart
試しに、
$ sudo modprobe ftdi_sio
として、先にrmmod してあった ftdi_sio を読み込ませて、その後で、USBを抜き差ししてみます。
dmesgの最後を見てみると、
[ 5431.756641] udevd[4801]: starting version 175 [ 5479.158712] USB Serial support registered for FTDI USB Serial Device [ 5479.159765] usbcore: registered new interface driver ftdi_sio [ 5479.159768] ftdi_sio: v1.6.0:USB FTDI Serial Converters Driver [ 5490.096591] usb 1-1.3: USB disconnect, device number 10 [ 5492.337738] usb 1-1.3: new full-speed USB device number 11 using ehci_hcd [ 5492.434666] cdc_acm 1-1.3:1.0: This device cannot do calls on its own. It is not a modem. [ 5492.434688] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
となっていて、とりあえず ttyACM0 として認識しているようです。
しかし再起動してみると・・・・ftdi_sioとして認識してしまう・・・orz
どうやらどちらのドライバが先に認識するか・・・だけみたい。/etc/udev/rules.d/10-cdcacm.rules ではコントロールできなさそうなことはわかりました・・・。
やっぱり ftdi_sioをblacklistして、rules.dでFTDIドライバを読ませるとかすればいいのでしょうかね・・・?
<追伸>
ちなみに、バージョン3.12-rcや3.2.51のカーネルソースでは、上記パッチが適用されてるっぽいです。一方で、
$ uname -a Linux G530-2-Mint 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:41:14 UTC 2012 i686 i686 i386 GNU/Linux
ん~?カーネルのバージョンを上げれば解決するのだろうか??
Synapticでカーネルパッケージを入れてみました。
$ uname -a Linux G530-2-Mint 3.2.0-53-generic-pae #81-Ubuntu SMP Thu Aug 22 21:23:47 UTC 2013 i686 i686 i386 GNU/Linux
・・・・治りました。ここまでの苦労は何だったんでしょう(^^;
やっぱり、アップデートはちゃんとやっとかないとダメですね・・・。