From 67d25d837ac55f28a366c0a3b262e439a6e75fc3 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 19 Aug 2017 12:15:28 +0200 Subject: Add AmForth --- amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt | 136 +++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt (limited to 'amforth-6.5/avr8/lib/hardware/i2c-twi-master.frt') 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 +; -- cgit v1.2.3