やっと! 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の内容を呼び出して、年月時分を表示したいと思います^^