Linux serial port dropping bytes

Mar 31, 2008 113 Replies

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.


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]: Try the download section.

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/

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:

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 visi.com SOAP DISH!!

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

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

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...

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 visi.com collection!

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:

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

Derek

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 visi.com with at least six studio SLEAZEBALLS!!

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]: Try the download section.

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]: Try the download section.

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:

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.

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

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]: Try the download section.

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, visi.com Marvin?? Don't you know your own ZIPCODE?

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... visi.com

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required