Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12603 Discussions

Problem with non-blocking UART I/O

Altera_Forum
Honored Contributor II
3,436 Views

Hi guys, 

I'm struggling with non-blocking UART (RS-232) I/O these days. 

I'm using the 9.1 suite with Software Build Tools for Eclipse, but it seems that the very same problem was also in previous releases (8.0SP1 for sure). 

 

When I enter main() I already have stdin,stdout,stderr already open, and I use them to do my I/O on a serial port. 

Then, I set the stdin to the non-blocking mode with  

 

if (fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK)==-1) // set stdin to non-blocking mode 

printf("fcntl() error\n"); 

 

and I have no errors. 

Then, I try to get chars from the UART with getc(stdin) inside a while(1) loop, but it always returns -1, even when I send chars from the terminal. 

 

I also tried setting the interrupt control register in the UART core with IOWR_16DIRECT(UART_0_BASE,12,128); which should enable the "interrupt on read ready", but nothing changed. 

I have no such problem using JTAG_UART, and that's ok while prototyping the system, but soon I need to go with the RS232, so I need to find a solution. 

 

Anyone of you had problem with this and got a way to solve it? 

 

Thank you very much in advance, 

Bye 

mantoz
0 Kudos
8 Replies
Altera_Forum
Honored Contributor II
1,475 Views

Hi, 

 

Here's how I have solved it: 

 

1) Copy altera_avalon_uart_read.c file (from C:\Altera\91\ip\altera\sopc_builder_ip\altera_avalon_uart\HAL\src directory) to your local project directory (so that it's compiled with your sources and thus will override the Altera's version). 

 

2) Modify the altera_avalon_uart_read() function's (the FAST DRIVER version at the end of the file) last line 

 

return count; 

 

to 

 

if (!block && count == 0 ) 

return -EWOULDBLOCK; 

else 

return count; 

 

This way getc() call will not block if O_NONBLOCK is used. 

 

I remember reporting this to Altera several years ago as a bug because the JTAG UART does it like this and can handle O_NONBLOCK correctly, but the normal UART can't. But it has not been fixed yet ... 

 

Jari
0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

JariS, 

thank you really really much for your help and your solution. 

I tested it today with the UART driver and it works flawlessy!! 

Now it works like a charm, thank really very much. 

I will try reporting it to Altera, directly via the MySupport service and if possible also to an Altera FAE, to see if it can be fixed in the next releases. 

All credits go to you, of course. 

 

Bye bye and hope I can return the favor in the future :) 

mantoz
0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

FYI, I was able to do non-blocking I/O (or at least input) successfully by just using the low-level read() system call, without replacing any library source files. I think the implementation of the STDIO routines in the version of newlib that's included with the Nios II IDE doesn't handle non-blocking FDs properly.

0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

I've noticed that Altera has fixed this O_NONBLOCK issue starting from version 10.0. 

 

With these latest versions of Altera tools there's no need to copy the altera_avalon_uart_read.c file to your local project and modify it ... 

 

Regards, 

Jari
0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

I have seen this problem in 10.1SP1. I ended up copying the entire altera_avalon_uart directory into the syslib in order to modify the altera_avalon_uart_read.c file. 

 

Why does it return an error for no data on a non-blocking call in the first place?
0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

Probably because that is what a posix/unix system would do. 

zero means 'end of file', so an error code is used for 'no data'.
0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

I think the altera_avalon_uart_read.c module has a bug in the handling of read in the high-speed driver. 

 

the very end of altera_avalon_uart_read() is ... 

 

/* Return the number of bytes read */ 

if(read_would_block) { 

return ~EWOULDBLOCK; 

else

return count; 

 

I think that instead of the 1's compliment of EWOULDBLOCK that it should be returning the 2's compliment (negative) value. 

 

The return value of this function (if negative) gets negated (made positive) and stuffed in ALT_ERRNO. The result of retuning ~EWOULDBLOCK is that ALT_ERRNO gets 12 or ENOMEM and not EWOULDBLOCK. 

 

 

0 Kudos
Altera_Forum
Honored Contributor II
1,475 Views

Hi, 

 

I'm facing the same problem with Quartus Prime 16.0 Lite edition. 

I have made the following changes to make the fgets function Non Blocking : 

_serialPort = fopen("/dev/uart_0", "r+"); 

fd = fileno(_serialPort); 

fcntl(fd, F_SETFL, O_NONBLOCK); 

 

After this it's been set to Non-Blocking, but inside the while loop when I'm passing a "STOP" command (should break out of the while loop) it's not reading the command and goes on continuously.  

I've tried your method but it's still not working. I've also checked that with getc(_serialPort) "-1" is being returned.  

 

Can you please kindly help me with this issue ?
0 Kudos
Reply