Renesas Synergy™

FAQ 1006553 : 78K0/Kx2のCSIによるマイクロワイヤ・EEPROMの制御プログラム例(78K0/Kx2)

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



[78K0/Kx2の処理例]
78K0/Kx2でのEEPROMの制御処理は以下の部分から構成します。マイクロワイヤ方式では、それほどのスピードは要求されないことから、制御プログラムは全てC言語で記述します。制御関数は引数として、読み出しや書き込みでは以下のパラメータを用います。例えば、1ワード・データの読み出しでは第1引数で読み出すアドレスを指定します。1ワード・データの書き込みでは第1引数で書き込むアドレスを指定し、第2引数で書き込みデータを指定します。第3引数まで使用するのはブロック単位での読み書きの場合です。

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

(1)初期化部
ポート、CSI10、割り込みの初期化を行ないます。ここでは2.7VPOCを使用することで、リセット解除後にはそのまま動作させます。基本的にベクタ割り込みは使用しないので、割り込みは禁止状態のままとします。

(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ワードのデータを読み出し、戻り値で返します。

(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) バイトデータ受信
CSI10を使って実際にEEPROMからバイトデータを受信します。(これは内部で使うだけです。)

(11) バイトデータ送信
CSI10を使ってEEPROMにコマンドやアドレス、バイトデータを送信します。(これは内部で使うだけです。)


[C言語でのプログラム例]
ここではC言語でプログラムを作成した場合のプログラム例を示します。

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

#pragma SFR
#pragma NOP

bit selrom(unsigned char leng); // アドレス長設定
void putmw(unsigned char data); // 1文字送信
unsigned char getmw(void); // 1文字受信
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 P1.3 // CS信号の定義

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

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

(1) 初期化部
使用するポート及びCSIの初期化を行なう部分をhdwinit関数として記述した例を以下に示します。実際の通信を行なうときにCSIM10のビット7(CSIE10)をセットしてください。

Void    hdwinit(void)
{
P1 = 0b11110011; // 出力ラッチの設定
PM1 = 0b00000010; // SI10/P11以外は出力に
CSIC10 = 0b00011101; //
// |||||+++--------: シリアルクロックはfPRS/64
// |||++-----------: タイプ4
// +++-------------: 0に固定
CSIM10 = 0b01000000; // MSBファースト、送受信モード
// ||+|++++--------; 0に固定
// || +------------; MSBファースト
// |+--------------; 送受信モード
// +---------------; 動作禁止
}

(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し、スタート・ビット~アドレスを送信したら一旦CSIを停止します。動作モードをモード3に変更して再起動します。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);

CSIE10 = 0; // CSIを動作停止
CSIC10.3 = 0; // モード3を選択
CSIE10 = 1; // CSI動作許可
work = getmw(); // 上位データの読み込み
work = work << 8; // 上位にシフト
work |= getmw() ; // 下位データの読み出し

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

CSIE10 = 0; // CSIを動作停止
CSIC10.3 = 1; // モード4を選択
CSIE10 = 1; // CSI動作許可

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);

CSIE10 = 0; // CSIを動作停止
CSIC10.3 = 0; // モード3を選択
CSIE10 = 1; // CSI動作許可

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

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

CSIE10 = 0; // CSIを動作停止
CSIC10.3 = 1; // モード4を選択
CSIE10 = 1; // CSI動作許可
}

(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(P1.1 == 0); // 書き込み完了待ち
Cssignal = 0; // CS 信号をリセット
}

(10)バイトデータ受信
CSI10を直接制御してバイトデータの受信処理を行ないます。受信完了は割り込みフラグをポーリングします。割り込みフラグがセットされたことを確認したらフラグをクリアし、受信データを読み出して戻ります。

unsigned char   getmw(void)
{
unsigned char work;
SOTB10 = 0x00; // 受信のためのダミー・データ送信
while(CSIIF10 == 0){ // 転送完了待ち
NOP();
}
CSIIF10 = 0; // 転送完了割り込みをクリア
work = SIO10; // 受信データの読み出し
return work;
}

(11) バイトデータ送信
CSI10を直接制御してバイトデータの送信処理を行ないます。送信完了は割り込みフラグをポーリングします。割り込みフラグがセットされたことを確認したらフラグをクリアして戻ります。

void    putmw(unsigned char data)
{
SOTB10 = data; // データをシリアルで送信
while(CSIIF10 == 0){ // 転送完了待ち
NOP();
}
CSIIF10 = 0; // 転送完了割り込みをクリア
}


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

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

#pragma SFR
extern bit selrom(unsigned char spi_adr); // 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[16];              // read buffer
unsigned int eep_read_buf2[16]; // read buffer
unsigned int eep_read_buf3[16]; // read buffer
unsigned int eep_write_buf[16]; // write buffer
typedef unsigned int data4[4];
const data4 txdata1 = {0x1234,0x5678,0x9ABC,0xDEF0};
const data4 txdata2 = {0x55AA,0x33CC,0xf00f,0xff00};

(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, 8); // ブロックデータリード
// 第1引数でEEPROMアドレス(0xcc)を指定、
// 第2引数でリードバッファ・メモリのアドレス(eep_read_buf1)を指定
// 第3引数でデータ数(8ワード)を指定
}

(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); // ブロック書き込み
}
他にご質問がございましたら、リクエストを送信してください