aboutsummaryrefslogtreecommitdiff
path: root/amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt
diff options
context:
space:
mode:
Diffstat (limited to 'amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt')
-rw-r--r--amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt136
1 files changed, 136 insertions, 0 deletions
diff --git a/amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt b/amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt
new file mode 100644
index 0000000..3bd2190
--- /dev/null
+++ b/amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt
@@ -0,0 +1,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
+;