1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IchigoJamAdvent Calendar 2021

Day 10

IchigoJamからISPで自分のファームウェアを書き込む

Posted at

何をするか

IchigoJam (Rではない) のシリアル通信機能を利用し、
プログラムを実行中の石に書き込まれているファームウェアを別のIchigoJam (Rではない) 互換機に書き込みます。

「ファームウェア」と書いていますが、今回はユーザプログラムを含むFlash全体の内容をコピーします。
コピー先に既にIchigoJamのユーザプログラムが保存されている場合、消去・上書きされます。

Flash書き込みの手順

IchigoJam (Rではない) のFlashに書き込む方法は、『LPC111x/LPC11Cxx User manual』(UM10398) の
Chapter 26: LPC111x/LPC11Cxx Flash programming firmware に載っています。

これを参考に、以下の手順でIchigoJam (Rではない) Flashに書き込むことができます。
なお、ここで「改行」はCRLFを表します。
また、数値は十進数で送受信します。

  1. ハードウェアを準備する
    1. 電源とシリアル通信を接続する
    2. PIO0_1ピンをLOWにする
  2. 通信を初期化する
    1. 起動する (電源投入 or リセット解除)
    2. ? を送信する (通信速度は自動で設定される)
    3. Synchronized と改行を受信する
    4. Synchronized と改行を送信し、OK と改行を受信する
    5. クロック周波数(例えば12000)と改行を送信し、OK と改行を受信する
  3. Flashへの書き込みを許可させる
    1. U 23130 と改行を送信し、0と改行を受信する (Unlock)
  4. Flashの内容(全て)を消去する
    1. P 0 7 と改行を送信し、0と改行を受信する (Prepare sector(s) for write operation)
    2. E 0 7 と改行を送信し、0と改行を受信する (Erase sector(s))
  5. Flashにデータを書き込む (これを繰り返す)
    1. RAMに、Flashに書き込むデータを書き込む
      1. W (書き込み先) (書き込むバイト数) と改行を送信し、0と改行を受信する
      2. 書き込むデータをuuencodeして送信する
        • 1行の長さは61バイト以下 (改行文字は除く)
        • 20行送信するか最後まで送信したら、送信したバイトの合計と改行を送信し、OKと改行を受信する
    2. P (セクタ番号) (セクタ番号) と改行を送信し、0と改行を受信する
    3. C (書き込み先) (書き込むRAMのアドレス) (書き込むバイト数) と改行を送信し、0と改行を受信する
      (Copy RAM to flash)

実装

タイトルと、接続の方法を書いておきます。

10 ' ファームウェア カキコミ
20 'OUT1->RESET,OUT2->PIO0_1

自分のFlashの内容を読み取るためのマシン語を用意します。

アセンブリコード
' R0 で指定したアドレスから256バイトを、#780 にコピーする
R1 = @DATA
R2 = 0
@LOOP
R3 = [R0 + 0]L
[R1 + 0]L = R3
R0 += 4
R1 += 4
R2 += 1
R2 - 64
IF CC GOTO @LOOP
RET

ORGR #80
@DATA
30 POKE#700,31,161,0,34,3,104,11,96,4,48,4,49,1,50,64,42,248,211,112,71

CRLFを送信します。

130 ?CHR$(13)

データをE+1行受信します。
ただし、1行の受信に1.5秒以上かかった時は、受信を打ち切ります。

140 P=0:CLT
150 K=INKEY():IFK>31POKE#740+P,K:P=P+1ELSEIFK=10IFEE=E-1:GOTO140ELSERETURN
160 IFTICK()>89E=0:RETURNELSEGOTO150

データを受信し、それが期待したものかをチェックします。
170行目では、受信したデータがOKかをチェックします。
180行目では、受信したデータが0かをチェックします。
データが期待したものでなかった場合、書き込み対象をリセットし、Failed!を出力して終了します。

170 GOSUB130:IFP=2ANDPEEK(#740)=79ANDPEEK(#741)=75:RETURNELSEGOTO190
180 GOSUB130:IFP=1ANDPEEK(#740)=48:RETURNELSEGOTO190
190 OUT1,0:?"Failed!"

?を送信し、1行読み込みます。
Synchronizedが送られてくるはずですが、1.0.0で実際に試してみると途中までしか読み込めませんでした。

40 OUT1,0:OUT2,0:OUT1,1?"?";:E=0:GOSUB140:

Synchronizedと改行を送信し、2行読み込みます。
ここでは送信した内容もそのまま送り返されてくるので、その分を含めた2行となっています。
OKが送られてくるはずですが、うまく読み込めなかったため、チェックを無効にしています。
また、Synchronizedを一気に送信してしまうとうまくいかなかったため、ウェイトを挟んでいます。
(本当はソフトウェアフロー制御(XON/XOFF)に対応しないといけないとされていますが、サボっています)

?"Synchr";:WAIT9:?"onized";:E=1:GOSUB130:

12000(クロック周波数)と改行を送信し、2行読み込みます。
ここではOKがうまく読み込めるようだったので、チェックを有効にしています。
ただし、そのままだと1.3.1で12000OKが1行として読み込まれてしまい失敗したので、
ここにもウェイトを挟んでいます。

?"12000";:WAIT9:E=1:GOSUB170:

Echoコマンドを送信し、送信した内容が送り返されないようにします。
ここまでは送信した内容が送り返されるので、その分を含め2行読み込みます。
このコマンドの実行後は1行読み込めばよく、読み込み処理の後はE=0となるためEの設定を省略できます。

?"A 0";:E=1:GOSUB180

Flashへの書き込みを許可させ、全部のデータを消去します。

50 ?"U 23130";:GOSUB180:?"P 0 7";:GOSUB180:?"E 0 7";:GOSUB180:

Flashに書き込むデータを自分のFlashから読み込み、転送していきます。
読み込みは256バイト単位で行うことにしました。
転送は、256の約数であり、かつ1行で転送できる32バイト単位で行うことにしました。

FORI=0TO#7F00STEP#100:X=USR(#700,I):FORJ=0TO#E0STEP32

データのRAMへの転送を開始します。
転送先のアドレスの下位の数字としてJを使うとJが小さい時桁数が少なくなって失敗するので、
J+100を用いて桁数が変わらないようにしました。

60 ?"W 268436";J+100;" 32";:GOSUB180:

uuencodeの送信を開始します。
uuencodeでは、3バイトをひとかたまりとして送信します。
行の最初の@は、その行に32バイトのデータがあることを表します。

?"@";:S=0:FORK=0TO30STEP3

uuencodeへのエンコードを行い、データを送信します。
データは# 780# 880に書き込まれており、配列・変数領域の前半部分も用いているので、
作業用にはそれと被らない配列の後ろの方を用います。
70行目で1個ずつ# 780を足したり、80行目で1個ずつ63とのANDを取ったりすると長くなってしまうので、
1箇所にまとめています。

70 M=#780+J+K:A=PEEK(M):B=PEEK(M+1):C=PEEK(M+2)*(K<30):S=S+A+B+C
80 [64]=A/4:[65]=A<<4|B>>4:[66]=B*4|C>>6:[67]=C
90 FORL=64TO67:V=[L]&63:?CHR$(32+V+64*!V);:NEXT

送信したバイトの合計を送信し、OKを受信します。
データの送信を繰り返し、256バイト転送します。

100 NEXT:?CHR$(13):?S;:GOSUB170:NEXT

転送したデータをFlashに書き込みます。

110 T=I/#1000:?"P ";T;" ";T;:GOSUB180:?"C ";I;" 268436100 256";:GOSUB180

データの読み取り・転送・書き込みを繰り返します。
最後まで書き込んだら、Done!を出力し、書き込み先をリセットして起動します。

120 NEXT:OUT1,0:?"Done!":OUT2,1:OUT1,1:END

コード全体

10 ' ファームウェア カキコミ
20 'OUT1->RESET,OUT2->PIO0_1
30 POKE#700,31,161,0,34,3,104,11,96,4,48,4,49,1,50,64,42,248,211,112,71
40 OUT1,0:OUT2,0:OUT1,1:?"?";:E=0:GOSUB140:?"Synchr";:WAIT9:?"onized";:E=1:GOSUB130:?"12000";:WAIT9:E=1:GOSUB170:?"A 0";:E=1:GOSUB180
50 ?"U 23130";:GOSUB180:?"P 0 7";:GOSUB180:?"E 0 7";:GOSUB180:FORI=0TO#7F00STEP#100:X=USR(#700,I):FORJ=0TO#E0STEP32
60 ?"W 268436";J+100;" 32";:GOSUB180:?"@";:S=0:FORK=0TO30STEP3
70 M=#780+J+K:A=PEEK(M):B=PEEK(M+1):C=PEEK(M+2)*(K<30):S=S+A+B+C
80 [64]=A/4:[65]=A<<4|B>>4:[66]=B*4|C>>6:[67]=C
90 FORL=64TO67:V=[L]&63:?CHR$(32+V+64*!V);:NEXT
100 NEXT:?CHR$(13):?S;:GOSUB170:NEXT
110 T=I/#1000:?"P ";T;" ";T;:GOSUB180:?"C ";I;" 268436100 256";:GOSUB180
120 NEXT:OUT1,0:?"Done!":OUT2,1:OUT1,1:END
130 ?CHR$(13)
140 P=0:CLT
150 K=INKEY():IFK>31POKE#740+P,K:P=P+1ELSEIFK=10IFEE=E-1:GOTO140ELSERETURN
160 IFTICK()>89E=0:RETURNELSEGOTO150
170 GOSUB130:IFP=2ANDPEEK(#740)=79ANDPEEK(#741)=75:RETURNELSEGOTO190
180 GOSUB130:IFP=1ANDPEEK(#740)=48:RETURNELSEGOTO190
190 OUT1,0:?"Failed!"

実行

以下のように接続します。

書き込む側 書き込まれる側
RXD TXD
TXD RXD
GND GND
OUT1 RESET
OUT2 ISP

書き込み用の接続

1.0.0 で書き込みプログラムを走らせた結果、約14分で書き込みが完了しました。
書き込みが完了後、書き込んだファームウェアを実行した結果、
バージョン情報が送られてきて、書き込む側でSyntax errorになっています。
さらに、?VER()を送信し、出力されるバージョン情報をINPUTZで受け取ることができています。

書き込み完了 (1.0.0)

1.3.1では、約7分で書き込みが完了しました。
なぜかSyntax errorが大量に出てきてしまいましたが、シリアル通信の接続を抜いたら止まりました。

書き込み完了 (1.3.1)

おわりに

書き込んだファームウェアの扱いは、必要な契約をせずに譲渡目的で使用しないなど、
利用規約に準じるべきであると推測できます。
(あくまで推測です。確定させるには権利者に問い合わせるのがいいでしょう)

IchigoJamはjig.jpの登録商標です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?