Hello!

I´m using RS485 2-wire communication and found the following behaviour of
the serial port driver:

The condition for RS485 communication in both directions is to set
dcb.fRtsControl = RTS_CONTROL_TOGGLE.

Now sending some bytes over the serial port depends on the speed of the
processor. Using a Geode GX2 and 115200 baud the bytes are all sent. Using a
GeodeLX and 115200 baud the last byte is not sent correctly. Using the
GeodeGX2 with slower baudrate eg. 110 baud the last byte is also not
correctly sent.

This behaviour is caused by the Com_Write Function in mdd.c which clears the
RTS without waiting for the Transmitter Empty Flag of the Line Status
Register.

So i made the following changes:

if ( pSerialHead->DCB.fRtsControl == RTS_CONTROL_TOGGLE ) {
// Patch
if(pFuncTbl->HWGetLSR != NULL)
while(!(pFuncTbl->HWGetLSR(pHWHead) & 0x40)); // wait for
Transmitter Empty (TEMT) Flag
// End Patch
pFuncTbl->HWClearRTS(pHWHead);
}

HWGetLSR is a extension of the HW_VTABLE Struct, which is linked with the
included SerGetLSR Function in cserpdd.c.
The SerGetLSR Function uses the GetLineStatus Function in pdd16550.cpp.

The functions are implemented like the HWClearRTS and SerClearRTS functions.

Now the serial RS422 2-wire communications works well.

Regards,
Andy

Re: Serial port driver bug by Remi

Remi
Thu Mar 08 04:55:23 CST 2007

Hi,

The RTS_CONTROL_TOGGLE bug is quite ancient and has been fixed in 6.0 with a
not-so-happy piece of code for people who need a quick line inversion.
However, at least this code calls Sleep while waiting for TEMT, what your
code fails to do: remember you are using a RTOS and that active waitings are
not recommended in this context. Also remember that the time needed to
serialize a byte at 110 bauds is about 100 ms.

Here is what I suggest for the "Wait for TEMT" function:

// Experience shows that we come to this code about 0.5 ms after the
// THRE interrupt. In the meanwhile, the last character of the RS485
// frame is being serialized.
// In order to avoid polling almost actively TEMT for too long, we
// can sleep most of the time before actually polling it.
// Remember that Sleep(n) where n > 0 will sleep for *at least* n ms.
// SleepTillTick will yield for up to 1 ms.
nMs = (1000 * (1 // start
+ pHWHead->dcb.ByteSize // bits
+ (pHWHead->dcb.Parity == NOPARITY ? 0 : 1) // parity
+ 1) // at least 1 stop
+ pHWHead->dcb.StopBits * 500) // extra stops
/ pHWHead->dcb.BaudRate; // time for char transmission
switch (nMs)
{
case 0: // 19200 Bauds and above
case 1: // 9600 Bauds
break;
case 2: // 4800 Bauds
SleepTillTick(); // sleep for maximum 1 ms
break;
default: // more than 2 ms
Sleep(nMs - 2); // sleep for at least (nMs - 2) ms
break;
}
}

// Finally almost-actively wait for the end of serialization.
EnterCriticalSection(&(pHWHead->RegCritSec));
while (!(INB(pHWHead, pLSR) & SERIAL_LSR_TEMT))
{
Sleep(0); // resched if needed
}
LeaveCriticalSection(&(pHWHead->RegCritSec));

Hope this will help someone.
Remi



Re: Serial port driver bug by Andy

Andy
Thu Mar 08 09:12:02 CST 2007

Thanks for the hint with the sleep.
I´ve not found anything about this bug before.
I´m wondering why this is not patched by a QFE.

Regards,
Andy

"Remi de Gravelaine" wrote:

> Hi,
>
> The RTS_CONTROL_TOGGLE bug is quite ancient and has been fixed in 6.0 with a
> not-so-happy piece of code for people who need a quick line inversion.
> However, at least this code calls Sleep while waiting for TEMT, what your
> code fails to do: remember you are using a RTOS and that active waitings are
> not recommended in this context. Also remember that the time needed to
> serialize a byte at 110 bauds is about 100 ms.
>
> Here is what I suggest for the "Wait for TEMT" function:
>
> // Experience shows that we come to this code about 0.5 ms after the
> // THRE interrupt. In the meanwhile, the last character of the RS485
> // frame is being serialized.
> // In order to avoid polling almost actively TEMT for too long, we
> // can sleep most of the time before actually polling it.
> // Remember that Sleep(n) where n > 0 will sleep for *at least* n ms.
> // SleepTillTick will yield for up to 1 ms.
> nMs = (1000 * (1 // start
> + pHWHead->dcb.ByteSize // bits
> + (pHWHead->dcb.Parity == NOPARITY ? 0 : 1) // parity
> + 1) // at least 1 stop
> + pHWHead->dcb.StopBits * 500) // extra stops
> / pHWHead->dcb.BaudRate; // time for char transmission
> switch (nMs)
> {
> case 0: // 19200 Bauds and above
> case 1: // 9600 Bauds
> break;
> case 2: // 4800 Bauds
> SleepTillTick(); // sleep for maximum 1 ms
> break;
> default: // more than 2 ms
> Sleep(nMs - 2); // sleep for at least (nMs - 2) ms
> break;
> }
> }
>
> // Finally almost-actively wait for the end of serialization.
> EnterCriticalSection(&(pHWHead->RegCritSec));
> while (!(INB(pHWHead, pLSR) & SERIAL_LSR_TEMT))
> {
> Sleep(0); // resched if needed
> }
> LeaveCriticalSection(&(pHWHead->RegCritSec));
>
> Hope this will help someone.
> Remi
>
>
>

Re: Serial port driver bug by Remi

Remi
Thu Mar 08 11:27:38 CST 2007

> I´ve not found anything about this bug before.

Did not try Google Groups?

http://groups.google.fr/group/microsoft.public.windowsce.platbuilder/browse_frm/thread/9a722695ae3e2067/4115f81c89ad05ee?lnk=st&q=RTS_CONTROL_TOGGLE+com16550&rnum=1&hl=fr#4115f81c89ad05ee

> I´m wondering why this is not patched by a QFE.

Me too ;-)
Actually, I can't remember of a single fix for all the bugs I signaled to
this group that were acknowledged by MS.
This is not a real issue as long as Google keeps doing the filing but it
tells a lot about MS reactivity for what they do not consider as 'critical'.

Remi