Arduino上でTinyUSBを使ったCH32VのUSBデバイス

TinyUSBがCH32に対応した事を知ったので,それを使ってUSBデバイスを作ってみた. TinyUBBを使ってみた感想だが,USB serialなどの頻繁に使われるデバイスを作るのは簡単だが,癖が強くてファイルの構造が複雑なので,独自のデバイスの開発は難しいように感じた. 今回は,CH32シリーズの中で,USB機能が内蔵されている安いものとして,CH32V203K8T6を使ったが,そのときに分かったことを,簡単に説明する. ArduinoにWCHの公式サポートを入れた後に,スケッチ-ライブラリをインクルード-ライブラリを管理から,TinyUSBを検索してインストールする. 他のライブラリもセットでインストールするかを聞かれるが,すべてインストールして良い. それらのファイルは,~/Arduino/libraries/Adafruit_TinyUSB_Library/に保存されるので,必要に応じて参照することができる. 簡単な例はファイルのスケッチ例から見ることができるので,プログラムの参考になるだろう. 基本的な使い方としては,はじめに#include <Adafruit_TinyUSB.h>としてライブラリを組み込んでから,setup()でTinyUSBDevice.begin(0);を,loop()ではTinyUSBDevice.task();を実行する. 作りたいデバイスの種類に応じて,以下のようにオプションを指定することが出来,その後でライブラリをincludeするようにする. #define CFG_TUD_CDC 1 #define CFG_TUD_MSC 0 #define CFG_TUD_HID 0 #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 1 #define CFG_TUD_VIDEO 0 注意しなければならないのは,必ずUSB Serialが組み込まれてしまうという点である. いじっていて,何をやってもttyACM0として認識されるので,困っていたが,そういう仕様らしい. これを除くには,beginした後で,TinyUSBDevice.clearConfiguration()を実行すれば良い. その後で,自分が作りたいデバイスの定義をして行く. このとき,CDCを0にすると,うまく認識されなくなる. おそらくこれもUSB Serialが一旦組み込まれるからかも知れない. 以下ではvendor specificの場合について説明する. TinyUSBDevice.addInterfaceでAdafruit_USBD_Interfaceのサブクラスを指定すると,そのgetInterfaceDescriptorメソッドが呼び出されるので,その中でdescriptorを作るようにする. descriptorはTinyUSBDevice.allocInterfaceとTinyUSBDevice.allocEndpointとTUD_VENDOR_DESCRIPTORを使って簡単に作ることができる. control transferについては,device/usbd.cで記述されているtud_vendor_control_xfer_cbに処理を書いておくと,それが実行される. request->bRequestなどの値で分岐を行い,tud_control_xferでデータを返すことができる. end pointを介したデータのやりとりは,class/vendor/vendor_device.cに記述されている. データの読み書きは,tud_vendor_n_readやtud_vendor_n_writeを使って,指定したバッファに対して入出力する. この際,tud_vendor_n_availableやtud_vendor_n_write_flushなども併用すると良い. TinyUSBDevice.task()が呼ばれたときに,様々な処理が行われるが,その中で, マイコンがデータを受信したときにtud_vendor_rx_cbが, 送信し終えたときにはtud_vendor_tx_cbが呼び出される. これらの関数にデータの送受信の後に行う処理を記述することによって,デバイスの動作を制御することができる. これまでに書いたUSBデバイスのプログラムでは,PC側からの通信で割り込みがかかったときに,どのような処理をするかを書くことによって,データの送受信を行っていた. end pointの大きさは64バイトなので,データは64バイト毎に区切られるが,割り込みを使うことによって,送受信の要求があったときに次のデータの準備をするようにすると,バッファの大きさを気にせずにデータのやり取りをすることが出来た. しかし,TinyUSBでは割り込みの処理の部分はユーザーからは使わないような設計思想のようである. TinyUSBの現在の仕様では,送信用には1023バイトのバッファが用意されているようだが,バッファに64バイト以上のデータが溜まるか,flushされたときにのみ,実際にUSBへの転送が行われる. 64バイト未満のデータしか無い場合には,flashしないと,読み取ろうとしてもtimeoutしてしまうので,注意が必要である. また,64バイトより大きなデータの場合には,タイミングによっては64バイト溜まったときに一旦データが送られて,データの終了として0バイトのデータも送られることもあり,そこでデータが切れてしまうので,そこにも注意が必要である. 最小限の変更でデータが64byteで分割されないようにするために,tud_vendor_tx_cbがデータの終了の有無を返すようにして,終了のときにだけ必要に応じて0バイトのデータを送るようにしたら,64byteより大きなデータも途切れずに送信できるようになった. 具体的な変更するのは,vendor_device.hとvendor_device.cの中のtud_vendor_tx_cbの型をvoidからboolにして,defaultではtrueを返すようにして,vendor_device.cの中のtud_vendor_tx_cbを呼び出しているところで,その値を以下のように変数に入れて, // tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); bool fin=tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); その変数が真のときにのみ,終端信号を送るように,
Read more...

ruby/tkのインストール

rubyで扱うことのできるGUIには,現在は様々な選択肢がある. rubyの初期の頃には,GUIとしてはruby/tkが主流であり,私も以前はそれを使ってGUIを作っていた. しかし,十年ぐらい前にruby/tkが標準ライブラリから外れて,次に何を使おうか迷っていたが,その時はgtk2を使ってみた. 最近,久々にGUIを作ろうとしたら,debianにはruby/gtk2が無くなって,ruby/gtk3になっていたので,それも少し使ってみた.

今回,ずいぶん昔に書いたruby/tkのプログラムを,debian13で動かすことになったのだが,それをruby/gtk3に移植するのが大変そうだったので調べてみたら,ruby/tkは標準ライブラリでは無くなったものの,gemでインストールできることが分かった. 少しテクニカルだが,以下のようにすればインストールできる.

sudo apt-get install tcl8.6-dev tk8.6-dev 
sudo gem install tk -- --with-tcltkversion=8.6 \
 --with-tcl-lib=/usr/lib/x86_64-linux-gnu \
 --with-tk-lib=/usr/lib/x86_64-linux-gnu \
 --with-tcl-include=/usr/include/tcl8.6 \
 --with-tk-include=/usr/include/tcl8.6 \
 --enable-pthread

そして,昔のプログラムを走らせてみたら,rubyのversionによる違いのために,多少の書き換えが必要だったが,ruby/tkの部分は無事に走った. まだ,バグは残っているかも知れないが,ほとんど書き換える必要が無くなった.

GUIのプログラムはほとんど書かないので,久々に書こうとすると,使い方を思い出したりするのに時間がかかる. また,次々に新しいGUIの選択肢が出てきて,古いツールから新しいツールに移行すべきかを迷うこともある. ruby/tkがまだまだ使えることが分かったので,しばらくはそれを使い続ければ良いかなという気がして来た. ruby/tkを初めて使ったときには,その使い方を理解するのに時間がかかったが,それを覚えるのは無理だと感じて,自分がruby/tkを使いやすくするためのツールを書いて,それを介してtkを使うようにしたら,それなりに楽に使えるようになった. 簡単なGUIを作ろうとしているので,その手法でruby/tkで書いてみようと思う.

Read more...

最も安価な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アダプタが出来た. コネクタとケースを除いて価格を見積もってみると,基板が50円ぐらいで,CH32V003が50円ぐらい,三端子レギュレータとチップ抵抗とコンデンサで30円ぐらいだろうか. 以前作ったやつで使ったch552tが70円ぐらいで,チップコンデンサが5円ぐらいなので,そっちの方が僅かに安いかも知れないが,これはRENが制御できないという欠点がある. RENも制御できるものとしては,最安と言っても良いのでは無いだろうか. しかし,Low Speedなので,endpointのサイズが8byteしか無いという欠点もある. これらの欠点を解消した安いアダプターを作るには,USB機能のあるpin数の多い安いICを使う必要があるが,以前使ったCH32V203K8T6がその第一候補だろう. 価格は120円ほどなので,50円ほど高くなってしまうが,今度作ってみようと思う. 最後に少し長くなるが,ファイルの内容を書いておこうと思う. まず,Makefileでは,rv003usbを組み込むこと以外は,特記すべき点は無いが,以下の内容である.
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...