Kinetis Lシリーズをつかってみる3

20161123追:
FreeScaleはNxPに喰われました!



VersaloonのBBSにはすでにレポートしていますが、FreeScaleのKinetis-Lシリーズを
OpenOCDから使う際のフラッシュ書き込みのスピードを大幅に増加させる
ことに成功しましたのでこちらでもご報告します。


以前、私はKL25Z,KL05Z等のKintis-LシリーズのマイコンにOpenOCDからの
書き込みに対応させていました。しかしこれらのマイコンは"Program-LongWord"
という4バイト単位でフラッシュロムに書き込むコマンドしかなく、SWD接続で
ちまちまやり取りをしていると1KiB/Sec程度の速度しか出ないため、
役に立たない代物でした。

さらにそのときにSRAM上で動くブートローダーが必要だ…と言ってました。
結局自分で作成する羽目になりましたorz


原理はそこまで難しくは無く、上記のSRAM上で"Program-LongWord"を
送り込んだワード単位のデータの数だけ動作するプログラム(とデータ)を
送り込んで実行するだけです。

具体的には先ずC言語で以下の関数をコンパイルして…


void kinetis_lwrite(uint32_t *pLW,uint32_t faddr,uint32_t wcount)
{
volatile uint8_t * pfstat = (uint8_t*) (0x40020000u+0);
volatile uint32_t* pfcoob3 = (uint32_t*)(0x40020000u+4);
volatile uint8_t * pfcoob0 = (uint8_t*) (0x40020000u+7);
volatile uint32_t* pfcoob7 = (uint32_t*)(0x40020000u+8);
#define FTFx_FSTAT (*(pfstat))
#define FTFx_FCCOB3 (*(pfcoob3))
#define FTFx_FCCOB0 (*(pfcoob0))
#define FTFx_FCCOB7 (*(pfcoob7))

for(register uint32_t i=0;i<wcount;i++){

/* wait till CCIF bit is set */
while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){};
/* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
FTFx_FSTAT = FTFA_FSTAT_ACCERR_MASK|FTFA_FSTAT_FPVIOL_MASK|FTFA_FSTAT_RDCOLERR_MASK;

FTFx_FCCOB3 = faddr;
FTFx_FCCOB0 = 0x06;
FTFx_FCCOB7 = *pLW;
faddr += 4;
pLW++;

/* All required FCCOBx registers are written, so launch the command */
FTFx_FSTAT = FTFA_FSTAT_CCIF_MASK;
/* Wait for the command to complete */
while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){};

}
}

出てきたアセンブラリストをさらに最適化を行い今度はその最適化した
アセンブラファイルをコンパイルしてマシン語を得ます。
で、このマシン語をOpenOCDのおソースにデータの形で持ちます。
↓こんな感じです。
/* Kinetis Program-LongWord Microcodes */
const uint8_t kinetis_flash_write_code[] = {
/* Params:
* r0 - workarea buffer
* r1 - target address
* r2 - wordcount
* Clobbered:
* r4 - tmp
* r5 - tmp
* r6 - tmp
* r7 - tmp
*/

/* .L1: */
/* for(register uint32_t i=0;i<wcount;i++){ */
0x04,0x1C, /* mov r4, r0 */
0x00,0x23, /* mov r3, #0 */
/* .L2: */
0x0E,0x1A, /* sub r6, r1, r0 */
0xA6,0x19, /* add r6, r4, r6 */
0x93,0x42, /* cmp r3, r2 */
0x16,0xD0, /* beq .L9 */
/* .L5: */
/* while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){}; */
0x0B,0x4D, /* ldr r5, .L10 */
0x2F,0x78, /* ldrb r7, [r5] */
0x7F,0xB2, /* sxtb r7, r7 */
0x00,0x2F, /* cmp r7, #0 */
0xFA,0xDA, /* bge .L5 */
/* FTFx_FSTAT = FTFA_FSTAT_ACCERR_MASK|FTFA_FSTAT_FPVIOL_MASK|FTFA_FSTAT_RDCO */
0x70,0x27, /* mov r7, #112 */
0x2F,0x70, /* strb r7, [r5] */
/* FTFx_FCCOB3 = faddr; */
0x09,0x4F, /* ldr r7, .L10+4 */
0x3E,0x60, /* str r6, [r7] */
0x06,0x27, /* mov r7, #6 */
/* FTFx_FCCOB0 = 0x06; */
0x08,0x4E, /* ldr r6, .L10+8 */
0x37,0x70, /* strb r7, [r6] */
/* FTFx_FCCOB7 = *pLW; */
0x80,0xCC, /* ldmia r4!, {r7} */
0x08,0x4E, /* ldr r6, .L10+12 */
0x37,0x60, /* str r7, [r6] */
/* FTFx_FSTAT = FTFA_FSTAT_CCIF_MASK; */
0x80,0x27, /* mov r7, #128 */
0x2F,0x70, /* strb r7, [r5] */
/* .L4: */
/* while((FTFx_FSTAT&FTFA_FSTAT_CCIF_MASK) != FTFA_FSTAT_CCIF_MASK){}; */
0x2E,0x78, /* ldrb r6, [r5] */
0x77,0xB2, /* sxtb r7, r6 */
0x00,0x2F, /* cmp r7, #0 */
0xFB,0xDA, /* bge .L4 */
0x01,0x33, /* add r3, r3, #1 */
0xE4,0xE7, /* b .L2 */
/* .L9: */
0x00,0xBE, /* bkpt #0 */
/* .L10: */
0x00,0x00,0x02,0x40,/* .word 1073872896 */
0x04,0x00,0x02,0x40,/* .word 1073872900 */
0x07,0x00,0x02,0x40,/* .word 1073872903 */
0x08,0x00,0x02,0x40,/* .word 1073872904 */
};


引数に取るレジスタはARMの関数呼び出し規約に即します。ここで間違えると
失敗しますのでご注意を。
Kinetis系のマイコンの場合は最悪のケースになる場合がある(後述)
のでマジでご注意を!!

後は上のプログラムの小片を流し込んで実行させるだけです。
OpenOCDには"target_run_algorithm"という仕組みがあるので引数にとる
レジスタを正しく設定したあとこれを利用して実行するとSWDの通信を介さず
ターゲット上で書き込みプログラムが実行されます。通信のオーバーヘッドが
無いのでもちろん書き込み動作はとしては非常に早くなります♥


同じelfファイルの書き込み速度だけ抽出しましたが、書き込みスピードは
10倍以上改善されたのが分かると思います。
旧ドライバ:
wrote 36648 bytes from file main.elf in 26.328295s (1.359 KiB/s)
新ドライバ:
wrote 36648 bytes from file main.elf in 1.906275s (18.774 KiB/s)

これで市販のツールに勝るとも劣らないパフォーマンスを得ることが
出来ましたのでGCC環境でもVersaloonかSTLink/V2を持っていさえすれば
OpenOCDでバリバリ書き込み/デバッグが可能です!

あと、しつこいくらいに言っておきますがこちらの件だけはご注意ください。
securityとmass-erase disableを同時に有効にしてしまうとMDM-APでも
復帰不可能の完全なゴミにしてしまいます!
…ねむいさんも今回のドライバ改良の際にFRDM-KL25Zをゴミにしてしまいましたorz
簡単にゴミに出来て回復手段も全くないとか雄度高すぎですよこのマイコン…
で、仕方ないのでおなじのを買うはめになりました…


↑良く見ると基板りビジョンのほかにチップの刻印も違っていた…
ちなみにFRDM系ボードにあるOpenSDA側のK20マイコンもバッチリsecurityと
mass-eraseのdisableが掛けられていやがってSTマイクロのDiscovery系の板
みたいな自由度は全くありません!ぜんぜんFreedomぢぁない!!F**K!


…はぁはぁ…失礼、とにかくすでにバイナリには反映してますので皆さんもバリバリ使っ
てください…今のところ私以外で試された方はAlanさんただ一人のようですが‥



●おまけ
KinetisのOpenOCDのコード見ててなんとなくフラッシュドライバの追加の方法が
分かって来たのでNuvotonのNUC1xx系のマイコンのドライバの実装も試行中です。


実はすでに低速なSWD通信によるProgram-LongWordの書き込みには成功してたり
しますが、こちらもアトミックに書き込みできるようになったら別枠でご報告と
させていただきます!

Go to top of page