Frank's Random Wanderings

Atmel Xmega printf HowTo

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 
#include  

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.

7 thoughts on “Atmel Xmega printf HowTo

  1. Mike

    Thank you very much. I am working on getting scanf working too. Once I am done I will update you

  2. unnamed

    Hi, can you please show us how to send data from hyperterminal to xplain xmega ? I’am tryign for several days now, and i cant get it to work 🙁 Some help would be apprecieated 🙂

  3. Jörg

    Hallo Frank,
    thanks for the easy code.

    I tried to run this on 32 MHz
    If I use :

    USARTC0.BAUDCTRLB = 0; // BSCALE = 0 as well
    USARTC0.BAUDCTRLA = 207;

    It works.

    If I try

    USARTC0.BAUDCTRLB = 4; // BSCALE = 0 as well
    USARTC0.BAUDCTRLA = 12;
    (calculatet by a Baudrate Genrator from chip45)

    Sorry I´m just beginner in C 😉

    regards

    Jörg

Leave a Reply

Your email address will not be published.