Renesas Synergy™

FAQ 1006554 : 78K0S/Kx1+の汎用ポートによるマイクロワイヤ・EEPROMの制御プログラム例(78K0S/Kx1+)

[はじめに]
マイクロワイヤの概要やマイクロワイヤ・インタフェースのEEPROMについては「FAQ 1012000 : CSI によるマイクロワイヤ(Microwire)メモリの制御 [78K0/Kx2 他]」 を参照してください。78K0S/Kx1+にはCSI方式のシリアル・インタフェースが内蔵されていません。そこで、汎用ポートを使用して制御を行なう必 要があります。ここでは下記の接続例に示した場合に対応した具体的な制御プログラムについて説明します。また、制御プログラムの使い方についても簡単に触 れておきます。



[78K0S/Kx1+の処理例]
78K0S/Kx1+でのEEPROMの制御処理は以下の部分から構成します。78K0S/Kx1+では、マイクロワイヤとのインタフェースに使用する CSIが内蔵されていないので、汎用ポートをソフトウェアで制御して必要なインタフェースを行ないます。プログラムでの処理には時間が必要なことから、実 際のシリアルとパラレルのデータ変換処理(及び入出力処理)はアセンブラでも記述します。この処理をC言語記述のプログラムから利用する例と、全てをアセ ンブラ記述した例を示します。C言語記述の例では、78K0/Kx2のCSIを用いた制御例とできるだけ合わせるためにシリアルの処理は8ビット単位で行 ないます。アセンブラ記述の例では、EEPROMのアドレスに合わせたビット長での処理としています。ただし、全てアセンブラで記述した制御プログラムも C言語記述のプログラムからも使用できるようにします。制御関数は引数として、読み出しや書き込みでは以下のパラメータを用います。例えば、1ワード・ データの読み出しでは第1引数で読み出すアドレスを指定します。1ワード・データの書き込みでは第1引数で書き込むアドレスを指定し、第2引数で書き込み データを指定します。第 3引数まで使用するのはブロック単位での読み書きの場合です。(引数の定義及び使用できる機能はできるだけSPIの制御と合わせてあります。)

第1引数:EEPROMのアドレス
第2引数:バッファ・メモリのアドレス/ワード書き込みのデータ
第3引数:転送データ数で1~255及び0(256バイト)

なお、内蔵高速発振クロックを使用し、ウォッチドッグ・タイマは使用しないものとして、オプション・バイトは以下のように宣言しておくものとします。

        @@OPTB  CSEG    AT      0080H
        DB      10011100b       ; オプション・バイト
;                || |||+-----:低速クロック停止可
;                || |++------:高速内蔵発振クロック使用
;                || +--------:RESET端子を使用
;                ++----------:発振安定時間は最短
;
        DB      11111111b       ; プロテクトバイト
        END


(1)初期化部
ポートの初期化を行ないます。さらに、8MHzで使用するためにLVIを用いて、電源電圧4.0V以上になるまで待ちます。基本的にベクタ割り込みは使用しないので、割り込みは禁止状態のままとします。また、ウォッチドッグ・タイマも停止します。

(2)EEPROMアドレス長選択処理
この制御プログラムでは、6ビット~13ビットのアドレス長のEEPROMに対応できるようにアドレス長を指定する処理を付け加えてあります。これで指定 したアドレス長に対応して以下で使用するコマンド及びアドレスは必要なだけ頭に0を追加して合計で16ビットになるようにします。(アセンブラ記述の例で はこの処理は行いません。)

(3) 書き込み許可
EEPROMのCS信号をONにして、「WEN」コマンドを送ります。コマンド転送完了後CS信号をOFFにします。このコマンドによりEEPROMは書き込み可能状態になります。

(4)書き込み禁止
EEPROMのCS信号をONにして、「WDS」コマンドを送ります。コマンド転送完了後CS信号をOFFにします。このコマンドによりEEPROMは書き込み禁止状態になります。

(5) ワード・データの読み出し
第1引数で指定した(EEPROMの)アドレスから1ワードのデータを読み出し、戻り値で返します。コマンドとアドレスの転送後にSKとデータの位相関係 が変化することに対してはアドレス転送後にSKを立ち下げ、その後のバイトデータ受信処理でのSK立下りでのデータ読み込みで対応します。

(6)ブロック・データ読み出し
第1引数で示した(EEPROMの)アドレスから第2の引数で示されたアドレスのバッファに第3の引数で示されたデータ数(ワード)のデータを読み出します。

(7)ワード・データ書き込み
第1引数で指定した(EEPROMの)アドレスに第2の引数で示されたワード・データを書き込みます。書き込み(転送)終了後にCSをOFFにすると EEPROMは実際の書き込みを開始します。実際に書き込みが完了するまでの待ち合わせは行いません。次にEEPROMに対して操作を行なう前には(9) 書き込み完了待ちを実行して実際の書き込みが完了したことを確認する必要があります。

(8)ブロック書き込み
第1引数で示した(EEPROMの)アドレスに第2の引数で示されたアドレスのバッファのデータを第3の引数で示されたデータ数(ワード)分書き込みま す。EEPROMは1ワードの書き込みにしか対応していないので、ここでは、ワード・データの書き込みを必要な回数繰り返すことで必要な書き込みを行ない ます。ワードごとに書込みコマンドを繰り返し発行する必要があるので、書込み完了待ちまで処理しています。

(9) 書き込み完了待ち
EEPROMは書き込みデータを転送後、CS信号をOFFすることで実際の書き込みを開始します。書き込みが完了したかどうかは再度CS信号をONにしてSO端子の状態をチェックしてハイ・レベルになることで確認できます。

(10) バイトデータ受信
汎用ポートを使って実際にEEPROMからバイトデータを受信します。C言語記述の場合でも、ここはアセンブラで記述します。

(11) バイトデータ送信
汎用ポートを使ってEEPROMにコマンドやアドレス、バイトデータを送信します。C言語記述の場合でも、ここはアセンブラで記述します。

[C言語でのプログラム例]
ここではC言語でプログラムを作成した場合のプログラム例を示します。EEPROMへのアクセスでそれほど速度に制約がない場合に参考にして下さい。

(0) 宣言及び定義部分
ここでは、関数のプロトタイプ宣言、EEPROMに対するコマンド(最も小さな6ビットのアドレスに対応した値)をディフォルト値として定義しています。また、第1引数のアドレス値をEEPROMのアドレスに丸めるためのマスクデータもビット長に応じて準備しています。

#pragma SFR
#pragma NOP
extern void _putmw(unsigned char data);         // 1文字送信
extern unsigned char _getmw(void);              // 1文字受信

bit selrom(unsigned char leng);                 // アドレス長設定
void writeenb(void);                            // 書き込み許可設定
void writedis(void);                            // 書き込み禁止設定
unsigned int read_mw(int reg_adr);
void read_mw_block(int reg_adr, unsigned int *data, unsigned char size);
void write_mw(int reg_adr, unsigned int data);
void write_mw_block(int reg_adr, unsigned int *data, unsigned char size);
void waitwt(void);

/*------------------------------------------------------*/
/*                                                      */
/*      MW関連のコマンド定義                            */
/*                                                      */
/*------------------------------------------------------*/

#define READC   0b0000000110000000              // データ読み出し
#define WRITEC  0b0000000101000000              // データ書き込み
#define WENC    0b0000000100110000              // 書き込み許可
#define WDSC    0b0000000100000000              // 書き込み禁止

#define LENGTH  6                               // アドレスのビット長
#define CSsignal        P2.3                    // CS信号の定義
#define SKsignal        P2.2                    // SK信号の定義
#define SIsignal        P2.1                    // SI信号の定義

static  unsigned char adrlen = LENGTH;          // アドレス長の保存用

typedef unsigned int mask[8];                   //  アドレス・マスクデータ
const mask mask1 =     {0b0000000000111111,0b0000000001111111,
                        0b0000000011111111,0b0000000111111111,
                        0b0000001111111111,0b0000011111111111,
                        0b0000111111111111,0b0001111111111111};

(1) 初期化部
使用するポートの初期化や電源の立ち上がり待ちやクロック設定を行なう部分をhdwinit関数として記述した例を以下に示します。

void    hdwinit(void)
{
        int work1;
        P2      = 0b11110011;                   // 出力ラッチの設定
        PM2     = 0b00000010;
        LVIS    = 0x00;                         // select VLI=4V
        LVIM    = 0b10000000;                   // Start VLI detection
        PCC     = 0x00;                         // CPU clock is fx/4
        WDTM    = 0b01110111;                   // Stop WDT
        LSRSTOP = 1;                            // Stop Low Speed OSC

//      wait for 0.17ms(=0.2ms-(32+30)*52/1000)

        for (work1 = 0; work1 < 10; work1++){
                NOP();
        }

        while ( LVIF ){
                NOP();
        }                                       // wait VDD > 4V

        PPCC = 0;                               // CPU clock is fx=fR

}

(2) EEPROMアドレス長選択処理
EEPROMのアドレス長を指定します。アドレス長は引数で指定し、6~13ビットの範囲(これで、スタートビット~アドレスを16ビットで処理できます)とします。この範囲以外はエラーとして処理します。ここでは単に変数に記録するだけです。

Bit     selrom(unsigned char length)
{
        if((length < 6) || (length > 13))       return 1;
        adrlen = length;
}

(3) 書き込み許可
CS信号をONして、アドレス長に合わせて「WEN」コマンドをシフトして頭の0の個数を調整し、EEPROMのコマンドを作成します。作成したコマンドを上位バイト、下位バイトの順で送信します。送信が完了したらCS信号をOFFして処理を終了します。

Void writeenb(void)
{
        unsigned int work;
        Cssignal = 1;                           // CS 信号をセット
        work = WENC << (adrlen-6);              // コマンドをデバイスに合わせる
        _putmw(work / 0x100);                   // コマンドを転送
        _putmw(work & 0x0ff);
        Cssignal = 0;                           // CS 信号をリセット
}

(4) 書き込み禁止
CS信号をONして、アドレス長に合わせて「WDS」コマンドをシフトして頭の0の個数を調整し、EEPROMのコマンドを作成します。作成したコマンドを上位バイト、下位バイトの順で送信します。送信が完了したらCS信号をOFFして処理を終了します。

Void writedis(void)
{
        unsigned int work;
        Cssignal = 1;                           // CS 信号をセット

        work = WDSC << (adrlen-6);              // コマンドをデバイスに合わせる
        _putmw(work / 0x100);                   // コマンドを転送
        _putmw(work & 0x0ff);

        Cssignal = 0;                           // CS 信号をリセット
}

(5) ワード・データの読み出し
引数として渡されたEEPROMのアドレスから必要な部分以外をマスクし、コマンドを必要なビットだけシフトさせてコマンド+アドレスを生成します。CS 信号をONし、スタート・ビット~アドレスを送信したらSK信号をロウにします。2バイトのデータを読み出したら、CS信号をOFFして通信モードを元に 戻します。読み出した2バイトを結合してワードの戻り値とします。

unsigned int read_mw(int reg_adr){
        unsigned int work;

        work = reg_adr & mask1[adrlen-6];       // アドレスの上位をマスク
        work |= (READC << (adrlen-6));          // コマンドを合成

        CSsignal = 1;                           // CS 信号をセット

        _putmw(work / 0x100);                   // コマンドを転送
        _putmw(work & 0x0ff);

        SKsignal = 0;                           // SKの位相を変更する

        work = _getmw();                        // 上位データの読み込み
        work = work << 8;                       // 上位にシフト
        work |= _getmw() ;                      // 下位データの読み出し

        CSsignal = 0;                           // CS 信号をリセット

        SKsignal = 1;                           // SKの位相を変更する

        return work;
}

(6) ブロック・データ読み出し
EEPROMとのやり取りはワード・データの読み出しと同じですが、連続して読み出すと次のアドレスの内容が読み出せることを利用した処理です。読み出し データ数の処理の後、コマンド送信までの処理は同じです。その後さらにデータを読み出して、それをバッファ・メモリに書き込む処理を指定された回数ループ します。

void read_mw_block(int reg_adr, unsigned int *data, unsigned char size)
{
        unsigned int work;
        int count;                              // 受信データ数のカウンタ

        if(size){
                count = size;
        }else count = 0x100;                    // 入力が0なら100Hに

        work = reg_adr & mask1[adrlen-6];       // アドレスの上位をマスク
        work |= (READC << (adrlen-6));          // コマンドを合成

        CSsignal = 1;                           // CS 信号をセット

        _putmw(work / 0x100);                   // コマンドを転送
        _putmw(work & 0x0ff);

        SKsignal = 0;                           // SKの位相を変更する

        do{
                work = _getmw();                // 上位データの読み込み
                work = work << 8;               // 上位にシフト
                work |= _getmw() ;              // 下位データの読み出し
                *data++ = work;                 // データの保存
        }while(--count);

        CSsignal = 0;                           // CS 信号をリセット

        SKsignal = 1;                           // SKの位相を変更する

}

(7) ワード・データ書き込み
コマンド転送までの処理は読み出しと同じです。第2の引数として渡されたワード・データを送信する部分が異なるだけです。なお、この関数では書き込みの起動までで、書き込みの完了は待ちません。

void write_mw(int reg_adr, unsigned int data)
{
        unsigned int work;

        work = reg_adr & mask1[adrlen-6];       // アドレスの上位をマスク
        work |= (WRITEC << (adrlen-6));         // コマンドを合成

        CSsignal = 1;                           // CS 信号をセット

        _putmw(work / 0x100);                   // コマンドを転送
        _putmw(work & 0x0ff);

        _putmw(data / 0x100);                   // データを転送
        _putmw(data & 0x0ff);

        CSsignal = 0;                           // CS 信号をリセット

}

(8) ブロック書き込み
1ワード書き込みのループを回すので、コマンド処理もその分繰り返す必要があります。コマンドのシフト処理やアドレスとの結合をその度にやるのは処理能力 の低下となるので、前処理としてEEPROMに書き込むコマンドとアドレスを結合して変数(command)にしておきます。ループでのEEPROMのア ドレスの更新はこの結合した変数で処理します。そのため、EEPROMのアドレスがオーバーフローするような場合には対応できないので、注意してくださ い。

void write_mw_block(int reg_adr, unsigned int *data, unsigned char size)
{
        unsigned int work, command;
        int count;                              // 送信データ数のカウンタ

        if(size){
                count = size;
        }else count = 0x100;                    // 入力が0なら100Hに

        command = reg_adr & mask1[adrlen-6];    // アドレスの上位をマスク
        command |= (WRITEC << (adrlen-6));      // コマンドを合成

        do{
                CSsignal = 1;                   // CS 信号をセット

                _putmw(command / 0x100);        // コマンドを転送
                _putmw(command & 0x0ff);

                work = *data++;                 // 送信データのセット

                _putmw(work / 0x100);           // 上位バイト書き込み
                _putmw(work & 0xff);            // 下位バイト書き込み

                CSsignal = 0;                   // CS 信号をリセット

                command++;                      // アドレス更新

                waitwt();                       // 書き込み完了を待つ

        }while(--count);
}

(9) 書き込み完了待ち
書き込み後にこの関数を使うことでEEPROMへの書き込み完了を待つことができます。CS信号をONにしても直ぐにはEEPROMから正しいステータスが出てこないので、その分はNOP()命令4個で待ち合わせを行ない、それからステータス確認を行ないます。

Void waitwt(void)
{
        Cssignal = 1;                           // CS 信号をセット

        NOP();                                  // ステータス出力待ち
        NOP();
        NOP();
        NOP();

        while(SIsignal == 0);                   // 書き込み完了待ち

        Cssignal = 0;                           // CS 信号をリセット

}

(10)バイトデータ受信
汎用ポートを制御してバイトデータの受信処理を行ないます。この処理はアセンブラ記述となります。

;
;       シリアル受信処理
;
; <機能>
; 8ビットのデータをシリアルで転送(受信)します。
;転送が完了したら受信データを持って戻ります。
; SKのデューティを変えることで、周期を守りながら全体の転送レートを
;下げすぎないようにしています。汎用ポート(P2.1)のデータをキャリー・
;フラグを介して取り込みます。新しいデータの取り込みとループ・カウント
;を一つの命令で兼用するためにAレジスタに設定する初期値を工夫しています。
;
; <入力パラメータ(引数)> なし
; <戻り値>
;       受信データ
;
;unsigned char _getmw(void)
        public  __getmw

__getmw:
        MOV     A,#11111110b    ; 4: 初期値を設定
RXLOOP:
        SET1    P2.2            ; 6: SKを立ち上げる
        NOP                     ; 2:
        NOP                     ; 2:
        SET1    CY              ; 2: 入力ディフォルト値設定
        CLR1    P2.2            ; 6: SKを立ち下げる
        BT      P2.1,$RXNEXT    ;10: 入力をチェック
        CLR1    CY              ; 2: データ0用
RXNEXT:
        ROLC    A,1             ; 2: 入力ビットを組み入れる
        BC      $RXLOOP         ; 6: 8回ループ
        MOV     C,A             ; 戻り値に設定
        RET

(11) バイトデータ送信
汎用ポートを直接制御してバイトデータの送信処理を行ないます。

;
; <機能>
; 引数で渡された8ビットのデータをシリアルで転送します。
;転送が完了したら戻ります。
; 処理は250kbps以下にするため、SKの制御間隔を2マイクロ以上
;確保させます。
;
; <入力パラメータ(引数)>
;       送信データ
; <戻り値>   なし
;
;void _putmw(unsigned char)
        public  __putmw

__putmw:
        PUSH    BC
        MOV     B,#8            ; ビットカウンタ設定

TXLOOP:
        MOV     A,X             ; 4: 出力データを持ってくる
        SET1    P2.2            ; 6: SKを立ち上げる
        ROL     A,1             ; 2: 出力ビットをLSBに
        MOV     X,A             ; 4:
        AND     A,#1            ; 4: その他のビットをマスク
        OR      A,#8            ; 4: CSビットをセット
        MOV     P2,A            ; 4: SO出力とSK立ち下げ
        NOP                     ; 2:
        DBNZ    B,$TXLOOP       ; 6: 8回繰り返す
        POP     BC              ; 6:
        SET1    P2.2            ; 6: SKを立ち上げる
        RET


[プログラムの使用例1]
ここでは、これまで説明してきたプログラムの使用方法を説明します。

(1) 宣言部
ここではこれまで説明した関数を使用するためにextern宣言しています。また、ハードウェアの初期化関数のプロトタイプ宣言も行なっています。

#pragma SFR
extern bit selrom(unsigned char leng);          // ROMのアドレス長指定
extern void writeenb(void);                     // 書き込み許可設定
extern void writedis(void);                     // 書き込み禁止設定
extern unsigned int read_mw(int reg_adr);       // ワード・データ読み出し
extern void read_mw_block(int reg_adr, unsigned int *data, unsigned char size);
// ブロック読み出し
extern void write_mw(int reg_adr, unsigned int data);
// ワード・データの書き込み
extern void write_mw_block(int reg_adr, unsigned int *data, unsigned char size);
// ブロック書き込み
extern void waitwt(void);                       // 転送データの書き込み完了待ち

void hdwinit(void);

以下の部分は関数を用いて読み書きを行なう際のデータ・バッファ及び、書き込むデータを定義しています。

unsigned int    eep_read_buf1[8];       // read buffer
typedef unsigned int data4[4];
const data4 txdata1 = {0x1234,0x5678,0x9ABC,0xDEF0};

(2) 読み出し処理
ここでは、これまで説明した関数を使用して、実際にEEPROMからデータを読み出します。最初に、アドレス幅を8ビットに指定して、読み出しをおこない ます。なお、書き込みは行なわないので、書き込みは禁止にして読み出します。この例では、0x33番地と0xAA番地からのワード・データを読み出し、及 び0xCC番地から8ワードのデータをバッファ・メモリに読み出す処理を行なっています。

void rxtest(void)
{
        unsigned int work;
        selrom(8);                              // アドレス幅を設定
        writedis();                             // 書き込み禁止
        work = read_mw(0x33);                   // 0x33からリード
        work = read_mw(0xAA);                   // 0xAAからリード
        read_mw_block(0xcc, eep_read_buf1, 4);  // ブロックデータリード
// 第1引数でEEPROMアドレス(0xcc)を指定、
// 第2引数でリードバッファ・メモリのアドレス(eep_read_buf1)を指定
// 第3引数でデータ数(4ワード)を指定

}

(3)書き込み処理
ここでは、これまで説明した関数を使用して、実際にEEPROMにデータを書き込みます。最初に、アドレス幅を8ビットに指定し、書き込みを許可状態にし てから実際の書き込みをおこないます。なお、ワード・データの書き込みでは、その後に実際の書き込みが完了するまでの待ち合わせを行ないますが、完了待ち の前に他の処理を入れることも可能です。

void    txtest(void)
{
        selrom(8);                              // アドレス幅を変更
        writeenb();                             // 書き込み許可
        write_mw(0xaa, 0x1234);                 // ワード・データ書き込み

// ここに他の処理を入れて構いません。

        waitwt();                               // 書き込み完了待ち
        write_mw(0xaa, 0x55aa);

// ここに他の処理を入れて構いません。

        waitwt();
        write_mw_block(0xaa, txdata1, 4);       // ブロック書き込み
}


[アセンブラでのプログラム例]
ここではアセンブラ記述での制御プログラム例を示します。

(0) 宣言及び定義部分
ここでは、各種の宣言及び作業領域の定義を行ないます。プログラムの大きさを小さくするために、ここではよく使用する3つのサブルーチンをCALLT命令 で呼べるようにCALLTテーブルを定義します。また、マクロを定義して意味のある名前を使用して使えるようにしています。
汎用ポートの制御についてもマクロを使用して例えばCS信号をONする処理はCSsignalONと直感的に処理が分かるような記述ができるようにしています。

PUBLIC __selrom                 ; ROMのアドレス長を指定する。
PUBLIC __writeenb               ; 書き込みを許可状態にする
PUBLIC __writedis               ; 書き込みを禁止状態にする
PUBLIC __read_mw                ; 1ワードを読み出す。
PUBLIC __read_mw_block          ; ブロック読み出し
PUBLIC __write_mw               ; 1ワードを書き込む
PUBLIC __write_mw_block         ; ブロック書き込み
PUBLIC __waitw                  ; 書き込み完了待ち
;
;       作業領域
;
WDATA   DSEG    SADDR
ADRLEN  DS      1               ; アドレス長パラメータ
COMMAND DS      2               ; コマンド生成用ワーク
;
;       シリアル処理マクロ定義
;
CSsignalON      macro
        SET1    P2.3
        endm

CSsignalOFF     macro
        CLR1    P2.3
        endm

SKsignalON      mcro
        SET1    P2.2
        endm

SKsignalOFF     mcro
        CLR1    P2.2
        endm


putmw   macro
        CALLT   [48H]
        endm

getmw   macro
        CALLT   [4AH]
        endm

putbits macro
        CALLT   [4CH]
        Endm

RTX     CSEG    AT      48H
        DW      PUTMWS
        DW      GETMWS
        DW      TXBIT

(1) 初期化部
使用するポートの初期化や電源の立ち上がり待ちやクロック設定等を行なう部分です。オプション・バイトの設定で低速発振クロックを停止可能に設定してあるので、ウォッチドッグ・タイマは停止させておきます。

;
;       ポートのイニシャライズ
;
        MOV      P2,#11110000b          ; 出力ラッチの設定
        MOV     PM2,#11110010b          ; P20、P22、P23は出力に
;                        |||+-----: シリアル出力(SO)
;                        ||+------: シリアル入力(SI)
;                        |+-------: シリアルクロック(SK)
;                        +--------: チップセレクト(CS)
;
;       電源の立ち上がり待ち(4.0V以上になるのを待つ)
;
POWERON:
                DI
                MOV     LVIS,#00000000b ; VLI=4.0V
                MOV     LVIM,#10000000b ; 低電圧検出開始
                MOV     PCC,#00         ; CPU clock is fx/4
                MOV     WDTM,#01110111b ; WDTを停止
                SET1    LSRSTOP         ; 低速発振器停止
                MOV     A,#50
PONLOOP:
                DEC     A
                BNZ     $PONLOOP        ; 0.2ms待つ

PONLOOP2:
                BT      LVIF,$PONLOOP2  ; 電圧が4.0V以上まで待つ
                MOV     PPCC,#0         ; CPU clock is fx=fR

(2)EEPROMアドレス長選択処理
アドレス長を6~13ビットの範囲で設定するルーチンです。指定値に問題がなければ、指定されたビット長に対応したパラメータを保存します。指定値が範囲外の場合には、エラーとしてキャリー・フラグ(戻り値)をセットして戻ります。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             アドレス長設定                          */
;/*                                                     */
;/* <機能>                                           */
;/* 引数で指定された値をアドレス長として設定します。   */
;/*                                                     */
;/* EEPROMに対するコマンドとアドレスは合わせて    */
;/*16ビットで処理します。ここで設定した値を元にして   */
;/*アドレスの有効桁を抽出したり、コマンドのビット位置   */
;/*を調整します                                         */
;/* <入力パラメータ(引数)> アドレス長              */
;/* <戻り値>                                         */
;/*     エラーをキャリー・フラグにセットして戻る        */
;/*-----------------------------------------------------*/
;bit _selrom(unsigned char length)

__selrom:
SELROM:
        MOV     A,X             ; 6~13
        ADD     A,#(255-13)     ; 249~255
        SUB     A,#(255-7)      ; 0~7
        BC      $SELROMEXIT
        INC     A               ; 1~8
        MOV     ADRLEN,A        ; パラメータを保存
SELROMEXIT:
        RET

(3) 書き込み許可
CS信号をONして、「WEN」コマンドを転送し、その後に指定されたアドレス長に対応した数(アドレス長-2)の0を送ります。送信が完了したらCS信号をOFFして処理を終了します。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             書き込み許可コマンド発行                */
;/* <機能>                                           */
;/* EEPROMを書き込み許可に設定します             */
;/*                                                     */
;/* <入力パラメータ(引数)> なし                   */
;/* <戻り値> なし                                   */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _writeenb(void)

__writeenb:
WRITEENB:
        CSsignalON                      ; CS信号をオンする

        MOV     A,#01001100b            ; 書き込み許可コマンド

WRITENEXT:
        MOV     B,#6                    ; 書き込みは6ビット分
        putbits                         ; コマンドの書き込み
        MOV     A,ADRLEN
        ADD     A,#3                    ; 残りアドレス数を計算
        MOV     B,A
        MOV     A,#0                    ; 残りアドレスは0に
        putbits                         ; アドレスの残りに0を出力
        SKsignalOFF                     ; 最後にSKをロウ・レベルにする
        CSsignalOFF                     ; CS信号をオフする
        RET

(4) 書き込み禁止
CS信号をONして、「WDS」コマンドを転送し、その後に指定されたアドレス長-2の0を送ります。送信が完了したらCS信号をOFFして処理を終了します。コマンド以外は書き込み許可と同じです。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             書き込み禁止コマンド発行                */
;/* <機能>                                           */
;/* EEPROMを書き込み禁止に設定します。           */
;/*                                                     */
;/* <入力パラメータ(引数)> なし                   */
;/* <戻り値> なし                                   */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _writedis(void)

__writedis:
WRITEDIS:
        CSsignalON                      ; CS信号をオンする

        MOV     A,#01000000b            ; 書き込み許可コマンド
        BR      $WRITENEXT              ; コマンド書き込みへ

(5) ワード・データの読み出し
CS信号をONし、コマンドに引き続いて、引数として渡されたEEPROMのアドレスを必要なビット数だけ転送します。その後、SK信号をロウにして、2 バイトのデータを読み出し、読み出しが完了したらCS信号をOFFします。読み出したデータは戻り値としてBCレジスタに設定して戻ります。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             データの読み出し1                      */
;/*                                                     */
;/* <機能>                                           */
;/* EEPROMの引数で指定したアドレスから1ワードの */
;/*データを読み出します。                               */
;/*                                                     */
;/* <入力パラメータ(引数)>                         */
;/*  AX :EEPROM内のアドレス                       */
;/*                                                     */
;/* <戻り値>                                         */
;/*  BC :読み出したデータ                               */
;/*                                                     */
;/*-----------------------------------------------------*/
;unsigned int _read_mw(int reg_adr)

__read_mw:
READ_MW:

        CALL    !RDCMD                  ; コマンドとアドレス送信
        SKsignalOFF                     ; SKを立ち下げる
        SOsignalOFF                     ; SOをロウ・レベルに

        getmw                           ; 上位バイト受信
        MOV     B,A
        getmw                           ; 下位バイト受信
        MOV     C,A
        CSsignalOFF                     ; CSをオフして処理終了
        RET

(6) ブロック・データ読み出し
EEPROMとのやり取りはワード・データの読み出しと同じですが、連続して読み出すと次のアドレスの内容が読み出せることを利用した処理です。読み出し データ数の処理の後、コマンド送信までの処理は同じです。その後さらにデータを読み出して、それをバッファ・メモリに書き込む処理を指定された回数ループ します。引数がスタックを用いて渡されるので、コマンド転送後にそこから必要なパラメータを抽出します。具体的な処理はブロック書き込みと共用したサブ ルーチン(GETPARA)で行ないます。データの読み出しは上位バイトに続いて下位バイトの順なので、バッファ・メモリに格納する際には格納アドレスに 注意が必要です。(FAQのエンディアンを参照して下さい。)。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             データの読み出し(ブロック)            */
;/*                                                     */
;/* <機能>                                           */
;/* 引数として渡されたデータ数だけEEPROMから     */
;/*データを読み出します                                 */
;/*                                                     */
;/* <入力パラメータ(引数)>                         */
;/* AX  : 第1の引数 :EEPROM内のアドレス          */
;/* SP+2,3: 第2の引数 :バッファ・メモリのアドレス      */
;/* SP+4  : 第3の引数 :読み出しデータ数(ワード単位)  */
;/*                                                     */
;/* <戻り値>   なし                                  */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _read_mw_block(int reg_adr, unsigned int *data, unsigned char size)

__read_mw_block:
READ_MWB:
        CALL    !RDCMD                  ; コマンドとアドレス送信
        SKsignalOFF                     ; SKを立ち下げる

        PUSH    HL                      ; レジスタをセーブ
        PUSH    AX
;
; このサブルーチンはC(ノーマル・モード)からの関数コールに対応。
; そのため、この段階でのスタックのデータは以下のようになっている
;
;       sp  : Xレジスタ(第1引数)    :EEPROMアドレス(下位)
;       sp+1 : Aレジスタ(第1引数)    :EEPROMアドレス(上位)
;       sp+2 : Lレジスタ                :未使用(レジスタのセーブのみ)
;       sp+3 : Hレジスタ                :未使用(レジスタのセーブのみ)
;       sp+4 : PCの下位               :戻りアドレス下位
;       sp+5 : PCの上位               :戻りアドレス上位
;       sp+6 : 第2引数の下位           :バッファ・メモリのアドレス(下位)
;       sp+7 : 第2引数の上位           :バッファ・メモリのアドレス(下位)
;       sp+8 : 第3引数の下位           :読み出しデータ数
;       sp+9 :                          :未使用

        CALL    !GETPARA                ; 引数を作業領域(HL,DATANO)に

READLOOP:
        getmw                           ; 上位バイト読み出し
        MOV     [HL+1],A                ; 読み出したデータをセーブ
        getmw                           ; 下位バイト読み出し
        MOV     [HL],A                  ; 下位バイトの保存
        INCW    HL
        INCW    HL                      ; メモリポインタ更新
        DBNZ    DATANO,$READLOOP        ; 指定回数繰り返す

        CSsignalOFF                     ; CS信号をオフする

        POP     AX                      ; レジスタの復帰
        POP     HL
        RET

(7)共通処理部1
EEPROMへのコマンド転送と、その後のアドレス転送までの内部処理を行なうための部分です。これらの処理はリード/ライトで共通となるので、プログラ ムの大きさを小さくするために共通化しています。特にアドレス部分は長さが変わるので、共通化によるプログラム・サイズ削減に大きく影響します。
リードとライトでは入り口が異なり、対応するコマンドを設定したら、後の処理は共通になります。

;
;       リードコマンド発行
;
RDCMD:
        MOVW    ADDR,AX                 ; アドレスをワークに保存
        MOV     A,#01100000b            ; リードコマンド
        BR      $SENDCMD                ; コマンド送信へ
;
;       ライトコマンド発行
;
WRCMD:
        MOVW    ADDR,AX                 ; アドレスをワークに保存
WRCMD2:
        MOV     A,#01010000b            ; ライトコマンド
;
;       実際にコマンドの転送を行ないます。
;       (ここからはリードとライトは共通処理)
;
SENDCMD:
        CSsignalON                      ; CS信号をオンする
        PUSH    BC
        MOV     B,#4                    ; コマンドのビット数セット
        putbits                         ; コマンド転送
;
;       アドレス処理
; EEPROMのアドレスが8ビット未満/8ビット/9ビット以上かに
;よって分けて処理します。
;
        MOV     A,ADRLEN
        SUB     A,#3                    ; アドレス長をチェック
        BZ      $LOWADR                 ; 8ビットなら分岐
        BC      $LESTHAN8               ; 8ビット未満なら分岐
;
;       アドレスの上位を処理する
;

        MOV     C,A
        MOV     B,A
        MOV     A,ADDR+1                ; 上位アドレスを読み出す
ADORLOOP:
        ROR     A,1                     ; 1ビット右シフト
        DBNZ    C,$ADORLOOP
;       MOV     X,A                     ; 上位アドレスをセット
        putbits                         ; 上位アドレス出力(可変長)

;
;       アドレスの下位を処理する
;
LOWADR:
        MOV     B,#8
        MOV     A,ADDR                  ; アドレスを読み出す
        putbits                         ; 下位アドレス出力
        POP     BC
        RET
;
;       8ビット未満の処理
;
LESTHAN8:
        INC     A                       ; 7ビットならゼロに
        MOV     A,ADDR                  ; 下位アドレスを読み出す。
        MOV     B,#7
        ROL     A,1                     ; アドレスをMSB側につめる
        BZ      $LOWADR2
        DEC     B
        ROL     A,1
LOWADR2:
;       MOV     X,A
        putbits                         ; 下位アドレス出力
        POP     BC
        RET

(8)共通処理部2
ブロック処理で共通に使用する引数処理を行なう内部処理部分です。スタックを介して渡された引数をデータ数は作業用メモリ(DATANO)に、バッファ・メモリのアドレスはHLレジスタに設定します。ここで設定された値を用いて以降の転送を行ないます。

;
;       ブロックアクセスでのパラメータ引取り処理
;
;
; EPROM制御関数はC(ノーマル・モード)からの関数コールに対応。
; そのため、この段階でのスタックのデータは以下のようになっている
;
;       sp  : PCの下位               :戻りアドレス下位
;       sp+1 : PCの上位               :戻りアドレス上位
;       sp+2 : Xレジスタ(第1引数)    :EEPROMアドレス(下位)
;       sp+3 : Aレジスタ(第1引数)    :EEPROMアドレス(上位)
;       sp+4 : Lレジスタ                :未使用(レジスタのセーブのみ)
;       sp+5 : Hレジスタ                :未使用(レジスタのセーブのみ)
;       sp+6 : PCの下位               :メインルーチンへの戻りアドレス下位
;       sp+7 : PCの上位               :メインルーチンへの戻りアドレス上位
;       sp+8 : 第2引数の下位           :バッファ・アドレスタ(下位バイト)
;       sp+9 : 第2引数の上位           :バッファ・アドレスタ(下位バイト)
;       sp+10: 第3引数の下位           :書き込みデータ数
;       sp+11:                          :未使用
;

GETPARA:
        MOVW    AX,SP                   ; 2つ目の引数を取り出す準備
        MOVW    HL,AX                   ; ポインタをHLに設定

        MOV     A,[HL+10]               ; データ数(ワード)の取り込み
        MOV     DATANO,A                ; ワーク領域にコピー
        MOV     A,[HL+8]                ; バッファメモリのアドレスを
        MOV     X,A
        MOV     A,[HL+9]                ; 読み出して作業用に使用するため
        MOVW    HL,AX                   ; HLレジスタにセットする
        RET

(9) ワード・データの書込み
CS信号をONし、コマンドに引き続いて、引数として渡されたEEPROMのアドレスを必要なビット数だけ転送します。その後、2バイトのデータを転送し ます。転送が完了したらCS信号をOFFし、ここからEEPROMでは実際の書込みが開始します。書込みを行っている間に他の処理ができるように、書込み 完了を待ち合わせる処理は行いません。別途、書込み完了待ちを行って下さい。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             1ワードデータの書き込み                */
;/*                                                     */
;/* <機能>                                           */
;/* ワード・データを指定されたアドレスに書き込みます。 */
;/*                                                     */
;/* <入力パラメータ(引数)>                         */
;/* AX  :第1の引数 :EEPROM内のアドレス           */
;/* SP+2,3:第2の引数 :書き込みデータ(ワード)         */
;/*                                                     */
;/* <戻り値> なし                                   */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _write_mw(int reg_adr, unsigned int data)

__write_mw:
WRITE_MW:

        CALL    !WRCMD                  ; コマンド発行

        PUSH    HL
        PUSH    AX
;
; このサブルーチンはC(ノーマル・モード)からの関数コールに対応。
; そのため、この段階でのスタックのデータは以下のようになっている
;
;       sp  : Xレジスタ(第1引数)    :EEPROMアドレス(下位)
;       sp+1 : Aレジスタ(第1引数)    :EEPROMアドレス(上位)
;       sp+2 : Lレジスタ                :未使用(レジスタのセーブのみ)
;       sp+3 : Hレジスタ                :未使用(レジスタのセーブのみ)
;       sp+4 : PCの下位               :戻りアドレス下位
;       sp+5 : PCの上位               :戻りアドレス上位
;       sp+6 : 第2引数の下位           :書き込みデータ(下位バイト)
;       sp+7 : 第2引数の上位           :書き込みデータ(下位バイト)
;

        MOVW    AX,SP                   ; 2つ目の引数を取り出す準備
        MOVW    HL,AX                   ; ポインタをHLに設定
        MOV     A,[HL+7]                ; 上位バイトを読み出す
;       MOV     X,A
        putmw                           ; 上位バイト送信
        MOV     A,[HL+6]                ; 下位バイトを読み出す
;       MOV     X,A
        putmw                           ; 下位バイト送信

        SKsignalOFF                     ; SK信号を立ち下げる
        CSsignalOFF                     ; CS信号をオフする

        POP     AX
        POP     HL
        RET

(10) ブロック・データの書込み
1ワード書き込み処理をコマンド処理から必要な回数繰り返します。このために、書込み完了待ちまでの処理を内部で行うので、使用するうえでは別途、書き込み待ちを行なう必要はありません。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*             データ(ブロック)の書き込み            */
;/*                                                     */
;/* <機能>                                           */
;/* 引数として渡されたアドレスに指定された数のデータを */
;/*書き込みを行ないます。                               */
;/*                                                     */
;/* <入力パラメータ(引数)>                         */
;/*AX    :第1の引数 :EEPROM内のアドレス          */
;/*SP+2,3: 第2の引数 :バッファ・メモリのアドレス       */
;/*SP+4,5: 第3の引数 :書き込みデータ数(ワード単位)   */
;/*                                                     */
;/* <戻り値> なし                                   */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _write_mw_block(int reg_adr, unsigned int *data, unsigned char size)

__write_mw_block:
WRITE_MWB:

        PUSH    HL
        PUSH    AX

        MOVW    ADDR,AX                 ; EEPROMアドレスを設定
;
; このサブルーチンはC(ノーマル・モード)からの関数コールに対応。
; そのため、この段階でのスタックのデータは以下のようになっている
;
;       sp  : Xレジスタ(第1引数)    :EEPROMアドレス(下位)
;       sp+1 : Aレジスタ(第1引数)    :EEPROMアドレス(上位)
;       sp+2 : Lレジスタ                :未使用(レジスタのセーブのみ)
;       sp+3 : Hレジスタ                :未使用(レジスタのセーブのみ)
;       sp+4 : PCの下位               :戻りアドレス下位
;       sp+5 : PCの上位               :戻りアドレス上位
;       sp+6 : 第2引数の下位           :バッファ・アドレスタ(下位バイト)
;       sp+7 : 第2引数の上位           :バッファ・アドレスタ(下位バイト)
;       sp+8 : 第3引数の下位           :書き込みデータ数
;       sp+9 :                          :未使用
;

        CALL    !GETPARA                ; 引数を作業領域(HL,DATANO)に

WRITELOOP:
        CALL    !WRCMD2                 ; コマンド発行

        MOV     A,[HL+1]                ; 上位データの読み出して
;       MOV     X,A
        putmw                           ; それを送信
        MOV     A,[HL]                  ; 下位データを読み出して
;       MOV     X,A
        putmw                           ; それを送信

        SKsignalOFF                     ; SK信号を立ち下げる
        CSsignalOFF                     ; CS信号をオフする

        MOVW    AX,ADDR                 ; 次アドレスに更新
        INCW    AX
        MOVW    ADDR,AX
        INCW    HL
        INCW    HL
        CALL    !WAITW;                 ; 書き込み完了を待つ
        DBNZ    DATANO,$WRITELOOP
        POP     AX
        POP     HL
        RET

(11) 書込み完了待ち
1ワード書き込み処理を用いたときに書込み完了までの待ち合わせのために使用します。

;/*-----------------------------------------------------*/
;/*                                                     */
;/*                     書き込み完了待ち                */
;/*                                                     */
;/* <機能>                                           */
;/* EEPROMへのデータ転送後、CS信号が立ち下がる */
;/*と転送されたデータが実際に書き込みがおこなわれる。   */
;/*ここでは、完了するまで待つ。                         */
;/* <入力パラメータ(引数)> なし                   */
;/* <戻り値> なし                                   */
;/*                                                     */
;/*-----------------------------------------------------*/
;void _waitwt(void)

__waitw:
WAITW:
        CSsignalON                              ; CS 信号をセット

        NOP                                     ; ステータス出力待ち
        NOP
        NOP

WAITLOOP:
        NOP
        BF      P2.1,$WAITLOOP                  ; 書き込み完了待ち

        CSsignalOFF                             ; CS 信号をリセット
        RET
他にご質問がございましたら、リクエストを送信してください