やっと! I2C経由で RTC(リアルタイムクロック)を呼び出すことができましたのでメモしときますwww

以前にraspberry Pi経由でRTCの時間設定はできていたんですが Z80で呼び出すことができない状態でした^^;

ここでのハード環境は次のようなものです。
I2C変換デバイスとして、PCA9564(Digi-Keyで購入)を使用しています。
RTCとして、RTC-8564NB(秋月電子で購入)にボタン電池を接続しています。時間設定は I2C経由で前述のようにラズベリーパイで書き込みした後、PCA9564のI2C端子に接続し直しています。ボタン電池を接続していますので、電源に接続されていなくても、RTCは動作したままです。

RTCの読み出し手順としては、マスター受信モードで、スレーブ(RTC)を指定して読みたいレジスタをライトモードで指定します。
続いて、再びスレーブ(RTC)を指定して、1バイトだけリードモードで読み出します。

実際の手順を アセンブラソースで見ていきますね。
まずは PCA9564をイニシャライズします。

i2c_init:
LD      A,0xff                  ;;Timout Register
out0    (I2CTO),a
ld      a,0x64                  ;;Own Address
out0    (I2CADR),a
ld      a,0x44                  ;;Enable Serial io
out0    (I2CCON),a
call    dely500u                ;; 500u Wite
ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
ret

続いて、ライトモードでスレーブを指定します。
Dレジスタにスレーブアドレスをセットします。
ライトモードにするために、スレーブアドレスを左に1ビットシフトするとともに、下位0ビットに0(ライトモード)をセットします。
送信した後、スレーブから ACKが帰ってくるかチェックします。

i2c_read:
ld      a,0xe4                  ;;Master Receiver Mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 STA=1
i2c_r_si01:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_r_si01
in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x08
jp      nz,i2c_r_err
in0     a,(I2CDAT)
ld      a,d                     ;set slave addres set a reg
sla     a                       ;carry flag set at write mode
;slave address + write
out0    (I2CDAT),a              ;sleve address set
ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0

i2c_r_si02:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_r_si02

in0     a,(I2CSTA)              ;;Address+W has been trasimited
cp      0x18                    ;;ACK has been received
jr      nz,i2c_r_err

続いて
EレジスタにRTCのレジスタアドレスをセットします。
スレーブに向けて、送信します。
スレーブから ACKが帰ってくるかチェックします。

ld      a,e                     ;;read slave register set
out0    (I2CDAT),a
ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
i2c_r_si04:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_r_si04

in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x28                    ;ACK has been received
jr      nz,i2c_r_err

ここで、 ストップモードにせず、続けて、送信を継続します。

ld      a,0xe4                  ;not stop signal is startting
out0    (I2CCON),a              ; AA=1 ENSIO=1 STA=1 STO=0
i2c_r_si05:
in0     a,(I2CCON)              ;SI=1 ?
bit     3,a
jr      z,i2c_r_si05

再度、スレーブを指定して、今度はリードモードにセットします。
リードモードにするために、スレーブアドレスを左に1ビットシフトするとともに、下位0ビットに1(ライトモード)をセットします。
送信した後、スレーブから ACKが帰ってくるかチェックします。

ld      a,d                     ;read  slave address d reg
scf                             ;set read mode bit0=1
RLA
out0    (I2CDAT),a              ;set slave address
ld      a,0xc4                  ;send data
out0    (I2CCON),a
i2c_r_si06:
in0     a,(I2CCON)
bit     3,a                     ;SI=1 ?
jr      z,i2c_r_si06

in0     a,(I2CSTA)              ;Address+R has been transmitted
cp      0x40                    ;ACK has been received
jr      nz,i2c_r_err

スレーブからのデータを受信します。
受信したら、続きのデータを受信しないのでマスターから,NACKをスレーブに返します。
自分自身でNACKをチェックした後、受信したデータをEレジスタに格納します。
その後、ストップモードにします。

ld      a,0x44                  ;Reset SI And AA bit
out0    (I2CCON),a              ;AA=0 ENSIO=1 STA=0 STO=0
i2c_r_si07:
in0     a,(I2CCON)
bit     3,a                     ;SI=1 ?
jr      z,i2c_r_si07

in0     a,(I2CSTA)              ;Data has been received
cp      0x58                    ;NACK has been returned
jr      nz,i2c_r_err

in0     a,(I2CDAT)              ;Received Data read a reg
ld      e,a
ld      a,0xd4                  ;Generate STOP command
out     (I2CCON),a              ;AA=1 ENSIO=1 STA=0 STO=1

i2c_stop_loop:
in0     a,(I2CCON)
bit     4,a                     ;STO=0 ?
jr      nz,i2c_stop_loop
in0     a,(I2CSTA)
cp      0xf8                    ;reset or STOP command
jr      nz,i2c_r_err
xor     a
ret

ふ~~~ 一連の手続きはこれで終わります^^

次回は、実際にRTCの内容を呼び出して、年月時分を表示したいと思います^^

おすすめの記事