From 2f83a0bea9da444e3d70569eba3d6847ca02be03 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Fri, 21 Sep 2018 21:59:17 +0200 Subject: ... --- forth/forth/avr/i2c-base-avr.fs | 99 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 forth/forth/avr/i2c-base-avr.fs (limited to 'forth/forth/avr/i2c-base-avr.fs') diff --git a/forth/forth/avr/i2c-base-avr.fs b/forth/forth/avr/i2c-base-avr.fs new file mode 100644 index 0000000..50f9abc --- /dev/null +++ b/forth/forth/avr/i2c-base-avr.fs @@ -0,0 +1,99 @@ +\ i2c-base-avr.txt +\ Low-level words for TWI/I2C on Atmega328P. +\ +\ Modelled on i2c-twi.frt from amforth, +\ i2c_base.txt for FlashForth on PIC18 +\ and the Atmel datasheet, of course. +\ Peter J. 2014-10-27 +\ Watchdog added Mikael Nordman @ 12.5.2017 + +-i2c-base +marker -i2c-base +hex ram + +\ Two-Wire-Interface Registers +$b8 constant TWBR +$b9 constant TWSR +$bb constant TWDR +$bc constant TWCR + +\ Bits in the Control Register +%10000000 constant mTWINT +%01000000 constant mTWEA +%00100000 constant mTWSTA +%00010000 constant mTWSTO +%00001000 constant mTWWC +%00000100 constant mTWEN +%00000001 constant mTWIE + +: i2c.init ( -- ) \ Set clock frequency to 100kHz + %11 TWSR mclr \ prescale value = 1 + [ Fcy #100 / #16 - 2/ ] literal TWBR c! + mTWEN TWCR mset +; + +: i2c.wait ( -- ) \ Wait for operation to complete + \ When TWI operations are done, the hardware sets + \ the TWINT interrupt flag, which we will poll. + \ Watchdog timeout + 7 wd+ begin TWCR c@ mTWINT and until wd- +; + +: i2c.start ( -- ) \ Send start condition + [ mTWINT mTWEN or mTWSTA or ] literal TWCR c! + i2c.wait +; + +: i2c.rsen ( -- ) \ Send repeated start condition + i2c.start \ AVR doesn't distinguish +; + +: i2c.stop ( -- ) \ Send stop condition + [ mTWINT mTWEN or mTWSTO or ] literal TWCR c! +; + +\ Write one byte to bus, returning 0 if ACK was received, -1 otherwise. +: i2c.c! ( c -- f ) + i2c.wait \ Must have TWINT high to write data + TWDR c! + [ mTWINT mTWEN or ] literal TWCR c! + i2c.wait + \ Test for arrival of an ACK depending on what was sent. + TWSR c@ $f8 and $18 = if 0 exit then \ SLA+W + TWSR c@ $f8 and $28 = if 0 exit then \ data byte + TWSR c@ $f8 and $40 = if 0 exit then \ SLA+R + -1 \ Something other than an ACK resulted +; + +\ Read one byte and ack for another. +: i2c.c@.ack ( -- c ) + [ mTWINT mTWEN or mTWEA or ] literal TWCR c! + i2c.wait + TWDR c@ +; + +\ Read one last byte. +: i2c.c@.nack ( -- c ) + [ mTWINT mTWEN or ] literal TWCR c! + i2c.wait + TWDR c@ +; + +\ Address slave for writing, leaving true if slave ready. +: i2c.addr.write ( 7-bit-addr -- ) + 2* \ Build full byte with write-bit as 0 + i2c.start i2c.c! if false else true then +; + +\ Address slave for reading, leaving true if slave ready. +: i2c.addr.read ( 7-bit-addr -- ) + 2* 1+ \ Build full byte with read-bit as 1 + i2c.start i2c.c! if false else true then +; + +\ Detect presence of device, leaving true if slave responded. +\ If the slave ACKs the read request, fetch one byte only. +: i2c.ping? ( 7-bit-addr -- f ) + 2* 1+ \ Build full byte with read-bit as 1 + i2c.start i2c.c! 0= if i2c.c@.nack drop true else false then +; -- cgit v1.2.3