2013/01/17(木)XMOS、ファームアップデートメモ

1年以上前に書いたメモそのままです。


XMOS公式サイトから開発ツールをダウンロード。登録が必要なようです。

http://www.xmos.com/products/development-tools

メールでダウンロードURLが送られてきます。

XDE(統合環境/Eclisp)が64bit環境では動かないので、

C:\Program Files (x86)\XMOS\DevelopmentTools\11.2.2\xde_bin\jre

以下に bin や lib といった32bitなJava環境をインストールする必要があります。面倒なので、TiのCCE(同じくEclispによるTi製チップ*1統合開発環境)から

C:\ti\ccsv5\eclipse\jre

を丸コピーして済ませました……。

デバイスをUSBケーブルでつないでから、JTAGをつなぎます。

じゃないと、xflashに失敗して次のエラーで悩みます(汗)

C:\Program Files (x86)\XMOS\DevelopmentTools\11.2.2>xflash d:\usb_audio.xe
xrun: Problem in connection to device
Error: F03034 Failed to fully run flash inquisitor.
Error: F03034 By default xflash will try to connect to a target in order to determine
Error: F03034 which flash device is being used even when outputting only to file.  To
Error: F03034 prevent this connection supply the --noinq option.

参考にしたサイト

*1 : MSP430等

2008/10/23(木)SDのCRC7計算ルーチン

SD Card専用のCRC7計算ルーチン(C言語汎用)。戻り値をそのまま「6byte目」として送信できる。このソースは自由にご利用ください。

//******************************************************************************
// Calc SD CRC7
//******************************************************************************
int calc_sd_crc7(char *buf) {
	int crc, crc_prev;
	int i,j;
	crc = buf[0];
	for(i=1; i<6; i++) {
		for(j=7; j>=0; j--) {
			crc <<= 1;
			crc_prev = crc;
			if (i<5) crc |= (buf[i]>>j) & 1;
			if (crc & 0x80) { crc ^= 0x89; }	// Generator
		}
	}
	return crc_prev | 1;
}

元データに x7 かけるのを見落としていたため、えらいハマった(汗)

思うに

CRCの説明って、どこもあんまりストレートじゃないなあ。

「引き算の代わりにXORを使った」(2進数)のわり算でいえばいいんですが、桁借り*1を無視した(2進数の)わり算って書いてあれば、すぐに思い出せたのにと思ったのでした。*2

*1 : 上の桁から1借りてくること。上の桁に影響なくいつでも桁狩りできると思えばいい

*2 : さもなくばもっとシンプルに「GF(2)における多項式除算」とか

2007/04/05(木)PL2303X + Linuxで高速通信はできるか

FT232RLはとりあえず諦めて、PL-2303Xのドライバの動作を検討しました。

パッチを当ててインストール

Linuxソースの drivers/usb/serial/pl2303.c がデバイスドライバです。カーネルを再構築するのは大変なので、FT232のデバイスドライバから Makefile と Rules.make を拝借し、適当に書き換えてカーネルモジュールを作り増した。

1Mbpsは対応していませんので、ドライバをごにょごにょと書き換えます。

baud = 0;
switch (cflag & CBAUD) {
	case B0:	baud = 0;	break;
	case B75:	baud = 75;	break;
	case B150:	baud = 150;	break;
	case B300:	baud = 300;	break;
	case B600:	baud = 600;	break;
	case B1200:	baud = 1200;	break;
	case B1800:	baud = 1800;	break;
	case B2400:	baud = 2400;	break;
	case B4800:	baud = 4800;	break;
	case B9600:	baud = 9600;	break;
	case B19200:	baud = 19200;	break;
	case B38400:	baud = 38400;	break;
	case B57600:	baud = 57600;	break;
	case B115200:	baud = 115200;	break;
	case B230400:	baud = 230400;	break;
	case B460800:	baud = 460800;	break;
	default:
		err ("pl2303 driver does not support the baudrate requested (fix it)");
		break;
}
baud = 1000000;
dbg("%s - baud = %d", __FUNCTION__, baud);
if (baud) {
	buf[0] = baud & 0xff;
	buf[1] = (baud >> 8) & 0xff;
	buf[2] = (baud >> 16) & 0xff;
	buf[3] = (baud >> 24) & 0xff;
}
<中略>
i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
		     SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 
		     0, 0, buf, 7, 100);

ソースをみれば分かりますが、このデバイスはかなり変わっていて、通信速度(Baud rate)を直接デバイスに送る(設定する)仕組みになっています(普通は分周カウンタの値を送る)。

さてこれで通信……としてみたものの、データがすべて化けてしまって全くだめでした。100Kbpsでもダメでした。これは通信速度が合っていないときに起こる症状です。どうやら、うまく分周されていないようなのですが、データシートには 6Mbps まで対応と書かれています。

原因

ここでみつけたPL-2303の資料(PDF)(Xなし)によれば(表3の少し手前)、

The programmable baud rate generator supports baud rates up to 1.2M bps

とのことで、どうやらドライバが PL-2303X に対応しておらず、PL-2303互換デバイスとして使用しているためではないかと思うのですが。つまり、PL-2303Xのデバイスドライバをみつければよいのではないかと……。

訂正。PL-2303X資料(pdf)によれば、高速な baud として設定可能な値は

921600, 1228800, 2457600, 3000000, 6000000

だそうです。微妙に使えない PL-2303X。

2007/04/02(月)FT232RL を Linux kernel 2.4.17 で認識させる

FTDI製FT232RL(FT232R)とは、3Mbpsまでの速度に対応した高速USBシリアルチップ(Serial Conveter)です。USBに接続するだけで、TTLレベルで高速シリアル通信が実現できます。

デバイスドライバの組み込み

ドライバ配布サイトでWindows用、Mac用、Linux用のドライバが配布されています。Linux kernel 2.4.20以降には標準でドライバが組み込まれていますが、2.4.17には組み込まれていません。

実験中ドライバの利用

Kernel 2.4.17にはFTDI USB Serialのドライバが実験中として組み込まれています。

USB support
 -> USB Serial Converter support
   -> <*> USB FTDI Single Port Serial Driver (EXPERIMENTAL)
usbserial.c: FTDI 8U232AM converter detected
usbserial.c: FTDI 8U232AM converter now attached to ttyUSB0 (or usb/tts/0 for devfs)

カーネルにこれを組み込むことで一応認識はするのですが、次の問題が起きました。

  • 9600, 19200, 38400, 78600……921600(最大)といった系列しか指定できない。*1
  • 試しに460800に設定したところ、使用したマシンが非力なのかKernelごと落ちた(応答しなくなった)

公式配布ドライバの使用

配布されているドライバソース ftdi_sio.tar.gz を展開し make します。make するためにはカーネルのソース(の一部、ヘッダ類)が必要です。

kernelソースを展開し適切にパスを設定後 make してみると、コンパイルエラーが発生しました。どうやらkernelが古いせいか

	.owner =		THIS_MODULE,

という項目が存在しない*2のが原因のようです。これらの行をすべて削除(またはコメントアウト)することでコンパイルできるようになります。make が無事成功すると、ftdi_sio.oというファイルができます。これがドライバ本体(カーネルモジュール)です。

このドライバをカーネルに組み込むためには root で次のようにコマンドを実行します。

組み込み
# insmod ftdi_sio.o
Kernelから削除
# rmmod ftdi_sio.o
組み込み済カーネルモジュールの確認
# lsmod

組み込んでみたのですが、エラーが出てしまい、ドライバが動作しません。

ftdi_sio.c: v1.3.5r1:USB FTDI Serial Converters Driver
hub.c: USB new device connect on bus1/1, assigned device number 3
usbserial.c: descriptors matched, but endpoints did not
usb.c: USB device 3 (vend/prod 0x403/0x6001) is not claimed by any active driver.

0x403/0x6001は、FTDIの8U232AMを示し、ドライバソースには実際その記述があるのですが、「but endpoints did not」と出て認識しません。endpoints とは何であるかということですが、調べてみるとUSBデバイスがホスト側と通信する際に利用するバッファのことのようです。

要するにエンドポイントの設定がおかしいと言っているのですが、ドライバのソースにはきちんと記述されています。

static struct usb_serial_device_type ftdi_8U232AM_device = {
/*	.owner =		THIS_MODULE, */
	.name =			"FTDI 8U232AM Compatible",
	.id_table =		id_table_8U232AM,
	.num_interrupt_in =	0,
	.num_bulk_in =		1,
	.num_bulk_out =		1,

usbserial.c をみてみると

/* verify that we found all of the endpoints that we need */
if (!((interrupt_pipe & type->needs_interrupt_in) &&
      (bulk_in_pipe & type->needs_bulk_in) &&
      (bulk_out_pipe & type->needs_bulk_out))) {
	/* nope, they don't match what we expected */
	info("descriptors matched, but endpoints did not");
	return NULL;
}

ということで、この項目が設定されてないことが原因のようです。

公式配布ドライバへのパッチ

ftdi_sio.c の中に記述されているすべてのデバイス情報(8U232AM, FT232BM等々)について、次のような書き換えを行います。

static struct usb_serial_device_type ftdi_8U232AM_device = {
/*	.owner =		THIS_MODULE,	*/
	.name =			"FTDI 8U232AM Compatible",
	.id_table =		id_table_8U232AM,
	.needs_interrupt_in =	DONT_CARE,
	.needs_bulk_in =	MUST_HAVE,
	.needs_bulk_out =	MUST_HAVE,
	.num_interrupt_in =	0,

色が変わっているところが追加部分です。これをコンパイルしてカーネルモジュールを作成しインストールすると、

usbserial.c: FTDI FT232BM converter detected
usbserial.c: FTDI FT232BM converter now attached to ttyUSB0 (or usb/tts/0 for devfs)

として認識されます。

FT232RLと表示されませんが仕様です。コンピューターデバイスではよくあることで、デバイスとして異なってもソフトウェア的に同一の場合は、同じプロダクトIDを持つことがあります。また1つのデバイスで仮想的に(ソフト的に)複数のデバイスが存在するということもあるため、デバイスの型とソフト的に見える型の不一致などが頻繁に起きます。

*1 : あたらしいドライバならば任意の速度が設定出来ることはソースより確認済

*2 : struct usb_serial_device_type

ターミナルによる通信 2007/04/03

シリアルポートの設定を変更したり、任意の速度で通信するためにはターミナルや設定ソフトが必要ですが、minicom や stty などはお節介なことに"9600, 19200……"系列しか指定できません。kermit もダメでした。

いろいろ調べたところ、cu というコマンドで指定できました。cu コマンドは uucp と一緒に配布されています(リンク先、左下のソースから uucp_1.07.orig.tar.gz をダウンロード)。

# tar zxvf uucp_1.07.orig.tar.gz
# cd uucp-1.07
# ./configure
# make
# make install
# mkdir /usr/spool
# mkdir /usr/spool/uucp
# chown uucp /usr/spool/uucp

利用方法は次のようになります。

# cu -l /dev/ttyUSB0 -s 38400

1Mbps通信はできるか?

早速

# cu -l /dev/ttyUSB0 -s 1000000 -d
cu: fconn_open: Opening port /dev/ttyUSB0 (speed 1000000)
cu: fconn_set: Changing setting to 1, 2, 2

と設定してみます(-d はデバッグフラグです)。ところが、公式ドライバでも、2.4.17付属ドライバでも通信速度が変更できないようです。ドライバソースを改造してデバッグメッセージを出力させてみると、

ftdi_sio.c: Set to 9600

などと出てしまいます。カーネルの段階(tty?)で通信速度が書き換えられている模様です(詳細不明)。

仕方がないので、ドライバのソース(ftdi_sio.c)を書き換えて、無理矢理 1Mbps 通信をさせてみました。

  • Linux 2.4.17付属ドライバ …… 99%程度取りこぼし、使い物にならない
  • 公式配布ドライバ …… 通信速度の設定によらず、1byteも受信できない

以上うまく通信できませんでした。Linux 2.4.17のドライバは未成熟である可能性は捨てきれず、逆に公式配布ドライバはカーネルが古すぎるために(非互換により)通信すら行えていない可能性が高いと思います。

Linux 2.4.17のドライバを改変し受信したデータ

00001,00001,00001,00001,00001,00001,00001,00001,00001,00001

00002,00002,00002,00002,00002,00002,00002,00002,00002,00002

00003,00003,00003,00003,00003,00003,00003,00003,00003,00003

00004,00004,00004,00004,00004,00004,00004,00004,00004,00004

00005,00005,00005,00005,00005,00005,00005,00005,00005,00005

00006,00006,00006,00006,00006,00006,00006,00006,00006,00006

00007,0000720,359205921,35921,35921,35921,35921,35921,35921,35921

35922,35922,35935922,35922

35923,35923,35923,35923,35923,35923,35923,35923,3535924,35924,35924,35924,35924,35924

35925,35925,35925,35925,35

35926,35926,35926,35926,35926,35926,35926,359

FT232Rとして認識しない原因 2007/04/04

ftdi_sio.h では

#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */

となっていて、いくつかの製品で同じプロダクトID(PID)を持っています。複数の製品をどうやって見分けているのかなと思ったのですが、productversion という2バイトの値で識別しているようです。

USB_DEVICE_VER (vendorId, productId, lo, hi)
	... like USB_DEVICE with lo <= productversion <= hi
<略>
static struct usb_device_id id_table_8U232AM [] = {
	{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
<略>
static struct usb_device_id id_table_FT232BM [] = {
	{ USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
<略>
static struct usb_device_id id_table_FT232R[] = {
	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x600, 0xffff) },

0xffff0x5ff に書き換えることで、FT232R と認識しますが、特に挙動は変わりませんでした。usb_serial_device_type をみても表示文字列以外、内部処理に特に違いはないようです。

その後の検討とまとめ

  • 公式ドライバの ftdi_read_bulk_callback() 内の "port->open_count" の条件文を無効化(常に真)することでデータ通信はできましたが、Linux 2.4.17ドライバ同様に99%取りこぼしでした。
  • 試しに usbserial.c を別バージョンのカーネルから引っ張ってきましたが、案の定コンパイルすらできませんでした。
  • Linux 2.4.17で 100kbps で受信させてみましたが、それでも多少取りこぼしが発生しました。
  • Linux 2.6.17カーネルで試したところ、何の問題*3もなく動作しました。
    Linux version 2.6.17
    [17179838.796000] usb 1-1: configuration #1 chosen from 1 choice
    [17179838.800000] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected
    [17179838.800000] drivers/usb/serial/ftdi_sio.c: Detected FT232BM
    [17179838.800000] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
    
    # stty -F /dev/ttyUSB0 1000000
    # cat /dev/ttyUSB0
    

Linux 2.4.17時代にはおそらく高速シリアル通信は考えられておらず、そのためまともに通信できないのではないかと思います。

もっとも、使用したマシンが非力すぎるという可能性も捨てきれない面はありますが、PowerPCベース200MHz程度あれば、いくら何でも100KB/sぐらい受信してよさそうですので(LANは3Mbps以上でてますし)。

残された道

  • Linux 2.4.17カーネルのドライバを適当に最新カーネルのものに入れ替える。
  • Linux 2.4.17カーネルのドライバを元に地道にパッチを当てる。
  • Linux 2.4.34等の最新カーネルをベースに、特殊ハード(組み込み)向けの改造を加える。
  • VCPドライバではなく、D2XXドライバの利用を検討する。x86バイナリのみの提供のため利用不可。

*3 : 取りこぼしもおそらくなし