\ 2006-07-09 EW
\ speaking to i2c bus as master
\
\  N O   E R R O R   C H E C KI N G
\  W H A T S O E V E R !
\
\ expects:
\  PinSDA PinSCL
\  PortI2C PddrI2C
\ 
\ provides:
\   NB>i2c ( xN .. x1.msB N addr -- )
\     send N bytes to i2c device at addr
\ 
\   NB<i2c ( N addr -- X1.msB .. xN ) 
\     read N bytes from i2c device at addr
\     expects previously sent addr/controlbyte
\     since REPEATED START condition is used

: sda0 PinSDA PortI2C bclr ;
: sda1 PinSDA PortI2C bset ;
: scl0 PinSCL PortI2C bclr ;
: scl1 PinSCL PortI2C bset ;

\ get Bit Nr. i from Byte x
: getBit ( x i -- b ) rshift 1 and ;
: sdaInput  ( -- ) PinSDA PddrI2C bclr ;
: sdaOutput ( -- ) PinSDA PddrI2C bset ;
: readSDA   ( -- f )
  PinSDA PortI2C btst IF 1 ELSE 0 ENDIF ;

: i2c_tick 2 us ;
: 2i2c_tick i2c_tick i2c_tick ;

\ send START
: i2c_start ( -- )
  i2c_tick sda0 2i2c_tick scl0 i2c_tick ;
\ send STOP
: i2c_stop  ( -- )
  i2c_tick scl1 2i2c_tick sda1 i2c_tick ;
\ send REPEATED START
: i2c_rstart
  sda1 i2c_tick scl1 i2c_tick
  sda0 i2c_tick scl0 i2c_tick
;
\ clock out 1 Bit
: bit>i2c ( f -- )
  IF sda1 ELSE sda0 ENDIF
  i2c_tick scl1 2i2c_tick scl0 i2c_tick
;
\ send 1 Byte, 8 Bit, msb first
: >i2c ( x -- )
  8 0 DO
    dup 8 I 1+ - getBit
    bit>i2c
  LOOP
  drop
;
\ read 1 Byte, 8 Bit, msb first
: <i2c ( -- x )
  sdaInput
  0
  8 0 DO
    1 lshift
    i2c_tick scl1 i2c_tick readSDA
    i2c_tick scl0 i2c_tick
    +
  LOOP
  sdaOutput
;
\ read ACK|NACK from device
: ack<i2c ( -- f )
  sdaInput
  i2c_tick scl1 i2c_tick readSDA
  i2c_tick scl0 i2c_tick
  sdaOutput
;
\ send n bytes from stack to device
: NB>i2c ( x1 .. xN.msB N addr -- )
  i2c_start
  >i2c ack<i2c drop   \ send address
  0 DO
    >i2c ack<i2c drop \ send next byte
  LOOP
  i2c_stop
;
\ read n Bytes from device to stack, assume
\ address and opt. controlbytes were sent
: NB<i2c ( N addr -- xN.msB .. x1 )
  i2c_rstart
  1+ >i2c ack<i2c drop \ send addr
  1- dup 0 > IF
    0 DO \ loop N-1 times
      <i2c 0 bit>i2c \ read byte, send ACK
    LOOP
  ENDIF
  <i2c 1 bit>i2c \ read last byte, send NACK
  i2c_stop
;