This is the mail archive of the ecos-discuss@sourceware.org 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: MPC555 serial driver delay


Thanks for your advice Andrew.

>Yes. Some devices have a FIFO and the interrupt is triggered 
>when a low water mark is reached. You can then write multiple 
>bytes to fill the FIFO. Hence the loop.

This processor has a 16 byte queue for one of it serial lines, but this
is not implemented yet in the driver.

>Maybe an interrupt problem. Is the TX interrupt getting 
>cleared properly when the DSR exists? If not the interrupt 
>will fire again once interrupts are reenabled. See how many 
>bytes get send out on average. It should be 1, but if there 
>are lots of 0s, you have a problem.
>
>        Andrew

I've tried to see how the interrupt gets cleared in the code and it
doesn't seem to get explicitely cleared.
The are two transmit interrput types, one when the single byte buffer is
empty and another when the last transmition is complete.
The driver as it stands uses the buffer empty interupt which asserts the
TDRE (Transmit data register empty) bit in the SCxSR SCI status
register.
After consulting the processor's manual it say in two places:

"The TDRE flag in the status register is readonly."

And seemingly contradictory:

"New data is not transmitted if TDRx is written without first clearing
TDRE."

Attempting to write to TDRE causes an exception so I can only assume
that the former is true.

I've conducted an number of tests at 57600 baud.

I have tried putting counters in the following code:

static bool mpc555_serial_putc(serial_channel * chan, unsigned char c)
{
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info
*)chan->dev_priv;
  cyg_addrword_t port = mpc555_chan->base;

  cyg_uint16 scsr;
  cyg_uint16 scdr;

  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
  if(scsr & MPC555_SERIAL_SCxSR_TDRE)
  { // Ok, we have space, write the character and return success
    scdr = (cyg_uint16)c;
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
    return true;
  }  
  else
    // We cannot write to the transmitter, return failure
    return false;
}

I've put separate counters in both sections that return either true or
false.
For a 64 byte packet there seems to be a time averaged fixed ratio of
about 2.06 times successful sends to no room in buffer sends.

Next I've tried to scope out what's going on by toggling some I/O lines.
In scope1.tif the cyan trace is my app toggling the state of a pin each
time it runs around a loop with cyg_thread_delay(1) and when the orange
trace goes low it is entering serial_xmt_char() in serial.c. It brings
the line high again only when it leaves the while loop after a sucessful
send and nothing else to send, but not if the buffer is still full.

It seems to confirm that my app thread's execution is blocked, or at
least the timer event is blocked until all of the serial data has been
sent.
Scope2.tif shows this closer up and that the selayed timer event occurs
imediately after serial transmission has finished. For scope3.tif I've
added to serial_xmt_char()that it will bring the line high even if it
returns because the buffer is full. This should show the interrupt
activity. Scope4.tif is the same but zoomed in on the timebase. So 300us
are spent idle and only 100us by the DSR attempting to transfer more
data for each buffer empty interrupt.

Using the same I/O line technique I've checked that the realtime clock
ISR and DSR are still being called on a regular basis even during serial
transmission. I've also tried reducing the number of clock ticks between
time slices to one in cdl, but this semms to make no diffence to the
problem.

I don't know enough about how the kernel uses the RTC, but is it
unrealistic for me to expect the kernel to context switch in 300us, or
12000 cpu cycles @ 40MHz ?

For lower baud rates the problem seems to reduce, at 9600 baud there's a
tiny amount of jitter in the timer period, at 19200 baud there's
noticable jitter, at 38400 there's very heavy jitter and at 57600 baud
the timer event just doesn't every occur when serial transmission is in
progress. 

Looks like I'll have to fall back to using the driver interupt-less mode
or investigate implementing the 16-byte queue to reduce the magnetude or
frequency of the delay problem.

Any insight into this is appreciated.

Steven

Attachment: scope4.tif
Description: scope4.tif

Attachment: scope1.tif
Description: scope1.tif

Attachment: scope2.tif
Description: scope2.tif

Attachment: scope3.tif
Description: scope3.tif

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

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