Customizing Helper Functions for XC8 AVR

When using the MPLAB XC8 Compiler for AVR MCUs, helper functions that can read and/or write one byte of data need to be written to define the source and destination respectively of the stdin and stdout streams used by IO functions like scanf() and printf(). In addition, objects of type FILE need to be defined and associated with each streams.

The FDEV_SETUP_STREAM() macro can assist with stream configuration. It expands to an initializer that can be used with the definition of a user-supplied buffer of type FILE, setting up that buffer so that it can be used with a stream that is valid for stdio operations. Streams can be read-only, write-only, or read-write, based on one of this macro's flag values _FDEV_SETUP_READ, _FDEV_SETUP_WRITE, or _FDEV_SETUP_RW.

The following example is applicable to the AVR128DA48 Curiosity Nano board and has writable FILE buffer assigned to stdout, which maps to USART1 via the uart_putchar() function.

#include <xc.h>

#define F_CPU                           (4000000UL)     /* using default clock 4MHz*/
#define USART1_BAUD_RATE(BAUD_RATE)     ((float)(64 * 4000000 / (16 * (float)BAUD_RATE)) + 0.5)

#include <util/delay.h>
#include <stdio.h>

void USART1_init(void)
{
    PORTC.DIRSET = PIN0_bm;                             /* set pin 0 of PORT C (TXd) as output*/
    PORTC.DIRCLR = PIN1_bm;                             /* set pin 1 of PORT C (RXd) as input*/
   
    USART1.BAUD = (uint16_t)(USART1_BAUD_RATE(9600));   /* set the baud rate*/
   
    USART1.CTRLC = USART_CHSIZE0_bm| USART_CHSIZE1_bm;  /* set the data format to 8-bit*/
                 
    USART1.CTRLB |= USART_TXEN_bm;                      /* enable transmitter*/
}

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);
    while(!(USART1.STATUS & USART_DREIF_bm))
    {
        ;
    }
   
    USART1.TXDATAL = c;
    return 0;
}

int main()
{
    USART1_init();
    stdout = &mystdout;
   
    int i = 0;
    while (1) {
        printf ("Hello world %d\n", i++);
    }
    _delay_ms(1000);
}