This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
Re: DSR latency
On Mittwoch, 12. February 2003 18:50, Nick Garnett wrote:
> Roland Caßebohm <roland.cassebohm@visionsystems.de> writes:
> > Yes with 38400bps I have no problems, but I want up to 460800bps. It
> > works till 115200bps, if I have a low trigger level. With trigger level 8
> > the UART starts to lose characters.
>
> OK. That makes things slightly different. I'm still surprised that you
> have a problem with a FIFO trigger of 8. That still gives you 8
> character times, nearly 700us at 115200bps, to recover.
I have seen some delays of more than 1ms, which I think has caused the
character lost.
But this problem I have found, in serial_read() and serial_write() the
scheduler is locked while the whole time data is read from or written to the
driver buffers. Because I have changed the buffer size to 1024, this can
cause such a long time.
I have attached a patch in which scheduler is only locked to make a copy of
the needed values of the buffer.
>
> None of the system alarm functions do anything significant, mostly
> they just wake a thread up somehow. So they should not be absorbing
> enormous amounts of time.
>
> Of course DSRs also get delayed by thread-level code when it claims
> the scheduler lock, so maybe a combination of several factors is
> causing problems.
>
> > I was thinking about before getting any data, using data_rcv_req() to get
> > a peace of the buffer and writing in the ISR direct in this buffer. In
> > the DSR I call then data_rcv_done() and get with data_rcv_req() a new
> > peace of the buffer.
>
> That's worth trying, but they only really work if you know how much
> data is coming, or can detect when there is no more to come. I'm not
> sure how well they would work for a normal serial device.
First I have started to use data_rcv_req() and data_rcv_done() in the the
actual DSR without changing the ISR. This seems to work well. I also think
about using an extra timer to get longer blocks of characters for the
application.
>
> > > The 1ms DSR latency you have seen is worrying, there's nothing is eCos
> > > that should be absorbing all that time. There must be something else
> > > going on. Either there is some software in a DSR which should not be
> > > there, or interrupts are being missed in the hardware, or maybe
> > > something is disabling interrupts for a long time.
> >
> > I think I have to search for the reason more.
>
> I would be very interested to find out where this time is going.
Roland
Index: serial.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/serial/current/src/common/serial.c,v
retrieving revision 1.17
diff -u -5 -p -r1.17 serial.c
--- serial.c 23 May 2002 23:06:27 -0000 1.17
+++ serial.c 13 Feb 2003 09:23:19 -0000
@@ -51,10 +51,11 @@
//==========================================================================
#include <pkgconf/io.h>
#include <pkgconf/io_serial.h>
+#include <cyg/hal/hal_diag.h>
#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>
#include <cyg/infra/cyg_ass.h> // assertion support
#include <cyg/infra/diag.h> // diagnostic output
@@ -222,10 +223,11 @@ restart_rx( serial_channel *chan, cyg_bo
static void
serial_init(serial_channel *chan)
{
if (chan->init) return;
+ chan->overruns=0;
if (chan->out_cbuf.len != 0) {
#ifdef CYGDBG_IO_INIT
diag_printf("Set output buffer - buf: %x len: %d\n", chan->out_cbuf.data, chan->out_cbuf.len);
#endif
chan->out_cbuf.waiting = false;
@@ -321,15 +323,28 @@ serial_write(cyg_io_handle_t handle, con
; // Ignore full, keep trying
#endif
buf++;
}
} else {
+ int put, nb, onb;
+
cyg_drv_dsr_lock(); // Avoid race condition testing pointers
+ HAL_DIAG_LED(1<<14,1<<14);
+ put=cbuf->put;
+ nb=cbuf->nb;
+ onb=cbuf->nb;
+ HAL_DIAG_LED(1<<14,0<<14);
+ cyg_drv_dsr_unlock();
+
while (size > 0) {
- next = cbuf->put + 1;
+ next = put + 1;
if (next == cbuf->len) next = 0;
- if (cbuf->nb == cbuf->len) {
+ if (nb == cbuf->len) {
+
+ cyg_drv_dsr_lock(); // Avoid race condition testing pointers
+ HAL_DIAG_LED(1<<14,1<<14);
+
cbuf->waiting = true;
// Buffer full - wait for space
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
#endif
@@ -342,10 +357,14 @@ serial_write(cyg_io_handle_t handle, con
// Optionally return if configured for non-blocking mode.
if (!cbuf->blocking) {
*len -= size; // number of characters actually sent
cbuf->waiting = false;
res = -EAGAIN;
+
+ HAL_DIAG_LED(1<<14,0<<14);
+ cyg_drv_dsr_unlock();
+
break;
}
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
cbuf->pending += size; // Have this much more to send [eventually]
if( !cyg_drv_cond_wait(&cbuf->wait) )
@@ -356,24 +375,41 @@ serial_write(cyg_io_handle_t handle, con
// Give up!
*len -= size; // number of characters actually sent
cbuf->abort = false;
cbuf->waiting = false;
res = -EINTR;
+
+ HAL_DIAG_LED(1<<14,0<<14);
+ cyg_drv_dsr_unlock();
+
break;
}
+
+ HAL_DIAG_LED(1<<14,0<<14);
+ cyg_drv_dsr_unlock();
+
} else {
- cbuf->data[cbuf->put++] = *buf++;
- cbuf->put = next;
- cbuf->nb++;
+ cbuf->data[put++] = *buf++;
+ put = next;
+ nb++;
size--; // Only count if actually sent!
}
}
+
+ cyg_drv_dsr_lock(); // Avoid race condition testing pointers
+ HAL_DIAG_LED(1<<14,1<<14);
+ cbuf->put=put;
+ cbuf->nb+=nb-onb;
+
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
#endif
(funs->start_xmit)(chan); // Start output as necessary
+
+ HAL_DIAG_LED(1<<14,0<<14);
cyg_drv_dsr_unlock();
+
}
cyg_drv_mutex_unlock(&cbuf->lock);
return res;
}
@@ -422,27 +458,44 @@ serial_read(cyg_io_handle_t handle, void
#else
*buf++ = c;
#endif
}
} else {
+ int get, nb, onb;
+
cyg_drv_dsr_lock(); // Avoid races
+ HAL_DIAG_LED(1<<13,1<<13);
+ get=cbuf->get;
+ nb=cbuf->nb;
+ onb=cbuf->nb;
+ HAL_DIAG_LED(1<<13,0<<13);
+ cyg_drv_dsr_unlock();
+
while (size < *len) {
- if (cbuf->nb > 0) {
+ if (nb > 0) {
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
- if ( (cbuf->nb <= cbuf->low_water) &&
+ if ( (nb <= cbuf->low_water) &&
(chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) )
restart_rx( chan, false );
#endif
- *buf++ = cbuf->data[cbuf->get];
- if (++cbuf->get == cbuf->len) cbuf->get = 0;
- cbuf->nb--;
+ *buf++ = cbuf->data[get];
+ if (++get == cbuf->len) get = 0;
+ nb--;
size++;
} else {
+
+ cyg_drv_dsr_lock();
+ HAL_DIAG_LED(1<<13,1<<13);
+
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
if (!cbuf->blocking) {
*len = size; // characters actually read
res = -EAGAIN;
+
+ HAL_DIAG_LED(1<<13,0<<13);
+ cyg_drv_dsr_unlock();
+
break;
}
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
cbuf->waiting = true;
#ifdef XX_CYGDBG_DIAG_BUF
@@ -465,14 +518,28 @@ serial_read(cyg_io_handle_t handle, void
// Give up!
*len = size; // characters actually read
cbuf->abort = false;
cbuf->waiting = false;
res = -EINTR;
+
+ HAL_DIAG_LED(1<<13,0<<13);
+ cyg_drv_dsr_unlock();
+
break;
}
+
+ HAL_DIAG_LED(1<<13,0<<13);
+ cyg_drv_dsr_unlock();
+
}
}
+
+ cyg_drv_dsr_lock(); // Avoid race condition testing pointers
+ HAL_DIAG_LED(1<<13,1<<13);
+ cbuf->get=get;
+ cbuf->nb-=onb-nb;
+ HAL_DIAG_LED(1<<13,0<<13);
cyg_drv_dsr_unlock();
}
#ifdef XX_CYGDBG_DIAG_BUF
cyg_drv_isr_lock();
enable_diag_uart = 0;
@@ -665,10 +732,40 @@ serial_get_config(cyg_io_handle_t handle
}
*(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
break;
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
+#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
+ case CYG_IO_GET_CONFIG_SERIAL_FLOW_CONTROL_METHOD:
+ {
+ cyg_uint32 *f = (cyg_uint32 *)xbuf;
+
+ if (*len < sizeof(*f))
+ return -EINVAL;
+
+ cyg_drv_dsr_lock();
+
+ *f=chan->config.flags & (CYGNUM_SERIAL_FLOW_XONXOFF_RX|
+ CYGNUM_SERIAL_FLOW_XONXOFF_TX|
+ CYGNUM_SERIAL_FLOW_RTSCTS_RX|
+ CYGNUM_SERIAL_FLOW_RTSCTS_TX|
+ CYGNUM_SERIAL_FLOW_DSRDTR_RX|
+ CYGNUM_SERIAL_FLOW_DSRDTR_TX);
+ cyg_drv_dsr_unlock();
+ }
+ break;
+#endif
+
+ case CYG_IO_GET_CONFIG_SERIAL_OVERRUNS:
+ {
+ if ( *len < sizeof(unsigned long) )
+ return -EINVAL;
+
+ *(unsigned long*)xbuf=chan->overruns;
+ }
+ break;
+
default:
res = -EINVAL;
}
return res;
}
@@ -922,18 +1019,21 @@ serial_rcv_char(serial_channel *chan, un
if ( cbuf->nb < cbuf->len ) {
cbuf->data[cbuf->put++] = c;
if (cbuf->put == cbuf->len) cbuf->put = 0;
cbuf->nb++;
} // note trailing else
-#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
else {
// Overrun. Report the error.
- cyg_serial_line_status_t stat;
- stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
- serial_indicate_status(chan, &stat);
- }
+ chan->overruns++;
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+ {
+ cyg_serial_line_status_t stat;
+ stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
+ serial_indicate_status(chan, &stat);
+ }
#endif
+ }
if (cbuf->waiting) {
#ifdef XX_CYGDBG_DIAG_BUF
extern int enable_diag_uart;
int _enable = enable_diag_uart;
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss