Nordic UART転送速度調査1: nRF52840 と Android端末間編

前回nRF52840 と Android端末間で、Nordic UARTの基本的な送受信を行いました。次にどのくらい実際に通信量を流せるか試します。Bluetooth5での公称通信速度は 2Mbps です。実際にそんなに出るわけありません。昔々、有線TCP/IPでも実効転送速度は一割でシステム設計するよう叩き込まれたものです。

BTマスターハードウェアnRF52840-DK
BTマスターVersion5.4
BTマスターIDESEGGER5.6 (デバッガ有効)
BTスレーブモトローラG32, 2.4Gz x 4 coe
BTスレーブVersion5.2
BTスレーブIDEAndroidSdtio 4.0 (デバッガ有効)
IDE用PC Windows10, Core i7 3.8GHz x 8 coe

通信方向マスタ → スレーブ
通信周期3 sec
1セットの通信量2,000 byte
通信1セットのパケット分割数8回
パケットサイズ244
パケット間隔スレーブ内で BLE_NUS_EVT_TX_RDY:次送信許可 イベント発生後、即時。

シーケンス全体:

パケット間シーケンス:

スレーブ側で以下の計算を行い秒辺りの送信バイト数を画面表示する。

( 通信1セットの終了開始時刻(sec) - 通信1セットの受信開始時刻(sec) ) ÷ 通信1セットの受信Byte数

2MBpsで、1byte=10bit仮定し、200kbyte/秒すると、性能の1%しか達成していない。

少し予想はしていましたが、なぜこのような結果となるのでしょう? 引続き調査をしていきます。

横河オシロスコープDLM2024の導入memo

これまで弊方の開発では本気のオシロまでは必要ないかなと思いPCオシロ POS-4 を使用していました。一応4chで出先でも扱いやすい、日本製だし、低速のシリアル通信なら十分見れます。

しかし高速のシリアル通信やクロックの確認は難しいです。 弊方顧客先でも古巣3を除くと高性能なオシロをお持ちでない場合が多いです。

そこで横河DLM2024を導入にした覚書です。10年前くらいのモデルです。もっと古いDL1740でもフルカラーだし十分ですがフロッピーはつらいです。オプションでロジアナ、オプション無でシリアル通信のByte変換解析(少し怪しい)があります。CAN解析もできるらしいですがオプションが必要かは不明です。

購入はメーカリース会社さんのリースアップ品です。丁寧に使用されていて、近々で校正ずみ、付属品もそろっていて半年保障ありです。中古計測器屋さんやヤフオクでも同じくらいの値段だったのでこの方が効率的かと思います。

ロギングも可能なDL750 + 波形モジュール4ch でも+数万円 でしたので悩みどころでしたが、持ち運びする場合を考慮してコンパクトな方にしました。

まずプローブ未接続で起動してみます。このモデルは初期状態が波形太く光るモードです。(用途は分かりません。後で波形フォーマットを変更します。)

機器スペックを表示してみます。

イーサがあるのでネットワークを設定します。本体でUtility -> NetWork -> TCP/IP から設定します。デフォルトはDHCPなので、OFFして固定IPを設定し、ping確認します。設定を反映するには本体を再起動が必要です。

続いて波形画像を取り出すため FTP 設定を本体で行います。FTP は FFFTP を使用します。本体への接続手順は以下のとおりです。本体側デフォルトユーザ設定は anoymous (パスワードは不要) です。

ブラウザからの波形表示もサポートされていましたが、Flash Player で作られており、現在のブラウザでは使用禁止のため以下のようになります。本体でWEB表示設定はOFFしておきます。(インターネットは介さないのでHyper-Vなど仮想環境からWindows7等からなら見れるかもしれません ) Ruffleという代替えプラグインもあるようです。(今度試す)

お試しでCAN生波形をみてみます。初期状態だとなぜか波形トレースがかかっており、一旦トレースクリアをします。波形がなまっているのでレコードレングスを4ch時の最大1.25Mにします。波形フォーマットも何故か破線設定になっているので、曲線か直線に変更します。

以上で、DLM2024 の導入が完了しました。電子コントローラの開発現場でも、トリガーくらいでオシロの機能を使いこなせていない場面もよく見受けられます。そのた機能の使い方もレポートしていきたいと思います。

オシロで計測したいが手持ちオシロが無い、古すぎる、買うほど使用頻度が低い、リースも短期間だと高いなどお困りの方は計測サービスをいたします。詳しくはこちらまでご相談ください

Xperia Z4 TabletでFullバックアップを試す

セットアップ済み端末から、.ftf を再生成できればもしかすると… 気になって試してみたメモです。わかっていたことですが、root化できないとダメみたいです。

以下メニューがそれを示すのでしょうか? “Root access denid(拒否)“となりダメでした。

検索すると “Backup-TA” なるツールが見つかります。2010年代前半と古いものです。SUコマンド がないとダメでした。(しかしよくよくみると当ツールは Flash Tool に含まれているようです)

root化で検索すると “EASY Rooting Toolkit” が見つかります。これはソースコードだけでした。Android StduioNDK を追加し、make をかけます。コードが古く、#include漏れ、変数型不足、prototype宣言不足だらけでかなり修正しましたが Build できました。adb /data/local/tmp に転送し、実行しても無反応でした。(しかしよくよくみると当ツールは Flash Tool に含まれているようです)

これも実行ファイル、スクリプト、Superuser.apk 等を、adb /data/local/tmp に転送し実行するものでした。BusyBox(バイナリ結合コマンド)も転送しているので、bootバイナリにroot権限を埋込しそうです。しかし動作しますが成果は無しです。

あと実行するとウイルス検知されます。ヤバいやつです。


バックアップから .ftf 生成するには、root化が肝のようです。XDAで最新の手法を見ると、

  • boot loader をunlock
  • .ftf から .sin を展開し、boot.img を取出し。
  • Andeoid 上で、magisk のapkをインストール後、boot.img にroot権限を付与。
  • fastboot flash boot で、boot.img を書き込み。

実施するには実験用の SGP771 か SGP712 が必要ですね。

Javaと組込み機器Cで通信するときの留意事項

AndroidアプリなどJava言語と、組込み機器C言語で通信させるとき、せちがらい制約があります。その制約と対応方法の覚書です。

古くはVB6(VBA)C#Switf には構造体はありますが Java だけなんで?て感じです。Java側でByte配列へ編集もしくは分解するしかないようです。以下事例です。

組込み側

///  BTスレーブ要求フレーム ///
typedef struct _ST_SLAVE_REQ {
  uint8_t		head[ 4 ];	// HERAER兼パケット識別
 	uint16_t	len;		    // パケット長
 	uint16_t	req;		    // 要求コード
  uint8_t		foot[ 4 ];	// FOOTER
 	uint16_t	csum;		    // CHECKUSUM
} ST_SLAVE_REQ;
// Memo: 実際にはCPUアーキテクチャによってパウンダリ調整なし、2byte調整、4byte調整があるのでよく確認します。

Java側 :

///  BTスレーブ要求フレーム ///
short   frmLen = 14;
byte[]  buff = new byte[frmLen];

copyBytes(buff, 0, appCom.ID_SLAVE, 4 );          // 4: HERAER兼パケット識別
copyBin16(buff, 4, frmLen );            	        // 2: パケット長
copyBin16(buff, 6, appCom.REQ_START_MONITER );  	// 2: 要求コード
copyBytes(buff, 8, appCom.ID_TAIL, 4 );           // 4: HERAER兼パケット識別
short   csum = checksum(buff, frmLen - 2);        // Checksum
copyBin16(buff, 12, csum );            	           // 2: Checksum

Bundle arg = new Bundle();
arg.putByteArray( "BINARY",  buff );     // BIN DATA

WriteValueBLE( mServiceCANonNUS, mMessengerCANonNUS, arg );

byteコピー などはメソッドを追加します。web検索すると Unsafe.copyMemory なるものがでてきますが作った方が早い!

    ///////////////////////////////////////////////////
    // Byteコピー
    ///////////////////////////////////////////////////
    public boolean copyBytes(
        byte[]  to,
        int     offset,
        byte[]  from,
        int     len
    ) {
        if ( from.length < len ) {  // ちゃんと実体sizeをちぇっくしましょう。
            return false;
        }

        if ( to.length - offset < len ) {
            return false;
        }

        for( int i = 0; i < len; i ++ ) {
            to[ i + offset ] =  from[ i ];
        }
        return true;
    }

unit16変換関数を作ります。バイトオーダーは組込み機器側のCPUアーキテクチャに合せます。

///////////////////////////////////////////////////
// int16コピー
///////////////////////////////////////////////////
public boolean copyBin16(
    byte[]  to,
    int     offset,
    short   from
) {
    if ( to.length - offset < 2) {
        return false;
    }

    // ARMはリトルエンディアン
    to[ 0 + offset ] =  (byte)( from % 256 );
    to[ 1 + offset ] =  (byte)( from / 256 );
    return true;
 }


似たような言語では、C#はあり、Switf は無いようです。 (アプリだけ作ってる方々は、組込み機器ではsignedを基本使わないこと自体あまり知られていないのかもしれませんが…)

以下の場合、Java側で正しい値になりません。以下例では、frm.len は 4002( 0x9C42) となり、Java側で 0x9C がUnder Flow し -100 となります。そのまま extractBin16 で加算されると66 (0x42) + -100 * 256 = -25,534 と全く異なる値になってしまいます。

組込み側:

///  BTスレーブ応答フレーム ///
typedef struct _ST_SLAVE_RESP {
		uint16_t	len;		         // パケット長 6
    uint8_t    data[40000];    // CAN DATA部
} ST_SLAVE_RESP;

		:
	前略
		:
ST_SLAVE_RESP frm;

frm.len = sizeof(ST_SLAVE_RESP) - sizeof( uint16_t );	// パケット長 ,checksum分引く = 40,002(0x9C42)
		:
	中略
		:
 err_code = ble_nus_data_send( /*in*/    &m_nus,
			 						  /*in*/     &frm,
			  					  /*in-out*/ &sendLen,
									  /*in*/     m_conn_handle );

Java側:

/// BLEデータの取出し
byte alldata[] = characteristic.getValue();

// パケット長 6
short len = extractBin16(alldata, 4);
		:
	中略
		:

///////////////////////////////////////////////////
// int16取り出し
///////////////////////////////////////////////////
public short extractBin16(
    byte[]  from,
    int     offset
) {
    short   val  = 0;
    short    tmp;

    // QualcommはARM系なのでリトルエンディアン、Nordic もARM系なのでリトルエンディアン
    val  +=  from[ 0 + offset ];            // 0x42 → 10進 66
    val  +=  ( from[ 1 + offset ] * 256 );  // 0x9C → 10進 -100

    return val;
}

修正例は以下のとおりです。これは VB6(VBA) も同様で昔はよく引っ掛かっていたものです。

///////////////////////////////////////////////////
// int16取り出し
///////////////////////////////////////////////////
public short extractBin16(
    byte[]  from,
    int     offset
) {
    short   val  = 0;
    short    tmp;

    // ARMはリトルエンディアン
    tmp  =  from[ 0 + offset ];
    if ( tmp < 0 ) {    // Javaはunsignedがないため、1の補数で補完する
        tmp = (short)(255 + tmp + 1);
    }
    val  +=  tmp;

    tmp  =  from[ 1 + offset ];
    if ( tmp < 0 ) {    // Javaはunsignedがないため、1の補数で補完する
        tmp = (short)(255 + tmp + 1);
    }
    val  +=  ( tmp * 256 );

    return val;
}

チエックサム計算も同様にくるってしまいます。尚、shortがオーバーフローしたとき、プログラム異常になってしまうのかわかりませんが対策しておきます。

組込み側:

uint16_t CalcCheckSum(
 	 uint8_t *buf, 	// i : 対象Buffer
	 int16_t len	  // i : 対象Buffer長。
) {
	uint16_t i;
	uint16_t sum;

	sum = 0;
	for( i = 0; i < len; i ++ ) {
		sum += buf[ i ];
	}
	return	sum;
}

Java側:

 ///////////////////////////////////////////////////
 // checksum
 ///////////////////////////////////////////////////
 public short checksum(
     byte[]  to,
     int     len
 ) {
     long    sum = 0;
     short    tmp;

     for( int i = 0; i < len; i ++ ) {
         tmp = (short)to[ i ] ;
         if ( tmp < 0 ) {    // Javaはunsignedがないため補完する
             tmp = (short)(255 + tmp + 1);
         }
         sum += tmp ;
     }

     return((short)sum);
 }


組込みC側と送受信する文字列は、Stringでは渡せないです。copyValueOf(char[] data)、valueOf(char[] data) があるようですがコードもかさむんで、Byte[] でよいでしょう。

    final byte[]  ID_MASTER = {0x42,0x54,0x30,0x32};   // "BT02" MASTERから
    final byte[]  ID_TAIL   = {0x42,0x45,0x4E,0x44};   // "BEND"	 終了

SGP312:Xperia Tablet Z Wi-Fi 32GB版をAndroid 13相当にSetupする

ユーザさんから問合せがあり、Xperia Tablet Z Wi-Fi版 (SGP312) のSetupを実施した結果です。要点/固有事項だけ記載いたします。フル手順はSO-05Gの記事をみてください。


まずXperia Tablet Zのモデル展開状況を確認します。

仕様型番通称
Wi-Fi、16GBSGP311pollux_windy
Wi-Fi、32GBSGP312【今回】pollux_windy
4G、32GBSGP321pollux


LEDの位置

Xperia共通の fastbootモード時に青、flashモード時に緑に点灯するLEDはディスプレイ中央上でなく、ボディサイドにあります。何も光らないので最初は困惑します。


  • やや動作はもっさり。
  • Setup後、UPボタン + 電源on でのリカバリ起動はできません。


各種用意するツールやROMデータは公開状況が日々変化します。当方は以下の構成で行いました。当方から配布はできないため、くぐって入手してください。https://androidfilehost.com/が主な入手先です。

書換用Windowsアプリflashtool-0.9.36.0-windows.exeWindows用書込みソフトのインストーラです。GUIアプリ、Xperia用USBドライバ、CUIコマンドを含んでいます。
root化イメージ不要xperiaはroot化不要。
bootイメージ適用不可
カスタムリカバリtwrp-3.7.0_9-0-pollux_windy.imgboot領域に書込む。
OSイメージlineage-20.0-20231125-UNOFFICIAL-pollux_windy.zipAndroid13互換
OpenGappMindTheGapps-13.0.0-arm-20231025_200806_Z-Tab.zipSM_T800と同様に、オリジナルからスクリプトの修正が必要。


オリジナルは And 5.1.1 でした。


手順は他Wi-Fi系 Xperia と同じです。Bootloader unlock allowedIMEI を確認するためのサービスコードの入力方法は、連絡先 -> 設定 から 画面下部を長押します。

ポイントとなる Bootloader unlock allowed の状態は Yes でした。

Bootloader unlockするための解除コードの発行するSONY Unlock Bootloader サイトで選択するDevice名は WiFiと 4G は別々になっています。もちろんWiFi側を選びます。

Bootloader unlockは、fastboot コマンドで行います。

再びサービスコードを入力し、Bootloader unlockされたか確認します。


通常どおり、recovery領域に TWRP*.img、boot領域にセットアップ対象のOSから取出した boot.img を書き込んでも TWRP が起動しません。念のため容量が同じSPG321のboot.img もNGでした。

海外のWeb記事によるとこの方法でうまく行くようです。もしかすると SGP311SGP312 でメモリレイアウトが違い、通常OSは 16GB版のSGP311 に合わせてあるのかもしれません。SGP611 と同様に boot領域 に TWRP*.img を書込みます。以下、Boot領域から TWRP を起動した様子です。


lineage-20.0*.zip をSDカードにコピーして、TRWPからインストールします。ここは特に問題なしです。コンソールメッセージを見るとOSは 16GB版SGP311 用にジェネレーションされたもののようです。

一先ず起動はOKです。WiFi、BT、カメラ、SDカード、GPS( GPSTestアプリは古いためか無反応だったがGoogleMAPはOK ) は一通りはOKでした。

しかし、ホームボタン、戻るボタン が表示されません。

これはOS初期セットアップで以下の指定する必要がありました。Samsungなどハードボタンがある機種を自動識別しないようです。

ホームボタン、戻るボタンが表示されるようになりましたが、純正OSと違い右寄せに小さく表示されます。

またOSバージョン新しくなる他、画面分割が使えるようになるメリットがあります。

しかし 本端末の場合、少し処理負荷が高いようで、ややもっさり感があります。


TWRPから lineageOS用のGoogleサービス: MindGappをインストールしましたがエラーになってしまいます。原因は SM-T800と同様です。尚、TWRP を boot領域 に書込んでいるため、LinageOS と MindGapp は一回のTWRP の起動でインストールする必要があります。

SM-T800と同様にスクリプトを修正して、新しいzipを作りインストールします。本zipは、GitHubに公開済みです。

この後、Googleサービスを自動updateさせれば、追加インストール無くGoogleサービスが利用可能になりました。今日時点での各バージョンは以下のとおりでした。

アプリ名バージョン
Google検索13.21
Google Play45.1.12
Google Play開発者サービス25.8.32

他の基本アプリは、And12以降のGoogleアプリのオープン版 NikGapps は 32bit版が無いためインストールできませんでした。取り急ぎGoogle MAPは、Google Playから通常インストールし問題なく動作しました。


以上、SGP312:Z Tablet Wi-Fi 32GB版をAndoroid13相当にUpdateする手順です。しかしながら自分でやるのはメンドクサイ、忙しい、自身が無い方は、弊方でセットアップをお受けいたします。約1.5時間の個人様向け工数+事務費で税込4,000円 。ご相談、依頼はこちらから。