Howdy, I use this code I wrote before any 9S08s had an I2C module.
This copy is from a 9S08AC16 32pin QFP, managing an I/O expander, 2 Digital pots, 3 DACs & a 24C02 flash.
DPots & DACs are MicroChip series. I/O expander is NXP. Good Hunting... <<<)))
;* Port C: b0;1=I2C SCl;SDa /flash(a0)/10k DPot(52)/100k DPot(54)/
;* compressor DAC(c0)/balance DAC(c1)/LCD contrast DAC(c2)
; I2C direct constants
flhadr equ $a0 ;flash RAM address (LSb=R/W*)(=0)
tnKdev equ $52 ;10k DPot Amp device addr (LSb=R/W*)(=1)
hnKdev equ $54 ;100k DPot Amp device addr (LSb=R/W*)(=2)
rlydev equ $c0 ;relay driver/Refl % selector
rlybas equ $05 ; relay base: 00=Off, 01=On, 10=70%, 11=20%
baldev equ $c2 ;DAC OptoFET LED driver/Balance
condev equ $c4 ;DAC LCD display contrast
; I2C RAM
devreg ds.b 1 ;RAM data page base addr
devadr ds.b 1 ;I2C DPot address
;Initialize
;* read parmset from flash, parms all stay in these spots
jsr I2CStp ;send a couple Stops to clear I2C protocol
jsr I2CStp
;* read flash parms
ldhx #prmtnk ;set parameter base address
mov #flhadr,devadr ;set device address
mov #$00,devreg ;set flash addr
jsr RdPage
; ldhx #RefTbl ;lamp life ref table
; mov #$10,devreg ;set flash addr
; jsr RdPage
; mov #$20,devreg ;set flash addr
; jsr RdPage
; mov #$30,devreg ;set flash addr
; jsr RdPage
;* init relay driver, Duty Cycle parms NOT USED, Init as proof
IniRly: jsr I2CSrt ;xfr START
lda #rlydev ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs IRDErr ;C=1: error
lda #$11 ;register select & autoincr
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs IRDErr ;C=1: error
lda #$00 ;register PreScale 0 = max freq
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs IRDErr ;C=1: error
lda #hld_dc ;register PWM 0 = Hold %
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs IRDErr ;C=1: error
lda #$00 ;register PreScale 1 = max freq
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs IRDErr ;C=1: error
lda #cls_dc ;register PWM 1 = Close %
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
IRDErr: nop ;error trace trap
jsr I2CStp ;nml exit as stop
;------------------------------------------------------------------
;* init balance DAC, direct I2C calls: addr & cfg only
jsr DacRst ;reset DACs' I2C
jsr I2CSrt ;xfr START, ALT entry/set unit addr
lda #baldev ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
lda #cfgDaI ;page=reg select & cfg: DAC Config
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
jsr I2CStp ;xfr STOP
;* init contrast DAC, direct I2C calls: addr & cfg only
jsr DacRst ;reset DACs' I2C
jsr I2CSrt ;xfr START, ALT entry/set unit addr
lda #condev ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
lda #cfgDaI ;page=reg select & cfg: DAC Config
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
jsr I2CStp ;xfr STOP
;********************************************************************************
; LCD, DAC & DPot ~ I2C Manager Routines
;* RdPage - get <gpctr1>(16) bytes, put to (H:X)+; page base in devsel & chrtnk
RdPage: mov #15,gpctr ;16 bytes (15 loops + last)
RdAddr: jsr I2CSrt ;xfr START, ALT entry/read unit addr
lda devadr ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs RxErr ;C=1: error
lda devreg ;page base addr 7-0
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs RxErr ;C=1: error
jsr I2CClk
jsr I2CClk ;pause for page addr write to take
jsr I2CSrt ;send ANOTHER START after page addr write
lda devadr ;put/send devsel/addr (LSb=W*)
ora #$01 ;chg to Read
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs RxErr ;C=1: error
SRDRd: sta SRS
jsr I2CRx8 ;read a byte
clc ;clr Carry & send as Ack
jsr I2CTx1
sta ,x ;save data to ram
aix #1 ;inc index
dbnz gpctr,SRDRd ;dec ctr & loop
jsr I2CRx8 ;read last byte
sec ;set Carry & send as NAck
jsr I2CTx1 ; not really a NAck: 1 bit time B4 stop
RxErr: jsr I2CStp ;xfr STOP
sta ,x ;save last of data
aix #1 ;inc index
rts
;-------------------------------------------------------------------
;* WrPage - put <gpctr>(16) bytes, from (H:X)+; page addr in devreg
WrPage: bsr Wr8Flh ;AT24C02 Writes 8 bytes/page
lda devreg ;next page
add #$08
sta devreg
bsr Wr8Flh
rts
Wr8Flh: sta SRS ;Page Writes to FlashRAM only
bclr i2cWC,PTGD ;low enables write to flash
;* Note: flash roms can have 8/16/32 byte pages
WrAddr: mov #8,gpctr ;8 bytes
jsr I2CSrt ;xfr START, ALT entry/set unit addr
lda devadr ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxErr ;C=1: error
lda devreg ;RAM data page base addr
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxErr ;C=1: error
SRDWrt: sta SRS
lda ,x ;put/send byte
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxErr ;C=1: error
aix #1 ;incr index
dbnz gpctr,SRDWrt ;dec ctr, send all
jsr I2CStp ;xfr STOP
pshh ;save source addr
pshx
ldhx #wrtrom ;24C01 10mS write time
SRWDly: sta SRS
aix #-1
cphx #0
bhi SRWDly
pulx ;restore source addr
pulh
TxErr: jsr I2CStp ;nml exit does 2 stops: no problem
bset i2cWC,PTGD ;high disables write to flash
rts
;-------------------------------------------------------------------
; WrByte: Standard DPot setting: devadr, devreg=dev, reg sel, gptnk=value
WrDPot: jsr I2CSrt ;xfr START
lda devadr ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxBErr ;C=1: error
lda devreg ;register select
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxBErr ;C=1: error
sta SRS
lda gptnk ;put/send byte
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxBErr ;C=1: error
jsr I2CStp ;xfr STOP
TxBErr: nop ;error trace trap
jsr I2CStp ;nml exit does 2 stops: no problem
rts
;-------------------------------------------------------------------
; WrtDAC: devadr, devreg=register & value MSn, gptnk=value 2Sn/LSn
WrtDAC: jsr I2CSrt ;xfr START
lda devadr ;put/send devsel/addr (LSb=W*)
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxDErr ;C=1: error
lda devreg ;register select
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxDErr ;C=1: error
sta SRS
lda gptnk ;put/send byte
jsr I2CTx8
jsr I2CRx1 ;get NAck/Ack* (NAck=error)
bcs TxDErr ;C=1: error
jsr I2CStp ;xfr STOP
TxDErr: nop ;error trace trap
jsr I2CStp ;nml exit does 2 stops: no problem
rts
; Low Level bit-bang drivers ******************************************************
;-------------------------------------------------------------------
;* I2C routines: read byte/bit, start, stop, clk delay, write byte/bit
I2CRx8: bsr I2CRx1 ;Rx byte to A, get b7 in C
rola ;C->b0
bsr I2CRx1
rola ;C->b0, b0->b1...etc
bsr I2CRx1
rola ;C->b0
bsr I2CRx1
rola ;C->b0
bsr I2CRx1
rola ;C->b0
bsr I2CRx1
rola ;C->b0
bsr I2CRx1
rola ;C->b0
bsr I2CRx1
rola ;C->b0
rts ;----------
I2CRx1: sta SRS
bclr i2cDta,PTCDD ;Rx 1 bit to Carry, chg to In
bsr I2CClk
bset i2cClk,PTCD ;clock high
bsr I2CClk
sec ;init Carry=1
brset i2cDta,PTCD,IRx_0 ;=1: go clk
clc ; else: data = Lo
IRx_0: bsr I2CClk
bclr i2cClk,PTCD ;clock low
bsr I2CClk
bclr i2cDta,PTCD ;reset as low
bset i2cDta,PTCDD ;chg to Out, data out reg bit=0
bsr I2CClk
rts ;----------
;* I2C Common routines: start, stop, clk delay
I2CSrt: bset i2cClk,PTCD ;Start: inits a xfer
bset i2cDta,PTCD ;enters w/clk & data High
bsr I2CClk
bclr i2cDta,PTCD
bsr I2CClk
bclr i2cClk,PTCD ;exits w/clk & data Low
bsr I2CClk
rts ;----------
I2CStp: bsr I2CClk ;Stop: closes a xfer
bset i2cClk,PTCD ;enters w/clk & data Low
brn I2CClk
bset i2cDta,PTCD ;exits w/clk & data High
brn I2CClk
rts ;----------
;* Delay timer
I2CClk: mov scltnk,bittmr ;load clk count: 400kHz=2.5uS
I2CCLp: sta SRS
nop
dbnz bittmr,I2CCLp ;=3+1+5 :: ct=3->27cyc
rts ;----------
;* I2C Tx routines
I2CTx8: asla ;Tx byte in A, b7->C, 0->b0
bsr I2CTx1 ;send bit in Carry
asla ;b6->C
bsr I2CTx1
asla ;b5->C
bsr I2CTx1
asla ;b4->C
bsr I2CTx1
asla ;b3->C
bsr I2CTx1
asla ;b2->C
bsr I2CTx1
asla ;b1->C
bsr I2CTx1
asla ;b0->C
bsr I2CTx1
rts ;----------
I2CTx1: sta SRS
bset i2cDta,PTCD ;Tx 1 bit from Carry, init Hi
bcs I2CTxH ;Carry set: go clk
bclr i2cDta,PTCD ; else: set data Lo
I2CTxH: bsr I2CClk
bset i2cClk,PTCD ;clock set
bsr I2CClk
bclr i2cClk,PTCD ;clock clr
bsr I2CClk
bclr i2cDta,PTCD ;put data Lo
bsr I2CClk
rts ;----------