

;
; I2Cインタフェース + シリアルメモリ24LC64/256インタフェース
;
;
;       SCL:RB0, SDA:RB1
;       (RBポートは内部プルアップで使用）
;
;       CLOCK=10MHz
;
; 例のごとく本ソースは秋月のPA.EXE拡張インストラクションを使用して
; おりますのであしからず。  2000.5 RUU
;
;   2001.2.20   2nd ver.
;   2000.5      1st ver.
;
;


            .include 16f84.h


           .osc        hs
           .wdt        off
           .pwrt       on
           .protect    off

trisa       equ 5
trisb       equ 6

SCL         equ rb.0            ; 24LC64 SCL
SDA         equ rb.1            ; 24LC64 SDA

SCLIO       equ trisb.0         ; I/O bit = trisb.0
SDAIO       equ trisb.1         ; I/O bit = trisb.1

MEM_MAXH    equ     01fh        ; 1チップのメモリサイズ;24LC256=7fffh(32kb),64=1fffh(8kb)
MEM_MAXL    equ     0ffh

            org 0ch

;; I2Cインタフェース
cnt         ds  1               ; 送受ビットカウンタ
rw_dat      ds  1               ; 送受信バイトデータ
ACK_BIT		equ		rw_dat.0	; rw_dat.0 = acknowledge (0:ACK 1:NAK)
i2c_stat    ds  1               ; status .. bit0 = acknowledge (0:ACK 1:NAK)


;; 24LCxxアクセス
;;
;; 補足: ctrl_byteは 「1 0 1 0 A2 A1 A0 R/W」 の1バイト
;;       1010 = control code
;;       A2,A1,A0 = chip select bits(アクセス対象メモリチップの指定)
;;       R/W = 0:write, 1:read
mem_adr     ds  2               ; MemoryAddress [High/Low] byte
ctrl_byte   ds  1               ; 24LC256 control code + chip select + r/w
R_W         equ ctrl_byte.0
csb         ds  1               ; ChipSelectBits(#0～#7)
tmp_dat     ds  1


;; サンプル用
mydata      ds  1
count       ds  1




        org 0                       ; リセットベクター
        goto    start
        org 4                       ; 割り込みベクター
        goto    start

;
;       プログラムの開始
;
start
        ;; 初期設定
        setb    rp0                 ; Bank1
        clrb    rbpu                ; Bポート内部プルアップ
        mov     trisa,#00000000b    ; Aポート0-7を出力にする
        mov     trisb,#00000010b    ; Bポート SCL:OUT, SDA:IN
        clrb    rp0                 ; Bank0
        clr     ra                  ; Aポートクリア
        clr     rb                  ; Bポートクリア

        mov     ctrl_byte,#10100000b    ; コントロールバイト
        clr     csb


;;;;;;;; サンプル ;;;;;;;;

;;;;;;; ex.1    Byte Write ;アドレス0008hに55hを書き込む

        clr     mem_adr[0]
        mov     mem_adr[1],#08h
        mov     rw_dat,#55h
        call    byte_write


;;;;;;; ex.2    Random Read ;アドレス1234hの内容を読み出す

        mov     mem_adr[0],#12h
        mov     mem_adr[1],#34h
        call    random_read


;;;;;;; ex.3 Page Write ;アドレス0000hからmydayaをページ(32bytes)書き込み

        clr     mem_adr[0]
        clr     mem_adr[1]

        mov     count,#32
        call    write_prepare       ; Write準備
pw_loop
;       (任意処理)
        mov     rw_dat,mydata
        call    i2c_write           ; Write
        call    adr_inc             ; addr++
        djnz    count,pw_loop       ; 連続32回(bytes)以内

        call    i2c_stop


;;;;;;; ex.4 Sequential read ;アドレス0000hから100バイトの連続読み出し

        clr     mem_adr[0]
        clr     mem_adr[1]
        mov     count,#100

        call    read_prepare
sr_loop
        call    i2c_read
;       (任意処理)
        call    adr_inc             ; addr++
        djnz    count,sr_nxt
        goto    sr_end
sr_nxt
        call    i2c_ack
        goto    sr_loop
sr_end
        call    i2c_nac
        call    i2c_stop

;;;;;;; 

loop
        goto    loop




;; ******** I2Cインタフェースサブルーチン ********

; i2c_start
; Start Conditionを出力する

i2c_start
            setb    rp0                         ; Bank1
            clrb    SDAIO                       ; SDAを出力にする
            clrb    rp0                         ; Bank0

            clrb    SCL                         ; SCL=L (TLOW = 1600ns)
            nop
            setb    SDA                         ; SDA=H
            nop                                 ; (TSU:DAT = 800ns)
            setb    SCL                         ; SCL=H (THIGH = 1600ns)
            nop                                 ; (TSU:STA = 800ns)
;           nop
            clrb    SDA                         ; SCL=HでSDAがH->L : start condition
            nop                                 ; (THD:STA = 800ns)
;           nop
            clrb    SCL                         ; SCL=L (TLOW > 2000ns)

            setb    rp0                         ; Bank1
            setb    SDAIO                       ; SDAを開放(入力)にする
            clrb    rp0                         ; Bank0
            ret


; i2c_stop
; Stop Conditionを出力する

i2c_stop
            setb    rp0                         ; Bank1
            clrb    SDAIO                       ; SDAを出力にする
            clrb    rp0                         ; Bank0

            clrb    SCL                         ; SCL=L (TLOW = 1600ns)
            nop
            clrb    SDA                         ; SDA=L
            nop                                 ; (TSU:DAT = 800ns)
            setb    SCL                         ; SCL=H (THIGH = 1600ns)
            nop                                 ; (TSU:STO = 800ns)
;           nop
            setb    SDA                         ; SCL=HでSDAがL->H : stop condition
            nop
            clrb    SCL                         ; SCL=L (TLOW > 2000ns)

            setb    rp0                         ; Bank1
            setb    SDAIO                       ; SDAを開放(入力)にする
            clrb    rp0                         ; Bank0
            ret


; i2c_write (マスタ・トランスミッタ)
; 1バイトのデータを出力する
; rw_datの内容は破壊される
; ACK_BIT(rw_dat.0)に実行結果(0:ACK / 1:NAK)が設定される


i2c_write
            setb    rp0                         ; Bank1
            clrb    SDAIO                       ; SDAを出力にする
            clrb    rp0                         ; Bank0
            mov     cnt,#8                      ; カウンタセット
send_bit
            rl      rw_dat
            movb    SDA,c                       ; dataの7bit目から送信 (TSU:DAT = 800～1600ns)
            nop
;           nop
            setb    SCL                         ; SCL=H (THIGH = 800ns)
            nop
;           nop
            clrb    SCL                         ; SCL=L (TLOW = 2400～4000ns)
            djnz    cnt,send_bit                ; 6～0bit繰り返し

            ;; get acknowledge bit
            setb    rp0                         ; Bank1
            setb    SDAIO                       ; SDAを開放(入力)にする
            clrb    rp0                         ; Bank0
            setb    SCL                         ; SCL=H (THIGH = 2400ns)
            nop
            movb    ACK_BIT,SDA                 ; ACK_BIT = ACK/NO ACK
            clrb    SCL
            ret

; i2c_read (マスタ・レシーバ)
; 1バイトのデータを読み込む
; 受信データはrw_datに格納される
i2c_read
            mov     cnt,#8                      ; カウンタセット
read_bit
            setb    SCL                         ; SCL=H (THIGH = 2800ns)
            nop                                 ; (TAA > 2000ns)
            movb    c,SDA                       ; 1bit受信
            rl      rw_dat
            clrb    SCL                         ; SCL=L (TLOW = 1600ns)
            djnz    cnt,read_bit                ; 7-0bit繰り返し
            ret

; レシーバからACK/NACを送信する
i2c_ack
            setb    rp0                         ; Bank1
            clrb    SDAIO                       ; SDAを出力にする
            clrb    rp0                         ; Bank0
            clrb    SDA                         ; ACK (TSU:DAT = 800ns)
            nop
            setb    SCL                         ; SCL=H (THIGH = 800ns)
            nop
;           nop
            clrb    SCL
            setb    rp0                         ; Bank1
            setb    SDAIO                       ; SDAを開放(入力)にする
            clrb    rp0                         ; Bank0
            ret

i2c_nac
            setb    rp0                         ; Bank1
            clrb    SDAIO                       ; SDAを出力にする
            clrb    rp0                         ; Bank0
            setb    SDA                         ; NO ACK (TSU:DAT = 800ns)
            nop
            setb    SCL                         ; SCL=H (THIGH = 800ns)
            nop
;           nop
            clrb    SCL
            setb    rp0                         ; Bank1
            setb    SDAIO                       ; SDAを開放(入力)にする
            clrb    rp0                         ; Bank0
            ret


;; ******** 24LCxxアクセスサブルーチン ********

; set_csb
; csbをctrl_byteのメモリチップセレクトbitsに再設定する
set_csb
            mov     work,csb
            rl      work
            and     work,#00001110b
            and     ctrl_byte,#11110001b
            or      ctrl_byte,work
            ret


; send_ctrl
; START および Control Byte 送信 + ACK待ち
send_ctrl
            call    i2c_start
            mov     rw_dat,ctrl_byte
            call    i2c_write
            jb      ACK_BIT,send_ctrl           ; if NO ACK then retry
            ret

; adr_inc
; アドレスインクリメント
adr_inc
            incsz   mem_adr[1]                  ; address++
            ret
            inc     mem_adr[0]
            ret


; write_prepare
; 書き込み準備
write_prepare
            clrb    R_W                         ; r/w = 0 (write)
            call    send_ctrl                   ; START and control byte
            mov     rw_dat,mem_adr[0]           ; address high
            call    i2c_write
            mov     rw_dat,mem_adr[1]           ; address low
            call    i2c_write
            ret

; read_prepare
; 読み出し準備
read_prepare
            clrb    R_W                         ; r/w = 0 (write)
            call    send_ctrl                   ; START and control byte
            mov     rw_dat,mem_adr[0]           ; address high
            call    i2c_write
            mov     rw_dat,mem_adr[1]           ; address low
            call    i2c_write
            setb    R_W                         ; r/w = 1 (read)
            call    send_ctrl                   ; START and control byte
            ret

; byte_write
;
byte_write
            mov     tmp_dat,rw_dat
            call    write_prepare
            mov     rw_dat,tmp_dat
            call    i2c_write
            call    i2c_stop
            ret


; random_read
;
random_read
            call    read_prepare
            call    i2c_read
            call    i2c_nac
            call    i2c_stop
            ret



;; 以上
