parallel port communication...

For issues with communication ports, protocols, etc.
Post Reply
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

sample code....

Post by thesanman112 »

hey richard i hope your still looking....here is what i have learned so far...
i know its just the basics of what is happening at parallel port,,i have just found some pseudo code for i2c programming...looks very simple...now the only key im missing is how to get the programmer i built to do the pseudo code spec's like change sda to 0 or 1..ect.ect..once i find that step out ill be one step closer...

Code: Select all

dim as byte a,b,c,d 
'accessing data line is like this************
'set port to 00000000 
'OUT 888, 0 
'set port to 10000000 
'OUT 888, 1 
'set port to 01000000 
'OUT 888, 2 
'set port to 00100000 
'OUT 888, 4 
'set port to 00010000 
'OUT 888, 8 
'sets more than one port at a time'set port to 10110000 

OUT 888,0
'OUT 888, 255' 8 outputs 
'out 890,1111''''what will these actually do with i2c programmer!!!!!4 lines

a=inp(888)'data lines---- 8 of them for output ..reads current out ports. 
b=inp(889)' status lines----5 of them input ..reads current in ports
c=inp(890)' control lines----4 of them ---highest value 15

print a,bin(a),hex(a)
print b,bin(b),hex(b)
print c,bin(c),hex(c)
' why does out 890,63 result with 11111111
print:print
for a=1 to 15
    out 890,(a)
print inp(890),bin(inp(890))
next

sleep
end
Richard
Posts: 3096
Joined: Jan 15, 2007 20:44
Location: Australia

Post by Richard »

The bits are easy so I have been creeping forward sorting out the protocol rather than the bits. The protocols are quite involved and so I want to know what is needed before I have to stop and start again. It will take a day or two to produce something that will work.
So far just the empty shell:

Code: Select all

'===========================================================
' FreeBASIC program for Philips I2C Parallel Port Adapter 
'===========================================================
' first work out the addresses for the parallel port used
Enum
    LPT1 = &H378
    LPT2 = &H278
    
    BaseAddress = LPT1          ' select your parallel port
    
    DataReg = BaseAddress + 0
    StatReg = BaseAddress + 1
    ContReg = BaseAddress + 2
End Enum

'-----------------------------------------------------------
Function ReadI2cByte As Integer
    
    ReadI2cByte = -1
End Function

'-----------------------------------------------------------
Sub WriteI2cByte(Byval DataByte As Integer)
    
End Sub

'-----------------------------------------------------------
Sub TestI2cInterface
    ' test both loops to see if they are there 
    
End Sub


'-----------------------------------------------------------
Sleep

'===========================================================
' All has been based on the following data which may be wrong
'===========================================================
'  Port       Base addr
'   LPT1        378h
'   LPT2        278h
'-----------------------------------------------------------
'  Address     Register
'   Base+0      data
'   Base+1      status
'   Base+2      control
'-----------------------------------------------------------
' DB25   Signal   Dirn   Register  Bit  Invert  I2C Programmer
'   9     data7    I/O    data      7    no      Data Out
'  11     busy     in     status    7    yes     Data In
'  15     nError   in     status    3    no      Clock In
'  17     nSelP    out    control   3    yes     Clock Out
'-----------------------------------------------------------
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

ya

Post by thesanman112 »

i hear that...its the protocol thats the problem...i have found some c source code for some of it but it relies on different type of programmer.
to get the philips programmer to say set sda high, thats where the problem lies, or to i2c read byte..i see you have started to work on it...there has to be something out there that tells the specific state of ports to make a i2c state....i gotta google that...

here is some example written in c to get sda and scl states to change,
unfortunately i dont program in c...

http://www.phanderson.com/printer/8574/8574.html
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

is this right?

Post by thesanman112 »

'heres some inportant stuff....
'inp(890)'''''the 1 in the binary 1000, thats the status of pin 1
'inp(890)''''' the 1 in bin 0100, is actually pin 14
''''''''''''''''''''''''''''0010, is p''''''''''' 16
''''''''''''''''''''''''''''0001, ''''''''''''''''17
'is this correct?

OR
inp(891) is actually pin 14? i hope im wright....
maddogg6
Posts: 824
Joined: Dec 07, 2005 22:58
Contact:

Post by maddogg6 »

maybe stick with the hex numbers to avoid confusion...

but to get a single bit's value..

Code: Select all

controlReg = &h378+2
mask = &B00000010 'mask bit 1
if (INP(controlReg) AND mask) = &B00000010 then ? "HIGH"
if (INP(controlReg) AND mask) = &B00000000 then ? "LOW"
Tho - thats the line feed output, so unless you are reading the control port prior to writing to it (as is recommended in some cases for some reserved bits) - its value is moot.
note: you schematic in one of your other threads on this doesnt show pin 14 connected.

Conversely - to set a single bit...

Code: Select all

mask = &B00000010
OUT controlReg, (inp(controlReg) OR mask) 
Would set controlRegs bit 1 to High while preserving the rest of the bits we dont want to change.
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

check thus...

Post by thesanman112 »

who whould think it coul be so difficult....lots of reading...

Code: Select all


out(890,0111)'high state with scl'
'out (889,175)
'sleep hclk

out(888,1)'set sda high''toggle to clock sync
sleep 4
'sleep
'end

'call i2c bus to attention

out(888,255)'sda low--
'out (889,167)
out(890,1) 'scl low--
nw=timer:do:loop until timer>(nw+.0005)
out(888,0) 'sda high--
'out (889,175)
out(890,0111)'scl high--
nw=timer:do:loop until timer>(nw+.005)

generateclock:
if cclock=0 then 
'out (889,167)'
out(890,0000) 'scl low--
nw=timer:do:loop until timer>(nw+.005)
end if

b=inp(889)' the magic
'send random address
if multikey(72) then mode=1

if mode=1 and ack=0 then
    a=int(rnd*256)
  if count=7 then a=1 
    out(888,a)
count=count+1
if count=8 then mode=0:ack=1:count=0
end if
'889 47,167,175
'check for ack bit

if b<>inp(889) then 
  
  'status bit is cycling......
  
  'locate 2,1: 
   'if inp(889)=0 then v$=v$+"0"
   print bin(inp(888)),bin(inp(889)),bin(inp(890)),count,clock
   clock=1
 ' ack=0
  ' print bin(inp(a))inp(889)
end if
if clock=1 then
    'if bin(inp(889))="10100111" then 
       
     '   nw=timer:do:loop until timer>(nw+.005)'175 1111    167 0111
      ' out(889,167):cclock=0:b=0
   ' end if
b=0
end if
if clock=2 then mode=0
'if mode=0 then
    

if cclock=0 then
'out (889,175)'
out(890,0111)'scl high--
nw=timer:do:loop until timer>(nw+.05)
end if

'0100101 1' last 1 means read,0 would mean write
'sda or inp(888) will change while scl is low,you read it after the change.or while scl is high.

'locate 1,1:print bin(inp(888)),bin(inp(889)),bin(inp(890))

if multikey(1) then goto over:
goto generateclock

over:
sleep
sleep 
end

Last edited by thesanman112 on Mar 04, 2008 5:21, edited 1 time in total.
maddogg6
Posts: 824
Joined: Dec 07, 2005 22:58
Contact:

Post by maddogg6 »

you need to take that single data bit - and convert the *serial* data into a parallel value..
consider serial data comes in 1 bit at a time....
1
0
1
1
0
1
0
0
1
1
1
0

Now convert that to '101101001110'

What you are doing is turning the par port into a serial port. (aka 'bit banging')

So to read that bit - put into a temp var - SHL add another ... SHL etc - for a total of 8 times for each byte to receive. (use a loop)
Psudocode- (assuming msb's are sent first ???)
Do: If bit is high the tempvar += 1 else tempvar +=0:SHL:loop


BUT - before all that - it *looks* like you have to send the right combination of bits to the eeprom - and it may need an address too - there exists a command to READ info from it, and which address - and theres an acknowledge too - *then* wait for the incoming data - but I am not certain, Richard made it sound like there are different modes I2C can work in ??

And I am far from an FB expert either - I am more familiar with schematics/electronics... so - you'll probably need to wait for Richard or someone else to show the code that should work with I2C protocols... its way beyond my skills as well.
Richard
Posts: 3096
Joined: Jan 15, 2007 20:44
Location: Australia

Post by Richard »

State of play now. Still working away slowly at it.

Code: Select all

'===========================================================
' FreeBASIC program for Philips I2C Parallel Port Adapter 
'===========================================================
' first work out the addresses for the parallel port used
Enum    ' these are all integer constants
    LPT1 = &H378    ' IBM PC standards
    LPT2 = &H278
    
    BaseAddress = LPT1          ' select your parallel port
    
    DataRegAddr = BaseAddress + 0
    StatRegAddr = BaseAddress + 1
    ContRegAddr = BaseAddress + 2
End Enum

'-----------------------------------------------------------
Sub StartEvent
    ' 1. clock and data are initially both high
    ' 2. pull data low   sda = 0
    ' 3. pull clock low  scl = 0
    ' 4. clock and data are both now low
End Sub

'-----------------------------------------------------------
Sub RepeatedStartEvent
    ' 1. initially clock is low and data is high
    ' 2. set clock high   scl = 1
    ' 3. pull data low    sda = 0
    ' 4. pull clock low   scl = 0
    ' 5. clock and data are both now low
End Sub

'-----------------------------------------------------------
Sub MasterStopEvent
    ' 1. initially clock is low and data is high
    ' 2. pull data low    sda = 0
    ' 3. set clock high   scl = 1
    ' 4. set data high    sda = 1
    ' 5. clock and data are both now high
End Sub

'-----------------------------------------------------------
Sub WriteI2cByte(Byval DataByte As Integer)
    ' 1. initialy clock is low, data is high
    ' for bit = 7 to 0 step -1
    '   3. set clock high   scl = 1
    '   4. transmit data bit   sda = bit 
    '   5. pull clock low   scl = 0
    ' next bit
    ' 6. set clock high     scl = 1
    ' 7. wait for data bit low = ack
    ' 8. pull clock low     scl = 0
    ' 9. wait for data high
    ' data is now high and clock low
End Sub

'-----------------------------------------------------------
Function ReadI2cByte As Integer
    ' 1. initially clock is low and data is high
    ' 2. wait for data to go high following slave ack
    ' For bit = 7 to 0 step -1
    '   3. set clock high   scl = 1
    '   4. read bit data
        ReadI2cByte = 2 * ReadI2cByte ' + sda bit
    '   5. pull clock low   scl = 0
    ' Next bit
    ' 6. set clock high     scl = 1
    ' 7. wait for data bit low = ack
    ' 8. pull clock low     scl = 0
    ' ReadI2cByte now contains the received byte
End Function

'-----------------------------------------------------------

Sleep

'===========================================================
' All has been based on the following data which may be wrong
'===========================================================
'  Port       Base addr
'   LPT1        378h
'   LPT2        278h
'-----------------------------------------------------------
'  Address     Register
'   Base+0      data
'   Base+1      status
'   Base+2      control
'-----------------------------------------------------------
' DB25   Signal   Dirn   Register  Bit  Invert  I2C Programmer
'   9     data7    I/O    data      7    no      Data Out
'  11     busy     in     status    7    yes     Data In
'  15     nError   in     status    3    no      Clock In
'  17     nSelP    out    control   3    yes     Clock Out
'-----------------------------------------------------------
' speed limit to 100kbps = 10usec per cycle, slow = reliable.
' you will have to use Timer because cache inside PC will run
'  so fast that the I2C peripheral can't keep up. Example code.
' t = timer + 1e-5  ' wait 10 usec
' do while Timer < t
' loop
'===========================================================
' I2C sends MSBit first for all addresses and all data.
' After sending 8 bits the slave replies with acknowledge. 
'===========================================================
' To read a single data byte from an eeprom 
'-----------------------------------------------------------
' 1. StartEvent
' 2. Send eeprom chip address byte with Read/write bit low  1010aaa0
' 3. Send MSB address of data in eeprom                     0000aaaa
' 4. Send LSB address of data in eeprom                     aaaaaaaa
' 5. RepeatedStartEvent
' 6. Send eeprom chip address byte with Read/write bit high 1010aaa1
' 7. Receive 8 data bits from eeprom
' 8. MasterStopEvent
'===========================================================
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

check this

Post by thesanman112 »

heres what im workin on.....incorperated into your psuedo

Code: Select all

writebyte:
'******Sub WriteI2cByte(Byval DataByte As Integer)
    ' 1. initialy clock is low, data is high
     for dc = 7 to 0 step -1
    '   3. set clock high   scl = 1
    out(890,1)
    '   4. transmit data bit   sda = bit 
    if ep(dc)=1 then out(888,255) else out(888,-1)
    '   5. pull clock low   scl = 0
    out(890,253)
    next dc
    ' 6. set clock high     scl = 1
    out(890,1)
    ' 7. wait for data bit low = ack
    ack=inp(888)
    ' 8. pull clock low     scl = 0
    out(890,253)
    ' 9. wait for data high<-----sda cant switch with scl low
    ' data is now high and clock low

readbyte:
'******Sub readI2cByte(Byval DataByte As Integer)
    ' 1. initialy clock is low, data is high
     for dc = 7 to 0 step -1
    '   3. set clock high   scl = 1
    out(890,1)
    '   4. read data bit   sda = bit 
     a=inp(888)    
     if a=255 then ep(dc)=1 else ep(dc)=0 
    '   5. pull clock low   scl = 0
    out(890,253)
    next dc
    ' 6. set clock high     scl = 1
    out(890,1)
    ' 7. wait for data bit low = ack
    ack=inp(888)' have to dechiper the '*00000000' in this binary i think.??
                                                       'should switch to low or 0 i think...
    ' 8. pull clock low     scl = 0
    out(890,253)
    ' 9. wait for data high<-----sda cant switch with scl low
    ' data is now high and clock low
return

heres what im not sure about,,,when we wait for cycles of clock, ect,ect it has to be timed correctly...a 5 millisecond seems to be min. should we use sleep? also when recieved data byte comes in will the value actually be 255, or maybe 253? the only way to be sure is to specify relevant pin data, will it be high or low..0 or 1..thats the best way..im thinking anyways. The first most important thing seems to be clock sync or i2c init.....
Richard
Posts: 3096
Joined: Jan 15, 2007 20:44
Location: Australia

Post by Richard »

I’m still working on that program to drive your adapter.

The hold time delays are 5 microseconds, not milliseconds. Sleep counts milliseconds, Timer counts microseconds. There is a bit of code at the bottom of my last program in the comments that will do that delay.

The PC controller inverts some signals, the adapter also inverts some. Which inverts cancel? You could test what you have to do to make scl and sda high or low. Then read back in to check scl and sda are changing and if they are inverted or not. That exercise is simple and protocol free, you may have to slow it down with delay5us. Document the ports, bits and post them some time so I can check my analysis.
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

ya..

Post by thesanman112 »

just about done....heres what we got so far....these tidbit actually cycle the sda and scl of my programmer respectively as noted in rem's
and the specific bytes are changeing in control and status bits...

Code: Select all

'set both lines high
out(890,0111)'high state with scl'
'sleep hclk
out(888,1)'set sda high''toggle to clock sync
sleep 4

'call i2c bus to attention
out(888,255)'sda low--
out(890,1) 'scl low--
nw=timer:do:loop until timer>(nw+.005)
out(888,1) 'sda high--
out(890,0111)'scl high--
nw=timer:do:loop until timer>(nw+.05)

generateclock:
out(890,1) 'scl low--
nw=timer:do:loop until timer>(nw+.005)
print bin(inp(888)),bin(inp(889)),bin(inp(890))
out(890,255)'scl high--
nw=timer:do:loop until timer>(nw+.05)
print bin(inp(888)),bin(inp(889)),bin(inp(890))

if multikey(1) then goto over:
goto generateclock

over:
sleep
sleep 
end
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

heres whats more inportant....

Post by thesanman112 »

i decided to hook up some leds to dechiper a little more of the programmer interface...also looks pretty...
i figured I would hack the hard way..short ground to clk and ground to sda to see what ports are changing....

only the status bits change and here is the binary for each....

at reast
10101111 or 175

ground to clk(clock)
10100111 or 167

ground to sda(data)
101111 or 47

this should be all that is needed from the programmer interface...

also to add a neat note...the demo software I have that acccess's the i2c bus programmer..i logged the output to ports with my first fb basic..heres the output..

data ..... status ..... control
11101111.... 101111 .... 11011111
11111111.... 101111 .... 11011111
11101111.... 101111 .... 11011111
11111111.... 101111 .... 11011111
11101111.... 101111 .... 11011111
1111111 .... 10101111 .... 11011111
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

programmer.

Post by thesanman112 »

hey Richard?did you make your programmer yet?
man oh man im been working at this every free second for 2-3 days straight.....



im lost.....


when i want to read a byte It doesnt seem to keep going....
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Post by D.J.Peters »

Hello Richard
you know the SELECT() function is more stable as any other sleep command.
it works in kernel driver space not the user space on Win32 and Linux

Joshy

Code: Select all

dim as TIMEVAL TimeOut
TimeOut.tv_sec = 0 
TimeOut.tv_usec=50000 ' = 5 mili seconds
Select(0,NULL,NULL,NULL,@TimeOut)
Richard
Posts: 3096
Joined: Jan 15, 2007 20:44
Location: Australia

Post by Richard »

@D.J.Peters, thanks for that, I had not met select() before. We need to give CMOS logic time to settle (think). The maximum data hold time needed is 4.7 microseconds (NOT milliseconds), so I use:

Code: Select all

Dim As Double dt 
dt = Timer + 5e-6	‘ add 5us
Do : Loop Until Timer > dt
This makes sure we do not get back too soon. It does not matter if we wait 20 milliseconds, but we don’t want to do it too often because there are a few tens of thousands of delays to wait. This code loops in less than 1 microsecond which slows things down just enough when the code runs in a cached CPU. The multiple millisecond delays elsewhere in this topic are just being used testing the signals.

@thesanman112
1. I think you must be using –lang qb. You need to change to –lang fb in your command line soon.

2. Try to use &h hexadecimal ! It is much easier to follow when programming I/O ports.

3. You must output a high voltage on scl or sda before you will be able to see a change when you pull it to ground because it is open collector. Check you can see the voltage change from low to high before reading the input bits. You should be able to put a bit out through pin 17, (or 9) and see it come back inverted on pin15, (or 11). Notice all the inversions in the adapter and in the PC internals. Read the parallel I/F status port and display it using the Hex(databyte,2) or the Bin(databyte, 8) so you can see the bits change. If this does not work, look at the voltages on the parallel port input pins to see if your adapter hardware is the problem.

4. Get a copy of http://www.nxp.com/acrobat_download/lit ... 340011.pdf
THE I2C-BUS SPECIFICATION.

5. No point at this stage using an eeprom, the adapter, interface software and protocol are critical. All the code is quite involved and must be correct. That is why I am creeping forward very slowly and carefully.

6. No, I haven’t built an adapter yet. I just want to get the protocol sorted out first. There are lots of things that compete for my time. Some have priority over this code, I also have to sleep for a couple of hours every now and then.
Post Reply