[AVR] Implementing a non-blocking UART getchar() - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 05, 2019, 12:34:23 pm
content: I ran into a situation where it would be desirable to have a non-blocking getchar(). Basically, where I want to spit out data over the UART to a serial console, and keep doing so until the user presses a key. Obviously, when getchar() is blocking, it will stall the loop when checking if a key has been pressed.I was wondering about how I could go about implementing, in the context of using the avr-libc standard library's stdio (stdin, stdout, fdev_setup_stream(), etc.), a non-blocking read of the standard input stream.At the moment, I just have the usual blocking get() implementation to read a character from UART (AVR part I'm using has combined LIN/UART functionality, so registers are named LIN*):Code:int uart_getchar(FILE *stream) {loop_until_bit_is_set(LINSIR, LRXOK);return LINDAT;}A strategy I had in mind was to take advantage of fdev_set_udata(). I would use the udata value as a flag indicating whether I want blocking or non-blocking functionality. Then, in my UART get() implementation, I would simply switch functionality depending on the value of the flag. Something like this, perhaps:Code:int uart_getchar(FILE *stream) {if(*((uint8_t *)fdev_get_udata(stream)) & FLAG_NON_BLOCK) {return (bit_is_set(LINSIR, LRXOK) ? LINDAT : EOF);} else {loop_until_bit_is_set(LINSIR, LRXOK);return LINDAT;}}Will this work? Has anyone done anything like this before?

author: semir-t
author_rank: Regular Contributor
timestamp: February 05, 2019, 01:07:28 pm
content: In this case I would use the interrupt capabilities of AVR. Depending on what you need you can change the ISR, but in your case you could use some like this:Code:uint8_t state = 0x01;void main(void){if( state ){\\ receive data}}ISR(UART_RX_vect){status = 0x00}This is just concept for the ISR routine you might have to clear some flags in this routine ( more info in the datasheet of the MCU)

author: firewalker
author_rank: Super Contributor
timestamp: February 05, 2019, 04:22:06 pm
content: If I remember correctly Peter Fleury has a nice interrupt driven uart library.http://homepage.hispeed.ch/peterfleury/avr-software.htmlAlexander.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: February 05, 2019, 04:36:40 pm
content: The Peter Fleury lib is over 10 years old now, but of course that does not mean it won't work anymore.I would also use interrupts like semir-t.The ISR gets called whenever a character is received, and it puts it in a circular buffer.Your non blocking getch() then just checks if there are characters in this circular buffer.

author: @rt
author_rank: Super Contributor
timestamp: February 05, 2019, 04:47:49 pm
content: If you can’t have an interrupt driven routine, and your main loop is fast enough,you can check whether or not there’s a byte in the buffer for every cycle of your main loop.If there’s a byte received, rotate it into a buffer, check whether it’s a terminating character such as return, or the result of a count, etc.act on the receive buffer if it is, and reset that array index... or simply continue if no byte was received, and allow the main loop to check next cycle.

author: NorthGuy
author_rank: Super Contributor
timestamp: February 06, 2019, 12:54:12 am
content: The purpose of the Interrupt would be to do something with the character quicklyifyour code is busy doing something else. In such case, without the interrupt in place, the character may be lost.If you call "uart_getchar()" frequently enough, then there's absolutely no need for the interrupt. Your user cannot type really fast, so you probably have plenty of time between calls. The easiest way is to check if the character has arrived prior to the call to "uart_getchar()" and call it only if it has. This way you don't need to modify the function or mess with the flags.

author: westfw
author_rank: Super Contributor
timestamp: February 06, 2019, 02:25:06 am
content: QuoteWhy are you set on "the context of the avr-libc library"?Just implement a new function using the fdev-style arguments..."inputpending()" would be common, checked in "user" code, but you could go all the way to "getc_nb()"

author: cv007
author_rank: Frequent Contributor
timestamp: February 06, 2019, 04:48:41 am
content: No one is always going to remember to use a non-blocking attribute, and it could be long after it is forgotten before the trouble shows up.I would simply not block, returning eof if no data available. Let the caller call until data is available, if it wants to block it can, if it wants to do other things while waiting, it can. You now have a purpose for eof on a micro, and the caller will now be required to check it like it is supposed to. I would also check for uart errors and not give any uart data out that has an error associated with a byte (simply discard, set an error or inc an error counter, reset uart if needed). If one forgets to check return values, it will not take long for that mistake to reveal itself.It would seem to me that the case for blocking inside some library on a micro for something that may not ever happen is not a great idea. On your pc, at least you can still use your web browser while blocking on a getc.

author: Zarhi
author_rank: Contributor
timestamp: February 06, 2019, 05:15:08 am
content: Look at LUFA libraryhttp://fourwalledcubicle.com/LUFA.phpLUFA/Drivers/Peripheral/AVR8/Serial_AVR8.hCode:static inline bool Serial_IsCharReceived(void){return ((UCSR1A & (1 << RXC1)) ? true : false);}static inline int16_t Serial_ReceiveByte(void){if (!(Serial_IsCharReceived()))return -1;return UDR1;}LUFA/Drivers/Peripheral/AVR8/Serial_AVR8.cCode:int Serial_getchar(FILE *Stream){(void)Stream;if (!(Serial_IsCharReceived()))return _FDEV_EOF;return Serial_ReceiveByte();}int Serial_getchar_Blocking(FILE *Stream){(void)Stream;while (!(Serial_IsCharReceived()));return Serial_ReceiveByte();}

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 06, 2019, 03:46:32 pm
content: I did this from scratch (not in libc), using two circular buffers, and a series of functions for reading and writing the state of the buffers. Standard code is available elsewhere.Be careful that the buffers and state variables are declared volatile, and that other functions don't clobber their state, potentially in the middle of an operation -- you need atomic access to do this correctly. (Typically, the main()-facing functions will cli(); before and sei(); after making a check of the buffer, to ensure the buffer check operation doesn't get interrupted by its interrupt.)I forget if libc has a general-purpose file or character stream interface, i.e., one on which you can set a callback function which is used to implement the low-level functionality; a driver. This kind of approach would be able to use library functions as such; but it will be a rather heavy weight solution for just a puny AVR!Tim

author: TomS_
author_rank: Frequent Contributor
timestamp: February 06, 2019, 10:14:48 pm
content: My two suggestions, as most have already pointed out in some form or another:1. An interrupt on a received char which sets a flag somewhere, and in your main loop, check if that flag is set and process the received character2. If not using interrupts, on each iteration of the main loop, check if there is a char waiting in the UART receive buffer and if there is process itIn either cased you are probably going to want to implement some kind of state machine to handle the asynchronous nature of what you are trying to implement.Each iteration of the main loop, branch in to the state machine. The state machine at this point is in a state which is "wait for a character". If there is no character the state machine returns, leaving its state unchanged so next time you branch in to it, it checks for a character again. If there is a character it puts that character in to a buffer and changes state to "process a character" which may include some flavour of looking for line termination to determine if the user has pressed enter etc.Once the input has been processed the state machine could set a flag somewhere to signal to another state machine that it can proceed with the data that has been collected.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 07, 2019, 10:24:01 am
content: Thanks for all the suggestions everybody.I was mainly looking to see if there were any gotchas with my udata idea. I'm not really looking to move to interrupt-driven buffered UART I/O, as in fact pretty much all of my other UART I/O code on this project relies on blocking behaviour of getchar(). Also, I have previously written my own buffered UART functionality, so actually I'm no stranger to what's involved. There's just this one particular situation I have run into where it would be handy to switch to non-blocking behaviour, and I was pondering ideas for toggle-able behaviour.The loop where I'd be calling a non-blocking getchar() would indeed be fast enough to register user input, so that's not a worry. And, it's not even really taking textual input, just a 'press any key to stop' kind of thing. It's for a diagnostic function that just spews out data until the user wants to quit.Think I'll just experiment with my initial idea and see if it works out, otherwise I'll consider alternatives.Quote from: westfw on February 06, 2019, 02:25:06 amBecause I'm using puts, printf, scanf, etc. for serial I/O, and so a solution needs to fit with that.Quote from: Zarhi on February 06, 2019, 05:15:08 amThanks for directing me to have a wander within the LUFA code... but for tangential reasons.I noticed this recent entry in the changelog:"Added AVRISP-MKII support for target OSCCAL calibration". A while back I was wishing LUFA's AVR-ISP MkII code supported that, as I could have made use of it. I shall have to update my clone MkII's firmware once this change makes it to a stable release.

author: VinzC
author_rank: Frequent Contributor
timestamp: February 07, 2019, 11:57:46 am
content: Interrupt-driven receiving is not the only way and there are some interesting points to take into account.If you can only rely upon a "getchar()" call, then you might want to return anint(at least more than 8-bits) instead of achar(just 8 bits). That is if your receiving routine expects bytes from the whole 8-bit range.Since it involves 2 registers and that might be overkill on an 8-bit architecture, depending on your software needs, yourgetchar()routine might as well return 0 (zero) or 0xFF if there's no character available.Other than that you might check the bit for "receive buffer full" (the LRXOK bit) *before* processing any input data. However this must be done from the main loop instead. Or at least from anywhere you want to process received data.Another possibility, if you like OOP, is to abstract the returned type and use a (specifically crafted) C++ struct with a pair of overloaded conversion operators, one for type "bool", i.e.operator bool() const {...}, that returns "true" if there's a character in the UART input register, one that returns that character, e.g.operator uint8_t() const {...}. You can design such a structure with inline member functions so that it provides absolutely zero code overhead, by the way. I've done that and it works like a charm.This doesn't prevent from making the test before processing the character if it's available, of course. However the abstraction class/struct is all you'd need to rewrite if the platform changed.