Maker Pro
Maker Pro

Confused about synchronous communications

J

Jon Slaughter

Jan 1, 1970
0
I'm trying to implement a general prarallel port communications program but
I'm a little confused about the timing issues involved.

In all of the protocols I'm looking at(I2C, SPI, and ICSP) it seems that the
communications is edge triggered.

What I see is that a data bit is sent when the clock changes and then the
clock changes again.

something like


Data
/---------\
/ \
/ \----



\ /---\
\ / \
\---/ \---/
Clock


So is this normally the case? Also, when does the data have to be valid? On
the second edge transition? (So in some sense the clock is 2x the data rate
so actually the data would be sampled 1/2 inbetween the data transfer rate?)

Basically I'm trying to figure out how I am to write my routine as at the
moment I'm and just changing the clock with the the data but then I realized
that there is no way to keep it synched up perfectly.

I also thought about sorta offseting the clock half way sorta like the above
but with

Data
/---------\
/ \ /
/ \---------/



/---------\
/ \ /
------/ \---------/
Clock

But then this has a problem of the data changing towards the end of the
clock.

So, I guess my actual question is, when is it required for the data to be
valid?


Data
/*****-----\
/ \
/ \----



\ /---\
\ / \
\---/ \---/
Clock

Do I have to get "valid data" at **** so that it can be sampled by every
other edge(every rising edge in this case)? If so, is this pretty much how
all synchronous communications works?

Thanks,
Jon
 
J

Jon Slaughter

Jan 1, 1970
0
I guess what I'm asking is if the data needs only to be valid on the rising
edge(or falling edge) of the clock and maybe a little after... and hence by
having the clock rate 2x faster it will "sample" it in the middle of the
data which means I have about 1/2 the clock to get the data there?
 
C

colin

Jan 1, 1970
0
Jon Slaughter said:
I'm trying to implement a general prarallel port communications program
but I'm a little confused about the timing issues involved.

In all of the protocols I'm looking at(I2C, SPI, and ICSP) it seems that
the communications is edge triggered.

What I see is that a data bit is sent when the clock changes and then the
clock changes again.

something like


Data
/---------\
/ \
/ \----



\ /---\
\ / \
\---/ \---/
Clock


So is this normally the case? Also, when does the data have to be valid?
On the second edge transition? (So in some sense the clock is 2x the data
rate so actually the data would be sampled 1/2 inbetween the data transfer
rate?)

Basically I'm trying to figure out how I am to write my routine as at the
moment I'm and just changing the clock with the the data but then I
realized that there is no way to keep it synched up perfectly.

I also thought about sorta offseting the clock half way sorta like the
above but with

Data
/---------\
/ \ /
/ \---------/



/---------\
/ \ /
------/ \---------/
Clock

But then this has a problem of the data changing towards the end of the
clock.

So, I guess my actual question is, when is it required for the data to be
valid?


Data
/*****-----\
/ \
/ \----



\ /---\
\ / \
\---/ \---/
Clock

Do I have to get "valid data" at **** so that it can be sampled by every
other edge(every rising edge in this case)? If so, is this pretty much how
all synchronous communications works?

you have to meet set up and hold times,
this is the time before and after the clock edge used
to clock in the data that the data has to be valid
often the most conveneint
way to do this is to make the data change on the
opposite clock edge.

so in your first diagram this would be the case with the clock rising edge
clocking in the data, and the data changing on the falling edge.

if you try to change both the clock and the data always
at the same time then what you have is double data rate,
this is more complicated and generaly uneccessary unless you
are going after very high data rates and wish to
reduce the inteference from the clock signal.


Colin =^.^=
 
J

Jon Slaughter

Jan 1, 1970
0
Jon Slaughter said:
I guess what I'm asking is if the data needs only to be valid on the
rising edge(or falling edge) of the clock and maybe a little after... and
hence by having the clock rate 2x faster it will "sample" it in the middle
of the data which means I have about 1/2 the clock to get the data there?

also, does this pretty much get all synch'ed communication? I know(I think
;) there are such things as level triggered but are they really used for
commerical devices? Bascailly do I have write a routine for both types? or
will get pretty much cover everything with edge triggered?
 
J

Jan Panteltje

Jan 1, 1970
0
But then this has a problem of the data changing towards the end of the
clock.

So, I guess my actual question is, when is it required for the data to be
valid?

Depends on the system.
Some systems data is clocked in on the positive edge of the clock,
and in some systems it is clocked in on the negative edge.

And, there could be systems were data is latched when the clock is high,
and systems where data is latched when the clock is low......

In i2c you need to pay especialy attention to start and stop sequences too..

Look at the datasheets is all I can say.
 
J

Jan Panteltje

Jan 1, 1970
0
I guess what I'm asking is if the data needs only to be valid on the rising
edge(or falling edge) of the clock and maybe a little after... and hence by
having the clock rate 2x faster it will "sample" it in the middle of the
data which means I have about 1/2 the clock to get the data there?

Imagine a 74HC74 D flipflop.
It is positive edge triggered.
If you put data on the D input, and send the clock from 0 to 1,
that data will appear on the Q output.

After it has changed state (respect hold time) you can do with data what you want,
and lower clock whenever you want (after min clock hold time).

Again look at the datasheets, it should be there.
 
T

Tom2000

Jan 1, 1970
0
I'm trying to implement a general prarallel port communications program but
I'm a little confused about the timing issues involved.

Jon,

I'm not sure it's safe to generalize. My advice is to refer to the
data sheet for your device of interest and see what the manufacturer
wants and expects.

In general, though, it looks like you have the general principle
down pat.

When I'm bitbanging, I don't try to center the clock, as a rule. I
put my data up, then immediately toggle a clock pulse. Next data bit,
toggle again. Repeat as necessary, as long as that's within the
manufacturer's timing specs.

When I'm reading, I read the data as soon as I detect the
appropriate clock transition.

So far, it's worked.

BTW - when reading, make sure you understand the data sheet.
You'll find yourself seeing the first data bit present before the
first clock pulse. If you don't prepare yourself for that conditon,
you'll be chasing your tail.

The data sheet is your friend!

Good luck,

Tom
 
J

Jon Slaughter

Jan 1, 1970
0
Tom2000 said:
Jon,

I'm not sure it's safe to generalize. My advice is to refer to the
data sheet for your device of interest and see what the manufacturer
wants and expects.

In general, though, it looks like you have the general principle
down pat.

When I'm bitbanging, I don't try to center the clock, as a rule. I
put my data up, then immediately toggle a clock pulse. Next data bit,
toggle again. Repeat as necessary, as long as that's within the
manufacturer's timing specs.

When I'm reading, I read the data as soon as I detect the
appropriate clock transition.

So far, it's worked.

BTW - when reading, make sure you understand the data sheet.
You'll find yourself seeing the first data bit present before the
first clock pulse. If you don't prepare yourself for that conditon,
you'll be chasing your tail.

The data sheet is your friend!

Yes, I have been looking at it but was confused because I wasn't sure when
the data had to be rock solid. It showed the data changing but doesn't say
when it has to be ready. I should have known that if its edge triggered then
it should be on an edge. But this is the first time I've done any low level
communications like this and I just wanted to be sure. The data sheets
giving the timing but they assume you already understand the basics.

Just didn't want to assume something that wasn't true and then spend days
trying to figure out why my code isn't working.

I'll go ahead and try to implement the stuff down and see what happens. Just
a slight modification of my code(sending clock 2x as fast).

Thanks,
Jon
 
J

Jon Slaughter

Jan 1, 1970
0
Jan Panteltje said:
Depends on the system.
Some systems data is clocked in on the positive edge of the clock,
and in some systems it is clocked in on the negative edge.

And, there could be systems were data is latched when the clock is high,
and systems where data is latched when the clock is low......

In i2c you need to pay especialy attention to start and stop sequences
too..

Yes, but I don't think that is anything to difficult? I just have to make
sure I set the lines correctly and wait atleast the minimum times.
Look at the datasheets is all I can say.

I did but was confused when exactly the data on the data line had to be
correct. They show the data edge right and the clock edge rise at the same
time. This can't work though and I didn't really notice the clock was 2x as
fast ;/ It make sense and everything but I really wanted to make sure
before I went any farther with my code(which I essentially have the clock at
the same rate as the data(but I was just testing my code with some leds so
it wasn't critical).


Thanks,
Jon
 
J

Jon Slaughter

Jan 1, 1970
0
colin said:
you have to meet set up and hold times,
this is the time before and after the clock edge used
to clock in the data that the data has to be valid
often the most conveneint
way to do this is to make the data change on the
opposite clock edge.

Yeah, this is exactly what I was going to do. Just that the data sheets
don't point that out because I guess its suppose to be implicit. I was
thinking, for some reason, that the data had to be valid when it reached
level but its just when the edge of the clock is triggered(which ever one it
is, which isn't important cause I can just invert the clock I suppose)
so in your first diagram this would be the case with the clock rising edge
clocking in the data, and the data changing on the falling edge.

if you try to change both the clock and the data always
at the same time then what you have is double data rate,
this is more complicated and generaly uneccessary unless you
are going after very high data rates and wish to
reduce the inteference from the clock signal.

Well, thats what I coded

public void SyncSend(ParallelPortPins DataLines, int[] DataBits)
{
int m = (((int)DataLines) | (int)ClockPin) ^ ((int)InvertedPins);
int cp = ((int)ClockPin) ^ ((int)InvertedPins);
int clock = cp;


for (int k = 0; k < DataBits.Length; k++)
{
// Toggle ClockPin
clock = clock ^ cp;
DataBits[k] = (DataBits[k] & ~cp) ^ clock;

// Send data before clock
if ((((int)ClockPin) >> 16) > 0)
{
Data = (Data & ~m) | (DataBits[k] & m);
Control = ((Control & ((m >> 16) & 0xFF)) | ((DataBits[k] & m)} else
{
Control = ((Control & ((m >> 16) & 0xFF)) | ((DataBits[k] & m)Data = (Data & ~m) | (DataBits[k] & m);
}

Thread.SpinWait(DataRate);
}
}

Basically I just sendt he clock like its a piece of data but I alternate it
every time I send a piece of data. Of course then I thought that this
wouldn't work because theres no way to make sure the data would be valid
before the clock changed(if it was edge triggered... which I think I was
thinking that it was level triggered and thats why I did it).

I just have to change the clock 2x as fast I think and it should work fine.
Then I just have to worry about getting it to work within the protocol but I
think I can handle that.

Thanks,
Jon
 
J

Jon Slaughter

Jan 1, 1970
0
Jan Panteltje said:
Imagine a 74HC74 D flipflop.
It is positive edge triggered.
If you put data on the D input, and send the clock from 0 to 1,
that data will appear on the Q output.

After it has changed state (respect hold time) you can do with data what
you want,
and lower clock whenever you want (after min clock hold time).

Yeah. that was the way I was thinking about it... but the timing diagrams
don't show this. They show the data like I graphed it in the OP and not
cutting it in half were the data isn't necessarily valid. I was thinking
that it had to be valid on the whole level and that it had to do this on the
edge.


I think I got it now.

Thanks,
JOn
 
J

Jonathan Kirwan

Jan 1, 1970
0
<snip>
you have to meet set up and hold times,
<snip>

Jon Slaughter? These are the two phrases to get nailed hard into your
head... "set up time" and "hold time." You should look them up, but
in general the idea is that a digital input needs a certain amount of
time while the data is stable __before__ you 'clock it' in -- the set
up time. And, that same input requires a certain amount of time that
you need to keep that same data stable __after__ you clock it -- the
hold time. These surround your clock edge, for edge-triggered inputs.

If you are bit-banging, you can often ignore all if you change the
latching clock edge on a different cpu cycle than you change the data
-- because most of the time your bit banging is way, way slower than
the digital latch its talking to. So I think a lot of programmers
don't even know that it would be a good idea to read a datasheet, just
do the same old bit banging they've done in the past, and manage to
sneek by in life without getting caught. But in some cases, it can
get you hard.

Most cpu datasheets will provide some documentation on the worst case
rise time and worst case fall time (often different figures) for their
I/O pins relative to the cpu clock cycle. If you change an I/O pin,
or think you did on some cpu cycle edge, it really takes place some
time later on. If the cpu has multiple clocks per instruction cycle,
it may happen synchronous to that internal clock between instructions,
plus a little analog delay to that. But if you change the clock edge
on a later instruction from the data change, then you are assured of
at least one cpu cycle delay, which is usually more than enough. If
you try and change two I/O pins at once, the data and clock, then you
are probably playing with fire unless you have some reason to believe
otherwise. A delay line on the clock pin, for example, or else that
the data sheet of the target device says that the setup time is zero
and puts the setup+hold into its hold time spec because one is
internally delayed relative to the other, perhaps.

Jon
 
C

colin

Jan 1, 1970
0
Jon Slaughter said:
colin said:
you have to meet set up and hold times,
this is the time before and after the clock edge used
to clock in the data that the data has to be valid
often the most conveneint
way to do this is to make the data change on the
opposite clock edge.

Yeah, this is exactly what I was going to do. Just that the data sheets
don't point that out because I guess its suppose to be implicit. I was
thinking, for some reason, that the data had to be valid when it reached
level but its just when the edge of the clock is triggered(which ever one
it is, which isn't important cause I can just invert the clock I suppose)
so in your first diagram this would be the case with the clock rising
edge
clocking in the data, and the data changing on the falling edge.

if you try to change both the clock and the data always
at the same time then what you have is double data rate,
this is more complicated and generaly uneccessary unless you
are going after very high data rates and wish to
reduce the inteference from the clock signal.

Well, thats what I coded

public void SyncSend(ParallelPortPins DataLines, int[] DataBits)
{
int m = (((int)DataLines) | (int)ClockPin) ^ ((int)InvertedPins);
int cp = ((int)ClockPin) ^ ((int)InvertedPins);
int clock = cp;


for (int k = 0; k < DataBits.Length; k++)
{
// Toggle ClockPin
clock = clock ^ cp;
DataBits[k] = (DataBits[k] & ~cp) ^ clock;

// Send data before clock
if ((((int)ClockPin) >> 16) > 0)
{
Data = (Data & ~m) | (DataBits[k] & m);
Control = ((Control & ((m >> 16) & 0xFF)) | ((DataBits[k] & m)} else
{
Control = ((Control & ((m >> 16) & 0xFF)) | ((DataBits[k] & m)Data = (Data & ~m) | (DataBits[k] & m);
}

Thread.SpinWait(DataRate);
}
}

Basically I just sendt he clock like its a piece of data but I alternate
it every time I send a piece of data. Of course then I thought that this
wouldn't work because theres no way to make sure the data would be valid
before the clock changed(if it was edge triggered... which I think I was
thinking that it was level triggered and thats why I did it).

I just have to change the clock 2x as fast I think and it should work
fine. Then I just have to worry about getting it to work within the
protocol but I think I can handle that.

it also depends how fast you are sending and how fast you are polling at the
receiving end.
if the port you are receiving with doesnt actually 'clock' the data in
then you have to make sure you poll
it fast enough to detect both the high and low state of the clock.

if you are sending quite slow you could actually afford to toggle the clock
and change the data at the same time, when the receiving end detects the
clock has changed it quickly reads the port again
and the data should be stable at that time.

it is sometimes relied on that the hold time is 0
so that the clock and data can be changed at the same time,
but this is not good if the clock can be delayed more than the data wich
could happen with long cable,
it is possible to overcome this by introdicing a delay on the data,
some chips have tunable data delays to allow the fastest comunication
possible.

Colin =^.^=
 
J

Jon Slaughter

Jan 1, 1970
0
Jonathan Kirwan said:
Jon Slaughter? These are the two phrases to get nailed hard into your
head... "set up time" and "hold time." You should look them up, but
in general the idea is that a digital input needs a certain amount of
time while the data is stable __before__ you 'clock it' in -- the set
up time. And, that same input requires a certain amount of time that
you need to keep that same data stable __after__ you clock it -- the
hold time. These surround your clock edge, for edge-triggered inputs.

ok. I had some intuitive idea about didn't know the exact terms. I was
uncertain when the set up time started in the datasheets. I know now though
;)
If you are bit-banging, you can often ignore all if you change the
latching clock edge on a different cpu cycle than you change the data
-- because most of the time your bit banging is way, way slower than
the digital latch its talking to. So I think a lot of programmers
don't even know that it would be a good idea to read a datasheet, just
do the same old bit banging they've done in the past, and manage to
sneek by in life without getting caught. But in some cases, it can
get you hard.

Yeah, thats why I'm trying to get more information about it. I know I could
just bang them and probably get it to work but I'd know enough about it so I
don't have any anomalous behavior.
Most cpu datasheets will provide some documentation on the worst case
rise time and worst case fall time (often different figures) for their
I/O pins relative to the cpu clock cycle. If you change an I/O pin,
or think you did on some cpu cycle edge, it really takes place some
time later on. If the cpu has multiple clocks per instruction cycle,
it may happen synchronous to that internal clock between instructions,
plus a little analog delay to that. But if you change the clock edge
on a later instruction from the data change, then you are assured of
at least one cpu cycle delay, which is usually more than enough. If
you try and change two I/O pins at once, the data and clock, then you
are probably playing with fire unless you have some reason to believe
otherwise. A delay line on the clock pin, for example, or else that
the data sheet of the target device says that the setup time is zero
and puts the setup+hold into its hold time spec because one is
internally delayed relative to the other, perhaps.

I think I do not have to worry about that though? The clock itself will
change 2x as fast and the edge trigger will never change with data because
the data is twice as slow. Basically every other edge will change with the
data but thats not the edge that triggers so its no big deal which one comes
first?

Thanks,
Jon
 
D

Don Bowey

Jan 1, 1970
0
I'm trying to implement a general prarallel port communications program but
I'm a little confused about the timing issues involved.

In all of the protocols I'm looking at(I2C, SPI, and ICSP) it seems that the
communications is edge triggered.

What I see is that a data bit is sent when the clock changes and then the
clock changes again.

something like


Data
/---------\
/ \
/ \----



\ /---\
\ / \
\---/ \---/
Clock


So is this normally the case? Also, when does the data have to be valid? On
the second edge transition? (So in some sense the clock is 2x the data rate
so actually the data would be sampled 1/2 inbetween the data transfer rate?)

Basically I'm trying to figure out how I am to write my routine as at the
moment I'm and just changing the clock with the the data but then I realized
that there is no way to keep it synched up perfectly.

I also thought about sorta offseting the clock half way sorta like the above
but with

Data
/---------\
/ \ /
/ \---------/



/---------\
/ \ /
------/ \---------/
Clock

But then this has a problem of the data changing towards the end of the
clock.

So, I guess my actual question is, when is it required for the data to be
valid?

In the synchronous data work I've done, at the business machine interfaces
data is transmitted on the positive going clock edge and it is read during
the negative going clock edge; for each direction of transmission. The data
should be valid for most of the bit-length, but by sampling at the center at
the receiver, any affects from jitter will be essentially eliminated.
 
J

Jon Slaughter

Jan 1, 1970
0
it also depends how fast you are sending and how fast you are polling at
the receiving end.
if the port you are receiving with doesnt actually 'clock' the data in
then you have to make sure you poll
it fast enough to detect both the high and low state of the clock.

For my communications I don't have to poll but I will eventually add that
ability. There are some major problems that I see with polling because I
cannot do it in a consistent way(because of windows). I will try and poll it
fast as possible but not sure how its going to work out cause I haven't done
any tests.
if you are sending quite slow you could actually afford to toggle the
clock
and change the data at the same time, when the receiving end detects the
clock has changed it quickly reads the port again
and the data should be stable at that time.

Ok, I see what your saying. Basically the set up time is "artificial" in
that its only used because it takes time to get stable data? So if I know
for a fact that I can do something like this

out data
out clock

and the setup time is just a few cycles of the then it would work just fine
because the data would be valid(by assumption). Of course I'll still needt
toggle the clock 2x unless it would be both + and - edge triggered?


Although the problem I have, because I was thinking about using this method
which I called "interleaved" where I offset the clock 1/2 the clock freq so
its

out data
delay
out clock
delay
out data
....

so the clock always changes in the middle of when the data
changes(approximately). This wouldn't work with just a single edge trigger
though.

The problem I wast thinking is right at the transition between two
consecutive data changes. Basically, Does the data have to be valid durring
the whole hold time or just basically durning most of it at the start? (I
would imagine it depends on the integrity of the clock signal though?)


it is sometimes relied on that the hold time is 0
so that the clock and data can be changed at the same time,
but this is not good if the clock can be delayed more than the data wich
could happen with long cable,
it is possible to overcome this by introdicing a delay on the data,
some chips have tunable data delays to allow the fastest comunication
possible.


Well, at this point I'm just trying to do simple I2C, SPI, and ICSP stuff
for a few projects I have in mind. I think just "bit-banging" is pretty
much going to do it though. Theres just a few issues I wanted to talk about
before I moved on so I didn't get down the wrong path.

Thanks,
Jon
 
J

Jon Slaughter

Jan 1, 1970
0
In the synchronous data work I've done, at the business machine interfaces
data is transmitted on the positive going clock edge and it is read during
the negative going clock edge; for each direction of transmission. The
data
should be valid for most of the bit-length, but by sampling at the center
at
the receiver, any affects from jitter will be essentially eliminated.

I'm not sure what you mean by sampling at the center? I shouldn't have to
sample anything because I'm in control of the master clock. (So basically I
can clock data to and from the slave?)

Although eventually I'll want to do some sorta asynchronous communications
and stuff like that were I will need to poll but this is going to be pretty
difficult under windows.

Thanks,
Jon
 
J

Jonathan Kirwan

Jan 1, 1970
0
I think I do not have to worry about that though? The clock itself will
change 2x as fast and the edge trigger will never change with data because
the data is twice as slow. Basically every other edge will change with the
data but thats not the edge that triggers so its no big deal which one comes
first?

If I understand you correctly then you are probably okay. I gather
you are saying that you DO change the data and clock at the same time,
but that when that takes place it is only on a benign clock change (in
other words, the clock edge that doesn't clock in the data but only on
the opposite phase.) Assuming set up and hold isn't a problem, that
seems okay. And with that terrible-looking c++ code I saw (I didn't
check to see when the data changed relative to the latching edge of
the clock), I am not much worried about the timing. I don't think
they build latches that slow or cpus that fast. ;)

Jon
 
J

Jon Slaughter

Jan 1, 1970
0
Jonathan Kirwan said:
If I understand you correctly then you are probably okay. I gather
you are saying that you DO change the data and clock at the same time,
but that when that takes place it is only on a benign clock change (in
other words, the clock edge that doesn't clock in the data but only on
the opposite phase.) Assuming set up and hold isn't a problem, that
seems okay. And with that terrible-looking c++ code I saw (I didn't
check to see when the data changed relative to the latching edge of
the clock), I am not much worried about the timing. I don't think
they build latches that slow or cpus that fast. ;)

Its actually C# code.

Essentially what I do is load the bits into an array and output them to the
port. But only on lines that are for output. So basically you would call the
code like

SyncSend(ParallelPortPins.Data0 | ParallelPortPins.Data1, new int[] {
i,j,k,l });
So that the only pins that are changed are the D0 and D1 + clock pins(which
is defined inside the class).

So all that mess is just masking out the pins that are to be changed and
putting the data in them (the data itself is in a special format and wastes
a lot of space but easier to work with(essentially matches the memory mapped
port).

The code I send only changes the data with the clock at the same rate... but
if I double the clock rate then its should match up just right and if its
the wrong edge then I can easily invert the pins.

The main problem now is actually implementing i2c. I'm not sure if I can
actually do it because its not clear to me(still reading over the specs) if
the clock is always in control of the master when sending and recieving
data. Basically I want to avoid polling for this as much as possible
because windows makes it a bitch to do.

My initial thoughts where that the master clock was always used to send and
recieve data and if thats the case then it shouldn't be a big problem. If
slaves take over the clock when they send data then its a problem cause I
have no way to know except for polling(or try to implement some interrupt
driver in windows which is probably much more trouble than its worth).

I think I'm going to go ahead and try to implement ICSP since that seems to
be the easiest and then see what happens.

Thanks,
Jon
 
J

Jan Panteltje

Jan 1, 1970
0
Yes, but I don't think that is anything to difficult? I just have to make
sure I set the lines correctly and wait atleast the minimum times.


I did but was confused when exactly the data on the data line had to be
correct. They show the data edge right and the clock edge rise at the same
time. This can't work though and I didn't really notice the clock was 2x as
fast ;/ It make sense and everything but I really wanted to make sure
before I went any farther with my code(which I essentially have the clock at
the same rate as the data(but I was just testing my code with some leds so
it wasn't critical).

Jon

I dunno what sort of code you have, asm, C, BASIC, or whatever, but for i2c
you could download C code from Philips IIRC.
I have open source drivers in C too, they are in iiclib.c
http://panteltje.com/panteltje/xkrs/xkrs-1.1.tgz
That program does i2c protocol via 3 par port pins.
 
Top