This is a surprisingly common question.  When using WinAVR, how do you get printf() working on an Atmel Xmega processor?  Hopefully this post will help explain how.

First of all, this documentation page has some good information regarding the different flavours of WinAVR printf:

http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

Note the existence of the printf_P() function, which makes it easy to work with strings kept in program space (flash).  This can be super useful on an AVR, which has very little SRAM but loads of flash.  The regular printf() function will put your text string in SRAM, which is not always ideal.

The big question after reading that documentation page is: how do I initialise the UART, and how do I implement the putchar function, on an Xmega?  Because the example code on that webpage is geared towards the non-xmega parts.

Here’s some Xmega example code. Feel free to use it however you see fit.

#include <stdio.h>
#include <avr/io.h> 
 
static int uart_putchar(char c, FILE *stream);
static void uart_init (void);
 
static FILE mystdout = FDEV_SETUP_STREAM (uart_putchar, NULL, _FDEV_SETUP_WRITE);
 
 
int main (void)
{
    uart_init();
    stdout = &mystdout;
 
    while (1)
        printf("Hello, world!\n");
}
 
 
static int uart_putchar (char c, FILE *stream)
{
    if (c == '\n')
        uart_putchar('\r', stream);
 
    // Wait for the transmit buffer to be empty
    while ( !( USARTC0.STATUS & USART_DREIF_bm) );
 
    // Put our character into the transmit buffer
    USARTC0.DATA = c; 
 
    return 0;
}
 
 
// Init USART.  Transmit only (we're not receiving anything)
// We use USARTC0, transmit pin on PC3.
// Want 9600 baud. Have a 2 MHz clock. BSCALE = 0
// BSEL = ( 2000000 / (2^0 * 16*9600)) -1 = 12
// Fbaud = 2000000 / (2^0 * 16 * (12+1))  = 9615 bits/sec
static void uart_init (void)
{
    // Set the TxD pin high - set PORTC DIR register bit 3 to 1
    PORTC.OUTSET = PIN3_bm;
 
    // Set the TxD pin as an output - set PORTC OUT register bit 3 to 1
    PORTC.DIRSET = PIN3_bm;
 
    // Set baud rate & frame format
    USARTC0.BAUDCTRLB = 0;			// BSCALE = 0 as well
    USARTC0.BAUDCTRLA = 12;
 
    // Set mode of operation
    USARTC0.CTRLA = 0;				// no interrupts please
    USARTC0.CTRLC = 0x03;			// async, no parity, 8 bit data, 1 stop bit
 
    // Enable transmitter only
    USARTC0.CTRLB = USART_TXEN_bm;
}

This code shows the things you need to do, in its most basic form. It only demonstrates transmitting out the UART; there’s no receive here (we are talking about printf, after all).  This code:

  • sets up the stdout FILE  (mystdout in this example)
  • initialises the UART. In this example USARTC0 is used, but you can of course use any USART block.
  • implements the putchar function
  • does a printf(“hello world”) forever in main().

Note the initialisation sequence. With the Xmega it’s important to manually set the UART transmit pin, ie the corresponding port pin, as an output, and set it high, before configuring the UART. This is specified in the Xmega documentation, and is different to most other AVR parts which don’t have this requirement.

Note also that the UART is set to 9600 baud, no parity, 8 data bits, 1 stop bit. I have this code running on an ATXmega128 board (an Atmel Xplain board).

This should be enough to get things started, and you can build on it from here.