趣味の電子工作などの記録。時にLinuxへ行ったり、ガジェットに浮気したりするので、なかなかまとまらない。
RSS icon
  • PIC18F14K50でI2C液晶を制御

    投稿日 2013年 9月 29日 コメントはありません

    CDCで動くようになった秋月800円PIC18F14K50ボードですが、これに秋月I2C小型液晶(他でも売ってますが・・・)をつけてみました。

    まあ、日本語データシートに沿ってI2Cの初期化と、液晶の説明書に沿って液晶の初期化をして、CDCでの入力された文字を(エコーバックに加えて)液晶にも表示させているだけです。

    実験風景はこんな感じです。

    OLYMPUS DIGITAL CAMERA

    OLYMPUS DIGITAL CAMERA

    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円(DIPSOP)で手に入ります。そもそもPICというのがプログラミングする上で多少ナニではありますが・・・、周辺コントローラ(Peripheral Interface Controller = PIC)なのでそう割り切ればまあいいでしょう。

    ここまでの作業はすべてLinuxMint13上で実施しているのですが、このやり方だとPICおよび周辺回路のプログラミング・デバッグはx86のLinuxでしっかりやっつけてほぼ完成したところでRaspberryPiに持っていく、ということが非常に容易になります。実際に今回作ったものを持っていってみました。

    Screenshot-rdesktop

    残念ながら、RaspberryPiではGtkTermは動かないようなのですが、上記の通りしっかり認識できています。
    削除していない評価ボードのプログラムが悪さしているものの、他のターミナルプログラム(cutecom)でも液晶に表示ができています。


  • CDCサンプルプログラムにシリアルナンバーをつける

    投稿日 2013年 9月 28日 コメントはありません

    複数の同じ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
        :
        :
       以下略

    となって、無事にシリアルナンバーがつきました。


  • PIC18F14K50でUSBシリアル

    投稿日 2013年 9月 26日 コメントはありません

    日経Linuxの9月号にPIC18F14K50をLinuxで使う、という趣旨の記事が載っています。

    要はLinux上のMPLABX環境でPIC18F14K50のCDC(Communication Device Class)のサンプルプログラムをコンパイルして、PICkit3で書き込んで、CDCとして認識させて動かす、というものです。このサンプル自体はずーっと昔にWindows上のMPLABでコンパイルして動かしたことがあるのですが、Linuxではうまく動かず放ってありました。

    手持ちに秋月のPIC18F14K50の800円ボードもPICkit3もあるし、ちょっとやってみたいこともあるので試してみました。環境は LinuxMint13 32bit です。

    大きな流れとしては、

    1. MPLABXをインストール
    2. MPLAB C18ツールチェーンをインストール
      MPLAB C18ツールチェーンは普通はたどり着けないところにあるので、wget で http://www.microchip.com/mplabc18-linux-installer からツールチェーンをもってきてインストール。これまでうまくいかなかったのはこれ。結局ライブラリは C18 でしか動かない、ってことなのですね。
    3. Microchip Library for Applications をインストール
    4. プロジェクトを作成し、サンプルプログラムを開く。
      IDE v8 Project から CDC Basic Demo – C18 – Low Pin Count USB Development Kit.mcp を開く。 開いたら「Power Target circuit from PICkit3」のチェックボックスをONにして、PICkit3から電源供給できるようにする。

    というところです。

    で、書き込んだ後、ボードを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

    ・・・・治りました。ここまでの苦労は何だったんでしょう(^^;
    やっぱり、アップデートはちゃんとやっとかないとダメですね・・・。


  • 祝!2020年東京オリンピック開催決定!

    投稿日 2013年 9月 8日 コメントはありません

    おめでとう~!やったね~!


  • TwitterのストリーミングAPIを試してみた

    投稿日 2013年 9月 3日 1つのコメント

    Twitterからリアルタイムに情報を得るStreaming APIを試してみました。

    $ sudo easy_install pip
    $ sudo pip install tweepy --upgrade

    として、パッケージ管理ツール pip をインストールした後、tweepy をアップグレードしました。その後、キーワードを含む tweet を入手するスクリプトをいろんなところを参考にしながらなんとか作りました。

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import sys
    import json
    import tweepy  
    import re
    
    # Account 
    consumer_key= '  '
    consumer_secret= ' '
    access_token= ' '
    access_token_secret= ' '
    
    class Listener(tweepy.streaming.StreamListener):
        def on_data(self, data):
            if data.startswith("{"):
                tweet = json.loads(data)
                if 'text' in tweet:
                    user = tweet['user']
                    text = re.sub(r'\n',r' ',tweet['text'].encode('utf-8')) # 改行コード除去
                    print tweet['id'],":",tweet['lang'],":",user['screen_name'].encode('utf-8'),":", \
                                  user['name'].encode('utf-8'),":", text
            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)
    #    filterの宣言部分 @ /usr/local/lib/python2.7/dist-packages/tweepy/streaming.py
    #    def filter(self, follow=None, track=None, async=False, locations=None, 
    #        count = None, stall_warnings=False, languages=None):
    #    パラメータの使い方は https://dev.twitter.com/docs/streaming-apis/parameters
        stream.filter(languages=['ja'],track=['AKB', 'HKT', 'NMB'])

    15~27行目がデータ受信時の処理で、データを分析してユーザー名やscreeen_name、tweetの内容などを表示します。29行目からが認証で、34行目でstreaming apiを呼び出しています。
    39行目でフィルタの内容を設定していて、ここでは日本語のTweetで、「AKB,HKT,NMB」を含むものをキーワードとしています。キーワードは日本語のようなスペース区切りではない言語では正常に動作しないようです。

    同じ処理は、on_data ではなく、 on_statusを使うとJSONの解析もTweepy側でやってくれるようで、on_status版も上げておきます。

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import sys
    import json
    import tweepy  
    import re
    
    # Account
    consumer_key= ' '
    consumer_secret= ' '
    access_token= ' '
    access_token_secret= ' '
    
    class Listener(tweepy.streaming.StreamListener):
        def on_status(self, status):
            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"))
            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)
    #    filterの宣言部分 @ /usr/local/lib/python2.7/dist-packages/tweepy/streaming.py
    #    def filter(self, follow=None, track=None, async=False, locations=None, 
    #        count = None, stall_warnings=False, languages=None):
    #    パラメータの使い方は https://dev.twitter.com/docs/streaming-apis/parameters
        stream.filter(languages=['ja'],track=['AKB', 'HKT', 'NMB'])

    取得できるデータは、あるtweetを参考に分析してみたところ、

    {u'contributors': None,
     u'truncated': False,
     u'text': u'\u301017\u6642....00#NMB #HKT48\u3000#HKT',
     u'in_reply_to_status_id': None,
     u'id': 3744....11520,
     u'favorite_count': 0,
     u'source': u'<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>',
     u'retweeted': False,
     u'coordinates': None,
     u'entities': {u'symbols': [],
                   u'user_mentions': [],
                   u'hashtags': [{u'indices': [68, 74], u'text': u'AKB48'},
                                 {u'indices': [75, 79], u'text': u'AKB'},
                                 {u'indices': [80, 86], u'text': u'SKE48'},
                                 {u'indices': [87, 91], u'text': u'SKE'},
                                 {u'indices': [92, 98], u'text': u'NMB48'},
                                 {u'indices': [99, 103], u'text': u'NMB'},
                                 {u'indices': [104, 110], u'text': u'HKT48'},
                                 {u'indices': [111, 115], u'text': u'HKT'}],
                   u'urls': [{u'url': u'http://t.co/f4....w6kL', u'indices': [8, 30], u'expanded_url': u'http://com.nicovideo.jp/community/co....411', u'display_url': u'com.nicovideo.jp/community/co....\u2026'}]},
     u'in_reply_to_screen_name': None,
     u'id_str': u'3744....1520',
     u'retweet_count': 0,
     u'in_reply_to_user_id': None,
     u'favorited': False,
     u'user': {u'follow_request_sent': None,
               u'profile_use_background_image': True,
               u'default_profile_image': True,
               u'id': 63.....87,
               u'verified': False,
               u'profile_image_url_https': u'https://.......png',
               u'profile_sidebar_fill_color': u'DDEEF6',
               u'profile_text_color': u'333333',
               u'followers_count': 1,
               u'profile_sidebar_border_color': u'C0DEED',
               u'id_str': u'63.....87',
               u'profile_background_color': u'C0DEED',
               u'listed_count': 0,
               u'profile_background_image_url_https': u'https://......png',
               u'utc_offset': 32400,
               u'statuses_count': 25632,
               u'description': None,
               u'friends_count': 1,
               u'location': u'',
               u'profile_link_color': u'0084B4',
               u'profile_image_url': u'http://......png',
               u'following': None,
               u'geo_enabled': False,
               u'profile_background_image_url': u'http://......png',
               u'name': u'\u308a\u3063..........\uff09',
               u'lang': u'ja',
               u'profile_background_tile': False,
               u'favourites_count': 0,
               u'screen_name': u'KK....ty',
               u'notifications': None,
               u'url': None,
               u'created_at': u'Sun Jul 15 18:..:.. +0000 2012',
               u'contributors_enabled': False,
               u'time_zone': u'Osaka',
               u'protected': False,
               u'default_profile': True,
               u'is_translator': False},
     u'geo': None,
     u'in_reply_to_user_id_str': None,
     u'possibly_sensitive': False,
     u'lang': u'ja',
     u'created_at': u'Mon Sep 02 08:..:.. +0000 2013',
     u'filter_level': u'medium',
     u'in_reply_to_status_id_str': None,
     u'place': None}

    というような感じで、ユーザー名などは入れ子になったデータ構造になっていますので、on_data版ではソースの20行目のように一旦’user’データを取り出しています。

     


  • あらためてBeagleBoneBlackにUbuntuをインストールしてみた

    投稿日 2013年 9月 2日 3個のコメント

    TAKEさんのLinuxブログをみてみたら、UbuntuがGUIで起動した、という記事がありました。
    自分の方は先日失敗しているので、ちょっとみてみたら、BeagleBoard UbuntuのWikiに8月24日付けで新しいarmhfイメージが上がっていて、BeagleBone Blackについては、

    BeagleBone/BeagleBone Black: v3.8.13-bone26 kernel
    ・Lots of hdmi fixes...

    という記載が・・・・(^^;

    ということで、BeagleBoard UbuntuのWikiに沿って改めて試してみました。
    まず、SDイメージをダウンロードしてきます。これは上記Wikiの中の「Raring 13.04 armhf」の項目の少し下にある Prebuilt image のリンクを辿って入手します。

    続きを読む »