I am coding with serial port in Linux.
And the requirement of the communication is 5ms inter-byte time
.
And It requires me to change parity mode(even and odd) for each byte before write()
call, according to what the byte's value is.
So I code like below(i describe code simply)
void setWakeupMode(int fd, bool mode) {
struct termios tio;
bzero(&tio, sizeof(tio));
tcgetattr(fd, &tio);
if (mode == false) {
tio.c_cflag &= ~PARODD;
} else if (mode == true) {
tio.c_cflag |= PARODD;
}
if(tcsetattr(fd, TCSADRAIN, &tio) < 0){
perror("tcsetattr Error");
}
}
int main(){
unsigned char a[2] = {0x01, 0x0F};
write(fd, a, 1);
setWakeupMode(fd, true);
write(fd, a+1, 1);
}
But the code doesn't satisfy inter-byte time resulting in almost 20ms.
So i tried print exact time between each system call like below.
int main(){
unsigned char a[2] = {0x01, 0x0F};
printf("write1 start : %s", /*time*/);
write(fd, a, 1);
printf("write1 end : %s", /*time*/);
setWakeupMode(fd, true);
printf("write2 start : %s", /*time*/);
write(fd, a+1, 1);
printf("write2 end : %s, /*time*/);
}
and This is the result
write1 start : 34.755201
write1 end : 34.756046
write2 start : 34.756587
write2 end : 34.757349
This result suddenly satisfy the 5ms inter-byte time, resulting in 1ms inter-byte time
.
So i tried several ways.
And finally i recognize that only when i print something right before tcsetattr(), inter-byte time is satisfied.
for example, if i remove printf("write1 end : %s, /*time*/);
like below
int main(){
unsigned char a[2] = {0x01, 0x0F};
printf("write1 start : %s", /*time*/);
write(fd, a, 1);
// printf("write1 end : %s", /*time*/); //remove this
setWakeupMode(fd, true);
printf("write2 start : %s", /*time*/);
write(fd, a+1, 1);
printf("write2 end : %s", /*time*/);
}
The result is surprisingly different, See the interval between write1 start
and write2 start
,
It is 18ms
.
write1 start : 40.210111
write2 start : 40.228332
write2 end : 40.229187
If i use std::cout instead of printf, the result is same.
Why does this weird situration happen?
-------------------------------EDIT--------------------------------
Since i see some answers, some are misunderstanding my problem.
I am not worrying printf()
overhead.
simply saying.
write()
s with 1byte But the interval between write()
s must be within 5mswrite()
, I have to change parity mode using tcsetattr()
18ms
, being blocked at tcsetattr()
almost time.printf()
or std::cout
right before tcsetattr()
, the interval reduce to 1~2ms
.that is, somehow, calling printf before tcsetattr()
make tcsetattr()
return from blocking faster.
--------------------------Update----------------------------
I have progress on this problem.
I said that i had to put printf()
or std::cout
to make blocking time short on tcsetattr()
.
But It was not printing something to affect to that problem.
It just needed some delay, that is, if i put usleep(500)
before calling tcsetattr()
, it also make an affect on inter-byte-time reducing by 1~2ms
, returning from tcsetattr()
faster.
I assume, if i call tcsetattr()
with TCSADRAIN
flag, it wait until all data in serial buffer is transmitted, and change to the setting i want.
and it could make some delay.
but if i calling specifically delay, before i call tcsetattr()
, the buffer state is already empty(because during the delay time, the data in serial buffer is transmitted), so that there is no blocking.
this is the scenario i assume, is it possible?
this is the scenario i assume, is it possible?
You must be quite right. sawdust wrote:
uart_wait_until_sent() in
drivers/tty/serial/serial_core.c
explains why the interval between characters is quantized when a "drain" is involved: the serial port driver is polled for the TIOCSER_TEMP (transmitter empty) status using a delay with only millisecond resolution.
That's almost right, except that the polling cycle resolution is not milliseconds, but jiffies:
while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time));
…
So if HZ is 100 and char_time
is 1 (the minimum), the status is checked every 10 ms. As you wrote:
but if i calling specifically delay, before i call
tcsetattr()
, the buffer state is already empty(because during the delay time, the data in serial buffer is transmitted), so that there is no blocking.
In other words, if you delay the process long enough that by the time it gets to the transmitter empty test !port->ops->tx_empty(port)
the transmitter is already empty, no sleep occurs; otherwise it sleeps for at least 1 jiffy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With