aboutsummaryrefslogtreecommitdiff
path: root/amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt
blob: 3bd2190ee4fbdfefa19fc92c719498efc21c0dda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
\ basic I2C operations, uses 7bit bus addresses
\ uses the TWI module of the Atmega's.

#require bitnames.frt
#require avr-values.frt

\ provides public commands
\  i2c.ping?         -- checks if addr is active
\  i2c.init          -- flexible configuration setup. see below
\  i2c.init.default  -- generic slow speed setup
\  i2c.off           -- turns off I2C

\ and more internal commands
\  i2c.wait          -- wait for the current i2c transaction
\  i2c.start         -- send start condition
\  i2c.stop          -- send stop condition
\  i2c.tx            -- send one byte, wait for ACK
\  i2c.rx            -- receive one byte with ACK
\  i2c.rxn           .. receive one byte with NACK
\  i2c.status        -- get the last i2c status

\
\ i2c (SCL) clock speed = CPU_clock/(16 + 2*bitrateregister*(4^prescaler))
\ following the SCL clock speed in Hz for an 8Mhz device
\      bitrate register (may be any value between 0 and 255)
\               4      8       16      32      64      128    255
\      prescaler                             
\      /1    333.333 250.000 166.667 100.000  55.556  29.412  15.209
\      /4    166.667 100.000  55.556  29.412  15.152   7.692   3.891
\      /16    55.556  29.412  15.152   7.692   3.876   1.946     978
\      /64    15.152   7.692   3.876   1.946     975     488     245
\
\

-#4000 constant i2c.timeout  \ exception number for timeout
#10000 Evalue   i2c.maxticks \ # of checks until timeout is reached
variable i2c.loop           \ timeout counter
variable i2c.current        \ current hwid if <> 0

: i2c.timeout?
    i2c.loop @ 1- dup i2c.loop ! 0=
;

\ turn off i2c
: i2c.off ( -- )
    0 TWCR c!
    0 i2c.current !
;

#0 constant i2c.prescaler/1
#1 constant i2c.prescaler/4
#2 constant i2c.prescaler/16
#3 constant i2c.prescaler/64
TWSR $3 bitmask: i2c.conf.prescaler

TWCR #7 portpin: i2c.int
TWCR #6 portpin: i2c.ea
TWCR #5 portpin: i2c.sta

\ enable i2c
: i2c.init ( prescaler bitrate  -- )
    i2c.off   \ stop i2c, just to be sure
    TWBR c!   \ set bitrate register
    i2c.conf.prescaler pin! \ the prescaler has only 2 bits
;

\ a very low speed initialization.
: i2c.init.default
    i2c.prescaler/64 #3 i2c.init 
;

\ wait for i2c finish
: i2c.wait ( -- )
    i2c.maxticks i2c.loop !
    begin
       pause \ or 1ms?
       i2c.int is_high?
       i2c.timeout? if i2c.timeout throw then
    until
;

\ send start condition
: i2c.start ( -- )
    %10100100 TWCR c!
    i2c.wait
;

\ send stop condition
: i2c.stop ( -- )
    %10010100 TWCR c!
    \ no wait for completion.
;

\ send the restart condition (AVR simply sends start again)
: i2c.restart ( -- )
  i2c.start
;

\ process the data, waits for completion
: i2c.action
    %10000100 or TWCR c! \ _BV(i2cNT)|_BV(TWEN)
    i2c.wait
;

\ send 1 byte
: i2c.tx ( c -- )
    TWDR c!
    0 i2c.action
;

\ receive 1 byte, send ACK
: i2c.rx ( -- c )
    %01000000 \ TWEA
    i2c.action
    TWDR c@
;

\ receive 1 byte, send NACK
: i2c.rxn ( -- c )
    0 i2c.action
    TWDR c@
;

\ get i2c status
: i2c.status ( -- n )
    TWSR c@
    $f8 and
;

\ detect presence of a device on the bus
: i2c.ping?   ( addr -- f )
    i2c.start 
    2* i2c.tx
    i2c.status $18 =
    i2c.stop
;