Reputation: 165
I what to send some commands to a LPC 1786 microcontroller over a serial port. To accomplish this task I open the serial port using this code.
struct termios tio;
int tty_fd;
memset(&tio,0,sizeof(tio));
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 5;
tty_fd = open(device, O_RDWR | O_NONBLOCK);
cfsetospeed(&tio, B9600); // 115200 baud
cfsetispeed(&tio, B9600); // 115200 baud
tcflush(tty_fd, TCIFLUSH);
This is for an embedded linux system using (iMX53). When I compile the code on my PC and run it. I get this:
sent: ?
recieve: Sinchronized<CR><LF>
sent: Sinchronized<CR><LF>
recieve: Synchronized<CR>OK<CR><LF>
sent: 16000<CR><LF>
recieve: 16000<CR>OK<CR><LF>
witch is fine. When I cross compile it and upload it to the system I get this.
Sent: ?
HEX: 0x53 0x79 0x6E 0x63 0x68 0x72 0x6F 0x6E 0x69 0x7A 0x65 0x64 0xA 0xA 0x53 0x79 0x6E 0x63 0x68 0x72 0x6F 0x6E 0x69 0x7A 0x65 0xA
ASCII: SynchronizedSynchronizedOKOKnchronized1K024K024chronized1
Sent: ?
HEX: 0xA 0xA 0xA 0xA 0xA 0xA 0xA 0x30 0xA 0xA 0x31 0xA 0xA 0xA 0xA 0xA 0xA 0x34 0xA 0xA 0x31 0xA 0xA 0xA 0xA 0xA 0xA 0xA 0xA 0xA 0A
ASCII: 014141hronized1111111ronized1
witch kind of ruins my day. For writing and reading I'm using write & read functions. I bet this is to do with the way I am opening the serial port. But what wrong. I have tried different settings but with little success. In the best case as a response I get "?????1???". And most of the time there is nothing to be read.
Upvotes: 2
Views: 563
Reputation: 17077
The fundamental problem is that your code indicates that you have not (properly) initialized the tty port. Essentially the initialization does not call tcsetattr()
to install the updated configuration that you tried to specify.
The proper way to initialize the tty port is to open the port, obtain the current attributes, save the current attributes for restoration on program exit, modify the attributes, and install the attributes. And always test the return codes from system calls.
tty_fd = open(device, O_RDWR | O_NONBLOCK);
if (tty_fd< 0) {
syslog(LOG_DEBUG, "failed to open: %d, %s", tty_fd, strerror(errno));
exit (-1);
}
rc = tcgetattr(tty_fd, &tio);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to get attr: %d, %s", rc, strerror(errno));
exit (-2);
}
savetio = tio; /* preserve original settings for restoration */
spd = B9600;
cfsetospeed(&tio, (speed_t)spd);
cfsetispeed(&tio, (speed_t)spd);
cfmakeraw(&tio);
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 5;
tio.c_cflag &= ~CSTOPB;
tio.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tio.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(tty_fd, TCSANOW, &tio);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to set attr: %d, %s", rc, strerror(errno));
exit (-3);
}
Of course there may also be cabling and hardware issues still to be resolved, but since the tty port has not been initialized to the operational state that you want or need, nothing is likely to function as you expect.
Here's a guide for programming the serial port.
Upvotes: 3
Reputation: 16832
I'm a hardware guy at heart, so when things like this happen, I tend to start from the bottom:
Get a scope or logic analyser out and look at the bits transmitted. Check the baud rate. Check the characters. A scope that interprets the bits for you is a huge help here :)
If they are OK, check the bytes are getting into the embedded processor OK. Check the interrupt service routine. Set a bit on entry and clear it before exit. Check that the characters coming in are not overrunning the ISR.
Work up from there - is there some low level driver taking the data from the ISR?
Upvotes: 1
Reputation: 215350
In addition to the problems mentioned in other answer, one likely cause is a bad pre-scaler clock fed to the MCU UART. UART requires a clock accuracy of +- 3%. If your pre-scaler isn't that accurate, you will exactly the kind of issues described in the question: the data looks fine most of the time, and then suddenly you get garbage.
When trouble-shooting this, you need to check for overrun, framing errors etc on your receiver side. Check the signal and measure the baudrate with an oscilloscope. You cannot develop embedded applications without an oscilloscope, it is just as essential a tool as the debugger.
Upvotes: 1
Reputation: 1969
There's a lot of good debugging comments for this question, but here's a summarized list of items to check for serial link: (Adding some of my own & slanted towards bring-up of developmental systems)
These two are sort of initial design level checks. Sometimes you end up revisiting them:
These are more general:
These are rarer checks:
Upvotes: 1