.include "m48def.inc" ; change if an other device is used
;**** Global I2C Constants ****
.equ SCLP = 5 ; SCL Pin number (port C)
.equ SDAP = 4 ; SDA Pin number (port C)
.equ b_dir = 0 ; transfer direction bit in i2cadr
.equ i2crd = 1
.equ i2cwr = 0
;**** Global Register Variables ****
.def i2cdelay= r16 ; Delay loop variable
.def i2cdata = r17 ; I2C data transfer register
.def i2cadr = r18 ; I2C address and direction register
.def i2cstat = r19 ; I2C bus status register
ldi r20, 0xFF
out ddrd, r20
;**** Interrupt Vectors ****
rjmp RESET ; Reset handle
; ( rjmp EXT_INT0 ) ; ( IRQ0 handle )
; ( rjmp TIM0_OVF ) ; ( Timer 0 overflow handle )
; ( rjmp ANA_COMP ) ; ( Analog comparator handle )
;***************************************************************************
;*
;* FUNCTION
;* i2c_hp_delay
;* i2c_qp_delay
;*
;* DESCRIPTION
;* Cristalclock 4,433MHz
;* Control SDA2516-2 with an ATMEGA8, ATMEGA48 or ATMEGA168
;*
;* SEE DOCUMENTATION !!!
;*
;* USAGE
;* no parameters
;*
;* RETURN
;* none
;*
;***************************************************************************
i2c_hp_delay:
ldi i2cdelay,2
i2c_hp_delay_loop:
dec i2cdelay
brne i2c_hp_delay_loop
ret
i2c_qp_delay:
ldi i2cdelay,1
i2c_qp_delay_loop:
dec i2cdelay
brne i2c_qp_delay_loop
ret
;***************************************************************************
;*
;* FUNCTION
;* i2c_rep_start
;*
;* DESCRIPTION
;* Assert repeated start condition and sends slave address.
;*
;* USAGE
;* i2cadr - Contains the slave address and transfer direction.
;*
;* RETURN
;* Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by i2c_start.
;*
;***************************************************************************
i2c_rep_start:
sbi DDRC,SCLP ; force SCL low
cbi DDRC,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
rcall i2c_qp_delay ; quarter period delay
;***************************************************************************
;*
;* FUNCTION
;* i2c_start
;*
;* DESCRIPTION
;* Generates start condition and sends slave address.
;*
;* USAGE
;* i2cadr - Contains the slave address and transfer direction.
;*
;* RETURN
;* Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by i2c_write.
;*
;***************************************************************************
i2c_start:
mov i2cdata,i2cadr ; copy address to transmitt register
sbi DDRC,SDAP ; force SDA low
rcall i2c_qp_delay ; quarter period delay
;***************************************************************************
;*
;* FUNCTION
;* i2c_write
;*
;* DESCRIPTION
;* Writes data (one byte) to the I2C bus. Also used for sending
;* the address.
;*
;* USAGE
;* i2cdata - Contains data to be transmitted.
;*
;* RETURN
;* Carry flag - Set if the slave respond transfer.
;*
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by i2c_get_ack.
;*
;***************************************************************************
i2c_write:
sec ; set carry flag
rol i2cdata ; shift in carry and out bit one
rjmp i2c_write_first
i2c_write_bit:
lsl i2cdata ; if transmit register empty
i2c_write_first:
breq i2c_get_ack ; goto get acknowledge
sbi DDRC,SCLP ; force SCL low
brcc i2c_write_low ; if bit high
nop ; (equalize number of cycles)
cbi DDRC,SDAP ; release SDA
rjmp i2c_write_high
i2c_write_low: ; else
sbi DDRC,SDAP ; force SDA low
rjmp i2c_write_high ; (equalize number of cycles)
i2c_write_high:
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
rcall i2c_hp_delay ; half period delay
rjmp i2c_write_bit
;***************************************************************************
;*
;* FUNCTION
;* i2c_get_ack
;*
;* DESCRIPTION
;* Get slave acknowledge response.
;*
;* USAGE
;* (used only by i2c_write in this version)
;*
;* RETURN
;* Carry flag - Cleared if a slave responds to a request.
;*
;***************************************************************************
i2c_get_ack:
sbi DDRC,SCLP ; force SCL low
cbi DDRC,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
i2c_get_ack_wait:
sbis PINC,SCLP ; wait SCL high
;(In case wait states are inserted)
rjmp i2c_get_ack_wait
clc ; clear carry flag
sbic PINC,SDAP ; if SDA is high
sec ; set carry flag
rcall i2c_hp_delay ; half period delay
ret
;***************************************************************************
;*
;* FUNCTION
;* i2c_do_transfer
;*
;* DESCRIPTION
;* Executes a transfer on bus. This is only a combination of i2c_read
;* and i2c_write for convenience.
;*
;* USAGE
;* i2cadr - Must have the same direction as when i2c_start was called.
;* see i2c_read and i2c_write for more information.
;*
;* RETURN
;* (depends on type of transfer, read or write)
;*
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by i2c_read.
;*
;***************************************************************************
i2c_do_transfer:
sbrs i2cadr,b_dir ; if dir = write
rjmp i2c_write ; goto write data
;***************************************************************************
;*
;* FUNCTION
;* i2c_read
;*
;* DESCRIPTION
;* Reads data (one byte) from the I2C bus.
;*
;* USAGE
;* Carry flag - If set no acknowledge is given to the slave
;* indicating last read operation before a STOP.
;* If cleared acknowledge is given to the slave
;* indicating more data.
;*
;* RETURN
;* i2cdata - Contains received data.
;*
;* NOTE
;* IMPORTANT! : This funtion must be directly followed by i2c_put_ack.
;*
;***************************************************************************
i2c_read:
rol i2cstat ; store acknowledge
; (used by i2c_put_ack)
ldi i2cdata,0x01 ; data = 0x01
i2c_read_bit: ; do
sbi DDRC,SCLP ; force SCL low
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
rcall i2c_hp_delay ; half period delay
clc ; clear carry flag
sbic PINC,SDAP ; if SDA is high
sec ; set carry flag
rol i2cdata ; store data bit
brcc i2c_read_bit ; while receive register not full
;***************************************************************************
;*
;* FUNCTION
;* i2c_put_ack
;*
;* DESCRIPTION
;* Put acknowledge.
;*
;* USAGE
;* (used only by i2c_read in this version)
;*
;* RETURN
;* none
;*
;***************************************************************************
i2c_put_ack:
sbi DDRC,SCLP ; force SCL low
ror i2cstat ; get status bit
brcc i2c_put_ack_low ; if bit low goto assert low
cbi DDRC,SDAP ; release SDA
rjmp i2c_put_ack_high
i2c_put_ack_low: ; else
sbi DDRC,SDAP ; force SDA low
i2c_put_ack_high:
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
i2c_put_ack_wait:
sbis PINC,SCLP ; wait SCL high
rjmp i2c_put_ack_wait
rcall i2c_hp_delay ; half period delay
ret
;***************************************************************************
;*
;* FUNCTION
;* i2c_stop
;*
;* DESCRIPTION
;* Assert stop condition.
;*
;* USAGE
;* No parameters.
;*
;* RETURN
;* None.
;*
;***************************************************************************
i2c_stop:
sbi DDRC,SCLP ; force SCL low
sbi DDRC,SDAP ; force SDA low
rcall i2c_hp_delay ; half period delay
cbi DDRC,SCLP ; release SCL
rcall i2c_qp_delay ; quarter period delay
cbi DDRC,SDAP ; release SDA
rcall i2c_hp_delay ; half period delay
ret
;***************************************************************************
;*
;* FUNCTION
;* i2c_init
;*
;* DESCRIPTION
;* Initialization of the I2C bus interface.
;*
;* USAGE
;* Call this function once to initialize the I2C bus. No parameters
;* are required.
;*
;* RETURN
;* None
;*
;* NOTE
;* PORTC and DDRC pins not used by the I2C bus interface will be
;* set to Hi-Z (!).
;*
;* COMMENT
;* This function can be combined with other PORTC initializations.
;*
;***************************************************************************
i2c_init:
clr i2cstat ; clear I2C status register (used
; as a temporary register)
out PORTC,i2cstat ; set I2C pins to open colector
out DDRC,i2cstat
ret
;***************************************************************************
;*
;* PROGRAM
;* main - Test of I2C master implementation
;*
;* DESCRIPTION
;* Initializes I2C interface and shows an example of using it.
;*
;***************************************************************************
RESET:
rcall i2c_init ; initialize I2C interface
;**** Write data => Adr(00) = 0x55 ****
ldi i2cadr,$A0+i2cwr ; Set device address and write
rcall i2c_start ; Send start condition and address
ldi i2cdata,$FF ; Write word address (0xFF)
rcall i2c_do_transfer ; Execute transfer
ldi i2cdata,$55 ; Set write data to 01010101b
rcall i2c_do_transfer ; Execute transfer
rcall i2c_stop ; Send stop condition
;**** Read data => i2cdata = Adr(FF) ****
ldi i2cadr,$A0+i2cwr ; Set device address and write
rcall i2c_start ; Send start condition and address
ldi i2cdata,$FF ; Write word address
rcall i2c_do_transfer ; Execute transfer
ldi i2cadr,$A0+i2crd ; Set device address and read
rcall i2c_rep_start ; Send repeated start condition and address
sec ; Set no acknowledge (read is followed by a stop condition)
ldi i2cdata,$FF ; Write word address
rcall i2c_do_transfer ; Execute transfer
rcall i2c_do_transfer ; Execute transfer (read)
rcall i2c_stop ; Send stop condition - releases bus
main:
out PORTD, i2cdata
rjmp main ; Loop forewer
;**** End of File ****
|