clarity on vfprintf function

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I am new to AVR GCC though I have been programming other microprocessors. In many compilers printf automatically sends the stream to serial port. Where does the string go in GCC? How do I open a FILE stream to use vfprintf etc. functions. Example code will be highly appreciated. Thank you all.

[/url]

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

in an obscure corner of the winAVR docs there's an explanation of the use of fdevopen() to associate standard output and input with I/O routines such as serial ports and LCDs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This obscure corner is under ``Standard IO facilities''. ;-)

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply, but can you also guide me to that obscure corner!

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

``Standard IO facilities'' are in the avr-libc Manual(WinAVR)
One example is i n /winAVR/examples/twitest/twitest.c or

....
int uart_putchar(char c)
{
  if (c == '\n')
    uart_putchar('\r');

	// wait for the transmitter to be ready
	while(!uartReadyTx[nUart]);
	// send byte
	if(nUart)
		UDR1 = c;
	else
		UDR0 = c;
	// set ready state to FALSE
	uartReadyTx[nUart] = FALSE;
	return 0;
}
.....
int16_t uart0getchar(void)
{
  uint8_t ch;

  if (bit_is_set(UCSR0A, RXC0))         // check if character is available
    {
    ch = inp(UDR0);                     // get the character

    if (!(inp(UCSR0A) & (BV(FE0) | BV(DOR)))) // check for errors
      return ch;                        // none, return character
    }

  return -1;                            // no valid cahracter
		                                
}
......

int LCD_putchar(char c)
{		
if(c < 0xc0)
	lcd_write(c);
	else
	lcd_write(PRG_RDB(&rus_table[c - 0xc0]));
	return 0;
}
...

main()

....
	fdevopen(uart_putchar, uart0getchar, 0);
//	fdevopen(LCD_putchar, uart0getchar, 0);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

beware slightly differfent code for UART based AVRs v.s. USART based AVRs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That was, what I was looking for too. Thanks for that. But I miss the tag for assigning different streams to different devices.

Ok, I have a somewhat intelligent VF-Display that also has a matrix keyboard controller inside. I want to use it as the standard output facility and now I understood how to do that.
Fine, but I also have a USART on that board talking to a PC. And I want to use both it with the printf() functions.

Am I right if I do the following:

FILE VFD
FILE SER
VFD = fdevopen(VFD_putchar, VFD_getchar, 0);
SER = fdevopen(uart_putchar, uart_getchar, 0);

This should assign stdin, stdout and stderr to the VFD stream and opens a second stream called SER.
Now accessing the steams with

printf( "hello");  // print to the VFD
printf("helloagain, SER); // print to the serial port

should be possible. Or am I wrong?
I ask before trying it inside my code, because it will be some work to recode that on my existing project. But if I have to redesign it, it would make the code much more elegant than it is now.

Best regards

Ulrich

best regards

Ulrich
-------------------------->>> connecting to car mains means connecting to the power supply from hell....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, a litte lef reply:

Yes I saw that it has to be:

FILE *VFD;
FILE *SER;

but
[code]
printf("hello again",SER) doesn't work. compiler says:
test.c:66: warning: too many arguments for format

so fprintf( SER, "hello again"); will be my friend?

could it be that easy?

thanks in advance

Ulrich

best regards

Ulrich
-------------------------->>> connecting to car mains means connecting to the power supply from hell....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everybody,
I found an easier way to write to serial port of our choice. I am using sprintf and have a routine which writes directly to serial port. Since the string is from sprintf is NULL terminated, the function waits till null.

Is this an OK approach compared to using vfprintf functions? interms of code size and speed

rgds

Parthasaradhi Nayani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uprinz wrote:

so fprintf( SER, "hello again"); will be my friend?

could it be that easy?

Yep. Plain standard C. ;-)

The only non-standard thing is fdevopen() which replaces the standard
fopen() function. fopen() takes a string argument (``file name''),
which I wanted to avoid to parse (parsing needs a lot more code). So
I thought fdevopen() would be a good compromise. The remainder of
stdio is basically according to the (C90) standard.

For convenience, the first stream opened for output will be assigned
to stdout [and stderr] as well, so you can shortcut fprintf(stream,
...) to just printf(...). This is in violation of the standard, of
course, since the standard requires that stdin/stdout/stderr are
already open by the time main() gets control. However, this is
basically impossible to have in our environment.

Still, you can always use explicit variables for the streams (as
you're doing), and avoid the stdin issue completely. You won't lose
anything by this.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To Jörg:

Thanks for that. As I wrote I need two (my be more) different streams with text-functionality. I.e. I need xprintf( "$d $h",x,y); as well as scanf( c); to a minimum of two or three devices existing parallel. ( Display with matrix keyboard connected to SPI, USART connected to an FTDI323B for PC communication and an option to attach some more of this boxes in master slave configuration via I2C)

By the way, how would you solve that? Should I generate a separate stream for each slave controller or should I implement an adressing option into the putc / getc routines?

OK, here is one advice for Nayani:
Serial port is slow. Even 230kBaud is slow in comparision to the speed of any AVR. So start sending characters immediately when the arrive in your putc() function. Otherwise there is a high chance to get a memory corruption if you send long strings without \0 at the end. Or you'll find out that you never have enough RAM for the rest of your application.

As you can see in the lot of app-notes for UART code you find on the net, U(S)ART routines have normally two types of buffer:
FIFO ( First In First Out). So a linear addressed char array where one pointer shows where to put new characters to and another pointer used for sending the characters. If pointer1 and pointer2 is pointing to the same position all data is send and the pointer can be reset to the buffers start.

The professional advance is to build a circularbuffer. So Pointer 1 fills in new characters, if the end of the buffer is reached, the pointer starts over at the beginning of the buffer. The second pointer runs behind the first sending out the characters. There are two pointer hits in this:
pointer2 (in) reaches pointer1 (out) so there is nothing more to send.
If pointer1 meets pointer2 your buffer is full. If your software is programmed as blocking, then put(c) will block the system until enough characters are send to store the remaining waiting characters.
If your putc() is non-blocking, it will send all bytes in the buffer but return immediately with an error-report and, may be, the ammount of bytes that where send.

Whoa, I hope I dind't get another 'How to post here' advice if this was to much detailed.

Regards
Ulrich

best regards

Ulrich
-------------------------->>> connecting to car mains means connecting to the power supply from hell....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ulrich,

Thanks a lot for your advice. In fact I have implemented similar round robin buffer in one of my applications, where I took a buffer size of 256 bytes. and the buffer itself starting at a page boundary. So the pointer automatically wraps around to the start of the buffer when increamented from 0xff.

It was really a nice piece of advice and I will definetly implement the same in my current project. Any more suggestions friend?

Thanks once again.

Regards

Parthasaradhi Nayani