Line 1... |
Line 1... |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;
|
;
|
; Copyright 2012, Sinclair R.F., Inc.
|
; Copyright 2012, 2014, Sinclair R.F., Inc.
|
;
|
;
|
; Major I2C functions:
|
; Major I2C functions:
|
; i2c_send_start ( - )
|
; i2c_send_start ( - ) send the start condition
|
; i2c_send_byte ( u - f )
|
; i2c_send_restart ( - ) send a restart after ACK during write
|
; i2c_read_byte ( - u )
|
; i2c_send_byte ( u - f ) send a byte (address, register, data, ...)
|
; i2c_send_stop ( - )
|
; i2c_read_byte ( f - u ) read a byte and either ACK (f=0) or STOP (f=1)
|
|
; i2c_send_stop ( - ) send a stop after ACK during write
|
|
;
|
|
; Example to set a single register (ignoring returned ACK/NACK value)
|
|
; .call(i2c_send_start)
|
|
; .call(i2c_send_byte,write_address) drop
|
|
; .call(i2c_send_byte,register) drop
|
|
; .call(i2c_send_byte,data) drop
|
|
; .call(i2c_send_stop)
|
|
;
|
|
; Example to read two bytes (ignoring returned ACK/NACK value)
|
|
; .call(i2c_send_start)
|
|
; .call(i2c_send_byte,write_address) drop
|
|
; .call(i2c_send_byte,register) drop
|
|
; .call(i2c_send_restart)
|
|
; .call(i2c_send_byte,read_address) drop
|
|
; .call(i2c_read_byte,0)
|
|
; .call(i2c_read_byte,1)
|
;
|
;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
; Compute how many iterations in the quarter-clock-cycle function are required.
|
; Compute how many iterations in the quarter-clock-cycle function are required.
|
; ceil(100 MHz / 400 kHz / 4) ==> 63 clock cycles per I2C SCL quarter cycle
|
; ceil(100 MHz / 400 kHz / 4) ==> 63 clock cycles per I2C SCL quarter cycle
|
Line 18... |
Line 35... |
; 1 clock cycle to initialize the loop count
|
; 1 clock cycle to initialize the loop count
|
; 2 clock cycles to return
|
; 2 clock cycles to return
|
; 9 TOTAL
|
; 9 TOTAL
|
; Add 2 to ensure rounding up when evaluting the integer fraction.
|
; Add 2 to ensure rounding up when evaluting the integer fraction.
|
; The loop is 3 clock cycles per iteration
|
; The loop is 3 clock cycles per iteration
|
|
.IFNDEF C_I2C_QUARTER_CYCLE
|
.constant C_I2C_QUARTER_CYCLE ${(63-9+2)/3}
|
.constant C_I2C_QUARTER_CYCLE ${(63-9+2)/3}
|
|
.ENDIF
|
|
|
; ( - )
|
; ( - )
|
.function i2c_send_start
|
.function i2c_send_start
|
0 .outport(O_SDA)
|
0 .outport(O_SDA)
|
.call(i2c_quarter_cycle,1)
|
.call(i2c_quarter_cycle,1)
|
Line 51... |
Line 70... |
; get the acknowledge bit at the middle of the high portion of SCL
|
; get the acknowledge bit at the middle of the high portion of SCL
|
; ( - f )
|
; ( - f )
|
.call(i2c_clock_cycle,1)
|
.call(i2c_clock_cycle,1)
|
.return
|
.return
|
|
|
; Read the next byte from the device.
|
; Read the next byte from the device and generate an ACK or a STOP.
|
; ( - u )
|
; ( f - u )
|
.function i2c_read_byte
|
.function i2c_read_byte
|
|
; Read 8 bits and pack them into the returned value.
|
|
; ( f - u f )
|
0 ${8-1} :loop
|
0 ${8-1} :loop
|
swap <<0 .call(i2c_clock_cycle,1) or swap
|
swap <<0 .call(i2c_clock_cycle,1) or swap
|
.jumpc(loop,1-) drop
|
.jumpc(loop,1-) drop
|
; send the acknowledgment bit
|
swap
|
.call(i2c_clock_cycle,0)
|
; Generate the ACK/STOP based on f.
|
.return(drop)
|
; ( u f - u )
|
|
0 .outport(O_SDA)
|
|
.call(i2c_quarter_cycle,0)
|
|
.call(i2c_quarter_cycle,1)
|
|
O_SDA outport
|
|
.call(i2c_quarter_cycle,1)
|
|
.call(i2c_quarter_cycle) ; SCL is high on STOP, low on ACK, consumes f
|
|
.return
|
|
|
; Send a stop by bringing SDA high while SCL is high.
|
; Send a stop by bringing SDA high while SCL is high.
|
; ( - )
|
; ( - )
|
.function i2c_send_stop
|
.function i2c_send_stop
|
0 .outport(O_SDA) .call(i2c_quarter_cycle,0)
|
0 .outport(O_SDA) .call(i2c_quarter_cycle,0)
|