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:
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.
Leave a reply