stdio setup, printf and pulling my hair out

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

I give up!

 

Porting some ICC projects over to GCC (WinAVR+AVRstudio4) All was going well until I had to get printf working.

My search of this forum has led me to the same stuff I found in the doco which basically says this:

#include <stdio.h>

static int uart_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

static int uart_putchar(char c, FILE *stream)
{
    if (c == '\n')
        uart_putchar('\r', stream);
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;
    return 0;
}

int main(void)
{
    init_uart();
    stdout = &mystdout;
    printf("Hello, world!\n");

    return 0;
}

The trouble is when I put this to my existing project I get the following error 4 times all for the 1 line where FDEV_SETUP_STREAM is used:

../Main.C:10: error: expected primary-expression before '.' token

 

I have also tried to go the other way and start with the above code in a new project. As I add each module 1 by 1 I can compile without errors but the last step is to add the hardware init routine (which includes the usart init) and then for some stupid reason it doesn't recognise the outside definition of the init file. ("undefined reference to HW_INI")

I can see no reason for this, its working perfectly for the partially ported project.

 

Does anyone have any clues? Am I missing some compiler option or setting somewhere?  I'm just using studio's default new project creation option.

These errors don't tell me anything.

 

Steve.

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

Zip and post the project

 

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

2 projects that exhibit each of the errors are attached.

 

Additionally I have performed a file comparison on the .aps and .aws files and the only significant difference I can see is the order of the source files. (-f unsigned char also)

Also note worthy is that one project doesn't seem to generate all the same .o and .o.d files as the other project does. I suspect this is the reason for 1 of the errors.

 

Steve

Attachment(s): 

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

I had trouble getting the macro to work inside C++ (Arduino) code, and ended up putting the following statement in the init (setup())code instead:

  static FILE mystdout;
  fdev_setup_stream(&mystdout, fput, NULL, _FDEV_SETUP_WRITE);
  stdout = &mystdout;

(that's a lowercase fdev_setup_stream() function call, rather than the uppercase macro.)

 

Oh, and for newlib-based code (including Atmel ARMs, I think?), you can do:

  static cookie_io_functions_t myVectors = { 0, fput, 0, 0 };
  stdout= fopencookie((void *)0, "w", myVectors);
  setlinebuf(stdout);

(which IMO is clearer than messing with _write_r(), which seems to be the usual newlib recommendation...)

 

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

No idea what you are doing here

	RS485_Tx0ON;			// enable RS-485 transmitter
	RS485_Rx0OFF;			// disable RS-485 receiver
	SETBIT(UCSR0A,TXC0);		// clear TXC flag (by writing 1)
	SETBIT(UCSR0B,UDRIE0);		// enable UDRE interrupt
	return 1;	

Are you turning on and off the RS485 transmit bit? The transmitter should be enabled BEFORE sending anything out and disabled AFTER TXC0 is 1.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Tue. Apr 7, 2015 - 03:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yep. On this board I have separate I/O for the DE and !RE pins. So I'm switching from receive to transmit.

 

Clearing the TXC flag is superfluous here because, in 485 mode, the TXC interrupt is used and takes care of it automagically.

On some other applications I have USARTs with both 232 & 485 drivers and when in 232 mode, the TXC interrupt isn't used but now I can still use the TXC flag to detect end of transmission.

In 485 mode I check if the DE line is released for EOT.

Last Edited: Tue. Apr 7, 2015 - 05:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I had trouble getting the macro to work inside C++ (Arduino) code, and ended up putting the following statement in the init (setup())code instead:

  static FILE mystdout;
  fdev_setup_stream(&mystdout, fput, NULL, _FDEV_SETUP_WRITE);
  stdout = &mystdout;

(that's a lowercase fdev_setup_stream() function call, rather than the uppercase macro.)

 

By "init (setup())code" do you mean the manual initialisation performed inside main() or are you referring to startup performed before the call to main()?

I'll give the function (vs macro) a shot. I expect since its performed at run-time, it will need to be inside main() where the assignment to stdout is done.

I also assume the declaration of mystdout still needs to be global?

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

As far as I know, FDEV_SETUP_STREAM uses named designated initializers to fill the struct. This language feature is only available in C, not in C++. That would probably explain the complaints about the .(full stop) in the macro expansion.

 

There's even a libc bug on it....

:: Morten

 

(yes, I work for Atmel, yes, I do this in my spare time, now stop sending PMs)

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

By "init (setup())code" do you mean the manual initialisation performed inside main()?

 

I also assume the declaration of mystdout still needs to be global?

 Yes; inside main should be fine.

I initially had mystdout as global, and that probably makes sense, but it should also work as a local defined with "static".

 

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

Well whadiya know - It works!

Many thanks.

Now onto the next porting challenge.

 

Steve