I2C AND SPI BUSES
ABOUT THE I2C AND SPI BUSES
The PCF8583 clock chip on board the TDS2020F is one of a number of available devices that will hang on the same 2-wire bus. Philips, Xicor, Microchip and others make these I2C devices. They can be a few metres from the computer board without having to add buffers. The SPI bus also has a data and clock serial connection to peripherals, but additionally needs a chip select (and other wires sometimes). Usually I2C and SPI chips can share the same two principal wires without problem. Maxim, Burr Brown, Analog Devices and others make SPI peripherals. Chips with similar buses, like Microwire from National Semiconductor, can also be used. Transfers on all these buses are synchronous and handshaken.
The PCF8574 and PCF8574A low cost chips are particularly useful for I/O expansion. You can connect up to 16 devices, giving 128 I/O lines, to just 2 wires of the I2C bus, see PARALLEL INPUT & OUTPUT EXPANSION, page 299. The TDS2020CM2 and TDS2020CAN adapters have an on-board socket for I2C Flash-EEPROMs, see ON-BOARD NON-VOLATILE MEMORY, page 257.
I2C BUS SOFTWARE
The TDS2020F has software to drive I2C devices at a speed up to 69k bits per second (48k with program in external Flash-EEPROM). The Forth words not only handle the data but also return a flag that is only true if the transfer actually happened.
For the I2C bus the main words are I2C! and I2C@ , the write and the read instructions, but the primitives from which they are constructed are made available since they enable you to use other modes in I2C peripherals, such as automatic internal address increment.
Each I2C chip has different possible chip addresses determined by the type of chip it is. For example the PCF8583 can be made addresses hex 50 or 51-on TDS2020F it is connected at address $50. Within each chip are several internal addresses that have nothing to do with the first one. In the case of the PCF8583 these are $00 to $FF and each represents one byte of data. $00 to $07 are clock registers, $08 to $0F are for alarms, $10 is used by clock software and the rest ($11 to $FF) are unused RAM. You can employ these as non-volatile memory by attaching a TDS2020BYN, TDS2020BYD or other battery.
Note that neither of these two addresses are the same as the microprocessor address space-that is something else again!
For example, to store 17 to address FF in the on-card clock & RAM chip:
$17 $FF $50 I2C!
A -1 (true) will be left on the stack if the transfer is successful, which it should be. Try device address $51 and you will find the transfer fails because there is no IC at that address. Recover the data like this:
$FF $50 I2C@
This leaves on the stack the validation flag with the data fetched underneath. Transfer times are of the order of half a millisecond.
Although you can do a lot with I2C! and I2C@ , it may be necessary to make up others from the primitives STARTI2C STOPI2C R1BYTE S1BYTE R1BIT . You can see the technique in use in files like #PCF8591.TDS.
When using I2C or SPI bus words on the TDS2020F the spare bits P10 P15 P16 & P17 should preferably be used as inputs since these words have to change the Data Direction Register of Port 1, and the unused bits are always afterwards set to 0 (for input).
SPI BUS SOFTWARE
Apart from the ready-made software for some SPI chips you can copy and modify primitives from files like #MAX186.TDS to interface TDS2020F to almost any serial synchronous peripheral device, whether it is called SPI or by another name. These primitives are written in assembler for speed.
USING CLOCK CHIP RAM
The following Forth words make it easy to use RAM in the clock chip for variables. Access time is slow (834�s write, 978�s read) but there is the added advantage that with a battery on pin VBATT (z3) the variables are non-volatile. The addresses 0 to hex 0F inclusive are clock registers in the chip and hex 10 is used as RAM on TDS2020F to keep track of the year number. Hex 11 to FF are free so put the first 16-bit variable at address hex 12 and the last at hex FE, giving a total of 119 16-bit non-volatile variables.
: !8583 ( n addr - ) \ Store 16-bit value n at address
>R DUP >< R@ $50 I2C! DROP R>
1+ $50 I2C! DROP ;
: @8583 ( addr - n ) \ Fetch 16-bit value n from address
DUP >R $50 I2C@ DROP >< R>
1+ $50 I2C@ DROP + ;
$12 CONSTANT XXXX
$14 CONSTANT YYYY
$16 CONSTANT ZZZZ . etc
Store to variables
$1234 XXXX !8583
$1234 YYYY !8583
$1234 ZZZZ !8583 . etc
Fetch from variables
ZZZZ @8583 . etc