Fprintf () on avr-libc crashes instantly

I am writing a program to run on an ATmega328p - bare avr-libc

, not an Arduino, although it uses an Arduino bootloader over the serial port (I don't think this touches on the next question though).

I have set stdout

to write to UART with explicitly:

void uart_putc(char c)
{
  // Turn LFs into CRLFs
  if(c == '\n')
    uart_putc('\r');

  while(!(UCSR0A & _BV(UDRE0)))
    ;

  UDR0 = c;
}

static int _putc(char c, FILE *_)
{
  uart_putc(c);
  return 0;
}

...
  fdev_setup_stream(stdout, &_putc, NULL, _FDEV_SETUP_WRITE);

      

If I now write my program using only fputc

and fputs

, then everything works fine. I can even call snprintf()

to format the formatted strings in char buffer[16]

and then fputs()

them; it all works great.

fputs("Hello, world\n", stdout);  /* works fine */

char buffer[16];
snprintf(buffer, sizeof buffer, "Hello, %s\n", "world");
fputs(buffer, stdout);             /* also works fine */

      

However, the moment I try to execute the real fprintf()

before stdout

, the program crashes and restarts the ATmega:

fprintf(stdout, "Hello, %s\n", "world");

      

Fails immediately before outputting the initial here H

.

Can anyone suggest something that might be missing that will stop working fprintf()

when both snprintf()

and fputs()

can work fine?

+3


source to share


1 answer


You are using fdev_setup_stream()

to update the destination stdout

. The documentationfdev_setup_stream()

explicitly states:

Note: Fdev_setup_stream () will not assign standard streams. If standard streams are to be used, they must be assigned by the user.

The same document provides example code for using stdio without malloc . The code looks very similar to yours, except for two things:

  • The custom flow is defined using a macro fdev_setup_stream()

    :

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

  • stdout

    initialized with this custom thread:

    stdout = &mystdout;
    
          



I think your code is using an uninitialized stream stdout

. An Introduction to Standard I / O Objects (www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#details) reads:

The standard streams stdin, stdout and stderr are provided, but contrary to the C standard, since avr-libc does not know about the applicable devices, these streams are no longer initialized when the application starts.

When uninitialized, the behavior of all function calls with help stdout

is undefined. Depending on where it actually points stdout

, some calls might work.

0


source







All Articles