何をするか
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を表します。
また、数値は十進数で送受信します。
- ハードウェアを準備する
- 電源とシリアル通信を接続する
-
PIO0_1
ピンをLOWにする
- 通信を初期化する
- 起動する (電源投入 or リセット解除)
-
?
を送信する (通信速度は自動で設定される) -
Synchronized
と改行を受信する -
Synchronized
と改行を送信し、OK
と改行を受信する - クロック周波数(例えば
12000
)と改行を送信し、OK
と改行を受信する
- Flashへの書き込みを許可させる
-
U 23130
と改行を送信し、0
と改行を受信する (Unlock)
-
- Flashの内容(全て)を消去する
-
P 0 7
と改行を送信し、0
と改行を受信する (Prepare sector(s) for write operation) -
E 0 7
と改行を送信し、0
と改行を受信する (Erase sector(s))
-
- Flashにデータを書き込む (これを繰り返す)
- RAMに、Flashに書き込むデータを書き込む
-
W (書き込み先) (書き込むバイト数)
と改行を送信し、0
と改行を受信する - 書き込むデータをuuencodeして送信する
- 1行の長さは61バイト以下 (改行文字は除く)
- 20行送信するか最後まで送信したら、送信したバイトの合計と改行を送信し、
OK
と改行を受信する
-
-
P (セクタ番号) (セクタ番号)
と改行を送信し、0
と改行を受信する -
C (書き込み先) (書き込むRAMのアドレス) (書き込むバイト数)
と改行を送信し、0
と改行を受信する
(Copy RAM to flash)
- RAMに、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で12000
とOK
が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.3.1では、約7分で書き込みが完了しました。
なぜかSyntax errorが大量に出てきてしまいましたが、シリアル通信の接続を抜いたら止まりました。
おわりに
書き込んだファームウェアの扱いは、必要な契約をせずに譲渡目的で使用しないなど、
利用規約に準じるべきであると推測できます。
(あくまで推測です。確定させるには権利者に問い合わせるのがいいでしょう)
IchigoJamはjig.jpの登録商標です。