C言語(SDCC)を使用して、TMPZ84C015でのI2Cアドレスサーチのプログラムを作成したいと思います。

回路図は、以前作成している「Z80(TMPZ84C015)に萌えたい。I2C回路編」の回路をそのまま使用します。

アセンブラとのリンクが必要になりますので、i2c_init、i2c_addrを新たに作成ました。

I2Cのアセンブラはこれまた以前作成している「Z80(TMPZ84C015)に萌えたい。I2Cソフト:LCD編」を参考に作成していきます。

まずは、i2c_initですが、PCA9564を初期化します。またここでは、マスタ側のアドレスを設定しています。ここでは0x02がマスタ(PCA9564)のアドレス設定(I2Cアドレスでは左シフトするので0x01)になります。

;;     void i2c_init(void)
;;
;;     PCA9564 Initialize
;;
I2CSTA  .equ    0x80    ;PCA9564 setting adress
I2CTO   .equ    0x80
I2CDAT  .equ    0x81
I2CADR  .equ    0x82
I2CCON  .equ    0x83

_i2c_init::
        LD      A,0xff                  ;;Timout Register
        out    (I2CTO),a
        ld      a,0x02                  ;;Own Address
        out    (I2CADR),a
        ld      a,0x44                  ;;Enable Serial io
        out    (I2CCON),a

	ld	b,	#124					;;500uS wait
loop:	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	djnz	loop

        ld      a,0xc4                  ;;Slave recciver mode
        out    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
        ret 

上記をi2c_init.asmとして保存します。アセンブルします。

$ asz80 -l -s -o i2c_init.asm

i2c_addrは、i2cのアドレスを引数として与えると、Address+Wの送信をしたのち該当のi2cアドレスが存在すれば、ACK(0x18)を存在しなければNACK(0x20)を返します。また、マスタアドレスであれば0x68を返します。errの場合は0x00を返します。
i2c_addrのリターン値(ACK、NACK、ERR)はLレジスタに保存されます。

;;     uint8_t i2c_addr(uint8_t)
;;
;;     i2c address search
;;     address is return is ack=0x18  nack=0x20 master=0x68 err=0x00
;;
I2CSTA  .equ    0x80    ;PCA9564 setting adress
I2CTO   .equ    0x80
I2CDAT  .equ    0x81
I2CADR  .equ    0x82
I2CCON  .equ    0x83

_i2c_addr::
	ld	hl,	#0x0002
	add	hl,	sp

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

i2c_a02:
        in     	a,(I2CCON)              ;; SI=1 ?
        bit     3,a
        jr      z,i2c_a02

        in     	a,(I2CSTA)              ;;Poll from transmission finished
	ld	l,a
	
        ld      a,0xd4                  ;Generate STOP command
        out     (I2CCON),a              ;AA=1 ENSIO=1 STA=0 STO=1

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


i2c_r_err:
	xor		a			;return nack 0x00
	ld		l,a
	ret

上記をi2c_addr.asmとして保存します。アセンブルします。

$ asz80 -l -s -o i2c_addr.asm

i2c関連の準備ができたので、さっそくC言語でI2Cアドレスサーチのブログラムを作成したいと思います。

i2c_initにてPCA9564をイニシャライズしたのち、二重のFOR文でアドレスを作成します。
アドレスとしては、00~7Fまでです。
i2c_addrにi2cアドレスを与えると、ACK(0x18)の場合、*を表示、NACKの場合、ーを表示、マスタ(0x68)の場合は Mを表示、エラーの場合、erを表示するようにしました。

//  I2C Address Search (PCA9564)

#include <stdio.h>
#include <stdint.h>


extern	void	i2c_init(void);
extern	uint8_t	i2c_addr(uint8_t);


int main(){

    uint8_t i, j, addr;
    i2c_init();
    printf("I2C Address Search (PCA9564)\n");
    printf("Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
    for (i = 0; i <= 0x7; i++) {
        printf("  %2x ", i*0x10);
        for (j = 0; j <= 0xf; j++) {
            addr = i * 0x10 + j;
	        switch(i2c_addr(addr)){
				case 0x18:					//addr+W >> ACK
		    		printf("* ");
		          	break;
				case 0x20:					//addr+w >> NACK
		          	printf("- ");
		          	break;
				case 0x68:					//Master
			   	  	printf("M ");
			    	break;
				default:
		           	printf("er");
	         }
        }
        printf("\n");
    };
    return(0);
}		

上記をi2c_addr_main.cとして保存、コンパイルします。
コンパイルにはprintfを使用しているので、putchar.relが必要になります。

$ sdcc -mz80 --out-fmt-ihx --code-loc 0xa000 --no-std-crt0 -o i2c_addr_main.ihx mycrt0.rel i2c_addr_main.c i2c_init.rel i2c_addr.rel putchar.rel
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA
Conflicting flags in area    _CODE
Conflicting flags in area    _DATA

モニタのlコマンドでダウンロードします。

>l                                                                              20A00000CDDBA0219EA0E5CD47A1F10E0069260029292929C5E5218AA0E5CD9AA1F1F1C148
20A0200006007907070707E6F05883C5F533CDF9A0337DC1FE18280AFE202812D668281AF0
20A040001824C52191A0E5CD9AA1F1C11822C52194A0E5CD9AA1F1C11816C52197A0E5CD1E
20A060009AA1F1C1180AC5219AA0E5CD9AA1F1C1043E0F9030ACC5219DA0E5CD47A1F1C1E6

中略

00000001FF
OK
>

>c a000 y:
I2C Address Search (PCA9564)
Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f
   0 - M - - - - - - - - - - - - - -
  10 - - - - - - - - - - - - - - - -
  20 - - - - - - - * - - - - - - - -
  30 - - - - - - - - - - - - - - - -
  40 - - - - - - - - - - - - - - - -
  50 - - - - - - - - - - - - - - - -
  60 - - - - - - - - - - - - - - - -
  70 - - - - - - - - - - - - - - - -

>

「KKHMF DC 5V 1602 LCD ディスプレイモジュール 16×2キャラクタ LCDブルーブラックライト」と「EasyWordMall 1602 LCD ブラック IIC/I2C/TWI/SPI シリアル インタフェース ボード モジュール」(amazonで購入) の組み合わせで、i2cモジュールのアドレス設定はオープンの状態で確認した結果、アドレスは、0x27でした。ちなみにマスタは0x01です。

次回は、このLCD+i2cモジュールのC言語でのLCD表示に挑戦したいと思います。

おすすめの記事