最も安価なUSB-GPIBアダプタ

CH32V003にはUSBを扱う機能が無い. しかし,rv003usbを使うとlow speedのUSBを使うことができる. 20pinのICでは,電源とグランドとUSBの二本を除くと,16ピン残る. これは,GPIBに必要なピンの数と一致する. CH32V003は非常に安価なので,これを使ってUSB-GPIBアダプタを作れば,最も安くUSB-GPIBアダプタが作れるのでは無いかと思ったので,作ってみた. rv003usbのインストールはdownloadしてunzipすればよいが,ch32funと組み合わせて使うので,近くのフォルダにすると便利である. プログラムは,通常はWCH-LinkEを用いて書き込みをするが,USBからプログラムを書くことができるbootloaderも作られており,最初以外はWCH-LinkEが不要になるので便利である. bootloaderを入れるには,rv003usbのbootloaderフォルダに行って,usb_config.hでUSBに使うピンを指定する. 私の場合は以下のようにした. #define USB_PORT A #define USB_PIN_DP 2 #define USB_PIN_DM 1 //#define USB_PIN_DPU 5 そして,Makefileの中のCH32FUNに,../../ch32fun-master/ch32funなどとch32funのソースファイルの場所を指定する. すると,make cleanと初期化して,make buildでコンパイルできる. WCH-LinkEに接続してmakeとすると,minichlinkで書き込みが行われる. USBケーブルとの接続は以下のようにする. USBの5Vから3.3Vを作って,それをCH32V003の電源に繋ぎ,USBのdata線は33ohmの抵抗を介してケーブルに接続する. Low speedであることを指定するために,USBDMは1.5kohmの抵抗を介して3.3Vに接続する. この状態でUSBにさすと,bootloaderが認識され,五秒後にユーザーコードが実行される. ch32funの書き込みツールであるminichlinkでプログラムを書き込むことができるので,この五秒間に書き込みを開始する. rv003usbを使うのは今回は初めてだったので,使い方を調べながらGPIB用のプログラムを書いたが,予想していたよりも単純だった. まず,control transferとendpoint in/outを扱うために,usb_config.hで以下のように設定する. #define RV003USB_HANDLE_IN_REQUEST 1 #define RV003USB_OTHER_CONTROL 1 #define RV003USB_HANDLE_USER_DATA 1 usb_config.hには,descriptorの情報も記述する. control transferのrequestはusb_handle_other_control_messageに何をするかを記述する. s->wRequestTypeLSBRequestMSBの下位バイトがRequestTypeで上位バイトがRequestなので,それらの値で分岐する. その際,s->lValueLSBIndexMSBの下位ワードがValueで上位ワードがIndexであるので,これらの値を必要に応じて使う. e->opaqueにはバッファ,e->max_lenにバイト数を指定すると,データを返すことができる. このバッファを示す変数に,関数の内部で定義した変数を使っていたら,関数が終わったときに開放されるのでうまく行かなかった. static volatileにしておく必要があるだろう. endpointのINとOUTはそれぞれusb_handle_user_in_requestとusb_handle_user_dataに何をするかを書く. INの処理では,usb_send_data(buf,len,0,tok)でデータを送ることができる. ここで,bufはデータのあるバッファで,lenはそのバイト数である. 空のデータを返すときには,usb_send_empty(tok)を使う. NAKを返す場合にusb_send_data(0,0,2,0x5a)を使えば良いことが分かるまでには少し苦労した. vendor specificなUSB-GPIBアダプタが出来たので,少し長くなるが,ファイルの内容を書いておこうと思う. まず,Makefileでは,rv003usbを組み込むこと以外は,特記すべき点は無いが,以下の内容である. all : flash TARGET:=usb003gpib CH32FUN:=../ch32fun-master/ch32fun TARGET_MCU:=CH32V003 ADDITIONAL_C_FILES+=../rv003usb-master/rv003usb/rv003usb.S .
Read more...

CH32V203K8T6をbootloaderでarduinoから使う方法

安価なマイコンとしてCHシリーズのいくつかを使ってきたが,新たにCH32V203を使ってみることにした. このマイコンは,USBを正式に使える32ビットマイコンの中で,最も安いものの一つであろう. 入手しやすくて,ピンの数がそれなりに多いものとして,32ピンのCH32V203K8T6について,USBからプログラムを書き込んで,使ってみることにした. しかし,予想よりもかなり苦労したので,その使い方を書いておこうと思う. USBを使うためには,三端子レギュレータとコンデンサーで,5Vから3.3Vを作って電源に供給する. 電源が3ピン,グランドが2ピンあるので,そのすべてを接続する. そして,USBのDPとDMを繋ぐ. すると,BOOT0を3.3Vにしながら,USBを繋ぐと,bootloaderが起動する. 通常はBOOT0は0Vにしておくために,適当な抵抗を介して,pull downしておくと良い. bootloaderが起動した状態で,dmesgを確認すると,以下のように表示される. usb 3-4: new full-speed USB device number 79 using xhci_hcd usb 3-4: New USB device found, idVendor=4348, idProduct=55e0, bcdDevice=27.00 usb 3-4: New USB device strings: Mfr=0, Product=0, SerialNumber=0 USBが認識したので,あとは簡単だろうと思ったら,大間違いだった. 書き込むソフトとして,minichlinkやopenocdを試したが,ダメだった. いろいろと探したり試したりして,wchispを使うと書き込めることが分かった. Arduinoからこのマイコンを使うには,主に以下の二つの方法がある. 一つは,arduinoのwch公式サポートを使う方法である. インストールの仕方は省略する. しかし,そのままではwchispは使えないので,一旦,コンパイルしたバイナリを出力する. wchispのバイナリをここから取ってきて,展開してchmod u+x wchispで実行可能とする. bootloaderが立上がった状態で,情報を表示するコマンドと,バイナリファイルtest.binを書き込むコマンドは以下の通りである. ./wchisp info ./wchisp flash test.bin もう一つは,arduinoのWCHサポートのフォークを使う方法である. そのために,環境設定のところに以下のURLを追加する. https://raw.githubusercontent.com/verylowfreq/board_manager_ch32/main/package_ch32v_index_sz.json board managerからCH32V Boards by M.S.を見つけたら,インストールできる. WCHの公式を入れているときには必要無いが,ユーザー権限で書き込みができるようにするためには, ~/.arduino15/packages/WCH_sz/tools/beforeinstall/1.0.0/50-wch.rules を/etc/udev/rules.d/にコピーして,sudo udevadm control –reload-rulesを実行する. ボードの設定は,Board - CH32V EVT Boards Support - CH32V20xとするが,WCH公式と共存している場合には,CH32V EVT Boards Supportが二つ出てくるので,CH32V20xだけがある方を選ぶ. USBから直接書き込む場合には,upload methodとしてWCH-ISPを選択する. これで,プログラムを書いたら,書き込むことができる.
Read more...

ch55xduinoとch32のarduinoのGPIO

CH32V用のプログラムを,リファレンスマニュアルを見ながら書いていたら,同じ会社のCH55xとは,GPIOの仕様がかなり違うことに気がついた. 機能としてはCH32Vの方が多いが,使い勝手はCH55xの方が良い気がする.

arduinoにWCHサポートを入れてCH32Vのプログラムを書く場合には,pinModeとして INPUT,INPUT_PULLUP,INPUT_PULLDOWN,INPUT_ANALOG,OUTPUT,OUTPUT_OD,OUTPUT_AF_PP,OUTPUT_AF_ODが指定できる. マニュアルの等価回路を見ると,出力modeのときには入力は無効で,INPUTとINPUT_ANALOGのときには出力は無効のようである. INPUT_PULLUPとINPUT_PULLDOWNは出力の値によって区別されているので,そのどちらかにしてからdigitalWriteをすると,modeをこれらの間で変えることが出来ると予想される. その動作は確認していないが.

ch55xduinoでCH55xのプログラムを書く場合には, INPUT,INPUT_PULLUP,OUTPUT,OUTPUT_ODとpinModeで指定できるmodeの種類は少なくなっている. 出力modeのときでも,入力は有効であり,INPUT_PULLUP modeのときには,出力は有効である. INPUT以外にしておけば,GPIOを入出力の両方で使うことが出来るのである.

arduinoでプログラムをしていると,マイコンの種類をあまり意識しないで使うことができる場合も多いが,これらのマイコンのGPIOを使うときには,細かな違いを意識した方が良いだろう.

Read more...

ch32funでCH32V003を使ってみた

WCH社のマイコンCH32を使うようになったが,以前はarduinoのWCH CH32Vサポートを使った. しかし,コンパイルしたときのサイズが大きくなるらしく,フラッシュの小さなマイコンで,複雑なプログラムをする場合には,適切ではないようだ. また,対応していない機能などもあるそうである. そこで,ch32funを試してみることにした. ch32funはもともとはch32v003用に開発されたようだが,他のマイコンにも徐々に対応して来ているが, フラッシュの小さなch32v003には特に有用だろう. まずはインストールであるが,debianでは思ったよりも簡単だった. 必要なパッケージを以下のようにしてインストールする. sudo apt-get install build-essential libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev libudev-dev そして,ch32funのサイトからzipをdownloadする. コマンドラインでやりたいときは,下のようにする. wget -O ch32fun-master.zip https://github.com/cnlohr/ch32fun/archive/refs/heads/master.zip そして,それを展開したらインストールは完了である. 書き込みソフトであるminichlinkを使えるようにするためには,権限の問題を解決するために,以下を実行する. sudo cp minichlink/99-minichlink.rules /etc/udev/rules.d/ sudo udevadm control --reload sudo udevadm trigger うまくインストール出来たかを確かめるために,examplesには,ch32v003用のプログラムの例があるので,そのどれかのフォルダに行って,コンパイルを試してみると良い. make buildとすると,コンパイルされて,やり直すときには,make cleanとしてから再度実行すれば良い. 単にmakeとすると,minichlinkを使ってマイコンへの書き込みまでやってくれる. 実行する前に,WCH-Link Eなどで接続しておけば良い. 新たなプログラムを作るときには,exampleの中のtemplateをコピーして使うと良い. Makefileでは,TARGETをc言語のファイル名として,includeはch32fun.mkのファイルの場所を指定する. プログラム中では,以下の順で実行する. まずは,初期化としてSystemInit();を実行する. 次に,使う機能を有効化する. 例えば,GPIOをすべて有効にするには,funGpioInitAll();とし,PDだけを使うならfunGpioInitD();とする. そして,やりたいことを記述する. 入力モードにして読み取って,出力モードにして出力するのは,以下のような感じ. uint8_t v; funPinMode( PD0, GPIO_CFGLR_IN_FLOAT ); v=funDigitalRead(PD0); funPinMode( PD0, GPIO_CFGLR_OUT_10Mhz_PP ); funDigitalWrite( PD0, FUN_HIGH ); funDigitalWrite( PD0, FUN_LOW ); 入力はアナログ(ANALOG),pull-up pull-down(PUPD),高インピーダンス(FLOAT)が選べる. 出力は周波数として2Mhz,10Mhz,50Mhzが,モードとしてpush-pull(PP)とopen drain(OD)が選べる. レジスタなどをあまり意識しないで,arduinoのように書くことが出来るようになって来ている.
Read more...

pcbエディタのみでプリント基板の設計

プリント基板の設計にはkicadを使っているが,複雑な回路を作るのには便利なのだが,逆に簡単な回路用の基板を設計するが面倒であると感じていた. kicadでは,まず回路図を書いてから,netlistを作って,pcbの配置を決めるのだが,単純な回路の場合には,回路図を書かずにいきなりpcbを作った方が楽な場合がある. 他にも,マイコンを使うときには,ピンの入れ替えができるので,回路図の段階ではどのピンを使うかを決めずに,pcb上でピンを決めた方が良い場合もある. さらに,使うICが回路図エディタのライブラリに無い場合には,外部のライブラリを探すか自分で作らなければならないが,データシートを見ながらpcb上で配線をどう繋げば良いかを考えるのは難しくない.

これまでは仕方なく回路図を書いてからpcbの設計をしていたが,回路図を書かずにpcbエディタだけを使って基板の設計をする方法が分かったので,そのやり方を書いておく. ます,pcbエディタを起動する. 原点はplace - drill/place file originで決めて置くと良い. 基板の外形はEdge.Cutsのレイヤーを選んでdraw lineで描く. そして,必要な部品をplace - place footprintsで配置して,それらの端子を配線で結べば良い. 配線で結ぶときに,netlistが無いので繋げないこともあったが,その場合には配線の設定でAllow DRC violationsとすると,繋げるようになる. 実は,このやり方がpcbエディアの本来の使い方なのかも知れないが,kicadの使い方を調べると回路図から始めるやり方しか見つからなかったので,これまで知らなかった.

マイコンの配線をするときには,回路図を作って,pcbエディタで配置を決めて,配線の取り回しが悪い場合には,回路図に戻ってピンを入れ替えて,またpcbエディタに戻るということを繰り返さなければならなかったが,pcbエディタのみで出来れば,効率化される. ユニバーサル基板上に部品を載せて,データシートを見ながらハンダ付けをする感じで配線を考えられて,訂正も出来るので,良い感じである. この方法でいくつかの基板を設計してみたが,やり方に少し慣れてきた. でも,配線の誤りが無いかは目でしっかりとチェックしなければならない. pcbエディタで配線した情報から,逆にnetlistを作って,回路図にするとかが出来れば,間違いのチェックも出来て良いのでは無いかと考えてしまう.

Read more...

WCH社のマイコンでUSBデバイス

WCH社のマイコンで単純なUSBデバイスを作るときに,どのICを使うと便利かを考えてみた. まず,WCH社の代表的なマイコンは,CH55xシリーズとCH32シリーズに大きく分けられる. これらはCPUのコアなどに違いがあるのだが,USBデバイスを作るハードという観点では,電源の違いが大きい. CH55xシリーズでは,コンデンサを付ければ3.3Vを作ってくれるので,ピンが一つ減ってしまうが,マイコン以外に余分な部品無しでUSBを扱える. 一方,CH32シリーズでは,USBの5Vから三端子レギュレータなどで3.3Vを作って,それをマイコンの電源として使わなければならない.

秋月で入手可能なWCH社の安価なICについて,USBを使う時の機能などについて比較して,表にまとめてみた. ピン数の少ないものは省いたが,似た型番のものとほぼ同じ性能と考えれば良い. データシートなどを見て,まとめたものなので,ミスなどはあるかもしれないが,ご容赦いただきたい. このpin数のところではUSBのデータ線の2本を引いてある. この表の中のデータ以外にも,細かい違いもあるので,私が理解している範囲で説明したい.

ICCH552TCH559TCH559LCH32V203K8T6CH32V305FBP6CH32V003F4P6
価格(円)7018015012025050
pin数202048322020
GPIO数16-216-24026-217-218-2
flash16k64k64k64k128k16k
RAM256+1k256+6k256+6k20k32k2k
default clock6M12M12M8M8M24M
USB version2.0FS2.0FS2.0FS2.0FS2.0HS1.1LS
EP番号0-40-40-40-150-150-2?
EP size646464合計51210248?

先日,CH552を使ってUSBデバイスを作ってみたが,ICとコンデンサ二つとUSBコネクタだけでUSB機器が作れて,クセはあるが有用なICだと感じた. 同じCH55xには,より高性能なCH559もあり,ほぼ同様の使い方ができるだろう. これらのマイコンは,MCS51と互換性のあるコアを使っており,フリーのコンパイラが限定されるために,C言語は使えるが,C++が使えない. Arduinoでは,ch55xduinoを組み込むことで使うことができる.

32bitマイコンであるCH32では,高性能なものはUSBを扱う機能が組み込まれている. 最も安価なCH32V003では,それ自体にはUSBを扱う機能は無いのだが,rv003usbを使うとLow SpeedでUSBを使えるようになる. CH32V003F4P6については,rv003usbを使う場合について表中に書いてあるが,まだ理解できていない部分も多いので,間違っているかも知れない. これらのマイコンは,CH32Vサポートを組み込むと,Arduinoからも使えるようになる. 当然,C++も使える. 特に,USB機能のあるマイコンは,TinyUSBライブラリを使ってプログラムすることができる.

まとめると,その目的に応じて,以下のようにマイコンを選択すると良いと思う. 安く少ない部品点数でUSBデバイスを作りたいときには,CH55xをch55xduinoから使うと良いだろう. プログラムにはコア特有のクセがあり,C言語で書かないといけないが,モードを切り替えればUSBからプログラムを書き込めるので,楽である. とにかく安く作りたいときには,CH32V003+rv003usbが選択肢として考えられる. コンパイル環境を整えたり,rv003usbをある程度理解する必要があるが,Low Speedで良い場合には十分に使えると思う. そうでなければ,USB機能のあるCH32Vを使うと良いだろう. ArduinoでのTinyUSBの使い方に関する文章が少ないが,例を参考にすれば,比較的短いコードで,プログラムを書くことができる.

raspberry pi picoの搭載されているRP2040やRP2350も,非常に安価に売られていることに気がついた. このICはUSB1.1のLow Speedには対応しているらしいが,リードピンの無いパッケージなので半田付けが非常に難しいらしい. 一方,このICを搭載したマイコンボードとしては,raspberry pi picoはサイズが大きいのでこれまで使おうとは思っていなかったが,非常に小型のRP2040-ZeroやRP2350-Zeroというものも発売されている. 小型のマイコンボードなら,今後使う候補として考えていこうと思う.

Read more...

ch55xでUSBのプログラムをするには

ch552を使ってUSBを扱うことができるようになったが,ch55xduinoを使って他の用途への適用を容易にできるようにしたいと考えていた. そこで,WCHの公式とch554_sdcc_usb_blinkyとch55xduinoにおけるUSBのプログラムの違いについて比較してみた. まず,最も違うのがdescriptorの書き方である. WCHでは,直接数値の羅列として指定しているので,修正するためには知識が必要である. blinkyでは,独自に構造体を定義して,それを使っている. ch55xduinoでは,LUFAのdescriptorで定義された構造体などを使っている. WCHが作ったCH554.Hにも,descriptor用の構造体が定義されており,上記のいずれの場合にもこれを取り込んでいるのだが,その構造体はあまり利用されていない. 16bitの変数のbyteの順番の問題があるかも知れないが,この構造体をうまく活用できると良いのでは無いかと思われる. また,string descriptorについても,それぞれ苦労して書いているが,それらを統合したこんな書き方はどうかなと思う. __code uint16_t ManufacturerString[] = { ( sizeof(ManufacturerString) | (USB_DESCR_TYP_STRING << 8)), 'w', 'c', 'h', '.', 'c', 'n' }; byte数やunicodeの0を自然な形でうまく処理できていると思う. これをマクロの形にすると,もっとスッキリするかも知れない. 一番難しいのが,構造が複雑なconfiguration descriptorであるが,vendor spacificな場合には,それほど複雑な構造にする必要は無いように思う. interfaceの数とそれに含まれるEnd pointの数を固定すると,比較的簡単な構造体が定義できる. 次に違うのが,割り込みの処理の中の分岐の仕方である. WCHとblinkyでは,switch caseを使って,長々と書いていて,多重にネストされているので,どの処理がどこに対応するのか,非常に分かりにくい. 一方,ch55xduinoでは,in,out,sof,setupの処理をそれぞれのend pointに分けてサブルーチンを呼ぶようにしていて,少しスッキリしている. しかし,end point 0のsetupの処理が必然的に非常に長くなって,読みづらい. ここの処理を,standardとclassとvendorに分けて,後ろの二つを別のサブルーチンにすると良いのでは無いかと思う. これらの方針の元に,vendor specificな機器用のプログラムを書きやすくするルーチンを作ってみた. USBの基本的な処理のためのルーチンは,USBhandler.hに書いてあり,descriptorやendpointの設定と処理をメインのinoファイルに書くようにした. USBhandler.hの内容は,以下の通りである. #ifndef __USB_HANDLER_H__ #define __USB_HANDLER_H__ void EP0_OUT_Callback(); void EP1_OUT_Callback(); void EP2_OUT_Callback(); void EP3_OUT_Callback(); void EP4_OUT_Callback(); void EP0_SOF_Callback(); void EP1_SOF_Callback(); void EP2_SOF_Callback(); void EP3_SOF_Callback(); void EP4_SOF_Callback(); void EP0_IN_Callback(); void EP1_IN_Callback(); void EP2_IN_Callback(); void EP3_IN_Callback(); void EP4_IN_Callback(); void EP0_SETUP_Callback(); void EP1_SETUP_Callback(); void EP2_SETUP_Callback(); void EP3_SETUP_Callback(); void EP4_SETUP_Callback(); uint8_t EP0_DATA_Callback(); uint8_t EP0_VENDOR_Callback(); uint8_t EP0_CLASS_Callback(); void USB_RESET_Callback(); #define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer) __data uint16_t SetupLen; __data uint8_t SetupReq; volatile __xdata uint8_t UsbConfig; volatile __xdata uint8_t UsbInterface; __code uint8_t *__data pDescr; void EP0_SETUP_Callback() { __data uint8_t len = USB_RX_LEN; if (len == (sizeof(USB_SETUP_REQ))) { SetupLen = ((uint16_t)UsbSetupBuf->wLengthH << 8) | (UsbSetupBuf->wLengthL); len = 0; // Default is success and upload 0 length SetupReq = UsbSetupBuf->bRequest; if ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK) !
Read more...

WCH社のCH32の使い方

半導体不足になって,マイコンの入手が困難な時期があった. その時期にはWCH社などの中国製のマイコンがもてはやされ,普及が進んだ気がする. そのWCH社のマイコンの代表の一つがCH32シリーズです. ch32には,いくつかの開発環境がある. 公式にCH32向けに開発されたMounRiver Studioに加えて,Arduinoや,個人が開発したch32funやwagiminatorさんの開発環境などもある. さらに,Arduinoにも何種類かの環境が発表されている. WCHの公式は,サイズが大きくなるらしく,いくつかの機能も使えないなどの欠点があるようです. これをインストールするには,File-PreferencesのAdditional Boards Manager URLsに https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json を加えて,Tools-Board-Boards ManagerからCH32 MCU EVT Boardsを選べば良い. AlexanderManderaさんの環境は,ch32funをベースにしたもののようで,同様に https://alexandermandera.github.io/arduino-wch32v003/package_ch32v003_index.json を追加してWCH Boardsをインストールすればよい. ちょっと変わったものとしては, ch32を載せたボード用にch32funをカスタマイズした UIAPduino もある. 安価に入手が可能なCH32V003F4P6をArduinoのWCH公式サポートを用いて使ってみたので,そのやり方を書いておく. Arduinoでのインストールの仕方はすでに説明した. プログラムについても,大した注意点は無いので,説明は割愛する. 問題なのが書き込み方法です. 書き込みにはWCH-LinkEを使いますが,Linuxからの使い方の情報が少なかったので,苦労した. WCH-LinkEを使うためのツールも何種類か存在する. WCH社はWCHISPToolというツールを出しているが,Linuxでは使いにくいようだ. Arduinoの公式サポートにも,openocdという書き込みツールが付属していますが,そのインストールスクリプトを見たら,ライブラリを/usr/libに書き込むようだったので,アンインストールが面倒そうで,インストールを止めました. それ以外には,wlinkやminichlinkなどがある. 以下では,minichlinkをlinuxで使う方法の説明をする. 自分でコンパイルする場合には,以下のようにする. wget https://github.com/cnlohr/ch32fun/archive/refs/heads/master.zip unzip master.zip cd ch32fun-master/minichlink sudo aptitude install libudev-dev libusb-1.0-0-dev make sudo cp 99-minichlink.rules /etc/udev/rules.d/ sudo udevadm control --reload sudo udevadm trigger binaryを使う場合には,ここから自分の環境にあったものを取って来る. そして,実行可能権限を与える. chmod u+x minichlink_linux_amd64 WCH-LinkEには3つのmodeがある. USBに挿した時に青いLEDが光っていたらARM modeで,最初はこの状態です. 青いLEDが点滅していたらIAP modeで,これはfirmwareをupdateするときにしか使いません. 青いLEDが消えていたらRISC-V modeで,minichlinkはこの状態で使うことができる. 古いminichlinkは,使う前にModeSボタンを押してUSBに挿すことによって,RISC-V modeに変更する必要があったが,最新のものでは,自動的にこのmodeに変更してくれるようになっている. 私はそれを知らずに,ModeSボタンを押ために,ケースにドリルで穴をあけてしまった. 20pinのch32v003F4P6とWCH-LinkEのpinは,7をGND,9を3.
Read more...

CH552でUSBのserial number

ch552を使ってUSB機器を作れるようになったが, ch55xduinoとch554_sdcc_usb_blinkyを組み合わせた方法では,serial numberを記述することが出来なかった. 同じ機器を同時にいくつも接続した場合に,それらを区別するのにはserial numberが便利である. そこで,前回使ったプログラムを改造して,serial numberを使えるようにした. まずは,serial numberのデータを他の文字列を参考にして定義する. #ifndef USB_CUST_PRODUCT_SERIAL #define USB_CUST_PRODUCT_SERIAL_LEN 10 #define USB_CUST_PRODUCT_SERIAL {'0','1','2','3','4','5','6','7','8','9'} #endif このデータから,その文字列を表すdescriptorを作る. __code struct {uint8_t bLength; uint8_t bDscType; uint16_t string[USB_CUST_PRODUCT_SERIAL_LEN];} sd003 = { sizeof(sd003), USB_DESCR_TYP_STRING, USB_CUST_PRODUCT_SERIAL }; そして,他の文字列を処理している部分と同様に,以下のプログラムを追加する. else if(UsbSetupBuf->wValueL == 3) { UsbIntrDescr = (uint8_t*) sd003; len = sizeof(sd003); } これで,serial numberが扱えるようになる. 実際,USBに挿してdmesgで確認すると,SerialNumber:の後に文字列が表示されている. しかし,それぞれのマイコンにプログラムを書き込む時に,異なったserial numberを与えたり,それを管理するのは面倒である. そこで,ch552のunique IDをserial numberにすることにした. 上では変更することが無いので,flash上にデータがあり,__codeと定義したが,それを変更できるようにvolatile __xdataと変更する. そして,USBの初期化の部分で,sd003の文字列の部分をunique IDを16進数に直した文字列に書き換える. uint16_t ser; uint8_t num,i; ser=*(__code uint16_t*)ROM_CHIP_ID_HX; for(i=0;2>i;ser>>=4){num='0'+(ser&0x0f); sd003.string[1-i++]=num>'9'?num+7:num;} ser=*(__code uint16_t*)ROM_CHIP_ID_HI; for(i=0;4>i;ser>>=4){num='0'+(ser&0x0f); sd003.
Read more...

USB-パラレル変換ケーブルの制御

昔のPCにはプリンターポートがあり,プリンターを使う以外にも,データ転送など様々な用途に転用することができた. 私も,WindowsでIOポートを叩いたり,Linuxでparportを使って制御することによって,GPIBをエミュレートして装置を制御したりしたことがある. しかし,最近のPCにはUSBポートぐらいしか無い. USB-パラレル変換ケーブルは,プリンターポートの代わりに使えるので,原理的にはそのケーブルによって,同様に装置の制御ができるはずである. しかし,USB-パラレル変換ケーブルを制御する方法が分からなかった. USBについて多少は詳しくなったので,変換ケーブルの制御の仕方が分かるのでは無いかと思い,いろいろと試してみた. 家にあった変換ケーブルをUSBポートに挿すと,/dev/usb/lp0ができた. lsusb -vで調べてみると,interfaceが一つあって,そのsettingが3つあり,そのうちの2つはprinter classでUnidirectionalとBidirectionalであり,もう1つがvendor specificであることが分かった. USBのprinter classについて調べてみると,最後の1つはプリンターポートの規格であるIEEE 1284に対応していると推定でき,その制御の仕方を理解することが重要であることが分かった. vendor specificの場合には,その制御方法はvendorが決めるのであるが,今回はIEEE 1284という規格を実現するためのものなので,おそらく共通の仕様になっていると予想した. いろいろなICの仕様を調べたら,control transferを使った制御の方法が分かってきた. それを手元にある変換ケーブルに試してみたら,多少の試行錯誤の後,うまく動かすことができた. まず,usblpとしてシステムに使われていると,こちらからの制御は出来ないので,これを開放する. /etc/modprobe.d/blacklist.confにusblpをblacklistに加えて再起動すると,変換ケーブルを制御できる状態になる. あとはlibusbを使ってアクセスすれば良い. 基本的な手順としては,interface0のsetting2にして,auto modeをoffにしてから,双方向通信で制御信号も自由に扱えるBidirectionalモードにしたら,様々な制御が可能になる. 参考までに,rubyで書いたUSB-パラレル変換ケーブルを制御するプログラムは以下の通りである. require "libusb" class UsbLp def initialize() usb = LIBUSB::Context.new device = usb.devices(idVendor: 0x0598, idProduct: 0x1001).first @handle=device.open @handle.claim_interface(0) @handle.set_interface_alt_setting(0,2) @handle.control_transfer(bmRequestType: 0x40, bRequest: 4, wValue: 0x07f8, wIndex: 0x0000) # SET_1284_REGISTER IC control register to auto mode off @handle.control_transfer(bmRequestType: 0x40, bRequest: 4, wValue: 0x0623, wIndex: 0x0000) # SET_1284_REGISTER extended control register to bidirectional status() end # 36pin attr_accessor :strobe # No.
Read more...