UART takes some "kicking" to start receiving data - linux

I am using a UART on a single board computer (Olimex A13) and I am trying to send and receive data through the UART. On the send side I have no problems. The Olimex board sends data to the serial buss and it is received on an external PC that is running putty terminal.
When I try to go in the other direction (PC sends data to be received by the Olimex board) I am running into a weird problem. When I start to send data, initially no data shows up on the Olimex board (I have tried 2 methods... cat /dev/ttyS0 and setting up a receive C program. Both exhibit the same results).
If I send data for a while (seems to vary from less than 10 characters to something over 20) at some point the uart seems to "wake up" and now data appears on the Olimex board. Once the data transfer starts it will keep going as long as I want and at fast or slow data rates. If I break out of the receive program or end the cat /dev/ttyS0 process and try to start receiving again, I need to go through the same process of "kicking" the uart until it decides it wants to receive again.
I have put an oscilloscope on the RX pin leading into the UART. The data coming in is at good levels and the data appears here from the very first send so the data is not being blocked initially and then arriving at the RX pin at some time later. So I am currently assuming that the issue is with a UART setting of some kind. Does anyone know of a UART setting that could possibly explain this behavior?
Below is the receive program that I am running. I don't think that there is an issue with it because I see the same behavior when I do a cat /dev/ttyS0. Any help here would be appreciated.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); return(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
buf[res]=0; /* so we can printf... */
printf("String:%s - Character Count:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
Sawdust made these comments....
"sends data to the serial buss" -- RS232 is not a "buss". "When I
start to send data" -- Your writing style is confusing. What kind of
data is sent to the Olimex? For the cat /dev/ttyS0 test, how did you
set up the serial port, or was it in an unknown mode? bzero(&newtio,
sizeof(newtio)); -- That is a dangerous way to setup the termios
structure. newtio.c_cflag = BAUDRATE... That is not the proper way to
set the baud rate; you need to use the cfset[io]speed() functions. You
write of a "kick", yet you don't mention doing anything explicit
ok, RS232 is not a buss, I misspoke....
The data I am sending is a stream of characters that are typed on Putty terminal.
For the /dev/ttyS0 test the settings are the same as are set in the c program. I verified this using stty.
I copied this code from another post. I was not sure what bzero did. If you could expand on "dangerous" that would be great. Or better if you have a better way to do what bzero does?
I will update the way to set baud rate.. but send is working perfectly and I verified using stty that baudrate was indeed 115200.
As far as "kicking" I mean that I need to send a number of bytes of data to the uart before any appear on the console. Others have mentioned a FIFO that may be an issue here but the first characters that are sent are lost. For example if I were to send the string of characters abcdefg.... I could type up until k and then l would appear on the console, and then any future characters after l would also appear in the console. If I were to go through the same process again after starting the receive program (or cat /dev/ttyS0) the point where the receive starts appearing could be in a different place (i.e. at h or n).

Related

Atmega8 microcontroller reading from bluetooth

I want to read a byte sent by Bluetooth to the Atmega8 to process it. I found this function online to receive a byte
uint8_t receiveByte()
{
// Wait until a byte has been received
while((UCSRA&(1<<RXC)) == 0);
// Return received data
return UDR;
}
but it doesn't work by say turning a led on if 'a' was sent, so when I changed it and enabled port c to HIGH just before the while loop, and turned it low after it, but port c never gone low - which means this loop is infinite.
so my question is how to fix it or how can I read a byte from Bluetooth module
its atmega8-16pu and I configured it as follows:
/** define the cpu clock frequency*/
#define F_CPU 8000000UL
and fuse = 0xD9C4, from this site http://www.engbedded.com/fusecalc/

Linux Serial Port Blocked using termios.h configuration

I'm writing an embedded Linux application that (1) opens a serial connection to another device, (2) sends a known command, (3) checks port for incoming characters (response) until expected response phrase or character is detected, (4) repeats step 2 and 3 until a series of commands are sent and responses received, (5) then closes the port.
My app would go through some cycles of the above sequence and every now and then it would be waiting for a response (reading) when all of a sudden the communication stops and my software faults out because of my built-in timeout logic.
Is there anything in my port configuration that would cause the port to be blocked due to specific byte sent (possibly due to electrical noise)?
Here is how I'm opening my ports (showing configurations via termios.h):
struct termios options;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
debug() << "Port open failed!"
return FAIL;
}
debug() << "Port Opened Successful"
fcntl(fd, F_SETFL, 0); // This setting interacts with VMIN and VTIME below
// Get options
tcgetattr(fd, &options);
// Adjust Com port options
options.c_cflag |= (CLOCAL | CREAD); // Program will not "own" port, enable reading on port
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Sets RAW input mode (does not treat input as a line of text with CR/LF ending)
options.c_oflag &= ~ OPOST; // Sets RAW ouput mode (avoids newline mapping to CR+LF characters)
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turns off SW flow c
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
// Set options
tcsetattr(fd, TCSANOW, &options);
//return fd;
return SUCCEED;
I can't figure out why the communication all of a sudden just freezes up and then goes away when I cycle power to my device. Thanks all!
More info - here are my read and write functions:
int Comm::Receive(unsigned char* rBuf)
{
int bytes;
ioctl(fd, FIONREAD, &bytes);
if (bytes >= 1)
{
bytes = read(fd, rBuf, 1);
if (bytes < 0)
return READ_ERR;
return SUCCEED;
}
else
return NO_DATA_AVAILABLE;
}
int Comm::Send(int xCt, unsigned char* xBuf)
{
int bytes;
if (fd == -1)
return FAIL;
bytes = write(fd, xBuf, xCt);
if (bytes != xCt)
return FAIL;
else
return SUCCEED;
}
Welcome to the joys of serial ports...
Thought 1: wrap your read calls with a select ()
Thought 2: Unset the ICANON flag in tcsetattr, and set a VTIME attribute for a deliberate timeout (and then, obviously, handle it)
Thought 3: Nothing about serial comms ever works perfectly.
I also had a similar problem with sending command to devices and reading responses from the device. Please refer to below SOF post and the answer this was working for my problem.
In these cases, We have to care about the protocol which we are going to use for device communication (send and receive). If we can send commands successfully and we didn't receive a response with a noise from device implies there is something wrong in the data packet which was sent to the device. First of all check the protocol specification first and create a byte array for a simple command (like make a beep sound) and send it.
Send data to a barcode scanner over RS232 serial port
I can do something for you If you can post your complete source code with the output.
Enjoy the code. Thanks.

Linux, serial port, non-buffering mode

I am trying to organize nob-blocking read-write functionality with serial port in Linux. Here is the code I have: http://pastebin.com/RSPw7HAi
It all works fine, but it is buffered. That means, that if I do input to serial via console + CR symbol, select detects new input, otherwise, if I do input via simple python script, it buffers all symbols and waits until I send it carriage return symbol.
So with this input (given below) it simply buffers symbols somewhere.
I have to PCs connected via USB2Serial converter
#!/usr/bin/env python3
import serial
cmd1_state = b'\x3E\x01\x00\x01'
#Selecting serial port for commands to be sent --> /dev/ttyUSB0
serial_0 = serial.Serial('/dev/ttyUSB2');
print("Using serial port ", serial_0.portstr);
serial_0.write(cmd1_state)
# closing serial port
serial_0.close()
So, can anybody tell me what to do here? Do I have to change something within port opening in my C file or it's to be done with python script? I used flush() method in later, but it also did not help.
BTW, I've googled out about F_NOCACHE arg to fcntl() function. BUT! It's all about BSD and Darwin OS's, there is no such thing (F_NOACHE arg to fcntl) in Linux, as far as I could see.
UPD:
Looks like I found out the solution.
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 char received */
tcflush(fd, TCIFLUSH);
Taken from : http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
Looks like I found out the solution.
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 char received */
tcflush(fd, TCIFLUSH);
Taken from : http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html

Linux 2.6.23 . Error In Receiving . Read function Returns -1

Please refer the Below code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <termios.h>
#define BAUDRATE B115200
#define SER_DEVICE "/dev/ttyS0"
#define FALSE 0
#define TRUE 1
int main()
{
int fd,c,res,i,n;
struct termios oldtio,newtio;
unsigned char buf[255] = "WELCOME TO THE WORLD OF LINUX PROGRAMMING\n";
unsigned char buf2[255]= {"\0"};
//Opening a Device for Reading Writing.
//O_NOCTTY : - The Port Never Becomes the Controlling Terminal of the Process.
//O_NDELAY : - Use NON-Blocking IO. on some system this also means Deactivating the DCD line.
fd=open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_NDELAY);
if(fd<0)
{
printf("\nError in opening the File\n");
exit(0);
}
else
{
printf("File Opened SuccessFull..HurraYYY !!!!1\n");
}
//printf("--------------Test Begin---------------\n");
//Save Current Serial Port Settings
tcgetattr(fd,&oldtio);
//clear the struct for New port settings
memset(&newtio,0,sizeof(newtio));
//Baud rate : Set bps rate .
//You could also use cfsetispeed and cfsetospeed.
//CRTSCTS : Output Hardware Flow control
//CS8 : 8n1(8bit No Parity 1 Stopbit)
//CLOCAL : local connection no modem control
//CREAD : Enable Receiving character
//printf("Setting Configuration for Port");
newtio.c_cflag |= (BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD);
//IGNPAR : Ignore bytes with parity error.
//ICRNL : map CR to NL
//printf("Setting Parity\n");
newtio.c_cflag |= (IGNPAR | ICRNL);
//RAW output
//printf("Raw Output\n");
newtio.c_oflag = 0;
//printf("Enabling Canonical format \n");
//ICANON : Enable canonical input.
newtio.c_lflag |= ICANON;
//printf("Initialising Char\n");
//Initialise all characters
newtio.c_cc[VMIN] = 1; /*Blocking read until one character arrives*/
newtio.c_cc[VTIME] = 0; /*Inter character timer unused*/
/*
Now clean the Modem Line and Activate the Settings for the Port.
*/
tcflush(fd,TCIFLUSH);
printf("Flushing Lines\n");
tcsetattr(fd,TCSANOW,&newtio);
n=write(fd,&buf,42);
printf("n=%d",n);
for(i=0;i<sizeof(unsigned int);i++);
for(i=0;i<sizeof(unsigned int);i++);
for(i=0;i<sizeof(unsigned int);i++);
for(i=0;i<200;i++)
printf("");
n=0;
n = read(fd,&buf2,42);
if(n==-1)
{
printf("\nError in Receiving");
}
else
printf("Received String = %s",buf2);
/*
Restore the Old Port Setting
*/
tcsetattr(fd,TCSANOW,&oldtio);
printf("==============TEST END==============\n");
close(fd);
}
I am able to transmit the String which appears on the Hyperterminal. But the Function Read returns value as -1.
The Possibility i found is :
1. for Receiving the Configuration is Wrong.
2. Looping back is needed or not.
I tried Looping Back to but it does not Work.
i executed the Code in while(1)
transmit ans Receive ... and if read returns something != -1 ..break from the Loop. But that to doesn't work.
What is the minimum delay that one should add in read/write cycle.
I am Executing this Code on MPC 8641d Processor.
Please Your Suggestion are important to me.
Hoping for your Guidence !!!! :)
To know the detailed reason for read() failing, you need to see what value is stored in the global variable errno (this is documented in the man page for read). An easy way to do that is to use perror() instead of printf() when you print the failure message--perror() will append a human-readable string that tells you the reason.
Read John Zwinck's answer before this one ;)
For background info about errno: http://www.gnu.org/software/libc/manual/html_node/Checking-for-Errors.html
To elaborate on the significance of the specific errno WRT read: not all "errors" mean "you've done something wrong" or "this connection cannot be read from". They may mean simply that this connection cannot be read from at this instant, eg, if errno is EAGAIN on a non-blocking connection.
That means you will have to figure out what the error is, and if it is of that sort, how to deal with it. Then you have to test against errno specifically, eg:
#include <errno.h>
int bytes = read(...);
if (bytes == -1) {
// example of an error which may happen under normal conditions
// for certain kinds of file descriptors:
if (errno == EAGAIN) {
// handle appropriately
} else {
// this is a real error which should not happen
}
}
You can find the constants by printing the int value of errno and looking thru errno.h. Chances are, they are actually in a file included by errno.h, such as /usr/include/asm-generic/errno.h and errno-base.h. Random example from the former on my system:
#define ECOMM 70 /* Communication error on send */
So perror() or strerror() would (probably) report "Communication error on send", but in any case, the int value of this is 70. Do not use that in your code, they can vary across implementations; #include <errno.h> and use the constant ECOMM.

Linux termios VTIME not working?

We've been bashing our heads off of this one all morning. We've got some serial lines setup between an embedded linux device and an Ubuntu box. Our reads are getting screwed up because our code usually returns two (sometimes more, sometimes exactly one) message reads instead of one message read per actual message sent.
Here is the code that opens the serial port. InterCharTime is set to 4.
void COMClass::openPort()
{
struct termios tio;
this->fd = -1;
int tmpFD;
tempFD = open( port, O_RDWR | O_NOCTTY);
if (tempFD < 0)
{
cerr<< "the port is not opened"<< port <<"\n";
portOpen = 0;
return;
}
tio.c_cflag = BaudRate | CS8 | CLOCAL | CREAD ;
tio.c_oflag = 0;
tio.c_iflag = IGNPAR;
newtio.c_cc[VTIME] = InterCharTime;
newtio.c_cc[VMIN] = readBufferSize;
newtio.c_lflag = 0;
tcflush(tempFD, TCIFLUSH);
tcsetattr(tempFD,TCSANOW,&tio);
this->fd = tempFD;
portOpen = true;
}
The other end is configured similarly for communication, and has one small section of particular iterest:
while (1)
{
sprintf(out, "\r\nHello world %lu", ++ulCount);
puts(out);
WritePort((BYTE *)out, strlen(out)+1);
sleep(2);
} //while
Now, when I run a read thread on the receiving machine, "hello world" is usually broken up over a couple messages. Here is some sample output:
1: Hello
2: world 1
3: Hello
4: world 2
5: Hello
6: world 3
where number followed by a colon is one message recieved. Can you see any error we are making?
Thank you.
Edit:
For clarity, please view section 3.2 of the Linux Serial Programming HOWTO. To my understanding, with a VTIME of a couple seconds (meaning vtime is set anywhere between 10 and 50, trial-and-error), and a VMIN of 1, there should be no reason that the message is broken up over two separate messages.
I don't see why you are surprised.
You are asking for at least one byte. If your read() is asking for more, which seems probable since you are surprised you aren't getting the whole string in a single read, it can get whatever data is available up to the read() size. But all the data isn't available in a single read so your string is chopped up between reads.
In this scenario the timer doesn't really matter. The timer won't be set until at least one byte is available. But you have set the minimum at 1. So it just returns whatever number of bytes ( >= 1) are available up to read() size bytes.
If you are still experiencing this problem (realizing the question is old), and your code is accurate, you are setting your VTIME and VMIN in the newtio struct, and the rest of the other parameters in the tio struct.

Resources