No output buffering with devc-ser8250

Hello,
I am trying to achieve no output buffering with devc-ser8250 driver,
i.e. I want to transmit bytes as close to realtime as possible. Input
buffering is OK for me. I start devc-ser8250 with -O option, with
default on chip fifo’s off. The problem is that I can not go lower
than -O4, because serial output hangs. Basically I would like to send
only one byte at a time which I suppose would be -O1?

How can I setup the driver to have completely NO output buffering?

bobik: bobik atsign os dot pl

bobik wrote:

Hello,
I am trying to achieve no output buffering with devc-ser8250 driver,
i.e. I want to transmit bytes as close to realtime as possible. Input
buffering is OK for me. I start devc-ser8250 with -O option, with
default on chip fifo’s off. The problem is that I can not go lower
than -O4, because serial output hangs. Basically I would like to send
only one byte at a time which I suppose would be -O1?

How can I setup the driver to have completely NO output buffering?

bobik: bobik atsign os dot pl

You cannot. The driver will reserve 5 bytes in the output buffer for
output processing, so that characters will not be dropped/overwritten
when control characters are injected into the output data stream. If
there is no buffering, things like software flow control, or ONLCR
processing would cause data to be lost/dropped.

The driver shouldn’t allow you to set the buffer size smaller then the
reserved space + 1, I’ll PR this and update the driver.

In the case where the client application is writing one byte to the
driver at a time, that byte will always be written out to the hw before
the next call to write() by the client can occur. Data will only be
buffered up if multiple bytes are passed to the driver at a time.

-Joe

On Tue, 17 Jan 2006 10:47:22 -0500, Joe Mammone <hw@qnx.com> wrote:

I am trying to achieve no output buffering with devc-ser8250 driver,

The driver shouldn’t allow you to set the buffer size smaller then the
reserved space + 1, I’ll PR this and update the driver.

I understand then, that minimum safe setting is -O6, right? The driver
works for me with -O4 - is that unsafe?


In the case where the client application is writing one byte to the
driver at a time, that byte will always be written out to the hw before
the next call to write() by the client can occur. Data will only be
buffered up if multiple bytes are passed to the driver at a time.

But this implies, that I cannot use simple blocking write. How can I
know, that the transmitter (or holding register at least) is empty and
I can submit next byte? I can of course just in8() appropriate status
register and check TxE bit, but this is so rude and unPosix…

Why I need this:

I have to send continous stream of back-to-back bytes over serial
line, but in critical moments I have to insert some special sequence
into the outgoing stream as soon as possible. Using blocking write
with -O6 I would have 6 or 7 bytes latency. I could read data back
from another port looped back locally, but there is just to many of
them, I can have up to 8 ports to service, so another 8 just for
controll would be to much.

On Tue, 17 Jan 2006 10:47:22 -0500, Joe Mammone <hw@qnx.com> wrote:

I’ll PR this and update the driver.

Just one after thought: If You are going to update the driver, could
You perhaps think of one more option to it, namely
no_output_buffering ?

With this option handling special sequences and controll chars would
be solely application responsibility, the driver would just pass bytes
out not looking at their meaning at all. I think I am not the only one
with this problem, I have read some posts concerning this before with
no good solution.

bobik: bobik atsign os dot pl

bobik wrote:

I understand then, that minimum safe setting is -O6, right? The driver
works for me with -O4 - is that unsafe?

What version of the OS are you using?

In the case where the client application is writing one byte to the
driver at a time, that byte will always be written out to the hw before
the next call to write() by the client can occur. Data will only be
buffered up if multiple bytes are passed to the driver at a time.


But this implies, that I cannot use simple blocking write. How can I
know, that the transmitter (or holding register at least) is empty and
I can submit next byte? I can of course just in8() appropriate status
register and check TxE bit, but this is so rude and unPosix…

Why do you say that? The driver is single threaded and will only process
one request at a time, so when only writing one byte at a time, the
serial driver will have written the character out to the hardware before
returning back to the client. So the drivers output buffer will be empty
when the client unblocks from the write() call.

The hardware should have more then enough time to push the one character
out before the initial call to write() unblocks, another call to write()
gets issued, and the driver processes the new request to the point of
writing the new character to the hardware.

Are you actually seeing a latency problem, and have you verified that
this latency is due to chacacters being buffered by the driver?

Regards,

Joe

Why I need this:

I have to send continous stream of back-to-back bytes over serial
line, but in critical moments I have to insert some special sequence
into the outgoing stream as soon as possible. Using blocking write
with -O6 I would have 6 or 7 bytes latency. I could read data back
from another port looped back locally, but there is just to many of
them, I can have up to 8 ports to service, so another 8 just for
controll would be to much.

On Wed, 18 Jan 2006 10:18:14 -0500, Joe Mammone <hw@qnx.com> wrote:

Why do you say that? The driver is single threaded and will only process
one request at a time, so when only writing one byte at a time, the
serial driver will have written the character out to the hardware before
returning back to the client.

This is not the behavior I observe. Apparently driver returns, until
it has its output buffer filled.

I am using QNX 6.3 SP2

Driver is started via script:

devc-ser8250 -F -b 50 -O4 200,7 208,7 210,7 218,7 220,7 228,7 230,7
238,7 &
sleep 2
stty par=even bits=8 stopb=2 </dev/ser1

serial is opened like this:

fdBuszOut= open( buszName, O_WRONLY );
buszName referrs /dev/ser1

writes follow like this:

x=write( fdBuszOut,&tel[0], 1);
After write there is diagnostic printf, so I see what happens.

What I see is: initially write does not block. Four consecutive writes
follow one after another. Only after that - write starts blocking.
When my program ends I can see driver outputting whats left in it,
without any writes to it. I can see it on the receiving end and on
diagnostic leds also. Bit speed is low, so things are visible this
way.

For trials I have set various -Ox numbers. The driver allways
initially swallows x writes without blocking, then blocks. After
ending writes it still spits out whats in it. Without -O it goes for
so long, that I have to kill it and start again.

bobik: bobik atsign os dot pl

On Wed, 18 Jan 2006 10:18:14 -0500, Joe Mammone <hw@qnx.com> wrote:

What version of the OS are you using?

Correction: OS is QNX 6.3 SP1, not SP2

I’ve done some testing on my side and have verified that only 1 byte is
ever in the drivers output buffer at any given time…Actually in doing
this testing and reviewing the code a little closer, it is actually
impossible to have more then 1 byte in the obuf in this scenario. The 5
byte reserved space is not available to data sent by user apps, so with
a 6 byte output buffer there is only 1 byte available to be used. (i.e.
if there is one byte in the output buffer, all other client requests
will be blocked, until that byte if passed to the hardware.)

You may see up to 3 characters being transmitted after the user app goes
away, this will only happen if the baud rate is very small. One byte can
be in the UARTs shift register, one byte in the transmit hold
register, and one byte in the drivers software output buffer. As the
baud rate increases this affect will diminishes as the hw will be able
to push the character out of the shift register before the next round of
data occurs.

-Joe


bobik wrote:

On Wed, 18 Jan 2006 10:18:14 -0500, Joe Mammone <> hw@qnx.com> > wrote:


Why do you say that? The driver is single threaded and will only process
one request at a time, so when only writing one byte at a time, the
serial driver will have written the character out to the hardware before
returning back to the client.


This is not the behavior I observe. Apparently driver returns, until
it has its output buffer filled.

I am using QNX 6.3 SP2

Driver is started via script:

devc-ser8250 -F -b 50 -O4 200,7 208,7 210,7 218,7 220,7 228,7 230,7
238,7 &
sleep 2
stty par=even bits=8 stopb=2 </dev/ser1

serial is opened like this:

fdBuszOut= open( buszName, O_WRONLY );
buszName referrs /dev/ser1

writes follow like this:

x=write( fdBuszOut,&tel[0], 1);
After write there is diagnostic printf, so I see what happens.

What I see is: initially write does not block. Four consecutive writes
follow one after another. Only after that - write starts blocking.
When my program ends I can see driver outputting whats left in it,
without any writes to it. I can see it on the receiving end and on
diagnostic leds also. Bit speed is low, so things are visible this
way.

For trials I have set various -Ox numbers. The driver allways
initially swallows x writes without blocking, then blocks. After
ending writes it still spits out whats in it. Without -O it goes for
so long, that I have to kill it and start again.

bobik: bobik atsign os dot pl

On Wed, 18 Jan 2006 17:08:34 -0500, Joe Mammone <hw@qnx.com> wrote:

I’ve done some testing on my side and have verified that only 1 byte is
ever in the drivers output buffer at any given time…
Thank you for your effort. It looks like we talk about different

drivers. Mine is /sbin/devc-ser8250 37,096 bytes from Apr-30-2004.

Could you perhaps post your driver startup parameters and your test
code?

bobik: bobik atsign os dot pl

On Wed, 18 Jan 2006 17:08:34 -0500, Joe Mammone <hw@qnx.com> wrote:

I’ve done some testing on my side and have verified that only 1 byte is
ever in the drivers output buffer at any given time…

I also have done some isolated testing:

I start the driver like this:

slay devc-ser8250
devc-ser8250 -F -O4 3f8,4 &
sleep 2
stty baud=50 par=even bits=8 stopb=2 </dev/ser1

Following test app I compile by simply “cc sertest.c”
and run “./a.out>out.txt”


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main( void )
{
int fd;
int i;
struct timespec before, after;
double db, da;

fd = open( “/dev/ser1”, O_WRONLY);

for( i=0; i<30; i++)
{
clock_gettime( CLOCK_REALTIME, &before );
write( fd, “x”, 1);
clock_gettime( CLOCK_REALTIME, &after );
db = (double)before.tv_sec +
(double)before.tv_nsec/1000000000;
da = (double)after.tv_sec +
(double)after.tv_nsec/1000000000;
printf(“write nr %d blocked for %f sec.\n”, i,da-db);
}
return( EXIT_SUCCESS );
}

And this is the output:

write nr 0 blocked for 0.001000 sec.
write nr 1 blocked for 0.000000 sec.
write nr 2 blocked for 0.000000 sec.
write nr 3 blocked for 0.000000 sec.
write nr 4 blocked for 0.000000 sec.
write nr 5 blocked for 0.751885 sec.
write nr 6 blocked for 0.000000 sec.
write nr 7 blocked for 0.000000 sec.
write nr 8 blocked for 0.000000 sec.
write nr 9 blocked for 0.958853 sec.
write nr 10 blocked for 0.000000 sec.
write nr 11 blocked for 0.000000 sec.
write nr 12 blocked for 0.000000 sec.
write nr 13 blocked for 0.957853 sec.
write nr 14 blocked for 0.000000 sec.
write nr 15 blocked for 0.000000 sec.
write nr 16 blocked for 0.000000 sec.
write nr 17 blocked for 0.957854 sec.
write nr 18 blocked for 0.000000 sec.
write nr 19 blocked for 0.000000 sec.
write nr 20 blocked for 0.000000 sec.
write nr 21 blocked for 0.957853 sec.
write nr 22 blocked for 0.000000 sec.
write nr 23 blocked for 0.000000 sec.
write nr 24 blocked for 0.000000 sec.
write nr 25 blocked for 0.957853 sec.
write nr 26 blocked for 0.000000 sec.
write nr 27 blocked for 0.001000 sec.
write nr 28 blocked for 0.000000 sec.
write nr 29 blocked for 0.956854 sec.

From this I can see, that despite writing only one byte at a time
initially only fifth write blocks, and later only every fourth. Output
buffer size is, as above -O4 shows, 4. With baud 50 every one write
should have blocked for about 0.25 sec, not every fourth for 1 sec.

OS is QNX 6.3 SP1 and the driver is
/sbin/devc-ser8250 37,096 bytes from Apr-30-2004.

Could perhaps somebody else interested repeat my test and confirm/deny
my results?

bobik: bobik atsign os dot pl

bobik wrote:

On Tue, 17 Jan 2006 10:47:22 -0500, Joe Mammone <> hw@qnx.com> > wrote:


I am trying to achieve no output buffering with devc-ser8250 driver,


The driver shouldn’t allow you to set the buffer size smaller then the
reserved space + 1, I’ll PR this and update the driver.


I understand then, that minimum safe setting is -O6, right? The driver
works for me with -O4 - is that unsafe?



In the case where the client application is writing one byte to the
driver at a time, that byte will always be written out to the hw before
the next call to write() by the client can occur. Data will only be
buffered up if multiple bytes are passed to the driver at a time.


But this implies, that I cannot use simple blocking write. How can I
know, that the transmitter (or holding register at least) is empty and
I can submit next byte? I can of course just in8() appropriate status
register and check TxE bit, but this is so rude and unPosix…

Why I need this:

I have to send continous stream of back-to-back bytes over serial
line, but in critical moments I have to insert some special sequence
into the outgoing stream as soon as possible. Using blocking write
with -O6 I would have 6 or 7 bytes latency. I could read data back
from another port looped back locally, but there is just to many of
them, I can have up to 8 ports to service, so another 8 just for
controll would be to much.

You can try to use function tcflush( fd, TCOFLUSH) for removing data
from output buffer before you call write function, and then you can send
your high priority data. (of course some data from output buffer will be
lost)

Regards
Marian.

With -O4 the write call will fail with a “Server fault on msg pass” with
an SP1 driver. Please do a “use -i /sbin/devc-ser8250” to ensure that
you using an SP1 driver. You size does not match, however you binary may
be stripped. Please also try using -O6 it is the minimum that should
be used.

Attached are the output from your test code (with the addition of error
checking on the call to write) with the SP1 driver started with both -O4
and -O6.

use -i /sbin/devc-ser8250

NAME=devc-ser8250
DESCRIPTION=Character device driver for the 8250 chipset
DATE=2004/10/28-16:09:47-UTC
STATE=Stable
HOST=osbld
USER=osbuild
VERSION=6.3.0SP1
TAGID=330

\

/sbin/devc-ser8250 -F -b50 -O4

./ser_test

write: Server fault on msg pass
write nr 0 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 1 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 2 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 3 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 4 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 5 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 6 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 7 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 8 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 9 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 10 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 11 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 12 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 13 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 14 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 15 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 16 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 17 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 18 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 19 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 20 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 21 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 22 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 23 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 24 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 25 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 26 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 27 blocked for 0.001000 sec.
write: Server fault on msg pass
write nr 28 blocked for 0.002000 sec.
write: Server fault on msg pass
write nr 29 blocked for 0.001000 sec.

/sbin/devc-ser8250 -F -b50 -O6

./ser_test

write nr 0 blocked for 0.001000 sec.
write nr 1 blocked for 0.000000 sec.
write nr 2 blocked for 0.020997 sec.
write nr 3 blocked for 0.198970 sec.
write nr 4 blocked for 0.199969 sec.
write nr 5 blocked for 0.198970 sec.
write nr 6 blocked for 0.198970 sec.
write nr 7 blocked for 0.199969 sec.
write nr 8 blocked for 0.198970 sec.
write nr 9 blocked for 0.198969 sec.
write nr 10 blocked for 0.199970 sec.
write nr 11 blocked for 0.198970 sec.
write nr 12 blocked for 0.198970 sec.
write nr 13 blocked for 0.199970 sec.
write nr 14 blocked for 0.199969 sec.
write nr 15 blocked for 0.198970 sec.
write nr 16 blocked for 0.199969 sec.
write nr 17 blocked for 0.199970 sec.
write nr 18 blocked for 0.198969 sec.
write nr 19 blocked for 0.199970 sec.
write nr 20 blocked for 0.199969 sec.
write nr 21 blocked for 0.198970 sec.
write nr 22 blocked for 0.199970 sec.
write nr 23 blocked for 0.199969 sec.
write nr 24 blocked for 0.198970 sec.
write nr 25 blocked for 0.199969 sec.
write nr 26 blocked for 0.199970 sec.
write nr 27 blocked for 0.198970 sec.
write nr 28 blocked for 0.199969 sec.
write nr 29 blocked for 0.199969 sec.

Regards,

Joe

bobik wrote:

On Wed, 18 Jan 2006 17:08:34 -0500, Joe Mammone <> hw@qnx.com> > wrote:


I’ve done some testing on my side and have verified that only 1 byte is
ever in the drivers output buffer at any given time…


I also have done some isolated testing:

I start the driver like this:

slay devc-ser8250
devc-ser8250 -F -O4 3f8,4 &
sleep 2
stty baud=50 par=even bits=8 stopb=2 </dev/ser1

Following test app I compile by simply “cc sertest.c”
and run “./a.out>out.txt”


#include <stdio.h
#include <stdlib.h
#include <time.h
#include <unistd.h
#include <sys/types.h
#include <sys/stat.h
#include <fcntl.h

int main( void )
{
int fd;
int i;
struct timespec before, after;
double db, da;

fd = open( “/dev/ser1”, O_WRONLY);

for( i=0; i<30; i++)
{
clock_gettime( CLOCK_REALTIME, &before );
write( fd, “x”, 1);
clock_gettime( CLOCK_REALTIME, &after );
db = (double)before.tv_sec +
(double)before.tv_nsec/1000000000;
da = (double)after.tv_sec +
(double)after.tv_nsec/1000000000;
printf(“write nr %d blocked for %f sec.\n”, i,da-db);
}
return( EXIT_SUCCESS );
}

And this is the output:

write nr 0 blocked for 0.001000 sec.
write nr 1 blocked for 0.000000 sec.
write nr 2 blocked for 0.000000 sec.
write nr 3 blocked for 0.000000 sec.
write nr 4 blocked for 0.000000 sec.
write nr 5 blocked for 0.751885 sec.
write nr 6 blocked for 0.000000 sec.
write nr 7 blocked for 0.000000 sec.
write nr 8 blocked for 0.000000 sec.
write nr 9 blocked for 0.958853 sec.
write nr 10 blocked for 0.000000 sec.
write nr 11 blocked for 0.000000 sec.
write nr 12 blocked for 0.000000 sec.
write nr 13 blocked for 0.957853 sec.
write nr 14 blocked for 0.000000 sec.
write nr 15 blocked for 0.000000 sec.
write nr 16 blocked for 0.000000 sec.
write nr 17 blocked for 0.957854 sec.
write nr 18 blocked for 0.000000 sec.
write nr 19 blocked for 0.000000 sec.
write nr 20 blocked for 0.000000 sec.
write nr 21 blocked for 0.957853 sec.
write nr 22 blocked for 0.000000 sec.
write nr 23 blocked for 0.000000 sec.
write nr 24 blocked for 0.000000 sec.
write nr 25 blocked for 0.957853 sec.
write nr 26 blocked for 0.000000 sec.
write nr 27 blocked for 0.001000 sec.
write nr 28 blocked for 0.000000 sec.
write nr 29 blocked for 0.956854 sec.

From this I can see, that despite writing only one byte at a time
initially only fifth write blocks, and later only every fourth. Output
buffer size is, as above -O4 shows, 4. With baud 50 every one write
should have blocked for about 0.25 sec, not every fourth for 1 sec.

OS is QNX 6.3 SP1 and the driver is
/sbin/devc-ser8250 37,096 bytes from Apr-30-2004.

Could perhaps somebody else interested repeat my test and confirm/deny
my results?

bobik: bobik atsign os dot pl

On Thu, 19 Jan 2006 10:46:30 -0500, Joe Mammone <hw@qnx.com> wrote:

use -i /sbin/devc-ser8250

VERSION=6.3.0SP1
You were right again, obviously > :slight_smile: > My driver reports VERSION=6.3.0. I

do not know, how has it happened. I distinctively remember applying
SP1 to my target system. Whats more curious - another node with SP2
applied (without SP1) also has an old driver :frowning:

You have been very patient with me, thank you very much.
bobik: bobik atsign os dot pl


bobik: bobik atsign os dot pl