Search code examples
cembeddedavr

writing to FILE for transmission over USART


I have a bit of code written by someone else that I'm trying to understand. I'm familiar with c enough to make basic/intermediate functions, but never really learned to use the FILE handler. The code relates to how i use/initialise the USART on an ATMEL microcontroller, and I am adding comments to every line to help keep track, but i'm struggling a little with this.

#include <stdio.h>


int USART_0_printCHAR(char character, FILE *stream) // character =  the received character, FILE = reference file, *stream = pointer
{
    USART_Transmit_Char(character); //send the character over USART
    return 0; // return 0 to the caller for exit success.
}

FILE USART_0_stream = FDEV_SETUP_STREAM(USART_0_printCHAR, NULL, _FDEV_SETUP_WRITE); //what do these arguments mean? is it replacing a standard output stream with the character that is written to the buffer.

void USART_Transmit_Char(char data)
{
// code omitted: 
// check the Transmit buffer
// wait for free space in the buffer
// put the character into the buffer
// enable the Data Register Empty Interrupt for TX
}


Thanks.


Solution

  • You example initializes the default stream for the standard IO facilities. It creates a write only stream that writes its output to USART_0_printCHAR.

    See Standard IO facilities

    The standard streams stdin, stdout, and stderr are provided, but contrary to the C standard, since avr-libc has no knowledge about applicable devices, these streams are not already pre-initialized at application startup. Also, since there is no notion of "file" whatsoever to avr-libc, there is no function fopen() that could be used to associate a stream to some device. (See note 1.) Instead, the function fdevopen() is provided to associate a stream to a device, where the device needs to provide a function to send a character, to receive a character, or both.

    As an alternative method to fdevopen(), the macro fdev_setup_stream() might be used to setup a user-supplied FILE structure.

    #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;
    }
    

    This example uses the initializer form FDEV_SETUP_STREAM() rather than the function-like fdev_setup_stream(), so all data initialization happens during C start-up.