Thursday, February 4, 2010

Getting Serial Port to work under Ubuntu!

The setup: I have a Intel motherboard inside my office desktop with a built-in serial port. Over the days, I managed to screw up the builtin COM port (and my friends at office did the same to their desktop PCs too.. haha!). What probably happened is that does to some ESD or overvoltage on one of the pins during experimentation caused the RS232 Driver on board the motherboard to get spoilt.
As a result, the COM port (COM1 in this case) was detected alright by windows XP but Bray's Terminal or Hyperterminal were either not able to receive or transmit data out of the port.

So we all got Serial Port PCI cards which costed around Rs.250 a piece. Each of these cards are based around the CH352 (more specifically CH325L) chip made by WCH (a chinese company).

WCH Website (Chinese): www.wch.cn
WCH Website (English): www.wch-ic.com
CH352 Product Page and Datasheet: http://www.wch-ic.com/product/pci/ch352.asp

All these cards have 2 Serial Ports on them. and they worked super fine on windows XP.
Then one day we all uninstalled Windows XP from our PCs and installed Ubuntu 9.10 x86 32bit. All of our hardware worked directly without any intervention on Ubuntu except the PCI Serial Cards.

Here is a list of what all I tried and what finally worked.

1) First I installed "Serial Port Terminal" from Ubuntu Software Center. This is actually "gtkterm"



2) Of course the serial ports werent working directly out of the box. The COM ports are named differently under ubuntu:

Windows Linux
COM1 /dev/ttyS0
COM2 /dev/ttyS1
COM3 /dev/ttyS2
COM4 /dev/ttyS3

Why? you ask: well under Linux and UNIX each and every hardware device treated as a file. These are called device files.
(as an aside: USB to serial convertors based around popular ICs like Prolific's PL2303 and FTDI's FT232RL work directly without any configuration on ubuntu. They appear as /dev/ttyUSB0 , dev/ttyUSB1 etc.
There is a blog post by swamytk on how to run FlashMagic (for programming P89V51RD2 microcontrollers via UART) on ubuntu using Wine: here . In the comments section on that page you can see how to redirect I/O from what appears as COM1 to /dev/ttyUSB0 - which is what USB-Serial convertors appear as under ubuntu)

Googling led me to the command for listing all the serial ports under ubuntu:
setserial -g /dev/ttyS*
But before you use that command, you will need to install the setserial package. You can install that by going over to Synaptic Package Manager and searching for and installing "setserial". Alternatively you can issuse the command "sudo apt-get install setserial" at the terminal prompt.

The output of the setserial -g /dev/ttyS* came out as:
/dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
/dev/ttyS1, UART: undefined, Port: 0x1108, IRQ: 18
/dev/ttyS2, UART: undefined, Port: 0x1100, IRQ: 18
/dev/ttyS3, UART: unknown, Port: 0x02e8, IRQ: 3
The first entry was of /dev/ttyS0 which would have been COM1 on Windows. Thats the motherboard's detectable but nor working COM port. The entries for ttyS1 and ttyS2 had the same Interrupt Request Number and so I knew those were the entries for the two serial ports on the PCI card that I had installed. The number "16550A" refers to the UART type. 16550 is the part number of the IC invented by National Semiconductor which was first used to implement UART. Read more about 16550 UART and 16550A (improved version) on wikipedia.

The output of lspci -v command for the serial port PCI card was:
05:04.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02)
Subsystem: Device 4348:3253
Flags: medium devsel, IRQ 18
I/O ports at 1108 [size=8]
I/O ports at 1100 [size=8]
Kernel driver in use: serial
and some of the serial port related system messages uncovered by dmesg were:
[ 0.808748] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[ 0.808852] serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 0.809268] 00:0a: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 0.809362] serial 0000:05:04.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
[ 0.809438] 0000:05:04.0: ttyS1 at I/O 0x1108 (irq = 18) is a XScale
[ 0.809530] 0000:05:04.0: ttyS2 at I/O 0x1100 (irq = 18) is a XScale




3) Next I found the driver CD that came with the PCI card. There was a linux driver for the card on it. There was am executable file named "ch35x_80x86.o" on it. The instructions were as follows:
This installation guide describes the procedures to install and uninstall CH35X PCI to two serial ports,one serial and one parport,
two serial ports and one parport,four serial ports in Linux platform.
1-install and uninstall CH35X PCI boards

(1)-install
<1>-copy ch35x_80x86.o to /usr/sbin
<2>-Add /usr/sbin/ch35x_80x86 at the end of the /etc/rc.d/rc.local.
<3>-reboot
if you inster two serials port board
The ttyS2 and ttyS3 are ready for application.

if you inster one serial port and one parport port board
The ttyS2 and LPT1 or LPT2 ready for application.

if you inster four serials port board
The ttyS2 ttyS3 ttyS4 and ttyS5 are ready for application.

if you inster two serials port and aone parport port board
The ttyS2 ttyS3 and LPT1 or LPT2 are ready for application.

(2)-uninstall
(1)-Remove /usr/sbin/ch35x_80x86 at the end of the /etc/rc.d/rc.local.
(2)-Remove /usr/sbin/ch35x_80x86.o



Of course this didnt work (note that on ubuntu, the file to be modified is "/etc/rc.local" instead of "/etc/rc.d/rc.local". You will have to do sudo gedit /etc/rc.local to edit that file.)

4) While I was doing all this (people with similar problems), my friend Rajesh somehow got the serial port to work on his PC. When we asked him how he did it, he said he didnt know. Being complete a n00b to linux (that includes all of us!) , he had forgotten that led him to get it to work. We tried gtkterm on his PC and shorted pins 2 and3 on the RS232 Connector and could see the characters being echoed back!
the setserial list command on Rajesh's PC yielded:
/dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
/dev/ttyS1, UART: 16550A, Port: 0x9000, IRQ: 19, Flags: spd_cust
/dev/ttyS2, UART: 16550A, Port: 0x9400, IRQ: 19
/dev/ttyS3, UART: unknown, Port: 0x02e8, IRQ: 3

which led me to believe that maybe the PCI was detected properly on my PC but the linux's serial driver didnt know what kind uart was there on the PCI card.

Further surfing on the web saw me stumble acrosss the following link: http://serial.sourceforge.net/
which is the Project repository for the Linux Serial Driver. The page refers to using the lspci-v command to get port address information about your PCI card and then using the information with setserial command to get your serial ports working. Here is the extract:
Hopefully, there are one or more I/O port regions associated with the card. If you're comfortable using the setserial command, try setting one of your unusued /dev/ttyS devices to one of the I/O port regions listed by lspci, and set its IRQ to the IRQ listed by the lspci listing, and see if you can communicate to your serial port or your modem. I recommend using a low-level modem communications program such as C-Kermit for this testing purpose. If you find that some number of the lspci's I/O regions allow you to talk to the serial port/modem, let me know in your report to me.


Reading this give me inspiration to go and read the manual pages for setserial. (how many times have we heard RTFM thrown at our face!!)

Some points I picked up from the setserial man pages:
uart uart_type
This option is used to set the UART type. The permitted types
are none, 8250, 16450, 16550, 16550A, 16650, 16650V2, 16654,
16750, 16850, 16950, and 16954. Using UART type none will dis‐
able the port.

Some internal modems are billed as having a "16550A UART with a
1k buffer". This is a lie. They do not have really have a
16550A compatible UART; instead what they have is a 16450 com‐
patible UART with a 1k receive buffer to prevent receiver over‐
runs. This is important, because they do not have a transmit
FIFO. Hence, they are not compatible with a 16550A UART, and
the autoconfiguration process will correctly identify them as
16450's. If you attempt to override this using the uart parame‐
ter, you will see dropped characters during file transmissions.
These UART's usually have other problems: the skip_test parame‐
ter also often must be specified.


..I can live with a few dropped characters.. as long as my serial works!!

MULTIPORT CONFIGURATION
Certain multiport serial boards which share multiple ports on a single
IRQ use one or more ports to indicate whether or not there are any
pending ports which need to be serviced. If your multiport board sup‐
ports these ports, you should make use of them to avoid potential lock‐
ups if the interrupt gets lost.

In order to set these ports specify set_multiport as a parameter, and
follow it with the multiport parameters. The multiport parameters take
the form of specifying the port that should be checked, a mask which
indicate which bits in the register are significant, and finally, a
match parameter which specifies what the significant bits in that reg‐
ister must match when there is no more pending work to be done.


...this multiport thing was probaly applicable to my card, but I thought lemme first get the ports working, and so I issued the following two commands to for the serial driver to think of my ports as 16550A:

sudo setserial /dev/ttyS1 uart 16550A
sudo setserial /dev/ttyS2 uart 16550A


and lo! and behold! they started working!! used gtkterm with 2 and 3 pins shorted and I was able to get the echo back!

The setserial -g /dev/ttyS* now yields:
/dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
/dev/ttyS1, UART: 16550A, Port: 0x1108, IRQ: 18
/dev/ttyS2, UART: 16550A, Port: 0x1100, IRQ: 18
/dev/ttyS3, UART: unknown, Port: 0x02e8, IRQ: 3

15 comments:

grzeziek said...

Good story ;) It works fine, but I have to type : setserial /dev/ttyS1 uart 16550A
every time I turn on the computer. THX
Now I am looking for solution how to make it happens automaticly.

beyond hack said...

mannnnnnn!! u r awsm! it worked perfectly....
thnxxx... anurag bro


@grzeziek: just add the setserial command for your port in the /etc/rc.local(for ubuntu) and make it happen everytime you boots up..

venkatganesh said...

i have 6 serial ports (two in system and 4 ports in pci) only enabled dev/tty(S0-3)how to remianing 2 serial ports enabled

Anurag Chugh said...

@venkatganesh:
Which four are working? the 2 in system and the 2 on one of the PCI cards or .. do all four working ones belong to the 2 PCI card?

maybe u need to enable builtin Serial ports via BIOS Setup?

NAVEEN said...

Hello anurag, this post is awesome, yesterday i bought 1serial 1 parallel PCI card and tested it on my windows xp , it was not working...After following your suggestion on this post may that card work on linux, but it is not working on windows...i have tested that card on codevision avr ( ide for atmel microcontrollers), it was not communicating..pls anurag help me to troubleshoot this problem....waiting 4 ur reply...

Venkatesan R said...

Hi Anurag chugh,

I have a PCI Card with 4 serial ports and 2 serialports in onboard while executing the setserial command it only displays ttyS0,ttyS1, ttyS2, ttyS3 remaining 2 is not listing can you suggest what is the problem

Regards
Venkatesan

Anurag Chugh said...

@Venkatesan, I have not encountered a similar problem so have no suggestions for you, sorry. Am not really that good at linux.

Venkatesan R said...

Anurag thanks for your reply, after i googling i found the solution that initially linux support only 4 ports if you want you have to add
8250.nr_uarts=[# of serial port you want]
in /boot/grub/grub.config after reboot the system it will display all the serial ports.

Now i am facing same problem faced by you but i dont know where is the key hole.

the result of set serial command is

/dev/ttyS0, UART:16550A, Port:0x03f8, IRQ:4
/dev/ttyS1, UART:16550A, Port:0x02f8, IRQ:3
/dev/ttyS2, UART:undefined, Port:0x0d010, IRQ:217
/dev/ttyS2, UART:undefined, Port:0x0d000, IRQ:217
/dev/ttyS2, UART:undefined, Port:0x0d030, IRQ:217
/dev/ttyS2, UART:undefined, Port:0x0d020, IRQ:217

when i run my program it only detect ttyS0 and ttyS1.

The work arrounds i have done is

1) copy the driver file to the sbin folder and edit the rc.local also not working.

2) as per your instruction i have also used

sudo setserial /dev/ttyS2 uart 16550A also not working.

Can you suggest

Anurag Chugh said...

@Venkatesan
I didn't know that Linux supports only 4 serial by default.

the output of your set serial command shows that all the 4 serial ports of your PCI card have the same IRQ number (even tho they have different addresses) - maybe that is the problem, I dont know who to manually set the IRQs but maybe you can look into that.

Also another possible solution is this: Install windows on your PC, and then install the drivers for your PCI card. Make sure all 6 serial ports are working in windows.

Then install VirtualBox or VMWare and install ubuntu on a virtual machine. While doing this, give ubuntu access to the COM ports:
http://www.virtualbox.org/manual/ch03.html#serialports

One drawback of virtualbox is that it allows only 2 com ports to be made available to the guest OS

I think VMware allows upto 4 serial ports to be made available to the Guest OS:
http://www.vmware.com/support/ws3/doc/ws32_devices3.html

Lokesh Venkateshaiah said...

Hey could tell how to remove the exisiting driver i.e serial so that i can re write the new driver for 3.x version

Anurag Chugh said...

@ Lokesh, I think you need not touch the existing driver, just let it be. Write your new driver and it will work without any problem. Just register a new differently named interface for your new driver. As for the old driver, simply don't use it, even if it is loaded!

herr flick said...

i wish refresh this theme because i have problem with this pci card.
i was seting up everything as i read here and its works but no ok
problem is that the rs port see hardware connected but comunication is no good just for few min and adio. what is wrong my ubuntu is 10.4 server

YAFU said...

Hi, I'm a little lost.
I have a PCI card with 2 serial and 1 parallel, based on wch chip. I can not find how to set parallel port on Linux. Already installed the driver and it is loaded. But I can not enable the parallel port. Can anyone give me a clue how to do?
Thanks!

YAFU said...

Ok, I answer to myself on how to enable the parallel port. Supposedly, in Ubuntu (Kubuntu in my case) no need to install driver. Anyway I've downloaded from Encore wch drivers and I've compiled and installed.
I used the following thread to know how to detect which is the value corresponding to the parallel port of my PCI card with two serial and one parallel:
http://www.linuxcnc.org/index.php/english/forum/18-computer/7941-pci-add-in-parallel-port-cards
In my case "lspci -v" shows:
05:02.0 Serial controller: Device 4348:7053 (rev 10) (prog-if 02 [16550])
Subsystem: Device 4348:3253
Flags: medium devsel, IRQ 19
I/O ports at c030 [size=8]
I/O ports at c020 [size=8]
I/O ports at c010 [size=8] <- lp0
I/O ports at c000 [size=16]
Kernel driver in use: serial
Kernel modules: wch

As my card has two serial and one parallel, I want the third value for lp0: "c010"
Then you need to create as root the file "/etc/modprobe.d/parport_pc" pasting in this:

options parport_pc io=0xc010

Save and close editor. You should replace c010 with the value you get in that position corresponding to lp0.
As I have manually installed the driver, to load the driver on each system startup I edit / etc / rc.local and add before "exit 0" the following line:

modprobe wch

Restart de system.

Mario A. Contreras Baruh said...

Muy buen post, me ayudo con mi problema. Gracias.

Post a Comment