Submitted by:
Glenn Clark
VersaTech Electronics
Parallax's Basic STAMP II has proved to be a very capable processor for a wide variety of tasks. Often STAMP based products require additional I/O capabilities, or the ability to perform tasks in background while it continues processing a foreground task. The I2C Xtender 73, made by Protean Logic Inc., can provide these capabilities with a minimum of additional components.
The Xtender can converter analog inputs to 8bit values for measuring voltages, etc. It can also generate PWM signals for motor control or servo control. It can count input pulses for measuring frequencies or RPM. It can control a stepper motor. It has 8 additional general purpose I/O pins. It has 128 bytes of RAM memory. And it can send and receive RS232 serial data.

The sample code below will not actually perform any useful task. It is simply a collection of two routines for writing to and reading from the Xtender IC. The trick here is to make these subroutines small enough to still have a useful amount of BS2 RAM and program space left.
When you use the si2c_write routine, simply assign an 8 bit address to the variable addr_byte, an 8 bit command to the variable comm_byte, and an 8 bit data value to the variable data_byte then execute: GOSUB si2c_write.
When you use the si2c_read routine, simply assign an 8 bit address to the variable addr_byte, an 8 bit command to the variable comm_byte and execute: GOSUB si2c_read. The variable data_byte will contain the 8 bit value read from the Xtender IC.
With these two routines you can use any of the resources on the Xtender device. These subroutines use 5 bytes and 2 bits of the STAMP's RAM, and 218 EEprom bytes. Which leaves approximately 20 bytes and 6 bits of RAM and 1830 EEprom bytes for your application to use.
The following application notes give actual working code samples for utilizing some of the Xtender with a STAMP II.
' Sample routines to do I2C on a STAMPII
' Special Thanks to Victor Epand
' Simulated Inter-Integrated Circuit driver (si2c)
' This driver consists of two internal routes (si2c_wbyte and si2c_rbyte)
' and two user functions (si2c_write and si2c_read)
' the si2c_write function needs three byte parameters:
' addr_byte: the i2c address of the device writing to
' comm_byte: the sub command to tell the device what to do
' data_byte: the byte of data to use for the command
'
' the si2c_read function needs two parameters and returns a byte:
' addr_byte: the i2c address of the device reading from
' comm_byte: the sub command to tell the device what to read
' data_byte: the value returned from the device that was read
' This routine used pin 0 as the I2C clock pin and pin 1 as the I2c data pin
' Both of these pins must be pulled high. Both of these pins should initially
' be configured as inputs at power up.
si2c_clk CON 0 ' I/O pin for I2C Clock line
' IN0 is used in some situations
si2c_data CON 1 ' I/O pin for I2C data line
' IN1 is used in some situations
' the following are the storage required by the si2c routines.
in_byte VAR byte ' used internally by the si2c_wbyte function
bit_count VAR byte ' used internally by both the si2c_wbyte and rbyte
send_ack VAR bit ' used to tell rbyte if it should ack or not
exit_ack VAR bit ' used to indicate if wbyte got an ack or not
data_byte VAR byte ' either the data to be written or the data just read
addr_byte VAR byte ' address of I2C device (LSB=read indicator)
comm_byte VAR byte ' I2C sub command
si2c_wbyte: ' returns 1 if successful, 0 = NACK
' in_byte is byte to be written
bit_count=%10000000
si2c_wbyte_lp:
low si2c_clk
input si2c_data
IF (bit_count & in_byte) then si2c_wbyte_do1
low si2c_data
si2c_wbyte_do1:
bit_count=bit_count>>1
input si2c_clk
IF bit_count then si2c_wbyte_lp
' now test the acknowledge bit
low si2c_clk
input si2c_data
input si2c_clk
exit_ack=0
IF in1 then si2c_wbyte_ex
exit_ack=1
si2c_wbyte_ex:
return
si2c_rbyte: ' send_ack is set for a post ack or not
bit_count=%10000000
low si2c_clk
data_byte=0
input si2c_data
si2c_rbyte_lp:
input si2c_clk
si2c_rbyte_wt:
IF NOT in0 then si2c_rbyte_wt
IF NOT in1 then si2c_rbyte_dl
data_byte=data_byte|bit_count
si2c_rbyte_dl:
low si2c_clk
bit_count=bit_count>>1
IF bit_count then si2c_rbyte_lp
' send ack bit if required
low si2c_data
IF send_ack then si2c_rbyte_ak
input si2c_data
si2c_rbyte_ak:
input si2c_clk
return
si2c_write: ' must set addr, comm, and data before calling
low si2c_data ' generate a start bit
si2c_write_lp:
in_byte=addr_byte
gosub si2c_wbyte
IF NOT exit_ack then si2c_write_lp
in_byte=comm_byte
gosub si2c_wbyte
in_byte=data_byte
gosub si2c_wbyte
low si2c_clk ' generate stop bit
low si2c_data
input si2c_clk
input si2c_data
return
si2c_read: ' must set addr, comm, data_byte will have return
low si2c_data ' generate a start bit
IF NOT (%00000001 & addr_byte) then si2c_read_sk
si2c_read_lp:
in_byte=addr_byte
gosub si2c_wbyte
IF NOT exit_ack then si2c_read_lp
in_byte=comm_byte
gosub si2c_wbyte
low si2c_clk
low si2c_data
input si2c_clk
input si2c_data ' generate the stop
low si2c_data ' generate a start
addr_byte=addr_byte-1
si2c_read_sk:
in_byte=addr_byte
gosub si2c_wbyte
send_ack=0
gosub si2c_rbyte
low si2c_clk
low si2c_data
input si2c_clk
input si2c_data ' generate the stop bit
return
Protean Logic Inc. Copyright 05/06/04 Top of Page