Linux serial port dropping bytes

Hi all,

I'm using an Arcom Viper PXA255 single board computer running Linux, and I'm trying to receive bytes over the built-in RS-422 serial port at

921.6 kbps. The received packets are 1500 bytes long. The UART is a 16C2850 (dual port version of the 16C850 with 128 byte FIFO).

Everything works fine at low speeds, but if the packet rate increases, I start to lose bytes.

I believe this is caused by the Linux serial port interrupt handler not responding fast enough. Some testing revealed that this problem only occurs when other peripherals (such as the flash drive or ethernet port) are active.

I searched online and found a utility called IRQtune which promises to fix exactly this sort of problem by allowing control of ISR priorities in Linux. Unfortunately, IRQtune only works for x86 processors.

Does anybody know of a simple way to modify the priorities of interrupts in Linux? I don't mind recompiling the kernel, but I don't have a lot of expertise in that sort of thing. (In fact, I would have preferred skipping the whole OS thing and implementing the entire solution on an FPGA/uController, but oh well... one doesn't always get to choose.)

Any advice would be greatly appreciated. Thanks!

Derek

-- remove the .nospam and rearrange appropriately to e-mail.

Reply to
Derek Young
Loading thread data ...

Your numbers indicate that you would need an interrupt roughly every 1 microsec. Not a chance.

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
 Click to see the full signature
Reply to
CBFalconer

Or not being relieved of the packet payloads fast enough by whatever is supposed to consume them.

You'll want to go looking around in the processor / board specific code, and especially the serial port driver, perhaps plus whatever programs the interrupt hardware. Look in places like

drivers/serial drivers/char arch/processorname/

Reply to
cs_posting

This means you have 1.388 mS to fill the FIFO - plenty of time to process it.

If some of these IRQ handlers hogs the CPU for 1mS or so you will have no way out, but if they do that they will be broken anyway.

I am not a wintel/linux etc person and I don't know how much can be achieved in click-and-try-this mode on your problem, you may be lucky and hit some working combination for all I know. Without luck you would want to know the worst case system IRQ latency, your UART IRQ load etc. and locate and fix the problem.

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

Derek Young wrote:

Reply to
Didi

Huh?

If he sets the FIFO threshold to 64, then the interrupt frequency is 921600.0/10/64 == 1440Hz.

If he sets it FIFO threshold to 96, then the interrupt frequency is 921600.0/10/96 == 960Hz. 960Hz should be no problem at all unless some of the other ISRs are running too long.

--
Grant Edwards                   grante             Yow!  .. the MYSTERIANS are
                                  at               in here with my CORDUROY
 Click to see the full signature
Reply to
Grant Edwards

I've done some poking around through drivers/serial and drivers/char, but I couldn't find anything that looks like it would control the interrupt priority. I did see something that defines the software buffer size (I think it's supposed to be 8K).

But I'll look through arch/... to see if there's anything there.

Thanks...

Derek

Reply to
Derek Young

Thanks everyone for all the responses so far...

Yes, I feel like there should be plenty of time to handle the interrupts. But from what I understand (which isn't a whole lot mind you :P), Linux isn't strictly a real-time OS. It doesn't normally have a preemptible kernel (I've turned on the "experimental" preemptible kernel flag) and it doesn't really have a standard way to tweak interrupt priorities.

Was wondering if anybody knew of a straight-forward hack. I just want the serial port ISR to get priority over the device driver ISRs.

Derek

Reply to
Derek Young

For which you need to find the code that sets up the interrupt hardware.

Another thing worth doing is looking in the processor/chipset manual and figuring out what registers would have to be programmed to do what you want. Then figure out what linux calls those registers (it will be in a board-specific include file), then grep the source tree for that name...

Reply to
cs_posting

Changing ISR priority isn't going to make any difference.

It only determines which of two pending interrupts get serviced. It doesn't allow "higher" priority interrupts to preempt lower priority ones. If a low-priority ISR runs for a long time, it's still going to block high-priority ISRs for the whole time it's running.

--
Grant Edwards                   grante             Yow! As President I have
                                  at               to go vacuum my coin
 Click to see the full signature
Reply to
Grant Edwards

Sadly true, except on 68k/coldfire platforms. Some newer PPC parts from Freescale offer separate mask bits for two interrupts (6809 F and I like), which is not bad either. Of course if the system has been designed properly and written properly (are they ever in commecrial land?... :-) ), every IRQ handler would reenable IRQ after a few cycles only - some of the Freescale PPC parts have a good priority encoder in front of the core IRQ input and things will then in effect be as good as in a 68k/CF. But good luck enforcing that if more than 1 person is doing the work... -).

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

Grant Edwards wrote:

Reply to
Didi

Darn. I thought a high-priority ISR would preempt all lower priority ones. Thanks for the heads-up.

Derek

Reply to
Derek Young

The Hitachi H8 series has the same feature, but linux doesn't allow one ISR to preempt another ISR even if the hardware is capable of that.

In Linux, the point where interrupts can be re-enabled is the end of the ISR. The portion of the event handling that can be done with other interrupts enabled is done in a different context. Back in the day, Linux ISRs used be divided into a top half and a bottom half, with the re-enabling of interrupts occurring between the two (both halves ran in a single ISR context). But, now the portion of the ISR that used to run with interrupts enabled is a "soft irq" or a tasklet or something like that (it runs in a different context, not in an ISR context). At least that's the way it was the last time I looked...

Even with only 1 person, you're chances aren't great. :)

--
Grant Edwards                   grante             Yow! I need to discuss
                                  at               BUY-BACK PROVISIONS
 Click to see the full signature
Reply to
Grant Edwards

I know of UARTs that can hold 64, or even 128, results. I gather that that one has a 128 byte storage. Okay, now consider how long it takes to empty that buffer, when full. That has to be done at least every 921600/128 (I don't know where you got /10/96), or roughly 10 khz, for about 100 uS between interrupts. Now you don't know how many items are stored, so that implies a one by one discharge loop. Nobody has mentioned the CPU speed, but I still have grave doubts. Don't forget that during the discharge the FIFO is still filling up, at roughly 1 item per microsec.

I would guess you are assuming the speed mentioned is a bit speed, not a per byte port speed, and the '10' is the length of the character, in bits. Nobody computes serial port speeds that way.

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
 Click to see the full signature
Reply to
CBFalconer

Oh? The unit fills up, with 1500 bytes, and interrupts. Bytes can be coming in at one per microsec (roughly) until you get at least some out. That doesn't happen until the interrupt is serviced, and control is transferred to the unloading code, after doing all the checks (for error, etc.) So that must have all happened in about one microsec, to avoid rejecting further input. Now the discharge loop has to remove items in less that 1 microsec per byte, just to keep up with the input line. I have doubts that you can even talk to the UART that fast.

--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
 Click to see the full signature
Reply to
CBFalconer

Oops, sorry, I have taken the 1500 for FIFO depth, not the 128, hence the wrong result. This means he will have (1388/1500)*128 uS to fill the FIFO, or about

118 uS. Still plenty of time to empty a FIFO into memory on most if not all todays CPUs which would have a 128 byte deep FIFO on the UART. But latency is bound to creep in as an issue in this context given that under linux other IRQ handlers will not unmask early (I am relying on Grants word for that), so there is probably no working linux option - which is I believe what you suggested initially.

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

CBFalc> > Derek Young wrote:

Reply to
Didi

No. Derek's unit is a FIFO'ed UART, and it already fills up with 128 bytes. And for the sake of sanity, let's hope it interrupts at a (configurable) threshold considerably below those 128.

No. He wrote 921.6 kbps. Assuming he didn't have some disfiguring typing accident, that's roughly a _bit_ per microsecond, not a byte.

100 kByte/sec is not exactly trivial to handle over a UART link --- but it's certainly possible. That's what FIFO UARTs exist for.
Reply to
Hans-Bernhard Bröker

I don't remember ever seeing serial port speed specified as other than bits/sec. And geven a lack of other information 10 seems like a reasonable place to start for a character with start and stop bits included.

Robert

--
Posted via a free Usenet account from http://www.teranews.com
Reply to
Robert Adsett

Well, I habitually set my serial ports to 300, 600, 2400, 9600,

56000 etc., all measured in bytes per second.
--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
 Click to see the full signature
Reply to
CBFalconer

You divide by 10 bits/byte to convert from bits/sec to bytes/sec. Then you divide by the interrupt threshold to convert from bytes/sec to interrupts/sec.

It's 921600 _bits_ per second (including start and stop). That's 92160 bytes per second. If he configures the FIFO threshold to be 96, then the _fastest_ he'll get interrupts is one interrupt every 96 bytes. That means 92160/96 interrupts per second.

You seem to be confusing bits and bytes.

It is.

Yes they do. They always do.

--
Grant Edwards                   grante             Yow!  Why don't you
                                  at               ever enter and CONTESTS,
 Click to see the full signature
Reply to
Grant Edwards

I've been doing serial port device drivers and serial communication applications professionally for Linux and other OSes for decades. Serial port speeds are 100% always specified in bits/second (and they always have been).

Exactly.

--
Grant Edwards                   grante             Yow!  .. I see TOILET
                                  at               SEATS...
 Click to see the full signature
Reply to
Grant Edwards

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.