前回までI2CでLCDやRTCの通信ができるようになりましたが、今回I2C対応EEPROMのデータ読み書きに挑戦してみました。
TMPZ84C015とI2Cとの受け渡しは、前回より使用しているPCA9564を使用します。
I2C対応EEPROMは、micrchipの24FC256(秋月電子で購入)を使用してみました。
EEPROM(24FC256)にはスレーブアドレスを変更できるA0-A2の設定端子がありますが、今回は3端子(A0-A2)ともLレベル(GND接続)にして、A0-A2=0のスレーブアドレス設定としました。
したがって、スレーブアドレスは0x50となります。
SDA,SCL端子は4.7KΩでプルアップ(他のI2Cデバイスでプルアップされていれば必要ありません。)しています。また、WP端子はGND(L)に接続し、書き込み可としています。
今回の作成したソフトはEEPROMに対して、読み書きアドレスを指定して、1バイトの読み書きを行います。
0xa000でモニターのCコマンドでコールすると、EEPROMのアドレスを聞いてくるので、4桁の16進で入力 (ここでは0x0120) します。続いて、指定したアドレスの1バイトのデータを読み込み表示(ここでは0xff)します。変更する場合続けて変更の1バイトの16進2桁を入力(ここでは0x77)します。
>c a000 y:
eeprom addr:0120 FF 77
>c a000 y:
eeprom addr:0120 77 01
>c a000 y:
eeprom addr:0120 01 ff
>c a000 y:
eeprom addr:0120 FF
>c a000 y:
eeprom addr:0120 FF
>
一部コードの中で、モニタのサブルーチンを読んでいるので、モニタバージョンに合わせる必要があります。(下記設定ではmonitor V0.71(SPI)となっています)
以下ソースを展開します。
;;TMPZ84C015 + PCA9564 on i2c >> EEPROM (microchip 24FC256) by pinecone 2019/08/23
;; i2c-bus controller PCA9564
;;
;; TMPZ84C015 cpu
;; rom 0000h -- 7fffh
;; ram 8000h -- ffffh
;; External clock 20MHz
;;
;; i2c-bus controller PCA9564
;;
;; i/o address
;; I2CSTA i/o 0x80(r)
;; I2CTO i/o 0x80(w)
;; I2CDTA i/o 0x81(r/w)
;; I2CADR i/o 0x82(r/w)
;; I2CCON i/o 0x83(r/w)
;;
;;
;; i2c slave address
;; EEPROM i2c i/f 0x50 (A2=A1=A0:low)
;; assembler
;; program a000H
;; data program_end +
;;
;; assemblers ASxxxx and ASlink V5.10
;; file name tmpz84c015_i2c_eeprom.asm
;; $ asz80 -l -s -o itmpz84c015_i2c_eeprom.asm
;; $ aslink -i tmpz84c015_i2c_eeprom
;; $ monitor l command hex download tmpz84c015_i2c_eeprom.ihx
.z80
;; dely timing set in 100uS
D100U .equ 70 ;;clock in 20MHz set
I2CSTA .equ 0x80 ;PCA9564 setting adress
I2CTO .equ 0x80
I2CDAT .equ 0x81
I2CADR .equ 0x82
I2CCON .equ 0x83
;slave address setting
EEPROM_ADDRESS .equ 0x50 ;EEPROM i2c slave address
;monitor V0.71(SPI) call address setting
hex_a_disp .equ 0x06a7
putchar .equ 0x06f3
cr .equ 0x0156
getchar .equ 0x06ea
msgout .equ 0x06e0
input_hl .equ 0x0650
input_l .equ 0x064b
; ;monitor V0.71 call address setting
;hex_a_disp .equ 0x0318
;putchar .equ 0x0364
;cr .equ 0x014e
;getchar .equ 0x035b
;msgout .equ 0x0351
;input_hl .equ 0x02c1
;input_l .equ 0x02bc
.area TEST (ABS)
.org 0xa000
start: ;; main program
call i2c_init ;i2c init
main_loop: ;main
call eeprom_byte_read_write
ret
eeprom_byte_read_write:
ld hl,eeprom_address_msg ;eeprom address message
call msgout
call input_hl ;change eeprom memory address hl reg
cp 0x00
jr z,eeprom_r01 ;no address hex code
ld a,0x0d
call putchar
ret
eeprom_r01:
ld de,i2c_w_buff ;write buff set de reg
ld a,h ;eeprom address h -> (de), l -> (dl+1)
ld (de),a
inc de
ld a,l
ld (de),a
ld hl,i2c_w_buff ;write buff set hl reg
ld b,0x02 ;2 byte write
ld c,EEPROM_ADDRESS ;eeprom slave address
call i2c_buff_write ;i2c write
ld hl,i2c_r_buff ;read buff set hl reg
ld b,0x01 ;1 byte read
ld c,EEPROM_ADDRESS ;eeprom slave address
call i2c_buff_read ;i2c read
ld a," "
call putchar
ld hl,i2c_r_buff
ld a,(hl)
call hex_a_disp ;eeprom read 1byte display
ld a," "
call putchar
inc de
call input_l ;change eeprom memory address
cp 0x00
jr z,eeprom_w01 ;no address hex code
ld a,0x0d
call putchar
ret
eeprom_w01:
ld a,l ;write data(1byte) buff set
ld (de),a
ld hl,i2c_w_buff ;write buff set hl reg
ld b,0x03 ;3 byte write
ld c,EEPROM_ADDRESS ;eeprom slave address
call i2c_buff_write ;i2c write
ret
i2c_buff_read: ;;buff >> HL reg
;;buff size >> B reg
;;Slave Address C reg
ld a,0xe4 ;;Master Receiver Mode
out (I2CCON),a ;; AA=1 ENSIO=1 STA=1
i2c_br_si01:
in a,(I2CCON) ;; SI=1 ?
bit 3,a
jr z,i2c_br_si01
in a,(I2CSTA) ;;Poll from transmission finished
cp 0x08
jp nz,i2c_br_err
in a,(I2CDAT)
ld a,c ;read slave address d reg
scf ;set read mode bit0=1
RLA
out (I2CDAT),a ;set slave address
ld a,0xc4 ;send data
out (I2CCON),a
i2c_br_si06:
in a,(I2CCON)
bit 3,a ;SI=1 ?
jr z,i2c_br_si06
in a,(I2CSTA) ;Address+R has been transmitted
cp 0x40 ;ACK has been received
jr nz,i2c_br_err
dec b
jr z,i2c_br_next_end
i2c_br_next:
ld a,0xc4 ;Reset SI And AA bit
out (I2CCON),a ;AA=0 ENSIO=1 STA=0 STO=0
i2c_br_si07:
in a,(I2CCON)
bit 3,a ;SI=1 ?
jr z,i2c_br_si07
in a,(I2CSTA) ;Data has been received
cp 0x50 ;data-ACK has been returned
jr nz,i2c_br_err
in a,(I2CDAT) ;Received Data read a reg
ld (HL),a
inc hl
djnz i2c_br_next
i2c_br_next_end:
ld a,0x44 ;Reset SI And AA bit
out (I2CCON),a ;AA=0 ENSIO=1 STA=0 STO=0
i2c_br_si08:
in a,(I2CCON)
bit 3,a ;SI=1 ?
jr z,i2c_br_si08
in a,(I2CSTA) ;Data has been received
cp 0x58 ;data-ACK has been returned
jr nz,i2c_br_err
in a,(I2CDAT) ;Received Data read a reg
ld (HL),a
ld a,0xd4 ;Generate STOP command
out (I2CCON),a ;AA=1 ENSIO=1 STA=0 STO=1
i2c_br_stop_loop:
in a,(I2CCON)
bit 4,a ;STO=0 ?
jr nz,i2c_br_stop_loop
in a,(I2CSTA)
cp 0xf8 ;reset or STOP command
jr nz,i2c_br_err
xor a
ret
;
i2c_br_err:
ld a,0xff
ret
err:
call hex_a_disp ;; err
call cr
ld a,"E"
call putchar
ld a,"r"
call putchar
ld a,"r"
call putchar
call cr
ret
i2c_buff_write: ;;write buff data >> HL reg
;;write buff size >> B reg
;;slave address >> C reg
ld a,0xe4 ;;Slave recciver mode
out (I2CCON),a ;; AA=1 ENSIO=1 STA=1
i2c_bw_loop1:
in a,(I2CCON) ;; SI=1 ?
bit 3,a
jr z,i2c_bw_loop1
in a,(I2CSTA) ;;Poll from transmission finished
cp 0x08
jp nz,err
in a,(I2CDAT)
ld a,c ;;Slave address set
sla a
out (I2CDAT),a
ld a,0xc4 ;;Slave recciver mode
out (I2CCON),a ;; AA=1 ENSIO=1 SI=0
i2c_bw_loop2:
in a,(I2CCON) ;; SI=1 ?
bit 3,a
jr z,i2c_bw_loop2
in a,(I2CSTA) ;;Poll from transmission finished
cp 0x20 ;;Write data N-ACK
jr z,data_bw_stop ;;go to Stop mode
cp 0x18
jr nz,err
;; HL reg = buffer adress
i2c_bw_next: ;; end buffer is "00
ld a,(hl) ;; write data Areg is I2CDAT
out (I2CDAT),a
ld a,0xc4 ;;Slave recciver mode
out (I2CCON),a ;; AA=1 ENSIO=1 SI=0
i2c_bw_loop3:
in a,(I2CCON) ;; SI=1 ?
bit 3,a
jr z,i2c_bw_loop3
in a,(I2CSTA) ;;Poll from transmission finished
cp 0x28
jr nz,err
inc hl
djnz i2c_bw_next
data_bw_stop:
ld a,0xD4 ;;Generate STOP mode
out (I2CCON),a ;; AA=1 ENSIO=1 SI=0
D_bW_ST0:
in a,(I2CCON) ;; STO=0 ?
bit 4,a
jr nz,D_bW_ST0
in a,(I2CSTA)
cp 0xf8
jr nz,err
ret
i2c_init:
LD A,0xff ;;Timout Register
out (I2CTO),a
ld a,0x64 ;;Own Address
out (I2CADR),a
ld a,0x44 ;;Enable Serial io
out (I2CCON),a
call dely500u ;; 500u Wite
; ld a,0xc4 ;;Slave recciver mode
; out (I2CCON),a ;; AA=1 ENSIO=1 SI=0
ret
delym: ;; B reg set *1mS dely
push bc
delyml: call dely1m
djnz delyml
pop bc
ret
dely1m: ;; 1mS dely
push bc
call dely500u
call dely500u
pop bc
ret
dely500u: ;; 500uS dely
push bc
ld b,5
dd5: call dely100u
djnz dd5
pop bc
ret
dely100u: ;; 100uS dely
push bc
ld b,D100U
l100u: djnz l100u
pop bc
ret
;; data
eeprom_address_msg:
.str "eeprom addr:"
.db 0x00
.org 0xff00
i2c_r_buff:
.ds 0x03
i2c_w_buff:
.ds 0x03
.end