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...

ch552tでvendor specificなUSB-GPIBアダプタ

先日,ch552tを使ってUSB-GPIBアダプタを作ったが,これにはいくつかの欠点があった. RENが制御出来ないのは,ch552tのピンの数の問題なので仕方がないが,binary通信が出来ないとか,データは256バイトまでしか扱えないとか,パラレルポールが出来ないなどである. binary通信は特殊文字をエスケープするとかの処理をすれば可能であり,データサイズもバッファを増やしたりバッファサイズで区切って処理することで対応でき,パラレルポールに関しては適切にプログラムを書けば対応はできるはずだ. しかし,それらのためにはマイコンのプログラムを書き換える必要があり,c言語で実装するのが面倒である.

vendor specificな機器の作り方も分かったので,それを応用すればこれらの問題を解消したUSB-GPIBアダプタが作れるのでは無いかと思ったので,作ってみた. ハードは以前のままで,マイコンのソフトだけを入れ替えれば良い. hand shake以外の制御信号はcontrol transferを使って制御し,データの転送はbulk transferを使って行って,マイコンがhand shakeをするというように設計した. データはバッファサイズである64バイト毎に区切られるが,GPIB側の処理が終わったらACKとすることで,大きなデータも扱うことができるようになる. multi-lineコマンドも,ATNしてからbulk transferしてATNを下げるという方法で実現している. PC側のソフトはrubyで書いてみた. デバイスにアクセスするためには,権限の問題がある場合もあるが,ch55xduinoのインストール時に設定していれば問題無い. マイコンとPCのソフトは,私のhomepageのツールの装置制御とマイコンのところにあるので,ここでは割愛する. まだ,検証が十分では無いので,細かいバグは残っているかも知れないが.

原理的には他のUSB-GPIBアダプタと互換性のあるものも作れるかも知れないが,プロトコルを解析するのも面倒だし,使う分には独自の仕様で十分だろう. GPIBを使い始めて以来,様々なGPIBアダプタを作って来たが,ほぼ満足できる仕様になったと考えている. 価格面ではこれ以上下げるのはほぼ不可能だし,RENが使えない以外で性能的には問題無い. PC側のソフトはまだ改善の余地はあるし,ハードを簡単に作れるような基板なども設計すれば,さらに良いものができるかも知れない. しかし,世の中にはすでに様々なGPIBアダプタがあるので,このアダプタが広まる可能性は低いとは思うが,今後GPIBを使うときには,活用して行こうと思う.

Read more...

ch55xduinoを使ってch552で独自のUSB機器

ch552を使って,vendor specificな独自のUSB機器を作ろうと思ったが,情報がなかなか見つからなかった. メーカーのサイトのCH554EVT.zipに含まれている EVT/EXAM/USB/Device/VendorDefinedDev.Cがその公式な例であるが,コメントが中国語だし,汎用性に乏しく,Keil C51という特殊なコンパイラ用のコードで書かれているため,流用が難しい. そこで,いろいろと調べたり試したりした結果,ch55xduinoでch552を使ったvendor specific機器の作り方が分かったので,それを記録に残しておこうと思う. ch55xduinoに含まれているusb関係の定義だけでは,基本的な処理をするコードが足りないので,sdcc用に書かれたコードを利用することにした. ch554_sdcc_usb_blinkyのprojects/includeからusb_desc.hとusb_intr.hを取って来て使う. このとき,usb_intr.hの中の次の一行目の行を,二行目のように変更すると,ch55xduinoで使えるようになる. void DeviceUSBInterrupt(void) __interrupt(INT_NO_USB) void USBInterrupt(void) これは,USBの割り込みがch55xduinoの中ですでに定義されているためである. これらのファイルと同じフォルダにinoファイルを作って,arduinoを使ってプログラムをするのだが,その段階では,いくつか注意するべき点がある. 例としてend point 0とend point 1を使う場合について説明しよう. Arduino.hを読み込む時に,ch5xx_usb.hが読み込まれるので,default値から変更する場合には,その前にEP0_BUFF_SIZEとMAX_PACKET_SIZEの値を定義しておく必要がある. その後,上記のusb_desc.hを読み込んで, 独自のUSBに関する関数の定義をしてからusb_intr.hを読み込む. そして,end point 1のためのバッファーを確保する. 独自の関数としては,end point 1の初期化と,control transferのIN/OUTの処理,end point 1のIN/OUTの処理を書く. setupではUSBの初期化ルーチンを呼び出し,loopでは送受信のデータの処理などを行う. end point 0は主に制御に使われて,USB機器を認識するための情報などがやり取りされるが,一部はvendorも使うことができる. ホストからvendor用のデータを転送する場合には,bRequestTypeを0x41とすると,USB_CUST_CONTROL_DATA_HANDLERで定義された関数が呼ばれる. ホストからのvendor用のデータを要求する場合には,bRequestTypeを0xc1とすると,USB_CUST_CONTROL_TRANSFER_HANDLERで指定された関数が呼ばれて,その返り値のバイト数のデータがホストに送られる. これらの関数中では,UsbIntrSetupReqにはbRequestの値が入っているので,その値によって適切な動作をするように定義する. さらに,UsbSetupBuf->wValueL,wValueHで値を受け取れるので,様々な動作をさせることができる. しかし,やり取りできるデータのサイズは最大でも64バイトであり,小さいデータしか扱うことが出来ない. 大きなデータのやりとりは,end point 0以外を使う. end point 1は,バッファーの大きさが64バイトだが,データを分割することによって,大きなデータを扱うことができる. bulk transferの場合について,この処理を説明する. マイコンへの送信(OUT)の場合には,64バイトのデータを受け取った段階で,NAKにすると,ホストが送信を待ってくれるので,次のデータを受け取れるようになったときに,ACKとすると,次のデータが送られてくる. 送られてきたデータが64バイトのときには,次のデータがあり,それよりも小さい場合には,データの終了であると判断できる. ここで,注意しなければならないのは,データのサイズが64バイトの倍数の場合には,最後のデータとして0バイトのデータを送らないと,データの終わりを判断できないということである. この処理はlibusbが自動でやってくれると思っていたが,最後の0バイトは,自分で送らないといけないということに気付くまでに,試行錯誤をしてしまった. マイコンからの送信(IN)の場合にも,同様の処理を行う. 送りたいデータの64バイトが準備できたら,ACKとすると,ホストが読み取りに来るが,読み取り終わったらNAKにして,次のデータを準備する,という感じで繰り返す. 最後のデータは0から63バイトのデータとして送る. 簡単な動作をさせるプログラムを例として示す. #define EP0_BUFF_SIZE 16 #define MAX_PACKET_SIZE 64 #if (EP0_BUFF_SIZE+2*MAX_PACKET_SIZE) > USER_USB_RAM #error "
Read more...

CH552Tを用いたGPIBアダプタ

これまでに様々なGPIBアダプタを作ってきたが,低コストで楽にGPIBアダプタを作れないかと考えていたところ,WCH社のCH552Tを使うと新たなものが作れると気がついた. CH552TはUSBと直接接続でき,それ以外に14pinの入出力と1pinの入力を扱うことができる. GPIBは,8本のデータバスと,8本の制御線からなる. GPIBのコントローラーを作るには,12本の入出力,3本の出力,1本の入力が必要である. これをCH552Tで実現するためには,足りない1本の線を省略しなければならない. 省略できる線としては,三つの可能性が考えられる. ASCIIデータのみを扱うことにして8bit目のDIO8を省略するか, Interface ClearをしないことにしてIFCを省略するか, Remote Enableをoffにするのを諦めてRENをGNDに落とすかである. この中で最もデメリットが少ないのは,最後の案であると思われるので,それを採用して,GPIBのコントローラーを作ってみた. CH552TにUSBケーブルのGNDと5Vと二本のdata線を接続して,GNDと5Vの間およびGNDと3.3Vの間に0.1uFのコンデンサを繋ぐと,USBで認識できるようになる. そして,省略するRENと入力のSRQ以外の14本の信号線に,14本の入出力ピンを割り当てる. SRQには入力ピンであるRSTピンを使うが,そのためにch55xtoolなどを使ってRST機能を無効にしなければならない. CH552TのパッケージはSSOP20であるが,DIPへの変換基板を使うと,24ピンのアンフェノール(セントロニクス)コネクタにギリギリ入るので,コネクタからUSBケーブルが出ているだけの,スッキリとした形にできる. あとはプログラムであるが,Arduino UNOやnano用に書いたものをch55xduino用に書き換えた. SerialからUSBSerialになるので,ボーレートの設定は不要である. GPIBの信号線は,プルアップしてオープンドレインとすると良いが,これはpinModeをINPUT_PULLUPとすると実現できる. 他にもいくつかの変更を行ったが,折角なのでシリアルポールの機能も追加してみた. その機能はまだ動作確認をしていないので,うまく動くかは分からないが. そのプログラムが以下のようなものである. // USB to GPIB converter using CH552T #include <string.h> #define DIO1 32 // CH552T 1, GPIB 1 : I/O data bit 1 #define DIO2 14 // CH552T 2, GPIB 2 : I/O data bit 2 #define DIO3 15 // CH552T 3, GPIB 3 : I/O data bit 3 #define DIO4 16 // CH552T 4, GPIB 4 : I/O data bit 4 #define EOI 17 // CH552T 5, GPIB 5 : End Or Identify #define DAV 10 // CH552T 7, GPIB 6 : DAta Valid #define NRFD 11 // CH552T 8, GPIB 7 : Not Ready For Data #define NDAC 31 // CH552T 9, GPIB 8 : Not Data ACcepted #define IFC 30 // CH552T 10, GPIB 9 : InterFace Clear #define SRQ bRST // CH552T 6, GPIB 10 : Service ReQuest #define ATN 33 // CH552T 11, GPIB 11 : ATteNtion // shield GND //USB shield, GPIB 12 #define DIO5 12 // CH552T 17, GPIB 13 : I/O data bit 5 #define DIO6 13 // CH552T 16, GPIB 14 : I/O data bit 6 #define DIO7 35 // CH552T 13, GPIB 15 : I/O data bit 7 #define DIO8 34 // CH552T 12, GPIB 16 : I/O data bit 8 #define REN 9 // CH552T 18, GPIB 17 : Remote ENable 9:non-existing pin // GND // CH552T 18, GPIB 18-23 // signal GND // CH552T 18, GPIB 24 // CH552 Vcc(19)-0.
Read more...

ch55xduinoの特徴

先日からCH552Tをいじり始めたが,開発環境としては,ch552xduinoが良いように思えたので,使ってみた. 多少はその特徴が分かってきたので,メモを残しておく.

まず,Arduino IDEを立ち上げて,File - Preferencesとして,Additional Boards Manager URLsのところに,以下のどちらかのURLを追加する.

https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json
https://raw.githubusercontent.com/WeActTC/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json

私は開発者のものである前者を選んだ. そして,Tools - Board:… - Boards Managerから,ch552で検索して,CH55xDuino MCS51 plain C core (non-C++)をインストールする. Linuxの場合には,権限の問題をクリアするために,以下のコマンドを実行する.

sudo cp ~/.arduino15/packages/CH55xDuino/tools/MCS51Tools/20??.??.??/linux/99-ch55xbl.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

これでインストールは完了である.

Arduinoでは,Tools - Board - CH55x Boards - CH552 Boardとして,その下のClock Sourceは24MHz (internal) 5Vを選ぶ. プログラムを作ったら,DFUモードにして書き込む. 具体的には,P3.6を3.3Vにpull upした状態で,USBコネクタを接続して,すぐに書き込む. 開発ボードには,それ用のボタンがあるので,ボタンを押したままUSBコネクタを接続すれば良い. USB Settingsがdefault CDCの場合には,二回目の書き込みからは,そのままで書き込める.

通常のArduinoはC++だが,ch55xduinoはC言語である. これは,このCPUのフリーのC++コンパイラが無いかららしい. そのためもあり,多少書き方に特徴がある. 他のサイトにも書いてあることだが,ピンは二桁の数字で指定する. ピンのmodeは,INPUT,OUTPUT,INPUT_PULLUPに加えてOUTPUT_ODがある. 最後のはopen drain出力である. USBSerial.printなどの代わりにUSBSerial_printなどを使う. それから文字列については以下の次の段落にあるように注意が必要である. これらの違いを意識するだけで,それなりのプログラムは書けると思う.

文字列は少し癖がある. そのため,文字列をポインタを使って指定して表示しようとしたら,最初はerrorが出てうまく行かなかった. ch55xduinoの表示ルーチンでは,genericという機能を使って,表示したいものの型を判定して,呼び出す関数を切り替えて,適切に表示されるようにしている. そのソースを見てみると,文字列には,__code char *c,__data char *c,__xdata char *cの三つの種類があり,errorはそれがきちんと指定されていないから起こっていることが分かった. ch552には,256byteの内部RAMと1024byteの外部RAMがあり,前者は__data,後者は__xdataというように指定する. ちなみに,内部RAMのほとんどは別の用途に使うので,通常の変数は外部RAMに置かれるが,速い応答が必要な変数は,__dataで指定することによって,内部RAMに置くこともできる. 一方,プログラム本体はプログラムROMというflashにある. その部分に書かれた文字列が,__codeという指定をするのだろう. 文字列はそれがどのメモリにあるかを適切に指定しなけらばならない. 私の今回の場合はポインタの指定に__codeを加えることによって,うまく動くようになった. 普段は,charの配列に__xdataをつけて__xdata charとしておけば,問題無いことが多い.

Read more...