Date: Wed, 21 Feb 1996 21:46:23 +0100 From: Per Finander [pfimdt93@tufvan.hv.se] Subject: LZ: I2C-routines for TI85/ZShell This message comes from the List-ZShell mailing list: I've developed routines to implement support for the I2C interface in ZShell programs. I'll not try to explain how the I2C protocol works, but by using these routines it's possible to connect i2c-compatible circuits directly to the linkport (you connect anything to your TI85 on your own risk!). Much information about I2C-circuits can be found on Internet. Philips have documents in adobe acrobat (PDF) format describing many of their I2C-circuits. These documents also contains timinginformation and electrical data for the i2c-interface if anyone is interested. Why use I2C? There are many circuits with built-in I2C-interface. To mention some of them: EEPROMs, Clocks, IO-controllers, IR-transmitter/receivers and CPU:s. Every ic have an unique address (sometimes selectable) and therefore many ic:s can be connected to the same bus. A disadvantage is the price because many of these ic:s are expensive. One possible project would be to connect a clock-circuit to the linkport (PCF8593 from Philips) and place the circuit (1 ic, 1 capacitor and 1 crystal) inside your TI85. By using a ZS-program, you'll have a real-time clock. The circuit can be powered from the linkport because it's high (+5 V) in stand-by. The clock-chip will probably not interfere with the ordinary linkprotcol since the I2C- and TI85 link-prototcol is different (I cannot guarantee this since I haven't tested it yet). Per Finander e-mail: pfimdt93@tufvan.hv.se An example (using a PCF8574 - Remote 8 bit IO-expander) Sending data (switch on/off LED:s): 1. Send a start-pulse by calling "I2CStart". This causes all I2C circuits to listen. 2. Send an address (A=$40 to select the 8574 below, bit0=0 -> Write) by calling "I2CSend". 3. If the Carry Flag = 0, then the device responed to the address (everythings ok). Otherwise an error occured, no response -> call "I2CStop", wait a moment and goto step 1 again. 4. A = $3F, enable LED0 & 1 (bit 0-3 must be high if you want to be able to read the switches). Check the CF to see if the device got the byte (step 3). 5. Call "I2CStop" to end communication with PCF8574. Receiving data (read switches): 1. Send a start-pulse by calling "I2CStart". This causes all I2C circuits to listen. 2. Send an address (A=$41 to select the 8574 below, bit0=1 -> Read) by calling "I2CSend". 3. If the Carry Flag = 0, then the device responed to the address (everythings ok). Otherwise an error occured, no response -> call "I2CStop", wait a moment and goto step 1 again. 4. Call "I2CRead" to read one byte from the IO-port (don't call "I2CReadA" because you only want to read one byte from the device. If the TI85 sends an acknowledge, then the device expects to send more data and the I2CStop-pulse wont work). 5. if any of bit 0 - bit 3 (in a-register) is zero,then one or more of the keys are down. 6. Call "I2CStop" to end communication with PCF8574. It's possible to have up to 8 PCF8574 on the bus since A0-A2 can be changed (and 8 PCF8574A too because the high address bits (=0111), are different from the PCF8574 (=0100)). ------------------------------------------------------------------- +-------- /-- --- ---| To TI85 < | \-- --- ---| | | | +-------- | | | | | Gnd | | +-------------------------------------------+ | | | +-------------------------------+ | | | | | +-------------------+ | | | | | | | +-------+ | | | | | | | | | | | | | | | +++ +++ +++ +++ | | | | -> | | 470 | | | | | | | | \---/ \---/ \---/ \---/ | | Ohm | | | | | | | | \ / \ / \ / \ / -> +5V | | | | | | | | | | ----- ----- ----- ----- | | | +++ +++ +++ +++ | | | | -> | | | | | | | | | | | | | | | | | | | LED0 | LED1 | LED2 | LED3 +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ | | | | |16| |15| |14| |13| |12| |11| |10| | 9| +------+------+------+ +----------------------------------------+ | | Vdd SDA SCL Int P7 P6 P5 P4 | | | | | +-+ | | | | PCF8574 | | +-+ | | | | | | A0 A1 A2 P0 P1 P2 P3 Vss | | +----------------------------------------+ | | 1| | 2| | 3| | 4| | 5| | 6| | 7| | 8| | +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ | | | | | | | | | | | | | o | o | o | o | | | | | | -+ -+ -+ -+ | | | | | o | o | o | o | | | | | | | S0 | S1 | S2 | S3 | | | | | | | | | | | +----+----+----+----+----+----+----+-------+ | - Gnd Address 0 1 0 0 0 0 0 R/W ---------- A2 A1 A0 PCF8574 Port 0 - 3 must be set to 1 if you want to read the switches. Port 4 - 7 : Bit = 1 -> LED On ------------------------------------------------------------------- ; ------------------------------------------ ; 2 ; I C routines for ZShell 4.0 ; ; Per Finander, 1996 ; e-mail: pfimdt93@tufvan.hv.se ; ; +-------- ; /-- --- ---| ; < | To TI85 ; \-- --- ---| ; | | | +-------- ; | | | ; SDA SCL Gnd ; ; ------------------------------------------ ; (updated 31 May 1996) ; ; Send I2C Start pulse ; I2CStart: ld a,$C0 ; SDA 1 ""\ CALL_(I2CDT) ; 0 \_____ ld a,$C4 CALL_(I2CDT) ; SCL 1 """""\ jr I2CDT ; 0 \__ ; ; Send I2C Stop pulse ; I2CStop: ld a,$CC ; SDA 1 /"" CALL_(I2CDT) ; 0 _____/ CALL_(I2CDT) ld a,$C0 ; SCL 1 /""""" jr I2CDT ; 0 __/ ; Send A to I2C bus ; ; In : A - Byte to send ; Out: CF - =1 if no acknowledge was returned (error) I2CSend: push bc ld b,$08 I2CNextB: rlca push af ld a,$CC jr nc,I2CNotS xor $04 I2CNotS: CALL_(I2CPulse) pop af djnz I2CNextB ld a,$C8 CALL_(I2CPulse) rr c pop bc ret ; Read byte from I2C bus, Send an acknowledge ; ; Out: A = byte I2CReadA: ld a,$CC jr I2CRead1 ; Read byte from I2C bus, Don't send an acknowledge ; ; Out: A = byte I2CRead: ld a,$C8 I2CRead1: push bc push af ld b,$08 xor a I2CGetB: push af ld a,$C8 CALL_(I2CPulse) pop af rr c rla djnz I2CGetB ld b,a pop af CALL_(I2CPulse) ld a,b pop bc ret I2CPulse: CALL_(I2CDT) CALL_(I2CDT) ld c,$07 in c,(c) I2CDT: out ($07),a xor $08 ret