これまで紹介したLED点滅処理の 1,2,3などは、
無限のループの中で、「待ち」、「LED点灯」、「LED消灯」、「待ち」を行うことで作っていました。
そのような作り方で、この無限ループを実行をしていまうと、USB通信が出来なくなってしまいます。
無限ループでなくても、下記のように作った のプログラムの処理が長すぎて、
下記赤矢印のリターンが遅れると、正しく動作できなくなります。
UME専用Hexコマンドが受付可能なUSB通信も正しく動作する作品を 実現するためには、その利用者のプログラム(左記 )で、 速やかに終わらせて赤矢印のリターンが行われるように作り方にします。 |
このためには、上記の で示す部分で、時間がかかる繰り返しを使わないで、 代わりにタイマーの割り込みで、 を次のように動作させます。
タイマーの割り込みの周期を、上手く調整すれば の部分で、 |
上記で青の流れが起動処理が、リセット時の呼び出しです。
ここでタイマー処理の準備と、割込み許可を行います。
この許可により、赤の流れのタイマー割り込みが一定周期で実行するするように作ります。
以下では、この具体的な例(D1のLEDでの「 Lチカ 」無限ループ)をC言語で示し、
この逆アセンブルしたコードを参考に、アセンブリリストを示しています。
(下記C言語ソースは、「umehoshiEdit」ツールで、ビルド実行できます。)
上記の赤の流れがLED点滅処理で、この関数をmain_loopの名前で0x9D020600番地に作ります。
そして、この関数をタイマー処理に登録する処理などのタイマー初期設定の起動関数(青の流れ)を、
0x9D020000番地に、init_timerの名前で作っています。
#include <xc.h> // test.c #include "common.h" int flag=0; // 0で点灯して1に変更 int count=0;// 点滅周期カウント用 //__attribute__((address( 0x80005100 ))) void main_loop (void); // 上記はRAM配置で、下記はROM配置用 __attribute__((address( 0x9D020600 ))) void main_loop (void); void main_loop(){ count++; //if( count <= 4000 ) return; // 0.2秒まで、カウント if( count <= 20000 ) return; // 1秒まで、カウント count=0; if(flag == 0) { PORTBSET = 0x8000; // D1 LED 点灯(RB15を1):0xbf886128番地への設定です. flag = 1; } else { PORTBCLR = 0x8000; // D1 LED 消灯(RB15を0):0xbf886124番地への設定です. flag = 0; } } //__attribute__((address( 0x80005200 ))) void init_timer(); // タイマーの初期化処理;上記はRAM配置で、下記の0x9D020000はEEPROM領域のリセット起動用アドレス __attribute__((address( 0x9D020000 ))) void init_timer(); void init_timer(){ flag=0; // 0で点灯して1に変更 count=0;// 点滅周期カウント用 T4CON =0x00000000;//typeB,16bit, [1:1]プリスケール TMR4=0x00000000; //16bitタイマの初期値(レジスタがカウントアップ) PR4=1999; //これは (1/40e6)*(1999+1) =0.05ミリ秒 IFS0bits.T4IF = 0;// Clear the timer interrupt status flag IEC0bits.T4IE = 1;// Timer4 Enable(割込み許可) _HANDLES[_IDX_TIMER_4_FUNC] = main_loop;// 割り込み関数のデフォルトを変更登録 T4CONbits.ON = 1;// timer4を有効にすることでスタート } /* // 以下はRAM配置時に使う起動関数登録当 __attribute__((address( 0x80005000 ))) void main(); void main() { //_HANDLES[_IDX_HANDLE_USER_SET_FUNC] = init_timer; // HANDLES領域の初期化用 //_handle_user_set_func(); _HANDLES[_IDX_INIT_SUB_FUNC] = init_timer; // 起動登録 //_init_sub_func(); } */ // 上記は、RAM配置用の登録関数で、『R00800050000061』の転送で実行するコードです。 // 上記で の部分がコメントになって、 // ROM領域で実行するプログラムになっています。 // (このコメントを外し、ROM用の__attribute__指定行をコメントにすることで、RAM動作用にに変わります。) /* EEPROM領域におけるリセットで起動するプログラムは 0x9D020000番地からに決まっており、 このアドレスのワード内容が0xffffffffでない場合だけ、このアドレス先の関数を実行する。 |
80008000 <flag>: 80008000: 00000000 nop 80008004 <count>: 80008004: 00000000 nop 9d020600 |
以下に、上記の実際に動作した、アセンブリリストを示します。上のC言語の逆アセンブルリストをコードにしてみました。
// 0x9D020000 〜 0x9D0207FF の EEPROM 領域を消去 #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); _nvm_erase_page(0x9D020400); } /* 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: 3c02a000 lui v0,0xa000 8000502c: 344240f0 ori v0,v0,0x40f0 80005030: 8c420000 lw v0,0(v0) 80005034: 3c039d02 lui v1,0x9d02 80005038: 34640400 ori a0,v1,0x0400 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番地のページ消去(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 lui v0,0xa000 ori v0,v0,0x40f0 lw v0,0(v0) lui v1,0x9d02 ori a0,v1,0x0400 # 消去対象のアドレス jalr v0 nop lw ra,4(sp) addiu sp,sp,8 jr ra nop |
左のコードで生成される[UME専用Hexコマンド]は、 0x9D020000 〜 0x9D0207FFのEEPROMを消去するアセンブラコードです。 実行するためには、「アッセンブル」のボタン操作前で、 [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 S0880008000000000000000000000 55チェックサム: 0 USB受信● b'S088000800000000000000000000055\r\n' USB受信● b'SET:80008000\r\n' S109D02060000F8FFBD270400BEAF21F0A0030180023C 2Eチェックサム: 0 USB受信● b'S109D02060000F8FFBD270400BEAF21F0A0030180023C2E\r\n' USB受信● b'SET:9D020600\r\n' S109D020610000480428C010043240180023C048043AC B3チェックサム: 0 USB受信● b'S109D020610000480428C010043240180023C048043ACB3\r\n' USB受信● b'SET:9D020610\r\n' S109D020620000180023C0480428C214E422803004010 C3チェックサム: 0 USB受信● b'S109D020620000180023C0480428C214E422803004010C3\r\n' USB受信● b'SET:9D020620\r\n' S109D0206300000000000A281400B000000000180023C F1チェックサム: 0 USB受信● b'S109D0206300000000000A281400B000000000180023CF1\r\n' USB受信● b'SET:9D020630\r\n' S109D02064000048040AC0180023C0080428C09004014 B3チェックサム: 0 USB受信● b'S109D02064000048040AC0180023C0080428C09004014B3\r\n' USB受信● b'SET:9D020640\r\n' S109D020650000000000088BF023C00800324286143AC A5チェックサム: 0 USB受信● b'S109D020650000000000088BF023C00800324286143ACA5\r\n' USB受信● b'SET:9D020650\r\n' S109D020660000180023C01000324008043ACA281400B B1チェックサム: 0 USB受信● b'S109D020660000180023C01000324008043ACA281400BB1\r\n' USB受信● b'SET:9D020660\r\n' S109D020670000000000088BF023C00800324246143AC A7チェックサム: 0 USB受信● b'S109D020670000000000088BF023C00800324246143ACA7\r\n' USB受信● b'SET:9D020670\r\n' S109D020680000180023C008040AC21E8C0030400BE8F 6Fチェックサム: 0 USB受信● b'S109D020680000180023C008040AC21E8C0030400BE8F6F\r\n' USB受信● b'SET:9D020680\r\n' S0C9D020690000800BD270800E00300000000 55チェックサム: 0 USB受信● b'S0C9D020690000800BD270800E0030000000055\r\n' USB受信● b'SET:9D020690\r\n' S109D02000000F8FFBD270400BEAF21F0A00300000000 55チェックサム: 0 USB受信● b'S109D02000000F8FFBD270400BEAF21F0A0030000000055\r\n' USB受信● b'SET:9D020000\r\n' S109D0200100080BF023C000C40AC80BF023C100C40AC 45チェックサム: 0 USB受信● b'S109D0200100080BF023C000C40AC80BF023C100C40AC45\r\n' USB受信● b'SET:9D020010\r\n' S109D0200200080BF023CCF070324200C43AC88BF033C 39チェックサム: 0 USB受信● b'S109D0200200080BF023CCF070324200C43AC88BF033C39\r\n' USB受信● b'SET:9D020020\r\n' S109D020030003010628CC49C027C301062AC88BF033C 53チェックサム: 0 USB受信● b'S109D020030003010628CC49C027C301062AC88BF033C53\r\n' USB受信● b'SET:9D020030\r\n' S109D020040006010628C01000424C49C827C601062AC 8Aチェックサム: 0 USB受信● b'S109D020040006010628C01000424C49C827C601062AC8A\r\n' USB受信● b'SET:9D020040\r\n' S109D0200500000A0023C94404234029D033C00066324 B4チェックサム: 0 USB受信● b'S109D0200500000A0023C94404234029D033C00066324B4\r\n' USB受信● b'SET:9D020050\r\n' S109D02006000000043AC80BF033C000C629401000424 A0チェックサム: 0 USB受信● b'S109D02006000000043AC80BF033C000C629401000424A0\r\n' USB受信● b'SET:9D020060\r\n' S109D02007000C47B827C000C62A421E8C0030400BE8F 43チェックサム: 0 USB受信● b'S109D02007000C47B827C000C62A421E8C0030400BE8F43\r\n' USB受信● b'SET:9D020070\r\n' S0C9D020080000800BD270800E00300000000 5Cチェックサム: 0 USB受信● b'S0C9D020080000800BD270800E003000000005C\r\n' USB受信● b'SET:9D020080\r\n' 終了確認の Enter >>> R:\work>
[command.txt」の転送が終わって、終了確認の Enter >>>のプロンプトが出て、ENTERキーを
入力することで終了しますが、
まだ「 Lチカ 」は実行しません。
実行するには、パワーオンの後でリセットボタンを押すと、「 Lチカ 」が始まります。
(それは、0x9D020000に存在する関数の実行で、_HANDLES[_IDX_TIMER_4_FUNC]に登録した関数をタイマー4割り込みで
0.05ミリ秒ごとに実行して実現しています)
動作例の動画がこちらでで紹介しています。