Re: TI-H: TI link protocol and PCB design software


[Prev][Next][Index][Thread]

Re: TI-H: TI link protocol and PCB design software




>How (electrically) does the TI protocol work? I understand what the format
>is to send data across, but I haven't found anything that describes how
>the data actually gets sent. Is there a clock and a data line (a
>synchronous connection), or it is some kind of async connection..?


    The rough answer is there are two data lines and a ground.  Sending
calculator pulls one to ground to signify the bit sent, and the recieving
one acks by pulling the opposite one to ground..(This is from memory;
someone who actually had to design link stuff should know the full answer,
but that's the really general idea.)

Wow.. here's a response to an earlier mail from you (October 96) on the same
topic:

Subject: Re: TI-H: TI85 Link Info?
From: KEITH T BURZINSKI <FFNP69C@prodigy.com>
Date: Mon, 21 Oct 1996 17:15:58, -0500
In-Reply-To: <TI-H: TI85 Link Info?>

----------------------------------------------------------------------------
----

>mpinsk41@maine.maine.edu wrote:
>>
>>         I've read through the basic link cable documents on ticalc.
org, but
>> I still have one question.
>>         The link cable has three wires: red, white, and ground.
From
>> reading, I seemed to get the impression that *both* red and white
transmit
>> *and* receive. Shouldn't one be transmit, the other recieve? If
I'm wrong,
>> does anybody know why TI did it this way? It seems like the
electronics
>> inside the calculator would have to be much more complicated, with
almost
>> no gain in function.
>>
>> Malin
>> mpinsk41@maine.maine.edu
>
>The TI does use both lines for data transfer. One of the two
actually
>carries the data, bit by bit, and the other provides a clock. The
clock
>is a signal provided by whichever calc is sending, so that the
receiving
>calc knows when the data lead is "for real"--not somewhere between
bits.
>Make sense?
>
>--
>Greg Hill
>http://braves.bhs.davis.k12.ut.us/
>ghill@lab.tech.bhs.davis.k12.ut.us
>greg_hill@email.state.ut.us
>
Sorry.  You're both WRONG!  :)
Here's how it ACTUALLY works:
First, you need to know that a low (0) signal is active and a high
(1) is considered inactive.  When you're not doing anything, you can
measure about 5 volts between R or W and the ground pin (sheild).
To send a bit, here is what happens:
First the sending calc pulls either R or W to ground, to indicate a 0
or 1, respectively.  The recieving calc then pulls the other wire to
ground, to confirm that the bit was recieved.  Both calcs then clear
the link (all lines are brought back to 1), and then repeat the
process for all 8 bits.


Here is a text file describing it in GREAT detail...
-----
This txt file covers the port 7 of the TI-85, that is the port that
is
connected to the link.  With the information presented here, you
should
know enough to be able to write a two player game, a file transfer
program,
or even connect two calculators together for any purpose.


Circuit-
The jack that connects the two calculators has three connections.
The big
one is GND.  Then other two are W and R.  They are both at 5V when
not
activated and pulled to ground when they are.


Example-
I wrote this program to help illustrate how the link works.  For now,
just
type it in, it will all be clear later. (hopefully)


#include "TI-85.H"


;Program Title
.org 0
.db "Port 7",0


Init:
     CALL_ROM(CLEARLCD)
KeyLoop:
     call GET_KEY
     cp   $37
     jr   z, Exit
     cp   $02                 ; <-?
     jr   z, SendW
     cp   $03                 ; ->?
     jr   z, SendR
     cp   $01                 ; \/ ?
     jr   z, SendWR
     cp   $04                 ; /\ ?
     jp   z, SendN



     ld   hl, $FC10
     in   a, ($07)
     ld   (hl), a
     ld   hl, $FC20
     ld   B, 11111111b
     ld   (hl), B


     jr   KeyLoop


SendN:
     ld   a, $C0
     out  ($07), a
     jr   KeyLoop


SendR:
     ld   a, $D4
     out  ($07), a
     jr   KeyLoop


SendW:
     ld   a, $E8
     out  ($07), a
     jr   KeyLoop


SendWR:
     ld   a, $FC
     out  ($07), a
     jr   KeyLoop


Exit:
     ld   a, $C0
     out  ($07), a
     ret
.end




This will display a guide line at the top left of the LCD and over
that it will show the status of port 7.  The Left, Right, Down, and
Up
keys will control the output of turning W, R, both W and R, and
neither
When you turn them active, you can see bits 2 and 3 turn on as they
are puuled to ground (0V).  Bits 1 and 0 show the input, notice if
it
is not connected to anything that it will show both, meaning that
they are
at 5V or not active.  When you turn on W or R, that pixel should shut
off
as it is pulled to ground, becomes 0V and is active. (0V=active,
5V=not
active).  Fool around with this, try hooking it up to someone elses
TI-85 and have them send or recieve stuff as you run port7.asm.
Learn
from it.


Sending Junk-
Now that you know how it works (you do, right?)  Here is how to make
it
do what you want.  Use the command
out ($07), a
to send what's in the accumulator to the port 7.  Here is what you
should
send:
11000000 ($C0) = Neither pulled to ground
11101000 ($E8) = W pulled to ground
11010100 ($D4) = R pulled to ground
11111100 ($FC) = W &amp; R pulled to ground
So you jsut put the value in the accumulator and then out it to port
7!


Recieving Junk-
To recieve is also simple, just read the bottom two bytes (remember
the
program at the begining)  Basicly if the bit is on then it is at 5V
and thus not active or off.  so you first
in a, ($07)
in order to put what's in port 7 into the accumulator. then you
and $03
to mask off bits 0 and 1, the input bits.  then all you do is compare
it
to what you want.
00000011 = Neither is pulled to ground
00000010 = R is pulled to ground
00000001 = W is pulled to ground
00000000 = R &amp; W are pulled to ground
NOTE: you cannot tell wheither YOUR TI-85 or the TI-85 on the other
end
of the link cable are pulling it to ground.  You might try also
putting
the rest into account, however.


Protocols-
The protocol that the TI-85 uses to send bytes is as follows:
The sending 85 pulls one wire for bit 0:
     W=1   R=0
The recieving 85 pulls the other wire in confirmation
Both 85s clear the link
Loop again for next bit


Sending Code-
After reading about all of this I was still confused, so I
dissasembled
the resieve and send byte routines of the TI-85's ROM.  I discovered
their address from another GREAT txt file on port 7 (Don't ask me
how
he figured them out) anyway, they are at page 5, 643Bh and 6559h
I will now go over and explain them (which is basicly the whole point


of this text file, the previous stuff was review)


;Send Byte   A=The sending byte
.org 0
     ld c, a        ; This just puts the byte to send in C
     ld b, $0008    ; There are 8 bits to send (Seriel remember)
SendBit:
     ld de, $FFFF   ; This is for the timing loop
     rr c           ; This rotates the register c right and puts the
right
                      bit in the carry flag.  So each loop has it's
bit
                      put in the carry flag.  Pretty neat.
     jr nc, SendR   ; If there is no carry (i.e. the current bit is
0)
                      then send a R
     ld a, $E8      ; Else send a W because we have a 1
     jp SendIt      ; Then actually Send it!!
SendR:
     ld a, $D4      ; We have a 0, so send a R (D4h)
SendIt:
     out ($07), a   ; This actually sends it!
WaitConfirmation:
     in a, ($07)    ; Read the port
     and $03        ; Mask off bits 1 and 0 (see above text)
     jp z, Continue ; If it is zero (both R and W pulled to ground,
                      then continue
     in a, ($07)    ; If not, then read the port and try again
     and $03
     jp z, Continue
     dec de         ; Both wern't active that means the calc on the
                      other side hasn't received it (The other TI
should
                      pull the other one to ground to show that it
has
                      recieved the bit) so loop through and try again.


                      It uses de as a counter (it was set in the
beg)
     ld a, d
     or e           ; This basiclly does or e,d and will make z 0 if
both
                      d and e are zero, or de is zero. (i.e. counter
is
                      0 and we are done with loop, or a time-out)
     jp nz, WaitConfirmation
Error:
     jp ErrorHandler; Branislav suggested this was an error handler,
                      I don't know, but whatever the case don't
include it
                      in your implementations.  Instead, put in a jr
to your
                      own error handlers.
     ld a, $0C      ; Get ready to clear R &amp; W (C0h = both off, see
above)
     out ($07), a   ; Actually clear them
     ld de, $FFFF   ; Get de counter ready for next loop to make sure


                      link is cleared.  when de reaches 0 it times
out.
ClearLoop:
     dec de
     ld a, d
     or e           ; Again this is or e,d and will continue if de is
not 0
     jr z, Error    ; We timed out, so go to error handler (see
above)
     in a, ($07)    ; Read the port 7 again
     and $03        ; Performs a Self-Destruct
     cp $03         ; makes sure link is cleared, or both are not
active
                      or both are at 5V
     jp nz, ClearLoop ; If not, then clear and wait again.
     djnz SendBit   ; Basiclky a 'dec b' &amp; 'jr nz, SendBit'  It will
loop
                      again to send the next bit
     ret            ; Goes back to your program


You should use a method similar to this when making your programs.
Make
sure to always shut off both W and R when you are done using them,
put
them at 5V, send C0h to port 7.  Isn't it amazing all the work that
calculator does while all you see is that little worm move in the
upper
right corner of your LCD. :)


Recieve Byte Code-
;Recieve Byte A=recieved byte
     .org 0
     ld b, $08      ; There are 8 bits to recieve
     ld de, $FFFF   ; Setup timeout counter to wait for bit
                      if this de reaches 0 it is a time-out and it
goes
                      to an error handler
     jr WaitLoopEnd ; This jumps to the end of the loop, I have NO
idea
                      why this "jr" is here???
WaitLoop:
     in a, ($07)    ; Read port 7
     and $03        ; Mask the last two bits
     jr z, Error    ; Cause an error if BOTH are active
     cp $03         ; Compare it to 11 (Both NOT active)
     jp nz, Continue; If at least one is active, continue.
                      Notice if both were active it would have caused
an
                      error, so this is really only one being active
     in a, ($07)    ; Read port 7 again
     and $03        ; Mask the last two bits
     jr z, Error    ; I think this will cause an error if they are
BOTH
                      active
     cp $03
     jp nz, Continue; Same as last time, continue if at lesat 1 is
active
     dec de         ; Decrease counter
     ld a, d
     or e           ; or d, e
     jp nz, WaitLoop; If counter (de) is not 0 then loop again.
     jp TimeOut     ; Cause an error if we timed out waiting for a
bit
Continue:
     sub $02        ; This is where is gets interesting.  It will
subtract
                      10b from the accumulator (or the last two bits
of
                      what it received)  Remember a W=1 R=0.
                      So:    W        R
                            01       10
                           -10 (02) -10
                           ----     ----
                            01 C     00
                      The C means the carry flag was set because the
result
                      was less then 0, (-1h)  So now the Carry flag
is set
                      if we recieved a W and clear if we recieved a R.
  NICE
     jp nc, Got0    ; Go to the part for receiving a 0 if we had no
carry
                      flag set (we got an R)
----------------------------------------------------------------------
-----
Got1:
     ld a, $D4      ; Get ready to send a R ($D4 = Send a R, see
above text)
     out ($07), a   ; Send the W in confirmation that we recieved the
bit.
                      now, both wires should be pulled
     rr c           ; This is neat.  We recieved a W or a 1, because
of that
                      our carry flag was set. so now we are rotating
that
                      carry flag into the register c.  So each loop
will
                      rotate the recieved bit into c until we have
the
                      complete byte.
     ld de, $FFFF   ; Get counter ready
LoopR:
     in a, ($07)    ; Read the link
     and $03        ; Tell the calc to emmit radio interference
     cp $02         ; Is the R (and ONLY the R) active?
                      The reason it does this is becasue when the
sending
                      85 receives the confirmation signal it will
clear it's
                      port, thus the W it sent will not be active
when
                      the port it clear.  The R will be, however,
because
                      WE are the ones pulling it.
     jp z, ClearLink
     dec de         ; lower time-out counter
     ld a, d
     or e           ; or e, d
     jp nz, LoopR   ; Loop until sending 85 has cleared it's side of
the
                      link.
     jr Error       ; We timed out, so cause an error.
----------------------------------------------------------------------
----
ClearLink:
     ld a, $C0      ; get ready to clear our side of the link
     out ($07), a   ; Just Do It!
     ld d, $04      ; Get counter ready.  The reason it is so low is
that
                      this time we aren't waiting for the other 85 to
do
                      anything.  We are just clearing our side, so it
SHOULD
                      clear AS SOON as we do it.  Thus the 3 loops.
ClearLoop:
     dec d          ; Lower counter
     jr z, NextBit  ; If we time-out it says, "oh well" and continues
with
                      the next loop.  We can do this because if there
is an
                      error, it will catch it on the next bit.  Note:
there
                      is no need for the or d, e shtuph because we
are
                      only dealing with the d, not de.
     in a, ($07)    ; See a pattern?
     and $03
     cp $03         ; Is it clear?
     jp nz, ClearLoop ; If it's not clear, try again
NextBit:
     djnz WaitLoop  ; Go back and do it ALL over again if B is not 0
                      i.e. we have more bits to recieve
     ld a, c        ; We don't have any more bits to recieve, so put
the
                      received byte in a.
     ret            ; and return ($C9)


----------------------------------------------------------------------
------
Got0:
     ld a, $E8      ; This is where we were sent if we got a R (0)
                      Put E8h into a to send a confirming W
     out ($07), a   ; Confirm
     rr c           ; rotate the 0 (of the carry flag) into the
register c
     ld de, $FFFF   ; Get counter ready for loop
LoopW:
     in a, ($07)    ; perform a memory checksum :)
     and $03        ; Mask off last two bits.
     cp $01         ; Is ONLY the W active.  (See above for indepth
analysis)
     jp z, ClearLink; Go clear link and finish
     dec de         ; Decrease counter
     ld a, d
     or e           ; or e, d
     jp nz, LoopW   ; Keep Looping!
Error:
     jr ErrorHandler ; This is where we are sent if there is an error


                      (except for one time at the beg) It goes off
                      somewhere in lala land.


OK!  You should now thoughrouly understand the port 7 and how to use
it.
Remember, don't limit yourself to this, get creative.  And also
remember I
didn't write this code, it is the ROM function call that is built
into
the TI-85.  I would like to thank Dan Eble (TI-85 GOD!), Branislav
Bozgai, and of course Texas Instruments.  If you have any comments or


questions you can reach me at:
site@xnet.co




Follow-Ups: