ラベル USB の投稿を表示しています。 すべての投稿を表示
ラベル USB の投稿を表示しています。 すべての投稿を表示

2015年8月15日土曜日

NUCLEO-L152REをUSBデバイスにする



NUCLEO-L152REにmbed USBDevice互換のUSBデバイススタックをHAL_PCDで作ってみました。

https://developer.mbed.org/users/va009039/code/L152RE_USBDevice/

STM32CubeMX
まずは、USBコネクタとの配線ミスを防ぐため、HAL_PCDの動作を知るために
STM32CubeMXでMSCのUSBデバイスやHIDデバイスを作成してパソコンに接続してみる。
ボードとUSBコネクタは次のとおりです。
PA12 --- D+
PA11 --- D-
F401REのようにPA9にVCCを接続する必要はない。

USBクロック設定
mbedのオフライン環境にSTM32CubeMXで作製したコードをそのまま取り込んだところ動かなくなってしまった
。USBの48MHzを作るためにクロック設定をしている。既にmbedのスタートアップが走ってクロック設定をしているので、
再設定するには HAL_RCC_DeInit() を呼んで初期状態に戻してから設定し直さないといけない。

ソフトコネクト
USBのDPをプルアップにしてパソコン(USBホスト)にUSBデバイスを検出させます。
ソフトウェアでプルアップを制御する事によって、任意の時点でUSBデバイスを検出させる事が出来ます。
L152REにはSYSCFG_PMCでUSB_PU 内部プルアップを制御できるのだが、システム設定コントローラはUSBコントローラとは
別のクロック供給なので__SYSCFG_CLK_ENABLE()の追加が必要です。

USBDevice
USBDevice互換にするためにUSBHAL_STM32L1.cppをHAL_PCDを使って実装する。
デバッグのためにDBG()PRINT文を入れると表示のタイムアウトでUSB認識しないところがある。
デバッグ情報をRAM上に残して、後から見れるようにトレースプログラムを追加してデバッグをします。
HAL_PCDからのSETUP,IN,OUTパケットのコールバックを使っているのでUSBAL.hにも若干修正をしています。

ソフトコネクト、割込み番号の違いだけで他のボードにも使えると思います。

F103RBは外部にプルアップ抵抗を付けて動作確認しています。他のボードでは未確認です。


各ボードのUSBの違いは以下のとおりです。

L152RE
ソフトコネクトは可能。STM32CubeMXでHAL_PCDEx_SetConnectionState の実装例はある。
_HAL_SYSCFG_USBPULLUP_ENABLE()、__HAL_SYSCFG_USBPULLUP_DISABLE()で内部プルアップ制御をしている。
割込みベクター番号 USB_LP_IRQn

F103RB F303RE
ソフトコネクトはない。プルアップが必要。
割込みベクター番号 USB_LP_CAN1_RX0_IRQn

F072RB(STM32F0) L053R8(STM32L0x3)
ソフトコネクトは可能だが、STM32CubeMXでHAL_PCDEx_SetConnectionState の実装はない。
USB_BCDR DPPU(bit15) を直接制御する。
割込みベクター番号 USB_IRQn

(2015/8/15)
---

2014年6月19日木曜日

LPC1114FN28でUSBパケットキャプチャ



USBロースピード(LS)1.5Mbpsだけですが、LPC1114FN28でUSBパケットキャプチャをしてみました。
一年ほど前に作ったLPC1768のロースピードUSBをパケットキャプチャ(USBLowsCap)に比較してまだまだ安定していなくてCRCエラーが頻発していますが、ホストとデバイスとのパケットのやりとりはだいたいわかります。



LPC1114の16ビットカウンタタイマ(CT16B1)のキャプチャ機能(CAP0)を使ってUSBのDATA+ラインの変化をみています。
割込みを使うとぜんぜん間に合わない。最小のビット0値の時の32サイクル以内に処理が終わらない。ポーリングでキャプチャ値(CR0)を読みだしてパルス幅からビット変換します。
SYNC、PIDまではキャプチャ値から直接デコードする。ビット1値が6個連続する事はないのでビット挿入を削除する必要はありません。
それ以降のデータはキャプチャ値を保存しておいてパケットを受信完了してからデコードしています。PIDからパケットの長さがわかる時はEOPの検出には問題ないが、DATA0/DATA1の可変長の時はDATA+ライン、DATA-ラインの状態をGPIOで読み取ってEOPを判断しています。GPIOの読み取りに時間がかかって検出出来ない時があるようです。

ソースコード:
LPC1114_USBProtocolAnalyzer

(2014/6/18)
---

2014年4月24日木曜日

EA LPC4088 QSB用のUSBホストライブラリの試作



EA LPC4088クイックスタートボードはmbedのUSBホストでサポートされていないので試作してみました。

LPC4088のUSBコントローラは0x10000000から始まるメインSRAMにはアクセス出来なく、
0x20000000からのメモリAHBSRAM0,AHBSRAM1のみにアクセス出来ます。(以下USBRAMと略す)

USBRAMに転送データがあれば問題無いのだがmbed OfficialのUSBHostとインターフェース互換に
したかったので、USBデバイスへの転送の都度、USBRAMにコピーしてからUSBコントローラを
起動してしています。
実装ではUSBRAMからfirst-fitアルゴリズムで64バイト単位で転送領域を切り出すようにしています。
もちろん、HCED,HCTD,HCITD,HCCAも切り出しています。

USBコントローラの初期設定はLPC1768のとほぼ同じです。
LPC4088のLPCOpenのサンプルコードを参考にしたところ、
USBポートの機能設定がLPC_PINCONからLPC_IOCONに変わっているだけでした。
LPCOpenサンプルコードとはP1_19の扱いが違うのでLPCOpenのように設定してはいけない。
EA LPC4088 QSBではUSBホストへの電力供給イネーブルに使っています。
#if defined(TARGET_LPC1768)
    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
    LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     
#elif defined(TARGET_LPC4088)
    LPC_IOCON->P0_29 = 0x01; // USB_D+1
    LPC_IOCON->P0_30 = 0x01; // USB_D-1
    // DO NOT CHANGE P1_19.
#else
LPC_USBのレジスタ名が違っていたのでLPC1768の名前で再定義しました。
#define HcRevision Revision
#define OTGStCtrl StCtrl

ハードウェア依存以外はKL46ZのUSBホスト試作のコードを使いました。
ノンブロック型転送の場合にUSBHost::poll()を呼び続ける事以外は
OfficialのUSBHostとインターフェース互換です。
制限事項も同じく、USBデバイスは予め接続しておかなければいけない。
USBデバイスの取り外しには対応していません。
USBハブは使えます。

アイソクロナス転送だけはKL46Zのとインターフェース互換ではありません。
Webカメラ用に専用のライブラリを作りました。

まだまだ不具合がありますが、使用例をmbedサイトに置きました。

USBフラッシュメモリの使用例
LPC4088-USBHostMSD_HelloWorld
Webカメラの使用例
LPC4088-USBHostC270_example

(2014/4/24)
---

2014年2月27日木曜日

FRDM-KL46Z用USBホストライブラリの試作(2)

・ソフトウェアリトライに変更。
 KL46ZのUSBコントローラにリトライを任せずに、ソフトウェア側でステータスを見てトークン転送レベルで再送処理をするように修正しました。
 今までトークン転送でバスエラーになってしまったUSBフラッシュメモリーが読み取れるようになった。
 少なくとも以前に比べて安定しているので、使えるUSBデバイスが多くなります。

・USBハブに対応。
 接続数の制限はほぼありません。

・アイソクロナス転送を追加。
 WEBカメラが使えるようになりました。
 KL46Z-USBHostC270_example

・なるべく公式USBホスト互換のインターフェースに変更。
 多くの対応ソフトが僅かな修正で動くようになりました。
 ただし、RTOSを使っていないのでノンブロックでコールバックが必要な転送では USBHost::poll()を呼び続けます。
 使用例:KL46Z-USBHostMouse_HelloWorld

その他の細かい修正、改造はコミットメッセージを参考にして下さい。
https://bitbucket.org/va009039/kl46z_usbhost/commits/all

Simple USBHost library for FRDM-KL46Z
http://mbed.org/users/va009039/code/KL46Z-USBHost/

***

FRDM-KL25Zも同じUSBコントローラなので、USBコネクタに電源を供給できればUSBホスト機能が使えるようになります。



(2014/2/23)
---

2014年1月22日水曜日

FRDM-KL46Z用USBホストライブラリの試作(1)

mbedのOfficialなUSBHostに期待しているだが、
試しに機能限定でコードを書いてみたらLPC1768のOHCIに比べて簡潔に書けたので参考のために公開します。
少なくともUSBHostLiteくらいの機能はあります。

現在の機能・制限

・コントロール転送 送信、受信。
・インタラプト転送、受信のみ。USBマウス、USBキーボードで使用。
・バルク転送 送信、受信。パケットサイズを64バイトに固定。USBフラッシュメモリ、GPSレシーバーで使用。
※全てブロック型なので、転送完了まで待ちます。
・USBハブには対応していない。
・USBデバイスの自動認識は対応していない。予めUSBデバイスを接続しておく。

FRDM-KL46Zで使うには、多くのUSBデバイスはバスパワーで動いているようなので、
例えば、J16をショートしてUSBコネクタに5Vを供給するようにする。


USBデバイスのAプラグをFRDM-KL46ZのミニUSBコネクタに変換するケーブルが無かったので、
とりあえずブレッドボードでAコネクタを2つ向かい合わせて変換しています。


ライブラリ、使用例はmbedサイトに置いてあります。
http://mbed.org/users/va009039/code/KL46Z-USBHost/

***

以下、製作時のメモ:

USBホストモードの基本的な使い方は、KL4x Reference Manualの 35.6 Host Mode Operation Examples が参考になる。
しかしながら、TXバッファだけを使うように書いてあるのは間違い。RXバッファも使う。

実際に動いているコードとしては Freescale USB Stack V4.0.2 のkhci_kinetis.c が参考になる。
USBモジュールの初期設定やバッファの使い方の理解には、mbed USBDevice の USBHAL_KL25Z.cpp が参考になる。
ただし、DMAで動かしているようで、片方のバッファだけに割り当てているようだ。

ホストモードではエンドポイントの送信・受信バッファは、1つのエンドポイントのバッファを共用する。
送信、受信の区別はある。それぞれ、ODD、EVENの2つのバッファを持っている。
つまり、バッファ(ポインタ)は4つだけ。

ロースピードUSBとフルスピードUSBの判断に、JSTATEを見るのだが、
SOFを送信状態にしていると、いつでもフルスピードUSBと誤認識してしまう。
USBデバイスがアタッチするまでは、SOFは止めておく。

DATA0,DATA1のトグルはUSBホストに任せて自動で切り替えてもらう方法と、都度設定する方法がある。
コントロール転送だけで送信、受信でトグルを共用する場合とか、
一方方向だけのインタラプト転送(例えばUSBマウス)、バルク転送(例えばGPSドングルでデータを受信するだけ)なら、
USBホストに任せてもいいが、USBフラッシュメモリのように送受信で2つのエンドポイントを
使う場合には、都度設定する方法を選ばなければならない。

khci_kinetis.c では、トークンのリトライをしているが、現在はしていない、
時々Bus_Timetoutしたり、NAKが返ってくるのは、USBケーブルの配線の問題かもしれない。
USBデバイスによって、エラーの発生具合にばらつきがある。

デバイスのリセットはリファレンスマニュアルでは 10ms だが、khci_kinetis.c では 500ms がいいらしい。

SETUPトークンが成功するとACKだが、USBマウスではNAKが返って来る時がある。

INトークンが成功するとDATA0またはDATA1のステータスが返る。Bus_Timeoutが返って来る時がある。
USBフラッシュメモリーのバルク転送受信で時々発生した。

OUTトークンが成功するとACKが返る。

USBマウスでコンフィグレーションを設定するとステータスステージでSTALLが返ってくる時がある。

(2014/1/22)
---

2013年9月30日月曜日

mbedでMSC+CDC+HIDのUSB複合デバイスの作成

mbed USBデバイスクラスでMSC+CDC+HIDのUSB複合デバイスを作りました。

USBMSD_LPC_HelloWorld

USBをパソコンに挿して次のようにデバイスを確認しました。



・MSC Windowsのファイル書込みに依存するが、ドラッグ・アンド・ドロップでファイルのデータを受け取る事が出来ました。
・CDC USBシリアル変換です。VID,PIDを同等したので、mbedのWindowsシリアルドライバ(mbedWinSerial_16466.exe)が使えました。
ボーレート設定、ブレーク送信、制御信号(DTR,RTS)を受け取るのも確認していますが使っていません。
・HID 64バイトのデータの送受信が出来ました。

本来は、FRDM-KL25Zで動いて欲しかったのですが、エンドポイントの割り当てがよくないためか動いていません。

参考記事:
FRDM-KL25Zでドラッグ・アンド・ドロップ

(2013/9/30)
---

|本来は、FRDM-KL25Zで動いて欲しかったのですが、エンドポイントの割り当てがよくないためか動いていません。

KL25Z、KL46Zはどのエンドポイントでも割り当てる事が出来ます。
動かなかったのはUSBHALの割込みハンドラーに間違いがあったためです。

USBDevice/USBHAL_KL25Z.cpp
http://mbed.org/users/va009039/code/USBDevice/rev/6dcb8023e437

(2014/2/21追加)
---

2013年5月4日土曜日

USBトークン、データCRCの計算

CRCの理論はよくわかってないが、テストが通るからたぶん計算方法はあっていると思う。

8.3.5.1 Token CRCs
8.3.5.2 Data CRCs


# coding:utf-8
# test_crc5usb.py 2013/5/3
#
import unittest

def crc5usb(data):
    assert(data >= 0 and data <= 0x3ff)
    r = data ^ 0x1f
    for _ in range(11): # 11bit
        if r & 1:
            r = (r>>1) ^ 0x14
        else:
            r = r>>1
    return r ^ 0x1f


class Test_crc5usb(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_80_2d_00_10(self): # SYNC SETUP
        u16 = 0x00 | 0x10<<8
        self.assertEqual(u16&0x7f, 0)     # ADDR=0x0
        self.assertEqual((u16>>7)&0xf, 0) # ENDP=0x0
        self.assertEqual(u16>>11, 0x02)   # CRC5=0x02
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x02)   # CRC5

    def test_80_69_87_d8(self): # SYNC IN
        u16 = 0x87 | 0xd8<<8
        self.assertEqual(u16&0x7f, 7)     # ADDR=0x7
        self.assertEqual((u16>>7)&0xf, 1) # ENDP=0x1
        self.assertEqual(u16>>11, 0x1b)   # CRC5=0x1b
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x1b)   # CRC5

    def test_80_00_10(self):
        u16 = 0x00 | 0x10<<8
        self.assertEqual(u16&0x7f, 0)     # ADDR=0x0
        self.assertEqual((u16>>7)&0xf, 0) # ENDP=0x0
        self.assertEqual(u16>>11, 0x02)   # CRC5=0x02
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x02)   # CRC5

if __name__=="__main__":
    unittest.main()

# coding:utf-8
# test_crc16usb.py 2013/5/3
#
import unittest

def crc16usb(data):
    r = 0xffff
    for d in data:
        r ^= d
        for _ in range(8):
            if r & 1:
                r = (r>>1) ^ 0xa001
            else:
                r = (r>>1)
    return r ^ 0xffff

class Test_crc16usb(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_00_00_ff_00_2bbe(self):
        data = [0x00, 0x00, 0xff, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0x2bbe)

    def test_00_ff_00_00_ebcf(self):
        data = [0x00, 0xff, 0x00, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0xebcf)

    def test_None_0000(self):
        data = []
        r = crc16usb(data)
        self.assertEqual(r, 0x0000)

    def test_80_06_00_01_00_00_40_00_94dd(self):
        data = [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0x94dd)

    def test_12_01_10_01_00_00_00_08_7711(self):
        data = [0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08]
        r = crc16usb(data)
        self.assertEqual(r, 0x7711)

    def test_58_04_07_00_00_00_01_02_487f(self):
        data = [0x58, 0x04, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02]
        r = crc16usb(data)
        self.assertEqual(r, 0x487f)

    def test_00_01_8f3f(self):
        data = [0x00, 0x01]
        r = crc16usb(data)
        self.assertEqual(r, 0x8f3f)

if __name__=="__main__":
    unittest.main()


(2013/5/4)
---

2013年4月29日月曜日

ロースピードUSBをパケットキャプチャ

12MHzのAVRはV-USBでロースピードlow speed(1.2Mbps)のUSBをソフトウェアだけで受信・送信しているので、
96MHzのmbed LPC1768なら余裕でパケットを取り込めるだろうと考えて作ったテストプログラムです。

USBLowsCap USB low speed packet capture

正しいのかわからないが、USBハブのAコネクタからDATA+/DATA-を取り出してmbedに直接接続しています。

動作例:

USBマウスをパソコンに接続した時。デバイスディスクリプタを読んでいるのがわかります。


USBマウスを動かした時。通常はパソコンからの要求INにNAKで返しているが、レポートとして4バイトのデータを返しています。

本来は、フルスピードfull speed(12Mbps)のパケットを取り込みたかったのだが、
現状のプログラムの書き方では少し速度が足りない。

(2013/4/29)
---

2013年1月20日日曜日

mbedでBluetoothのRSSI受信信号強度の取得



HCI_Write_Inquiry_Mode で Inquiry Result format with RSSI を設定すると、
Inquiry Result Event から Inquiry Result with RSSI Event に変わってRSSI付きの検索結果が
返って来るようになります。

更に、HCI_Periodic_Inquiry_Mode にしておけば Inquiry Command を都度送らなくても、
繰り返して Inquiry Result Event や Inquiry Result with RSSI Event が返って来るようになります。

上のグラフは自分の携帯電話のBluetoothのRSSIを一日間cosmに記録した例です。
mbedオレンジボードに繋いだBluetoothのUSBドングルで検出してcosmにデータを送っています。
cosmにはトリガーがあるので、例えば不検出になったらHTTP POSTすればみまもりに使えそうです。

mbedで実行していたプログラムは次のとおりです。

mimamoriBluetooth_example

(2013/1/20)
---

2013年1月16日水曜日

USBハブのSET_POWER


USBハブへSET_POWERをSET_FEATURE/CLEAR_FEATUREで送れば、
USBポートの電源管理ON/OFFが出来ると思っていたのは勘違いだったようだ。

セリアでUSB接続のLEDライトを購入してきてテストプログラムを書いたけど全然消灯しない。

エレコムの節電USBハブを調べていたら特別のコマンドを送っているらしいので専用のUSBハブらしい。

(2013/1/16)
---

2012年12月5日水曜日

mbedのUSBホストライブラリの作成

mbed用のUSBホストライブラリを作り直してみました。
まだまだ改良しなければならないらしいところはありますが,とりあえず動いているようなので公開します。

BaseUsbHost

UVCカメラにアイソクロナス転送、USBフラッシュメモリにバルク転送、マウスにインタラプト転送、
コントロール転送が使えます。USBハブが使えます。

実装での特徴としては、割り込みからのTDの通知にmbed-RTOSのqueueを使用。
ED,TD,ITD,HCCAの確保にposix_memalignを使用。
スレッドとは非同期に転送できるように、転送データのバッファはTD,ITDの末尾にも貼り付けれようにした。
アイソクロナス転送ではうまくいっているが、コントロール転送の連続コマンド送信はエラーになりやすいみたい。

使用例として以前のカラートラッキングのプログラムを動くようにしてみました。
UVCカメラはLogitechC270専用にしてコンフィグレーションディスクリプタを読み取るのを止めた。
SET_CONFIGURATION,SET_INTERFACE,UVCへのコントロールを送っいるだけです。

BaseUsbHost_example

下のキャプチャーはカメラからmbedにモーションJPEGをアイソクロナス転送したデータを
確認のためにパソコンのターミナルソフトで数値表示しているところです。
CCの行はITDのコントールのコンディションコード、
PSの行はITDの中のパケットステータスのコンディションコードの発生回数を表示しています。



(2012/12/4)
---

2012年12月3日月曜日

訂正:USBカメラをmbedに繋げてみた(3)

SET_CONFIGURATION を送らなくてもいいのは勘違いだった。
enumerate()で SET_CONFIGURATION config=1 を送っていた。SET_CONFIGURATION を送らなくても
各種のディスクリプタは読めるが、SET_INTERFACE を送るとステータス・ステージでエラーになってしまう。

>他の多くのUSBデバイスがSET_CONFIGURATIONを送らなくてもだいたい動くが、ハブの場合は>SET_CONFIGURATIONを送らないといけないようです。

(2012/12/3)
---