UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
[UMEHOSHI ITA]の制御で使っているIC「PIC32MX270F256B-I/SO」のフラッシュメモリには、テスト用プログラムが書き込まれいています。
以降では、このプログラムを「テスト・ウメ・フラッシュ」と呼ぶことにして解説します。
また、「テスト・ウメ・フラッシュ」を利用したユーザー用のプログラムを
「ウメ・エディットプログラム」と呼ぶことにします。
「ウメ・エディットプログラム」の開発では「umehoshiEditツール」が必要で、
その取得や最初の操作情報は、こちらを参照してください。
(「PICKit3などの書き込みツール」をお持ちの方で、「テスト・ウメ・フラッシュ」を利用しないで、
「MPLAB X IDE」の開発環境ですべてをプログラミングする場合の情報ではありません。)
「テスト・ウメ・フラッシュ」をどのように利用して、「ウメ・エディットプログラム」を
作るかの解説で、「umehoshiEditツール」の使用例を示しています。
各サンプルは、このWebページ上でドラック&コピーして、貼り付けしてご利用ください。
各種確認プログラム | 左記に必要な部品の追加例 |
---|---|
とくに必要ありません。 (D1のLEDは、あるとよい) | |
PWM対応の部品追加例 | |
ADC 対応の部品追加例 | |
BEEP SWITCH 対応の部品追加例 | |
Reset SW, Type-A, CN2 部品追加例 | |
U20,D4,D5,NPN, D3 部品追加例 | |
CN11,CN-12 部品追加例 | |
U19 部品追加例 | |
U17にRN4020の部品を追加する例 |
[UMEHOSHI ITA]このプロジェクトに必要な部品の追加例です。
このページは、こちらのリンク先で行ったpb5_pwd関数に相当する「PWDで鳴らす機能」を、 「ウメ・エディットプログラム」で再利用できるようにEEPROMに配置する過程を示しています。
MEMORY { kseg0_program_mem (rx) : ORIGIN = 0x80005000, LENGTH = 0x4fc0 exception_mem : ORIGIN = 0x9D03F000, LENGTH = 0x1000 debug_exec_mem : ORIGIN = 0x9FC00490, LENGTH = 0x760 kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0x0 kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490 config3 : ORIGIN = 0xBFC00BF0, LENGTH = 0x4 config2 : ORIGIN = 0xBFC00BF4, LENGTH = 0x4 config1 : ORIGIN = 0xBFC00BF8, LENGTH = 0x4 config0 : ORIGIN = 0xBFC00BFC, LENGTH = 0x4 kseg1_data_mem (w!x) : ORIGIN = 0x80008000, LENGTH = 0x1000 sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000 configsfrs : ORIGIN = 0xBFC00BF0, LENGTH = 0x10 }上記のORIGIN = 0x80008000, LENGTH = 0x1000が静的な変数で使う記憶領域の位置と長さです。
変数名 | _MEMO3のポインタ表現 | 絶対アドレス | 備考 |
---|---|---|---|
pwd_base | (char*)_MEMO3+3808 | 0x80009EE0 | =f"0x{0x80009000+0x0F00-2*16:8X}" 2byteのshort intが16個の配列 |
idx_base_P3 | (char*)_MEMO3+3804 | 0x80009EDC | =f"0x{0x80009EE0-4:8X}" 上記の配列領域より4byte前方の記憶域を使う | pwd_datas_P3 | (char*)_MEMO3+3800 | 0x80009ED8 | =f"0x{0x80009EDC-4:8X}" | pwd_size_P3 | (char*)_MEMO3+3796 | 0x80009ED4 | =f"0x{0x80009ED8-4:8X}" | pwd_idx_P3 | (char*)_MEMO3+3792 | 0x80009ED0 | =f"0x{0x80009ED4-4:8X}" | pwd_count_P3 | (char*)_MEMO3+3788 | 0x80009ECC | =f"0x{0x80009ED0-4:8X}" | change_count_P3 | (char*)_MEMO3+3784 | 0x80009EC8 | =f"0x{0x80009ECC-4:8X}" |
#include <xc.h> //change.c #include "common.h" #define NREP 6 // 1つ(4bit)のデータを、約(1/4410)秒周期で繰り返し使う回数(水平分解能指定パラメタ) //__attribute__((address( 0x80005000 ))) void change(void);// 【1】サイスを調べるために一時的に使う __attribute__((address( 0x9D03E620 ))) void change(void);// 【2】上記検討を経て決めた配置アドレス void change(void) // OC2割り込み関数 (PWMのデューティ サイクルの変更 { short int *pwd_base = (short int *)((char *)_MEMO3+3808);// PWDのデータテーブル int *idx_base_P3 = (int *)((char *)_MEMO3+3804);// 上記のPWDのデータテーブルのアクセス用添え字 char **pwd_datas_P3=(char **)((char*)_MEMO3+3800);// PWDのデータ添え字群の記憶領域の先頭アドレス int *pwd_size_P3 = (int *)((char*)_MEMO3+3796);// 上記ポインタから始まったデータのサイズ int *pwd_idx_P3 = (int *)((char*)_MEMO3+3792);// 上記アクセス用添え字 int *pwd_count_P3 = (int *)((char*)_MEMO3+3788);//(NREP+NREP)までのカウンタ int *change_count_P3 =(int *)((char*)_MEMO3+3784); // change()の割り込み回数計数で検証用 (*change_count_P3)++;//割り込み回数計測用 (約44100Hzの周期でカウント) if(*pwd_count_P3 == 0){ // 下位4ビットの周期へ *idx_base_P3 = (*pwd_datas_P3)[*pwd_idx_P3] & 0x0f; OC2RS = pwd_base[*idx_base_P3]; }else if(*pwd_count_P3 == NREP){ // 上位4ビットの周期へ *idx_base_P3 = ((*pwd_datas_P3)[*pwd_idx_P3] >> 4) & 0x0f; OC2RS = pwd_base[*idx_base_P3]; } if(++(*pwd_count_P3) == (NREP+NREP)){ //上位4ビットが終わって次の要素周期へ *pwd_count_P3=0; (*pwd_idx_P3)++; if( *pwd_idx_P3 >= *pwd_size_P3 ) {//周期要素の配列を使い終わった *pwd_idx_P3 = 0; OC2RS=0; OC2CONbits.ON =0; // OC2の動作OFF } } IFS0CLR = _IFS0_OC2IF_MASK; // Clear the OC2 interrupt flag }まず、上記change関数の定義の【1】の行のコメント外して有用行とし、 【2】の行をコメントにして「umehoshiEdit」ツールでビルドします。
S108000500000D8FFBD272400BEAF21F0A00300A0023C3E S108000501000E09E42340000C2AF00A0023CDC9E423467 ・・・省略・・・ S10800051D0002400BE8F2800BD270800E00300000000A6以上がプログラムコードを[UMEHOSHI ITA]のメモリに設定するコマンドコードとなる訳ですが、それは以下の範囲です。
#include <xc.h> #include "common.h" __attribute__((address( 0x80005000 ))) void main(void); void main() { PORTBCLR = 0x8000;// LED1を消去 _nvm_erase_page(0x9D03E000);// このアドレスから0x400(1024)バイトを消去 _nvm_erase_page(0x9D03E400);// このアドレスから0x400(1024)バイトを消去 PORTBSET = 0x8000;// LED1を点灯 _send_string("END program\r\n"); }この2048byteの消去範囲が前述のchange関数範囲より大きいのは、後述の関数pb5_pwdの定義領域を兼ねて消去するためです。
#include <xc.h> //pb5_pwd.c #include "common.h" #define NREP 6 // 1つ(4bit)のデータを、約(1/4410)秒周期で繰り返し使う回数(水平分解能指定パラメタ) //__attribute__((address( 0x80005000 ))) void pb5_pwd(char *pwd_adr, int size);// 【1】サイスを調べるために一時的に使う __attribute__((address( 0x9D03E000 ))) void pb5_pwd(char *pwd_adr, int size);// 【2】上記検討を経て決めた配置アドレス // pwd_adrの先頭アドレスからsizeバイトのサウンドデータの再生を割り込みで行わせる初期化関数 void pb5_pwd(char *pwd_adr, int size) { short int *pwd_base = (short int *)((char *)_MEMO3+3808);// PWDのデータテーブル pwd_base[0]=2; //{2, 62, 122, 182, 242, 303, 363, 423, 483, 543, 604, 664, 724, 784, 844, 905};の代わり pwd_base[1]=62; pwd_base[2]=122; pwd_base[3]=182; pwd_base[4]=242; pwd_base[5]=303; pwd_base[6]=363; pwd_base[7]=423; pwd_base[8]=483; pwd_base[9]=543; pwd_base[10]=604; pwd_base[11]=664; pwd_base[12]=724; pwd_base[13]=784; pwd_base[14]=844; pwd_base[15]=905; int *idx_base_P3 = (int *)((char *)_MEMO3+3804);// 上記のPWDのデータテーブルのアクセス用添え字 *idx_base_P3 = 0; // PWDのデータテーブルのアクセス用添え字 char **pwd_datas_P3=(char **)((char*)_MEMO3+3800);// PWDのデータ添え字群の記憶領域の先頭アドレス int *pwd_size_P3 = (int *)((char*)_MEMO3+3796);// 上記ポインタから始まったデータのサイズ int *pwd_idx_P3 = (int *)((char*)_MEMO3+3792);// 上記アクセス用添え字 int *pwd_count_P3 = (int *)((char*)_MEMO3+3788);//(NREP+NREP)までのカウンタ *pwd_datas_P3=pwd_adr; // PWDのデータ記憶領域の先頭アドレス *pwd_size_P3 = size; // PWDのデータサイズ *pwd_idx_P3 = 0; *pwd_count_P3 = 0; // PWDのデータアクセス用添え字 // Timer2の初期化------------------ T2CON =0x00000000;//typeB,16bit, [1:1]プリスケール これで(1/40e6)の周期で、TMR2をカウントアップ T2CONbits.TCKPS = 0;// 1:1プリスケール値 TMR2=0x0000; //16bitタイマの設初期値(上記設定周期でカウントして、PR2と一致するとクリアして割り込み) PR2=906; //16bitタイマの設定値(周期設定用 =int((1/44100)/(1/40e6)-1) IEC0CLR = 0x00000200;//T2IE Timer2 desable(割込み不許可) // Output Compare module 2の初期化-(割り込み指定を含む)----------------- OC2CON = 0x0000;// Turn off OC2 while doing setup. RPB5Rbits.RPB5R = 0x5; // RB5をOC2の出力にする。 OC2CONbits.SIDL = 0; // アイドルモード中も動作を継続する OC2CONbits.OC32 = 0; //OC2R<15:0> およびOC2RS<15:0> を使って16 ビットタイマ源と比較する OC2CONbits.OCTSEL = 0; // Timer2 をこの出力コンペア モジュールのクロック源として使う OC2CONbits.OCM = 5; // OC2 をPWM モードにし、フォルトピンを無効にする _HANDLES[_IDX_OUTPUT_COMPARE_2_VECTOR] = (void*)0x9D03E620; // OC2割り込みchange関数を登録 IFS0CLR = _IFS0_OC2IF_MASK; // Clear the OC2 interrupt flag IEC0SET = _IEC0_OC2IE_MASK; // Enable OC2 interrupt IPC2bits.OC2IP = 7;// Set OC1 interrupt priority to 7 IPC2bits.OC2IS = 3;// Set Subpriority to 3, maximum //OC2R = 0;//出力コンペア1 コンペアレジスタの初期値 //OC2RS = 905;//出力コンペア1 セカンダリコンペアレジスタ(デューティー比設定用で上記設定の最大値 ) T2CONbits.ON = 1; // Timer2の動作スタート OC2CONbits.ON =1; // OC2の動作スタート }上記をビルドした後に、[UMEHOSHI ITA]に転送する前に、得られたpb5_pwd.c.hexの「UME専用Hexコマンド」ファイル内容から、 0x9D03E000〜「0x9D03E2A0+0x10=0x9D03E2B0」の944バイトの範囲と確認します。
#include "common.h"
#define NREP 6 // 1つ(4bit)のデータを、約(1/4410)秒周期で繰り返し使う回数(水平分解能指定パラメタ)
__attribute__((address( 0x80005000 ))) void main(void);
void main()
{
void (*pb5_pwd)()=(void*)0x9D03E000;// 前述のpb5_pwd関数を配置したEEPOROMのアドレス
int *change_count_P3 =(int *)((char*)_MEMO3+3784); // change()の割り込み回数計数で検証用
*change_count_P3 = 0; // 検証用
PORTBINV = 0x8000; // LED1を反転
unsigned long count_now = _CP0_GET_COUNT();//(1/40e6)*2 =50ナノ秒でカウントするコアタイマーの値を取得
unsigned long count_end = count_now + 200000000;//の追加が10秒後のカウント値(10/50e-9=200000000)
pb5_pwd((char *) 0x80009000, 3451);// 0x80009000番地より3451byteサイズのデータを鳴らす
while(count_now < count_end && OC2CONbits.ON == 1){ // 10秒間、または再生中の実行
count_now = _CP0_GET_COUNT();//50ナノでカウントするコアタイマーの値を取得
}
PORTBINV = 0x8000;// LED1を反転
_send_decimal(*change_count_P3,10);
_send_string(" <==change_count\r\n");
}
この実行の再生音は、このページの実験でで示した音と同じです。この時点で使っている[UMEHOSHI ITA]内メモリ利用状態を以下に示します。
アドレス | 0x80005000〜 | 0x80009000〜0x80009D7B | 0x80009EC8〜0x80009F00 | 0x9D03E000〜のROM領域 | 0x9D03E620〜のROM領域 |
---|---|---|---|---|---|
内容 | main関数定義域 | 音データ記憶域 「え、何?」の音 |
change関数と pb5_pwd関数で使う グローバル記憶域 |
上記pb5_pwd関数定義域 アドレスが示す音データを 鳴らす指定関数 |
change割り込み関数定義域 PWDの周期を変更する |