このページは、パワーONでないリセット操作で実行するEEPROM上で起動するプログラムの作り方です。
似ていますが、RAM上でプログラムをリセットで起動する方法のページで、紹介していますの比較してください。
リセットに関係なく、"R00〜"の実行アドレスを指定した起動用のコマンド文字列で実行させる方法のリンクはこちらです
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){ power_on_start(); } else { void (* func)(void) = (void *) 0x9D020000;// EEPROM 領域 if( *((uint32_t *)func) != 0xffffffff ){// EEPROMの記憶内容が0xffでない? func();// EEPROMの0x9D020000番地の関数を呼び出す(リセットで自動的に起動) } } _init_sub_func(); // 起動時のマクロ関数呼び出し(「ウメ・エディットプログラム」の起動関数) この後で、『USB受信文字列処理用のループ』に進みます。
上記より、パワーオン時にマクロ関数用配列の_HANDLES[機能識別添え字] 群に関数を記憶しています。
利用者の「ウメ・エディットプログラム」で、このはそのマクロ関数をAPIの呼び出す手法でプログラミングします。
この関数記憶で、_HANDLES[_IDX_INIT_SUB_FUNC]に起動関数を登録しています。
その後で、この起動関数の_init_sub_func()を呼び出しています。
さてEEPROM領域の0x9D020000番地に関数が存在する場合、
パワーONを伴わないリセット時に、_0x9D020000番地の関数が実行される仕組みになっています。
(つまりROM領域の起動関数はRAM領域と異なり、_0x9D020000番地の関数を実行してから
_init_sub_func()を実行する構造になっています。)
下記C言語ソースは、上記仕組みを利用して、_0x9D020000番地に起動関数を配置しています。
これは、「umehoshiEdit」ツールで、ビルド実行できます。
右リストは逆アセンブルしたコードで、これを参考に、後述のアセンブリリストを作っています。
#include <xc.h> // test.c #include "common.h" // |
9d020000 <start_main>: 9d020000: 27bdffe8 addiu sp,sp,-24 9d020004: afbf0014 sw ra,20(sp) 9d020008: afbe0010 sw s8,16(sp) 9d02000c: 03a0f021 move s8,sp 9d020010: 00000000 nop 9d020014 <.L2>: 9d020014: 3c02bf88 lui v0,0xbf88 9d020018: 34038000 li v1,0x8000 9d02001c: ac436128 sw v1,24872(v0) 9d020020: 00000000 nop 9d020024: 0f408014 jal 9d020050 <wait> 9d020028: 3c04003f lui a0,0x3f 9d02002c: 3c02bf88 lui v0,0xbf88 9d020030: 34038000 li v1,0x8000 9d020034: ac436124 sw v1,24868(v0) 9d020038: 00000000 nop 9d02003c: 0f408014 jal 9d020050 <wait> 9d020040: 3c04003f lui a0,0x3f 9d020044 <.LBE2>: 9d020044: 0b408005 j 9d020014 <.L2> 9d020048: 00000000 nop 9d020050 <wait>: 9d020050: 27bdfff8 addiu sp,sp,-8 9d020054: afbe0004 sw s8,4(sp) 9d020058: 03a0f021 move s8,sp 9d02005c: afc40008 sw a0,8(s8) 9d020060: 00000000 nop 9d020064: 8fc20008 lw v0,8(s8) 9d020068: 2443ffff addiu v1,v0,-1 9d02006c: afc30008 sw v1,8(s8) 9d020070: 1440fffc bnez v0,9d020064 <wait+0x14> 9d020074: 00000000 nop 9d020078: 03c0e821 move sp,s8 9d02007c: 8fbe0004 lw s8,4(sp) 9d020080: 27bd0008 addiu sp,sp,8 9d020084: 03e00008 jr ra 9d020088: 00000000 nop |
以下に、上記の実際に動作した、アセンブリリストを示します。上のC言語の逆アセンブルリストをコードにしてみました。
#include <xc.h> // test.c #include "common.h" // RAMで動かす場合の絶対アドレス範囲は、(0x80005000〜0x80008000)とします。 __attribute__((address( 0x80005000 ))) void start_main (void); void start_main(){ _nvm_erase_page(0x9D020000); } /* EEPROMの0x9D020000番地から1024byteの領域を0xFFに消去する nvm_erase_pageの引数のアドレスは x9D020400,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: 03c0e821 move sp,s8 8000502c: 8fbf0014 lw ra,20(sp) 80005030: 8fbe0010 lw s8,16(sp) 80005034: 27bd0018 addiu sp,sp,24 80005038: 03e00008 jr ra 8000503c: 00000000 nop |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 |
#include <xc.h> // 0x9d020000番地のページ消去(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) lui a0,0x9d02 # 消去対象のアドレス jalr v0 nop lw ra,4(sp) addiu sp,sp,8 jr ra nop |
左のコードで生成される[UME専用Hexコマンド]は、
0x9d020000番地のページを削除するコードで、アセンブルして使います。 実行するためには、「アッセンブル」のボタン操作前で、 [0x80005000]番地から起動するコード埋め込みのチェックをして、生成してください。 そして「command.txt」の名前でファイル化して、pythonで実行させます。 なお、「command.txt」の先頭行に、「G109D0200000059」の行を追加することで、 実行前の0x9d020000番地の16byteの内容を確認することができます。 |
予め、pythonが動作するターミナル(コマンドプロンプト)を、開いて準備して置くとよいでしょう。
以下では、R:\workを作業位置(カレントディレクトリ)にして説明しています。
また、pythonプログラムでは、serialモジュールを追加しておく必要があります。
「pip show serial」のコマンド操作で、インストールされているか確認できます。
インストールされていない場合は、「pip install pyserial」の操作で、インストールしておくと良いでしょう。
上記の「アセンブラ編集部」の直下にある「アセンブル」ボタンをクリックします。
(このボタン右下の、指定アドレスから実行させるコード埋め込み用のチェックボックスがチェックされていること確認して行う)
「アセンブラ編集部」のソースにエラーが無ければ、[UME専用Hexコマンド]のテキストが、その下の TextArea に表示されます。
(エラーがあれば、エラーが無くHEXコードが生成されるまで、「アセンブラ編集部」の修正とアセンブル」を繰り返します)
メモ帳などで、「command.txt」のファイルを生成して開き、
上記操作で得られたTextAreaの[UME専用Hexコマンド]のテキストを、 コピー(CTRL+A CTRL+C)操作し、
それを「command.txt」編集画面で貼り付け((CTRL+V)して、保存します。
保存位置は、pythonが動作するターミナルの作業位置(カレントディレクトリ)です。(後述例では、R:\workで示しています)
上記で作った「instruct.py」と[command.txt」が存在する位置で、
pythonが動作するターミナル(コマンドプロンプト)を開きます。
以下では、この作業位置(カレントディレクトリ)が、R:\workである場合の例で説明しています。
まず [UMEHOSHI ITA]基板と、PCをUSBで接続します。
次にターミナルプロンプトを『powershell』にして、
『Get-CimInstance Win32_PnPEntity | Where-Object {$_ -like "*(COM*"} | Select-Object Caption』
のコマンド操作で、USBのシリアル デバイスのCOM番号を調べます。
R:\work>powershell Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6 PS R:\work> Get-CimInstance Win32_PnPEntity | Where-Object {$_ -like "*(COM*"} | Select-Object Caption Caption ------- Bluetooth リンク経由の標準シリアル (COM10) USB シリアル デバイス (COM4) Bluetooth リンク経由の標準シリアル (COM11) PS R:\work>
この実行例から、USB シリアル デバイス がCOM4が使える状態になっていることが分かります。
(このリンクページで示すように、デバイスマネージャで確認することもできます)
この番号の4を記憶して次の転送プログラム実行に進むのですが、
そのUSB シリアル デバイス が見つからない場合、次の点が考えられます。
R:\work>python instruct.py USB シリアル デバイスで、使用するCOMの番号を入力>>4 S109D0200000088BF023C00800334286143AC00000000 AFチェックサム: 0 USB受信● b'S109D0200000088BF023C00800334286143AC00000000AF\r\n' USB受信● b'SET:9D020000\r\n' S109D020010001480400F3F00043C88BF023C00800334 90チェックサム: 0 USB受信● b'S109D020010001480400F3F00043C88BF023C0080033490\r\n' USB受信● b'SET:9D020010\r\n' S109D02002000246143AC1480400F3F00043C0080400B 9Bチェックサム: 0 USB受信● b'S109D02002000246143AC1480400F3F00043C0080400B9B\r\n' USB受信● b'SET:9D020020\r\n' S049D0200300000000000 C7チェックサム: 0 USB受信● b'S049D0200300000000000C7\r\n' USB受信● b'SET:9D020030\r\n' S109D02005000F8FFBD270400BFAF21B88000FFFFF726 DAチェックサム: 0 USB受信● b'S109D02005000F8FFBD270400BFAF21B88000FFFFF726DA\r\n' USB受信● b'SET:9D020050\r\n' S109D02006000FEFFE016000000000800BD270800E003 7Dチェックサム: 0 USB受信● b'S109D02006000FEFFE016000000000800BD270800E0037D\r\n' USB受信● b'SET:9D020060\r\n' S049D0200700000000000 C3チェックサム: 0 USB受信● b'S049D0200700000000000C3\r\n' USB受信● b'SET:9D020070\r\n' 終了確認の Enter >>> R:\work>
[command.txt」の転送が終わって、終了確認の Enter >>>のプロンプトが出て、ENTERキーを
入力することで終了しますが、
まだ「 Lチカ 」は実行しません。
実行するには、パワーオンの後でリセットボタンを押すと、登録関数実行で「 Lチカ 」が始まります。
上記のプログラムは、USBで電源を供給するとすぐ動作するものではありません。
電源を供給後に、リセットボタン(SW1)を押すことで、起動する作品です。
電源を供給後にすぐ起動させるプログラムは、こちらのページで紹介しています。