NXP JN516X (TWELITE) をプログラミングする(OTA Update)

無線が使えるとなると無性に無線でファームウェア更新がしたくなってくる。所謂OTAというやつだ。なので頑張って作ってみようとしたもののハマリどころ満載でメチャ時間がかかってしまった。(-_-;)

有線ならエラーなど発生することはあまりないが無線というのは同じ周波数帯を使う他の電子機器等の電波干渉に加え設置場所付近の障害物による電波の乱反射等により通信が不安定になったりするものだ。車庫などの狭い空間に自家用車があったりするとその駐車位置により通信できなくなったりすることもある。

例えばAデバイスからBデバイスに送信したときBデバイスが受信できなかった、或いは、Bデバイスは受信し結果を送信したのにAデバイスが受信できなかったという2つの事象が発生してしまうのが厄介だ。つまり受信できなかったのはどちらなのかががわからないため単純なリトライだけでは解決できないことがある。これを解決するには重複パケットの除去処理に加え送信の再送処理が必要となる。しかも通信相手が複数ある場合はその複数の相手毎に管理が必要だ。送信側は送信処理中に再送することは簡単ではあるが受信側は受信パケット処理後はメイン処理に戻ってしまうため処理結果の再送は少し面倒だ。しかも、複数の相手と通信してる場合はさらに厄介なことになる。ということを踏まえたうえで完璧とは言えないが最善と思われるロジックを考えてみた。

送信先デバイス毎に管理されるカウントアップカウンターを含むパケットを送信し受信したデバイスは送信元デバイス毎に管理するカウンターと違うなら新たなパケットとして処理を行い同じならリトライパケットと見なし直前の送信データがあれば再送する。送信デバイス側は送信後のレスポンスが受信できなければ前回と同じカウンター値で再送処理を行うというだけだ。これだけでどちら側が受信できなかったかにかかわらず確実な再送処理が可能となる。

【通信中のOTA-BRIDGE(MONOSTICK)】
※赤点滅は通信中。途中で通信が途切れても再送処理により復旧している。リトライは5回まで行うが1回目でほぼ復旧できるようだ。

OTAというとESP32などのように2分割したフラッシュ領域を交互に切り替えるのが一般的らしい。JN5169/JN5179であればフラッシュ領域が512Kbあるので問題ないがJN5164は160Kbしかないので単純に分割するとアプリ領域が不足してしまう。なので最初はJN5169でないと無理かなと思っていたがJN5164になんとか対応できる方法はないものかと思案してみたところある方法を思いついた。JN516xシリーズのフラッシュは32Kbのセクターに分割されていて各セクターは自由に論理アドレス空間にマッピングすることができ複数のアプリを書き込むことも可能となっている。ブートローダーはフラッシュの先頭から順に各セクターを検索し最初に発見した有効なアプリを起動するようになっているのでOTAブートローダーを最終セクターに書き込んでおいてOTAアップデートを開始するときにアプリを起動できないようにしてから再起動するとOTAブートローダーを起動することができる。この方法であればOTAブートローダーが占有するセクター以外をアプリ領域とすることができる。ということで可能な限り小さいOTAブートローダーを作ってみたところ1セクターにギリギリ収まってしまった。これなら1セクター(32Kb)だけアプリ領域が少なくなるだけなのでJN5164にも対応することが可能だ。但し、アプリは簡単に100Kbを超えてしまうためJN5164では余裕があまりない...

で、実際にアプリの書き換えを試してみると誤動作してしまう。なぜなのかわからなくて調査に時間がかかってしまったがSDKのFlash-APIの引数で指定するセクター番号やアドレスは物理アドレスではなくマッピング後の論理アドレスであることがわかった。このことはドキュメントのどこにも書かれていないし、ブートローダーのマッピングの仕方が少しヘンというかアプリ領域以外の空きセクターが順不同でマッピングされてしまう。最悪はマッピングされないセクターもあったりするようなので目的のセクターにアクセスするには自分で再マッピングしたほうが賢明だ。それらのことを知らないとSDKのFlash-APIは使いものにならないだろう。

OTAブートローダーの機能はWPanクラスに組み込んである。なのでアプリは自動的にOTA対応になる。アプリで何か特別なことを行う必要もなく単にWPan::begin()を呼び出しWPanクラスを開始するだけでOKだ。またOTAブートローダーアプリ(最小サイズのOTAアプリ)もOTAで書き込めるようにしてみた。最初の書き込みにはプログラマーが必要であるが一度OTA対応アブリを書き込めばいつでもOTAアップデート可能となる。但し、アプリのアップデートに先立ち一度だけOTAブートローダーアプリの書き込みが必要となる。前もって書き込んでおくことも可能だが前投稿で紹介したプログラマーを使う必要がある。他社のプログラマーは一つのアプリしか書けないので使用できない。

【接続図】
PC(JN516X-OTA.exe)<--USB-->MONOSTICK(OTA-BRIDGE.bin)<--Wireless-->JN516X(OTA-BOOT.bin)

【使い方】

1.setup()にてWPan::begin(0)を実行するアプリ(userapp.bin)を作成し書き込んだデバイスを起動しておく。

  ※動作確認用にLチカ・アプリなどが最適。

2.OTA-BRIDGE.binを書き込んだデバイスをUSB接続する。

  ※TWELITE-R(2)/MONISTICK(推奨)が必要。

3.USB接続先の番号を調べる

  例:JN516X-OTA.exe -s

4.USB接続先の番号、ターゲットデバイスの無線アドレスとOTA-BOOT.binファイルを指定して実行する。(一度だけでOK)

  例:JN516X-OTA.exe -p 2 -a 0 -w JN5164-MWSDK-OTA-BOOT.bin

5.USB接続先の番号、ターゲットデバイスの無線アドレスと書き込むuserapp.binファイルを指定して実行する。

  例:JN516X-OTA.exe -p 2 -a 0 -w userapp.bin

6.途中でエラー時はアドレスに65534を指定し再実行する。(稀にある)

  例:JN516X-OTA.exe -p 2 -a 65534 -w userapp.bin

【修正履歴】
2022-06-01
JN5164で作成したプログラムが書き込みできなくて調べてみたらチップがJN5168だった。JN5161/JN5164/JN5168は同一パイナリーで動作するのでJN5161/JN5164/JN5168については同一チップと見なすように変更した。

【ダウンロード(eclipseプロジェクト)】

JN516X-OTA-eclipse
JN5164-MWSDK-OTA-BOOT-eclipse
JN5164-MWSDK-OTA-BRIDGE-eclipse
JN5169-MWSDK-OTA-BOOT-eclipse
JN5169-MWSDK-OTA-BRIDGE-eclipse

【OTA Update Utility】

【OTA-BOOT】

【OTA-BRIDGE】

【OTA対応WPanクラス】
※再送処理は、新たに追加したreTransmit()を実行するだけ。