====== EEPROM(Microwire)を繋ぐ ====== ===== EEPROM(Microwire)について ===== シリアルEEPROMは、8ピン程度のパッケージで、信号線も3、4本で接続できるROMです。\\ 容量は小さいので、初期値の保存や、MACアドレスの保存とかに使われます。\\ シリアルEEPROMの通信方式には3種類(Microwire、I2C、SPI)あり、今回はMicrowireを使います。 ^ メーカー ^ 型番 ^ メモリ容量 ^ プロテクト ^ 8Bit/ 16Bit ^ | アトメル(Atmel) | AT93C46 | 1KBit | ○ | ○/○ | |::: | AT93C56 | 2KBit | ○ | ○/○ | |::: | AT93C66 | 4KBit | ○ | ○/○ | ===== 回路図 ===== 今回は4線接続します。ORG端子をVCCにすると16Bitモード、GNDにすると8Bitモードになります。\\ CSは、起動時に誤動作しないように10KΩの抵抗でプルダウンしておきます。\\ {{microwire00.gif}}\\ ===== アクセスタイミング ===== アクセスタイミングはデータブックを見ながら調べていきます。\\ \\ 例えばCS(チップセレクト)をHighにしてから、SK(クロック)を出し始めるタイミングは、tCSS時間で\\ データブックを見ると50nsと書いてあります。\\ \\ 次にSK(クロック)のタイミングはtSKH、sSKLで250nsと書いてあります。\\ しかし下図を見ると1us必要とも書いてあります。よってH 500ns、L 500nsでクロックを出す事にします。\\ \\ 次にデータがいつ確定するかを見てみます。\\ \\ DI(データIN。H8側ではデータOUT)は、SKの立ち上がり(LowからHighに変化)時に確定されるようです。\\ プログラムを書く場合、まずデータをセットしてから、SKをHighにすることになります。\\ \\ DO(データOUT。H8側ではデータIN)は、SKの立ち下り(HighからLowに変化)時に確定されてます。\\ プログラムを書く場合、SKをHigh、Lowと変化させ、その後読み出せばよいことになります。\\ {{microwire01.jpg}}\\ 次にデータの読み出し方法を調べてみましょう。\\ DIに110、AN…A0を送ると、DOに0、DN…D0が帰ってくる。\\ \\ データブックを見ると 110はスタートビット(1)とREADコマンド(10)です。\\ \\ AN…A0は、アドレスでAT93C46の8BitモードならA6~A0、16BitならA5~A0のアドレスで、\\ 上位ビットから送ります。\\ \\ DN…D0は読み出したデータで、8Bit モードならD7~D0、16Bitなら D15~D0と、\\ これも上位ビットから送られてきます。\\ \\ DOの最初の0は、A0を送った時のSKの立下りで出力されますが、データ取得は次のSKで読み取るので\\ 無視します。\\ {{microwire02.jpg}}\\ ===== プログラムの作成 ===== ==== 設定の定義 ==== あとで結線を変えても良い用に、全て EQU で定義しておく。 MICROWIRE_PORT EQU PB MICROWIRE_DR EQU PBDR MICROWIRE_CS EQU 0 MICROWIRE_SK EQU 1 MICROWIRE_DO EQU 2 MICROWIRE_DI EQU 3 MICROWIRE_MASK EQU ((1 << MICROWIRE_CS) | (1 << MICROWIRE_SK) | (1 << MICROWIRE_DO)) ==== 初期化処理 ==== 数種のEEPROMに対応できるようにアドレスとデータのBit数を指定できるようにする。\\ 本来ポートのディレクションは別の場所でやるべき。\\ ディレクションは読み出せないので、PB-4~PB-7の方向まで変わってしまいます。\\ ;****************************************************************************** ; EEPROM の初期化(Microwire) ; ; _MicrowireInit ; 2004/12/20 : 初期バージョン完成 ; ; [書式] void MicrowireInit(Uint8 addr,Uint8 data) ; ; ; [IN] Uint8 addr = アドレスの bit 数 ; Uint8 data = データの bit 数 ; ; [OUT] なし ; ; [DED] R0 ;****************************************************************************** public _MicrowireInit _MicrowireInit: MOV.B @(5,ER7),R0H ; R0H = addr MOV.B @(7,ER7),R0L ; R0L = data MOV.W R0,@ADDR_BITS MOV.B @MICROWIRE_PORT,R0L ; 信号線のクリア AND.B #~MICROWIRE_MASK,R0L MOV.B R0L,@MICROWIRE_PORT MOV.B #MICROWIRE_MASK,R0L ; ポートのディレクション設定 MOV.B R0L,@MICROWIRE_DR RTS ==== ワークの作成 ==== アドレスとデータのBit数 保存用のワークを、初期化されないRAMセグメント(BSS)に作ります。 ;****************************************************************************** ; RAM 上のデータ(初期化なし) ;****************************************************************************** SEGMENT BSS ADDR_BITS: DS.B 1 DATA_BITS: DS.B 1 ==== ウェイト処理 ==== 次にクロックを刻むための500nsのウェイトルーチンを作ります。\\ サブルーチンの呼び出しと、戻り処理だけで500nsを超えてしまう。 ;****************************************************************************** ; 500ns Wait(どのモードでも 14 * 40 = 560ns 以上になる) ; ; WAIT500ns ; 2004/12/17 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] なし ; ; [DED] なし ;****************************************************************************** ; 6 BSR WAIT500ns: RTS ; 8 ==== クロック作成 ==== クロックを刻むルーチンを作ります。SK High→500ns→Wait SK Low→500ns Wait。\\ 近いサブルーチンの呼び出しは、ラベルの後ろに:8を付けコードと実行ステートを小さくします。\\ (なぜか自動で最適化されません) ;****************************************************************************** ; クロックの作成 ; ; MAKE_CLOCK ; 2004/12/20 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] なし ; ; [DED] なし ;****************************************************************************** ; SK High MAKE_CLOCK: BSET.B #MICROWIRE_SK,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait ; SK Low BCLR.B #MICROWIRE_SK,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait RTS ==== 受信処理 ==== 次に送信より簡単な受信ルーチンを作ります。8Bit/16Bitに対応させるためE0で受け、最後にR0に移します。\\ (なるべく少ないレジスタで作りたかったためです)\\ クロックを作成、1Bit取得を8or16回繰り返すだけです。 ;****************************************************************************** ; n Byte 受信 ; ; BYTE_RECV ; 2004/12/17 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] R0 = 受信データ(1 Byte 受信なら R0L) ; ; [DED] E0 ;****************************************************************************** BYTE_RECV: MOV.B @DATA_BITS,R0L ; 8 or 16 BYTE_RECV_LOOP: BSR MAKE_CLOCK:8 ; クロックの作成 BLD #MICROWIRE_DI,@MICROWIRE_PORT ROTXL.W E0 DEC.B R0L BNE BYTE_RECV_LOOP:8 MOV.W E0,R0 RTS ==== 送信処理 ==== 今度は送信ルーチンです。MSBから送るためMSBの頭だしルーチンが必要となります。\\ データを送る場合は頭だしが不要なので、もう一つの関数の入り口としてBIT_SEND_MSBがあります。\\ 受信とクロックを出すタイミングが違います。 ;****************************************************************************** ; n Bit 送信 ; ; BIT_SEND、BIT_SEND_MSB ; 2004/12/17 : 初期バージョン完成 ; ; [IN] E0 = 送信データ ; R0L = Bit 数 ; ; [OUT] なし ; ; [DED] R0 ;****************************************************************************** BIT_SEND: MOV.B #16,R0H ; 最上位 Bit の頭だし SUB.B R0L,R0H BIT_SHIFT_MSB: ROTL.W E0 DEC.B R0H BNE BIT_SHIFT_MSB:8 BIT_SEND_MSB: ROTL.W E0 ; 1 Bit 送信 BST.B #MICROWIRE_DO,@MICROWIRE_PORT BSR MAKE_CLOCK:8 ; クロックの作成 DEC.B R0L BNE BIT_SEND_MSB:8 RTS ==== 読み出し処理 ==== これで必要なサブルーチンは全てできたので、読み出しルーチンを作ってみます。\\ まずC言語の引数を受け取り、その後CSをHighにし、リードコマンド(110)とアドレス(An~A0)送信。\\ データ受信し、16Bitの場合は2Byte保存。これをサイズ分繰り返し、最後にCSをLowにして終了です。 ;****************************************************************************** ; EEPROM の読み出し(Microwire) ; ; _MicrowireRead ; 2004/12/17 : 初期バージョン完成 ; ; [書式] BOOL MicrowireRead(int addr,void *buff,int size) ; ; ; [IN] int addr = 読み出し開始アドレス ; void *data = 読み込みバッファ ; int size = 読み出しサイズ ; ; [OUT] なし ; ; [DED] ER0,ER1,ER2 ;****************************************************************************** public _MicrowireRead _MicrowireRead: MOV.W @( 4,ER7),R1 ; R1 = addr MOV.L @( 6,ER7),ER2 ; ER2 = *buff MOV.W @(10,ER7),E1 ; E1 = size ; CS High LOOP_READ: BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #110B,E0 ; READ 110 MOV.B #3,R0L BSR BIT_SEND MOV.W R1,E0 ; Address An-A0 INC.W #1,R1 ; Address ++ MOV.B @ADDR_BITS,R0L BSR BIT_SEND BSR BYTE_RECV ; n Byte 受信 MOV.B R0L,@ER2 INC.L #1,ER2 MOV.B @DATA_BITS,R0L ; 16Bit モードかチェック CMP.B #8,R0L BEQ READ_NEXT:8 MOV.B R0H,@ER2 INC.L #1,ER2 ; CS Low READ_NEXT: BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns ; 500ns Wait DEC.W #1,E1 BNE LOOP_READ RTS ==== 書き込み処理 ==== 書き込みも読み出しと大して変わりません。\\ まずC言語の引数を受け取り、その後CSをHighにし、ライトコマンド(101)、アドレス(An~A0)送信。 16Bitの場合は2Byte、8Bitなら1Byteデータを送信し、10ms書き込を待ちます。\\ これをサイズ分繰り返し、最後にCSをLowにして終了です。\\ \\ 書き込みをReadyではなくウェイトで待っている理由は、EEPROMが未接続の場合Readyが帰って\\ こないで永久ループに陥るためです。正しく書けているかは、ベリファイすれば良いのだし。 ;****************************************************************************** ; EEPROM の書き込み(Microwire) ; ; _MicrowireWrite ; 2004/12/17 : 初期バージョン完成 ; ; [書式] BOOL MicrowireWrite(int addr,void *data,int size) ; ; ; [IN] int addr = 読み出し開始アドレス ; void *buff = 読み込みバッファ ; int size = 読み出しサイズ ; ; [OUT] なし ; ; [DED] ER0,ER1,ER2 ;****************************************************************************** public _MicrowireWrite _MicrowireWrite:MOV.W @( 4,ER7),R1 ; R1 = addr MOV.L @( 6,ER7),ER2 ; ER2 = *buff MOV.W @(10,ER7),E1 ; E1 = size ; CS High LOOP_WRITE: BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #101B,E0 ; WRITE 101 MOV.B #3,R0L BSR BIT_SEND:8 MOV.W R1,E0 ; Address An-A0 INC.W #1,R1 ; Address ++ MOV.B @ADDR_BITS,R0L BSR BIT_SEND:8 MOV.B @ER2+,R0H ; Data の最初の 8 Bit MOV.W R0,E0 MOV.B @DATA_BITS,R0L ; 16Bit モードかチェック CMP.B #8,R0L BEQ DATA_SEND:8 MOV.B R0H,R0L ; Data の残りの 8 Bit MOV.B @ER2+,R0H MOV.W R0,E0 MOV.B #16,R0L DATA_SEND: BSR BIT_SEND_MSB:8 ; n Bit 送信 ; CS Low BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait MOV.W #10,E0 ; 10ms Wait BSR WAIT_1ms DEC.W #1,E1 BNE LOOP_WRITE RTS ==== ライトプロテクトのON/OFF処理 ==== 最後にライトプロテクトのON/OFF処理です。\\ コマンドは両方とも100なので、アドレスの上位2BitにON(00)かOFF(11)を出力して切り替えます。\\ 冒頭の処理は以下のようなことをしてます。\\ ^ ^ OFF(FALSE)の場合 ^ ON(TRUE) の場合 ^ |MOV.W @(4,ER7),E1|E1 = 0000000000000000B|E1 = 0000000000000001B| |DEC.W #1,E1 |E1 = 1111111111111111B|E1 = 0000000000000000B| ;****************************************************************************** ; EEPROM のプロテクト(Microwire) ; ; _MicrowireProtect ; 2004/12/20 : 初期バージョン完成 ; ; [書式] void MicrowireProtect(BOOL flag) ; ; ; [IN] flag = TRUE プロテクト ON ; = FALSE プロテクト OFF ; ; [OUT] なし ; ; [DED] ER0,E1 ;****************************************************************************** public _MicrowireProtect _MicrowireProtect: MOV.W @(4,ER7),E1 ; E1 = flag(0 or 1) DEC.W #1,E1 ; CS High BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #100B,E0 ; EWEN,EWDS 100 MOV.B #3,R0L BSR BIT_SEND:8 MOV.W E1,E0 ; Address An-A0 MOV.B @ADDR_BITS,R0L BSR BIT_SEND_MSB:8 ; CS Low BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait RTS ==== 全ソース ==== まとめるとこんな感じになります。 ;****************************************************************************** ; EEPROM 処理(Microwire) ; (C)YdlProg ;****************************************************************************** INCLUDE (../lib3052/3052.inc) MICROWIRE_PORT EQU PB MICROWIRE_DR EQU PBDR MICROWIRE_CS EQU 0 MICROWIRE_SK EQU 1 MICROWIRE_DO EQU 2 MICROWIRE_DI EQU 3 MICROWIRE_MASK EQU ((1 << MICROWIRE_CS) | (1 << MICROWIRE_SK) | (1 << MICROWIRE_DO)) segment TEXT ;****************************************************************************** ; EEPROM の初期化(Microwire) ; ; _MicrowireInit ; 2004/12/20 : 初期バージョン完成 ; ; [書式] void MicrowireInit(Uint8 addr,Uint8 data) ; ; ; [IN] Uint8 addr = アドレスの bit 数 ; Uint8 data = データの bit 数 ; ; [OUT] なし ; ; [DED] R0 ;****************************************************************************** public _MicrowireInit _MicrowireInit: MOV.B @(5,ER7),R0H ; R0H = addr MOV.B @(7,ER7),R0L ; R0L = data MOV.W R0,@ADDR_BITS MOV.B #MICROWIRE_MASK,R0L ; ポートのディレクション設定 MOV.B R0L,@MICROWIRE_DR MOV.B @MICROWIRE_PORT,R0L ; 信号線のクリア AND.B #~MICROWIRE_MASK,R0L MOV.B R0L,@MICROWIRE_PORT RTS ;****************************************************************************** ; EEPROM の読み出し(Microwire) ; ; _MicrowireRead ; 2004/12/17 : 初期バージョン完成 ; ; [書式] BOOL MicrowireRead(int addr,void *buff,int size) ; ; ; [IN] int addr = 読み出し開始アドレス ; void *data = 読み込みバッファ ; int size = 読み出しサイズ ; ; [OUT] なし ; ; [DED] ER0,ER1,ER2 ;****************************************************************************** public _MicrowireRead _MicrowireRead: MOV.W @( 4,ER7),R1 ; R1 = addr MOV.L @( 6,ER7),ER2 ; ER2 = *buff MOV.W @(10,ER7),E1 ; E1 = size ; CS High LOOP_READ: BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #110B,E0 ; READ 110 MOV.B #3,R0L BSR BIT_SEND MOV.W R1,E0 ; Address An-A0 INC.W #1,R1 ; Address ++ MOV.B @ADDR_BITS,R0L BSR BIT_SEND BSR BYTE_RECV ; n Byte 受信 MOV.B R0L,@ER2 INC.L #1,ER2 MOV.B @DATA_BITS,R0L ; 16Bit モードかチェック CMP.B #8,R0L BEQ READ_NEXT:8 MOV.B R0H,@ER2 INC.L #1,ER2 ; CS Low READ_NEXT: BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns ; 500ns Wait DEC.W #1,E1 BNE LOOP_READ RTS ;****************************************************************************** ; EEPROM の書き込み(Microwire) ; ; _MicrowireWrite ; 2004/12/17 : 初期バージョン完成 ; ; [書式] BOOL MicrowireWrite(int addr,void *data,int size) ; ; ; [IN] int addr = 読み出し開始アドレス ; void *buff = 読み込みバッファ ; int size = 読み出しサイズ ; ; [OUT] なし ; ; [DED] ER0,ER1,ER2 ;****************************************************************************** public _MicrowireWrite _MicrowireWrite:MOV.W @( 4,ER7),R1 ; R1 = addr MOV.L @( 6,ER7),ER2 ; ER2 = *buff MOV.W @(10,ER7),E1 ; E1 = size ; CS High LOOP_WRITE: BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #101B,E0 ; WRITE 101 MOV.B #3,R0L BSR BIT_SEND:8 MOV.W R1,E0 ; Address An-A0 INC.W #1,R1 ; Address ++ MOV.B @ADDR_BITS,R0L BSR BIT_SEND:8 MOV.B @ER2+,R0H ; Data の最初の 8 Bit MOV.W R0,E0 MOV.B @DATA_BITS,R0L ; 16Bit モードかチェック CMP.B #8,R0L BEQ DATA_SEND:8 MOV.B R0H,R0L ; Data の残りの 8 Bit MOV.B @ER2+,R0H MOV.W R0,E0 MOV.B #16,R0L DATA_SEND: BSR BIT_SEND_MSB:8 ; n Bit 送信 ; CS Low BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait MOV.W #10,E0 ; 10ms Wait BSR WAIT_1ms DEC.W #1,E1 BNE LOOP_WRITE RTS ;****************************************************************************** ; EEPROM のプロテクト(Microwire) ; ; _MicrowireProtect ; 2004/12/20 : 初期バージョン完成 ; ; [書式] void MicrowireProtect(BOOL flag) ; ; ; [IN] flag = TRUE プロテクト ON ; = FALSE プロテクト OFF ; ; [OUT] なし ; ; [DED] ER0,E1 ;****************************************************************************** public _MicrowireProtect _MicrowireProtect: MOV.W @(4,ER7),E1 ; E1 = flag(0 or 1) DEC.W #1,E1 ; CS High BSET.B #MICROWIRE_CS,@MICROWIRE_PORT NOP ; 80ns MOV.W #100B,E0 ; EWEN,EWDS 100 MOV.B #3,R0L BSR BIT_SEND:8 MOV.W E1,E0 ; Address An-A0 MOV.B @ADDR_BITS,R0L BSR BIT_SEND_MSB:8 ; CS Low BCLR.B #MICROWIRE_CS,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait RTS ;****************************************************************************** ; n Bit 送信 ; ; BIT_SEND、BIT_SEND_MSB ; 2004/12/17 : 初期バージョン完成 ; ; [IN] E0 = 送信データ ; R0L = Bit 数 ; ; [OUT] なし ; ; [DED] R0 ;****************************************************************************** BIT_SEND: MOV.B #16,R0H ; 最上位 Bit の頭だし SUB.B R0L,R0H BIT_SHIFT_MSB: ROTL.W E0 DEC.B R0H BNE BIT_SHIFT_MSB:8 BIT_SEND_MSB: ROTL.W E0 ; 1 Bit 送信 BST.B #MICROWIRE_DO,@MICROWIRE_PORT BSR MAKE_CLOCK:8 ; クロックの作成 DEC.B R0L BNE BIT_SEND_MSB:8 RTS ;****************************************************************************** ; n Byte 受信 ; ; BYTE_RECV ; 2004/12/17 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] R0 = 受信データ(1 Byte 受信なら R0L) ; ; [DED] E0 ;****************************************************************************** BYTE_RECV: MOV.B @DATA_BITS,R0L ; 8 or 16 BYTE_RECV_LOOP: BSR MAKE_CLOCK:8 ; クロックの作成 BLD #MICROWIRE_DI,@MICROWIRE_PORT ROTXL.W E0 DEC.B R0L BNE BYTE_RECV_LOOP:8 MOV.W E0,R0 RTS ;****************************************************************************** ; クロックの作成 ; ; MAKE_CLOCK ; 2004/12/20 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] なし ; ; [DED] なし ;****************************************************************************** ; SK High MAKE_CLOCK: BSET.B #MICROWIRE_SK,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait ; SK Low BCLR.B #MICROWIRE_SK,@MICROWIRE_PORT BSR WAIT500ns:8 ; 500ns Wait RTS ;****************************************************************************** ; 500ns Wait(どのモードでも 14 * 40 = 560ns 以上になる) ; ; WAIT500ns ; 2004/12/17 : 初期バージョン完成 ; ; [IN] なし ; ; [OUT] なし ; ; [DED] なし ;****************************************************************************** ; 6 BSR WAIT500ns: RTS ; 8 ;****************************************************************************** ; RAM 上のデータ(初期化なし) ;****************************************************************************** SEGMENT BSS ADDR_BITS: DS.B 1 DATA_BITS: DS.B 1 END ==== 呼び出し方 ==== Cからの呼び出しは以下のように行います。AT93C46しかチェックしていません。 #include #include "../lib3052/typedef.h" #define AT93C46_8BIT 7, 8 // Atmel AT93C46(1K) 8Bit #define AT93C46_16BIT 6,16 // Atmel AT93C46(1K) 16Bit #define AT93C56_8BIT 9, 8 // Atmel AT93C56(2K) 8Bit #define AT93C56_16BIT 8,16 // Atmel AT93C56(2K) 16Bit #define AT93C66_8BIT 9, 8 // Atmel AT93C66(4K) 8Bit #define AT93C66_16BIT 8,16 // Atmel AT93C66(4K) 16Bit // EEPROM の初期化(Microwire) extern void MicrowireInit(Uint8 addr,Uint8 data) ; // EEPROM の読み出し(Microwire) extern void MicrowireRead(int addr,void *buff,int size) ; // EEPROM の書き込み(Microwire) extern void MicrowireWrite(int addr,void *buff,int size) ; extern void MicrowireProtect(BOOL flag) ; // EEPROM のプロテクト(Microwire) void main(void) { Uint8 buff[128] ; int i ; for(i = 0 ; i < 128 ; i ++) buff[i] = i ; MicrowireInit(AT93C46_16BIT) ; // EEPROM の初期化 MicrowireProtect(FALSE) ; // EEPROM のプロテクト OFF MicrowireWrite(0,buff,64) ; // EEPROM の書き込み MicrowireProtect(TRUE) ; // EEPROM のプロテクト ON MicrowireRead(0,buff,64) ; // EEPROM の読み出し /* MicrowireInit(AT93C46_8BIT) ; // EEPROM の初期化 MicrowireProtect(FALSE) ; // EEPROM のプロテクト OFF MicrowireWrite(0,buff,128) ; // EEPROM の書き込み MicrowireProtect(TRUE) ; // EEPROM のプロテクト ON MicrowireRead(0,buff,128) ; // EEPROM の読み出し */ }