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表示に挑戦したいと思います。