ICE40 の spi programmer と jtag debugger その4

d2xx と libftdi1 の共有

d2xx のほう.

static int x_ft_write(void *tt, uint8_t *data, int length)
{
	struct d2xx *t = tt;
	DWORD rc;
	FT_STATUS s = FT_Write(t->h, data, length, &rc);
	assert(s == FT_OK);
	return rc;
}

static int x_ft_read(void *tt, uint8_t *data, int length)
{
	struct d2xx *t = tt;
	DWORD rc;
	FT_STATUS s = FT_Read(t->h, data, length, &rc);
	assert(s == FT_OK);
	return rc;
}

static void x_ft_close(void *tt)
{
	struct d2xx *t = tt;
	FT_STATUS s = FT_SetBitMode(t->h, 0, FT_BITMODE_RESET);
	assert(s == FT_OK);
	FT_Close(t->h);
}

static const struct mpsse_driver d2xx_driver = {
	x_ft_write, x_ft_read, x_ft_close
};

libftdi1 のほう.

static int mou_write(void *tt, uint8_t *data, int length)
{
	struct ftdi1 *t = tt;
	return ftdi_write_data(&t->mpsse_ftdic, data, length);
}

static int mou_read(void *tt, uint8_t *data, int length)
{
	struct ftdi1 *t = tt;
	return ftdi_read_data(&t->mpsse_ftdic, data, length);
}

static void mou_close(void *tt)
{
	struct ftdi1 *t = tt;
	if(t->mpsse_ftdic_open){
		if(t->mpsse_ftdic_latency_set){
			ftdi_set_latency_timer(&t->mpsse_ftdic, t->mpsse_ftdi_latency);
		}
		ftdi_disable_bitbang(&t->mpsse_ftdic);
		ftdi_usb_close(&t->mpsse_ftdic);
	}
	ftdi_deinit(&t->mpsse_ftdic);
}

static const struct mpsse_driver ftdi1_driver = {
	mou_write, mou_read, mou_close
};

こんな感じにクラスもどきを作って, 切り替える.

これの対応自体は大したことがないが C 故に void * を使うのでエラーチェックが雑で原因究明に困るとか、グローバル変数をローカル変数にかえる(必須ではないがやりたくなる)のが手間. void * は &data と書くべきところを data としていたので動かない系統のミスが多すぎるし予防できない.

flash_wait() の修正

verbose の都合なのか status register を待ち時間をいれて 2 度確認する仕様になってたので書き直した.

static void flash_wait(struct mpsse *t, const useconds_t first, const useconds_t every)
{
	if(verbose){
		fprintf(stderr, "waiting..");
	}

	useconds_t waitus = first;
	uint8_t data[2];
	do{
		usleep(waitus);
		waitus = every;
		data[0] = FC_RSR1;
		data[1] = 0;
		flash_xfer(t, data, sizeof(data));
	}while(data[1] & 1);

	if(verbose){
		fprintf(stderr, "R\n");
		fflush(stderr);
	}
}

戻り値 void, 引数 void の関数とか while(1) がやたらと多いソースはもしかするとダメなんじゃと予感がするがほぼ的中する.

flash_read() の分離

他に flash_read_status とかがあったので prefix を flash_read_data に改名. flash_read() のなかで [CS=L, コマンド発行, data 取得, CS=H ]の流れを毎回やっていたので flash_read_data_start() で [CS=L, コマンド発行], flash_read_data_continue() で [data 取得] に分離して、ループの内部での無駄な手続きを削除.

妙に長い待機時間を削減

ループの外とはいえ 200ms 待つ処理がコピペされてたので技術文書と確認. iceprog も C_RESET_B = 0 の期間にすべて転送していているので、規定時間というのが場当たり的対応になっている.
それでも 200 ms は明らかに長いのでこちらも場当たり的に削減.

根本的には時間が明言されている C_RESET_B = 0 をして SS = 0 で C_RESET_B = 1 にして slave mode に入ることが求められる. これの実装はソフトとハードも後回し.

総括

これらの対応で前回 6.9 秒かかった処理が 4.2 秒にまで縮んだ. これでとりあえず満足したので本来の目的に戻る.