【MEMSマイクアレイ】FT232H用C++コード(1)

FPGA

データ読み込み

//  ここからデータ読み込み ///////////////////////////////////////////////////////////
	// START用タクトスイッチを押せというプロンプトを表示しスイッチを押させる
	 printf("Please press the START button\n");
	 getchar(); //breakpoint ユーザはタクトスイッチを押し,リターンキーを押す

	for (int i = 0; i < loop_n; i++)
	{
		// FT232Hのステータスを取得
		 status = FT_GetStatus(fthandle1, &RxBytes, &TxBytes, &EventDword);
		// 読み込んだデータのバイト数がRxBytesに格納される
		
		memset(data_in, 0, num);
		r_data_len = RxBytes;
		// FT232Hから配列data_inにデータを読み込む 
		// data_readに実際に読み込まれたデータ数が格納される
		 status = FT_Read(fthandle1, data_in, r_data_len, &data_read);
		 if (status != FT_OK)
			 printf("status not ok %d\n", status);
		 else
		 {
			bytes_read[i] = data_read; // 確認用に読み込んだバイト数を記録
			// データを配列data_bufに追加	
			int nbias = i * num; // 追加データの先頭インデックス
			for (int j = 0; j < num; j++)
			{
				data_buf[nbias + j] = data_in[j];
			}
		 } // end of else
	} // end of i-loop
	 // 経過を確認
	 for (int i = 0; i < loop_n; i++)
	 {
		printf("bytes read %d\n", bytes_read[i]);// 読み込んだデータ数
	 } 
	// デバイスを閉じる
	status = FT_Close(fthandle1);

// ここからデータ読み込み /////・・・というコメント行からデータ読み込みの処理になる。

  • printf(“Please press the START button\n”);
    FPGA基板上のタクトスイッチを押してデータ収集をスタートするようになっているのでそのためのプロンプトを表示している。次のgetchar();はユーザがリターンキーを押すまで次の実行を待たせるために使っている。しかし,このやりかたは,ユーザのキーボード操作の速度に影響を受ける可能性があり,再現性に問題がある。タクトスイッチを使わずデータ収集を開始する方法に改めるべき。
  • status = FT_GetStatus(fthandle1, &RxBytes, &TxBytes, &EventDword);
    for (int i = 0; i < loop_n; i++)のループの中で最初に呼び出される。タクトスイッチを押すことでマイクのデータのFT232HのFIFOバッファへの書き込みとUSB転送が開始される。FT_GetStatus関数を呼び出すと,RxBytesには読み込まれたデータの総バイト数が格納されている。
  • r_data_len = RxBytes;
    RxBytesの値をr_data_lenに代入。(次のFT_Readの引数に直接RxBytesstatusを使えば,この代入文は不要のはず)
  • bytes_read[i] = data_read; // 確認用に読み込んだバイト数を記録
    ループから抜けた後で表示するため,読み込んだバイト数を配列bytes_readに記録する。前の版では,ループ内のprintf文で表示していたが,printf文の実行時間のオーバヘッドが心配なので,配列への書き込みに変更した。
  • FT_Read(fthandle1, data_in, r_data_len, &data_read);
    配列data_inにr_data_lenバイトだけデータを格納する。変数data_readには実際に受信されたデータのバイト数が格納される。
  • int nbias = i * num; // 追加データの先頭インデックス
    for (int j = 0; j < num; j++)
    {
    data_buf[nbias + j] = data_in[j];
    }
    このループ文で1回分の読み込みデータを配列data_bufに追加しています。変数n_biasはi番目のループ繰り返しの際に書き込むdata_bufの先頭インデックスになる。

N_CHは,送信するデータの“チャンネル数”を表す整数型の定数です。一方,N_BYTEは,1つのチャンネルが何バイトで構成されるかを表す定数です。FPGAはN_BYTEつまりN_BYTE×8ビット幅の入力ポートを使ってFT232Hへのデータを送信します。

実際には,FT232HのFIFOバッファの入力ポートは1バイト幅なので,N_BYTE = 1としています。なぜ,定数として定義しているかというと,将来,2バイト幅や4バイト幅の出力ポートを持つデバイスを採用することになったとき,この部分をN_BYTE = 2のように変更できるようにするためです。(現在使っているFT232HはN_BYTE = 1に固定です。しかし,FTDI社の製品の中には2バイト~8バイトの出力ポートを持つデバイスがラインアップされています。)

以上より,このシステムが扱えるマイクロフォンの個数はN_CH×N_BYTE×8個となり,このコードの設定では64個になります。

データの保存

受信したデータ配列data_bufを保存します。実はデータの保存はdata_bufをそのままテキストファイルに書き込むだけでOKです。しかし,このコードでは動作確認のため,指定した1個のマイクロフォンのデータも抽出して保存しています。マイクロフォンはチャンネル番号とビット番号で指定します。VHDLコードの信号でmic_in[チャンネル番号][ビット番号]と表された信号をバイトデータから抽出する例として参考にしてください。

// データの保存 /////////////////////////////////////////////////////
	// 特定のマイクからの信号を抽出
	int i_ch; // マイクのチャンネル番号
	int i_bit;// マイクのビット番号
	UCHAR mask;
	UCHAR mic_data;
	i_ch = 0;
	i_bit = 0;
	mask = 1 &lt;&lt; i_bit; // 右からi_bit番目のみ1にしたビットマスク
	  // でもこのマスクは使っていない

	/*
	// フレームを検出 96以上の値を持つデータの1つ前がスタート
	i = 0;
	int iStart, iTime = 0;
	while (iTime &lt; nTime) {
		//if (data_in[i] >= 96) {
			iStart = i - 1;
			mic_data = data_buf[iStart];
			//printf("%d,%d\n", iStart, mic_data);
			// mic_dataのi_bit番目のビットを取り出す
			data_out[iTime] =  (mic_data >> i_bit) &amp; 1;
			iTime += 1;
		//} 
		i += 1;
	}
	*/
	// 配列data_outに指定されたマイクの波形データを書き込む
	for (int i = 0; i &lt; nTime; i++)
	{
		// iサンプル目のデータの先頭インデックスはN_CH * N_BYTE * i
		// そこからi_chバイト目が目的のチャンネル
		mic_data = data_buf[N_CH * N_BYTE * i + i_ch];
		data_out[i] = (mic_data >> i_bit) &amp; 1; // 右からi_bit目
	}

	FILE* outputfile;

	if (fopen_s(&amp;outputfile, "data.txt", "w") != 0)
	{
		printf("ファイルを開けませんでした");
	}

	for (int i = 0; i &lt; nTime; i++)
	{
		//fprintf(outputfile, "%d : %d\n", i, data_out[i]);
		fprintf(outputfile, "%d\n", data_out[i]);
	}

	fclose(outputfile);

	//確認用 全受信データを保存
	FILE* file;

	if (fopen_s(&amp;file, "Mic.txt", "w") != 0)
	{
		printf("ファイルを開けませんでした");
	}

	for (int i = 0; i &lt; num*loop_n; i++)
	{
		//fprintf(file, "%d :%d : %d\n",i,i%8, data_in[i]);
		fprintf(file, "%d\n", data_buf[i]);
	}

	fclose(file);
  • // フレームを検出 96以上の値を持つデータの1つ前がスタート
    ・・・
    このコードブロックはコメントアウトされています。以前の実装ではデータ転送中に,データにステータス情報が重ねられる現象が観測されました。マイクロフォンが1個のときこの現象が起こるとバイトデータが10進数で96以上の値をとることがわかりました。その対応のためにこのコメントアウトした部分を使っていました。現在は,この現象は観測されていない。
  • // iサンプル目のデータの先頭インデックスはN_CH * N_BYTE * i
    // そこからi_chバイト目が目的のチャンネル
    mic_data = data_buf[N_CH * N_BYTE * i + i_ch];
    data_out[i] = (mic_data >> i_bit) & 1; // 右からi_bit目
    コメントのとおりです。時間サンプルのi番目のデータの先頭は配列のN_CH * N_BYTE * i番目になります。iチャンネル番号i_ch,ビット番号i_bitで指定されるマイクロフォンのデータ(VHDLコードのmic_in[i_ch][i_bit]に対応)は,この先頭アドレスから i_ch番目のバイトデータのi_bit番目のビットに対応します。

コメント