This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]