前回のブログでI2Cでの読み出しのルーチンができたので実際に、RTCと接続して、年月と時刻を呼び出してみます。

Z8S180とPCA9564との接続は過去プログのこちらの回路となっています。

PCA9564のレジスタはI/O空間の0x80~0x83に配置されます。
注意点として、PCA9564は3.3V動作なので、3.3Vレギュレターで5Vから3.3Vを得ています。
データバス等は5Vトレラントなので、Z8S180にそのまま接続できます。

今回のRTC(RTC-8564NB)の読み方として、16個のレジスタを1度にバッファに読み込み、その後、必要なレジスタをバッファから選択して、表示する方法としました。バッファはプログラムの最後尾に設けていますのでとりあえずは、RAM領域でプログラムを実行します。ここでは開始アドレスをRAM領域である0xa000に設定しました。

まずは、レジスタの定義と呼び出したデータを表示のために、モニターのサブルーチンをコールしているので、そのアドレスの定義を行います。

I2CSTA  .equ    0x80    ;PCA9564 setting adress
I2CTO   .equ    0x80
I2CDAT  .equ    0x81
I2CADR  .equ    0x82
I2CCON  .equ    0x83

putchar         .equ    0x07fe
disp_a_hex      .equ    0x07b1
cr              .equ    0x016d

プログラムの最初で PCA9564のイニシャライズとスレーブアドレス(RTC 0x51)の設定を行います。
続いて、バッファアドレスの設定とカウンター値(レジスターアドレス指定と兼用)の初期設定を行います。
カウンターは0x00から0x0fまで16カウントし、その値がレジスターアドレスとなります。

開始アドレス    0xa000
スレーブアドレス  0x51
バッファアドレス  rtc_buff(プログラム最後尾に設定)
カウンター初期値  0x00

.area   TEST (ABS)

.org    0xa000

start:  nop     nop
call    i2c_init                ;i2c init
ld      d,0x51                  ;i2c slave address set d reg
ld      b,0x00
ld      hl,rtc_buff             ;i2c receive data in buff set

カウントのループ内で、レジスターの内容を呼び出していきます。
ループ内のカウンタ
Bレジスタ ループカウント値 0x00~0x0f
HLレジスタ バッファアドレス 

呼び出しサブルーチン i2c_readは次の値を設定し、呼び出した後、戻り値をチェックします。
Dレジスタ スレーブアドレス 0x51    (プログラムの最初で設定済み)
Eレジスタ レジスタアドレス 0x00~0x0f 戻り値に指定したレジスタアドレスの読み出した値が入ります。
Aレジスタ 戻り値 正常終了 0x00 エラー時0xff 

loop:                                   ;rtc 8564 read register 0x00 to 0x0f
ld      e,b                     ;i2c slave register set e reg
call    i2c_read                ;i2c slave receive call
cp      0xff                    ;a reg 0xff receive err
jr      z,i2c_err_disp
ld      (hl),e                  ;i2c slave data in e reg
inc     hl
inc     b
ld      a,b
cp      0x10                    ;end rtc 8564 register
jr      nz,loop

バッファに対して、必要な位置を指定し、表示に必要なビットをマスクしてから、サブルーチンbcd2を呼び出して、BCD形式を数字2文字に変換して表示させます。

call    cr
ld      a,0x20                  ;Years 20 set
call    bcd2
ld      a,(rtc_buff+0x08)       ;Years ?? i2c read data set
call    bcd2
ld      a,"/"
call    putchar
ld      a,(rtc_buff+0x07)       ;Months ?? i2c read data set
and     0x1f
call    bcd2
ld      a,"/"
call    putchar
ld      a,(rtc_buff+0x05)       ;Days ?? i2c read data set
and     0x3f
call    bcd2
ld      a," "
call    putchar
ld      a,(rtc_buff+0x04)       ;Hours  ?? i2c  read data set
and     0x3f
call    bcd2
ld      a,":"
call    putchar
ld      a,(rtc_buff+0x03)       ;Minutes ?? i2c read data set
and     0x7f
call    bcd2
ld      a,":"
call    putchar
ld      a,(rtc_buff+0x02)       ;Seconds ?? i2c read data set
and     0x7f
call    bcd2
call    cr
ret

サブルーチンbcd2では、BCDの上位4ビットを右4ビットシフトし、マスクしたのち、0x30をORすることにより数字文字に変換して1文字表示します。BCD下位4ビットはシフトせず、以下同様に処理していきます。

bcd2:                                   ;bcd to putchar
push    af                      ; up bcd (7:4)
rlca
rlca
rlca
rlca
and     0x0f
or      0x30
call    putchar                 ;putchar up data
pop     af
and     0x0f                    ;down data (3:0)
or      0x30
call    putchar                 ;putchar down data
ret

実際に実行してみました^^
モニタのバージョンは 0.73です(表示のため、モニタ内部のサブルーチンを読んでいますのでモニタのバージョンが違うと、サブルーチンのアドレスが変わりますので注意してください)

モニタのlコマンドでアセンブルしたHEXコードを呼び込みます。
モニタのCコマンド(call)で実行します。

>c a000 Yes:

2018/09/23 14:54:38
>c a000 Yes:

2018/09/23 14:55:12
>

ちゃんと表示できたようですwww

まとめのソースファイルは次の通りです。

;; z8S180 i/o port on i2c >> i2c RTC  (RTC-8564NB)
;;
;; Z8S180 cpu
;; rom 0000h -- 7fffh
;; ram 8000h -- ffffh
;; External clock 16MHz
;;
;; 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)
;;
;;
;; assembler
;;  program A000H
;;  data    A000H
;;
;; assemblers  ASxxxx and ASlink V5.10
;; file name rtc07.asm
;; $ asz80 -l -s -o rtc07.asm
;; $ aslink -i rtc07
;; $ monitor l command hex(rtc07.ihx) read

.z180

;; dely timing set in 100uS
D100U   .equ    65      ;;clock in 16MHz set
;D100U  .equ    26      ;;clock in 8MHz set
;D100U  .equ    138     ;;clock in 32MHz set

I2CSTA  .equ    0x80    ;PCA9564 setting adress
I2CTO   .equ    0x80
I2CDAT  .equ    0x81
I2CADR  .equ    0x82
I2CCON  .equ    0x83

putchar         .equ    0x07fe
disp_a_hex      .equ    0x07b1
cr              .equ    0x016d

.area   TEST (ABS)

.org    0xa000

start:  nop     nop
call    i2c_init                ;i2c init
ld      d,0x51                  ;i2c slave address set d reg
ld      b,0x00
ld      hl,rtc_buff             ;i2c receive data in buff set
loop:                                   ;rtc 8564 read register 0x00 to 0x0f
ld      e,b                     ;i2c slave register set e reg
call    i2c_read                ;i2c slave receive call
cp      0xff                    ;a reg 0xff receive err
jr      z,i2c_err_disp
ld      (hl),e                  ;i2c slave data in e reg
inc     hl
inc     b
ld      a,b
cp      0x10                    ;end rtc 8564 register
jr      nz,loop

call    cr
ld      a,0x20                  ;Years 20 set
call    bcd2
ld      a,(rtc_buff+0x08)       ;Years ?? i2c read data set
call    bcd2
ld      a,"/"
call    putchar
ld      a,(rtc_buff+0x07)       ;Months ?? i2c read data set
and     0x1f
call    bcd2
ld      a,"/"
call    putchar
ld      a,(rtc_buff+0x05)       ;Days ?? i2c read data set
and     0x3f
call    bcd2
ld      a," "
call    putchar
ld      a,(rtc_buff+0x04)       ;Hours  ?? i2c  read data set
and     0x3f
call    bcd2
ld      a,":"
call    putchar
ld      a,(rtc_buff+0x03)       ;Minutes ?? i2c read data set
and     0x7f
call    bcd2
ld      a,":"
call    putchar
ld      a,(rtc_buff+0x02)       ;Seconds ?? i2c read data set
and     0x7f
call    bcd2
call    cr
ret

i2c_err_disp:                           ;i2c err disp
call    cr
ld      a,"e"
call    putchar
ld      a,"r"
call    putchar
ld      a,"r"
call    putchar
call    cr
ret
bcd2:                                   ;bcd to putchar
push    af                      ; up bcd (7:4)
rlca
rlca
rlca
rlca
and     0x0f
or      0x30
call    putchar                 ;putchar up data
pop     af
and     0x0f                    ;down data (3:0)
or      0x30
call    putchar                 ;putchar down data
ret

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

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

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

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
;
i2c_r_err:
ld      a,0xff
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

rtc_buff:
.ds     16
prog_end:
.end
おすすめの記事