このページは、パワーONでないリセット操作で実行するEEPROM上で起動するプログラムの作り方です。
似ていますが、ROM上でプログラムをパワーONでないリセットで起動する方法ページはこちらでで、紹介していますの比較してください。
下記は、0x9D020008番地 に『D1のLEDで「 Lチカ 」無限ループするstart_main関数』を
配置することで実現するプログラムです。
これは「umehoshiEdit」ツールで、ビルド実行できます。
右リストは逆アセンブルしたコードで、これを参考に、後述のアセンブリリストを作っています。
#include <xc.h> // test.c #include "common.h" // |
9d020008 <start_main>: 9d020008: 27bdffe8 addiu sp,sp,-24 9d02000c: afbf0014 sw ra,20(sp) 9d020010: afbe0010 sw s8,16(sp) 9d020014: 03a0f021 move s8,sp 9d020018: 00000000 nop 9d02001c <.L2>: 9d02001c: 3c02bf88 lui v0,0xbf88 9d020020: 34038000 li v1,0x8000 9d020024: ac436128 sw v1,24872(v0) 9d020028: 00000000 nop 9d02002c: 0f408018 jal 9d020060 <wait> 9d020030: 3c04003f lui a0,0x3f 9d020034: 3c02bf88 lui v0,0xbf88 9d020038: 34038000 li v1,0x8000 9d02003c: ac436124 sw v1,24868(v0) 9d020040: 00000000 nop 9d020044: 0f408018 jal 9d020060 <wait> 9d020048: 3c04003f lui a0,0x3f 9d02004c: 0b408007 j 9d02001c <.L2> 9d020050: 00000000 nop 9d020060 <wait>: 9d020060: 27bdfff8 addiu sp,sp,-8 9d020064: afbe0004 sw s8,4(sp) 9d020068: 03a0f021 move s8,sp 9d02006c: afc40008 sw a0,8(s8) 9d020070: 00000000 nop 9d020074: 8fc20008 lw v0,8(s8) 9d020078: 2443ffff addiu v1,v0,-1 9d02007c: afc30008 sw v1,8(s8) 9d020080: 1440fffc bnez v0,9d020074 <wait+0x14> 9d020084: 00000000 nop 9d020088: 03c0e821 move sp,s8 9d02008c: 8fbe0004 lw s8,4(sp) 9d020090: 27bd0008 addiu sp,sp,8 9d020094: 03e00008 jr ra 9d020098: 00000000 nop |
以下に、上記の実際に動作した、アセンブリリストを示します。上のC言語の逆アセンブルリストをコードにしてみました。
if( パワーオンリセットか? ){ マクロ用の関数へのポインタなど各種変数の初期化や_HANDLES配列の初期化を行う。 「ウメ・エディットプログラム」で使われるマクロ関数が登録される。そして、 _HANDLES[_IDX_HANDLE_USER_SET_FUNC] = dummy_init_function; の関数が登録される。 (上記関数へのポインタは、_handle_user_set_func()のマクロの関数で実行できる) _HANDLES[_IDX_INIT_SUB_FUNC] = dummy_init_function; の関数が登録される。 (上記関数へのポインタは、_init_sub_func()のマクロの関数で実行できる) power_on_flag = 1; } _handle_user_set_func(); // 起動時のマクロ関数呼び出し(ここで、_HANDLESの要素の変更などを行う) SYS_Initialize ( NULL );// ここでUSBや指定IOの初期化が行われる if(power_on_flag == 1){ // ここがEEPROM領域のパワーONで実行される領域 power_on_start(); } else { // ここがEEPROM領域のパワーONを伴わないリセットで実行される領域 void (* func)(void) = (void *) 0x9D020000;// EEPROM 領域 if( *((uint32_t *)func) != 0xffffffff ){// EEPROMの記憶内容が0xffffffffでない? func();// EEPROMの0x9D020000番地の関数を呼び出す(リセットで自動的に起動) } } _init_sub_func(); // 起動時のマクロ関数呼び出し(「ウメ・エディットプログラム」の起動関数) この後で、『USB受信文字列処理用のループ』に進みます。
void power_on_start(){ if ((PORTB & 0x80) == 0) return; // SW2が押されてれば、リターン // SW2が押されていない場合の起動 unsigned *flag = (unsigned *) 0x9D03fff0; if( *flag == 0xffffffff) return;// EEPROM領域の0x9D03fff0番地内容が0xffffffffならリターン void (* func)(void) = (void *) *flag; func();// 0x9D03fff0番地の内容が指し示す関数を実行する。 }上記コードで、0x9D03fff0番地が0xffffffffでなければ、0x9D03fff0番地の内容が指し示す関数が パワーオンの場合だけで実行することになります。
// 0x9D03fff0番地を0x9D020008にして、パワーオン実行を可能にする。 #include <xc.h> // power_exc_on.c #include "common.h" __attribute__((address( 0x80005000 ))) void start_main (void); void start_main(){ // *((unsigned *)0x9D03fff0) = 0x9D020008;に相当する処理 _nvm_write_word(0x9D03fff0,(unsigned )0x9D020008); } /* この実行で、0x9D03fff0番地の内容を0x9D020008に設定する。 それにより、0x9D03fff0番地内容が指し示す関数が、パワーオンの場合だけ起動する。 */ |
80005000 <start_main>: 80005000: 27bdffe8 addiu sp,sp,-24 80005004: afbf0014 sw ra,20(sp) 80005008: afbe0010 sw s8,16(sp) 8000500c: 03a0f021 move s8,sp 80005010: 3c02a000 lui v0,0xa000 80005014: 344240f4 ori v0,v0,0x40f4 80005018: 8c420000 lw v0,0(v0) 8000501c: 3c039d03 lui v1,0x9d03 80005020: 3464fff0 ori a0,v1,0xfff0 80005024: 3c039d02 lui v1,0x9d02 80005028: 34650008 ori a1,v1,0x8 8000502c: 0040f809 jalr v0 80005030: 00000000 nop 80005034: 03c0e821 move sp,s8 80005038: 8fbf0014 lw ra,20(sp) 8000503c: 8fbe0010 lw s8,16(sp) 80005040: 27bd0018 addiu sp,sp,24 80005044: 03e00008 jr ra 80005048: 00000000 nop |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 |
#include <xc.h> // 0x9D03fff0番地を0にして、パワーオン実行を可能にする。 .set noreorder #アセンブラに命令の順序を自動変更させない。 .section start_main,address(0x80005000),code .ent start_main addiu sp,sp,-8 sw ra,4(sp) lui v0,0xa000 ori v0,v0,0x40f4 lw v0,0(v0) # v0 に_nvm_write_word関数のポインタ0xa00040f lui v1,0x9d03 ori a0,v1,0xfff0 # 第1引数 a0をx9D03fff0 lui v1,0x9D02 ori a1,v1,0x0008 # 第2引数 a1をx9D020008 jalr v0 # _nvm_write_word関数呼び出し nop lw ra,4(sp) addiu sp,sp,8 jr ra nop |
左のコードで生成される[UME専用Hexコマンド]は、
x9D03fff0番地のワードをx9D020008に設定するコードで、アセンブルして使います。 実行するためには、「アッセンブル」のボタン操作前で、 [0x80005000]番地から起動するコード埋め込みのチェックをして、生成してください。 そして「command.txt」の名前でファイル化して、pythonで実行させます。 |
#include <xc.h> // erase.c #include "common.h" __attribute__((address( 0x80005000 ))) void start_main (void); void start_main(){ _nvm_erase_page(0x9D020000);//EEPROMの起動ページ _nvm_erase_page(0x9D03FC00);//最終ページ消去 } /* EEPROMの0x9D020000番地から1024byteの領域を0xFFに消去し、 EEPROMの0x9D03FC00番地から1024byteの領域を0xFFに消去する nvm_erase_pageの引数のアドレスは 0x9D020000,0x9D020400,0x9D020800,0x9D020c00,0x9D021000,・・ ・・,9D03F800,9D03FC00 の何れかを指定する。 */ |
80005000 <start_main>: 80005000: 27bdffe8 addiu sp,sp,-24 80005004: afbf0014 sw ra,20(sp) 80005008: afbe0010 sw s8,16(sp) 8000500c: 03a0f021 move s8,sp 80005010: 3c02a000 lui v0,0xa000 80005014: 344240f0 ori v0,v0,0x40f0 80005018: 8c420000 lw v0,0(v0) 8000501c: 3c049d02 lui a0,0x9d02 80005020: 0040f809 jalr v0 80005024: 00000000 nop 80005028: 3c02a000 lui v0,0xa000 8000502c: 344240f0 ori v0,v0,0x40f0 80005030: 8c420000 lw v0,0(v0) 80005034: 3c039d03 lui v1,0x9d03 80005038: 3464fc00 ori a0,v1,0xfc00 8000503c: 0040f809 jalr v0 80005040: 00000000 nop 80005044: 03c0e821 move sp,s8 80005048: 8fbf0014 lw ra,20(sp) 8000504c: 8fbe0010 lw s8,16(sp) 80005050: 27bd0018 addiu sp,sp,24 80005054: 03e00008 jr ra 80005058: 00000000 nop |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <xc.h>// 0x9d020000,0x9D03FC00のページ消去(0xffに設定) .set noreorder #アセンブラに命令の順序を自動変更させない。 .section start_main,address(0x80005000),code .ent start_main addiu sp,sp,-8 sw ra,4(sp) # 戻り番地記憶 lui v0,0xa000 ori v0,v0,0x40f0 # hex(0xA0004000+60*4)==>0xa00040f0より算出 lw v0,0(v0) # v0 = _nvm_erase_pageのアドレス0xa00040f0 lui a0,0x9d02 # 消去対象のアドレスを引数として与える jalr v0 # _nvm_erase_page(a0) nop lui v0,0xa000 ori v0,v0,0x40f0 # hex(0xA0004000+60*4)==>0xa00040f0より算出 lw v0,0(v0) # v0 = _nvm_erase_pageのアドレス0xa00040f0 lui a0,0x9d03 # 消去対象のアドレスを引数として与える ori a0,a0,0xFC00 # a0 = 0x9D00000 | 0x3FC00 jalr v0 # _nvm_erase_page(a0) nop lw ra,4(sp) addiu sp,sp,8 jr ra nop |
左のコードで生成される[UME専用Hexコマンド]は、 0x9d020000番地と0x9D03FC00番地のページを 削除するコードです。 実行するためには、「アッセンブル」のボタン操作前で、 [0x80005000]番地から起動するコード埋め込みのチェックをして、 生成してください。 そして「command.txt」の名前でファイル化して、 pythonで実行させます。 |