Standard I/O using a UART and ASF

Created on: 8 June 2016

Part 11 of the ASF ARM Tutorial

Standard Input/Output (I/O) is configured to use a UART in an Atmel Studio ASF project so that C stdio functions such as printf() and scanf() use the serial port UART as the standard input/output device.

An ASF module called the Standard serial I/O (stdio)(driver) is used to set up the UART as the stdio device. Strings printed using printf() are then sent out of the UART and scanf() receives input from the UART.

On the Atmel SAM4N Xplained Pro ARM Cortex board, UART0 is connected to the EDBG on-board embedded debugger. One of the functions of the EDBG, besides being used as a debugger, is to act as a virtual COM port when the board is plugged into a PC using the board's USB connector. The virtual COM port can be opened in a terminal emulator running on the PC and data can then be sent and received between the terminal emulator and microcontroller UART.

Standard I/O UART Project Hardware and Software

Hardware

This project simply uses the SAM4N Xplained Pro board and USB cable to connect to a PC. The virtual COM port of the EDBG then automatically appears on the PC and should be found by terminal emulator software.

If you are using a different board to the SAM4N, then check the board's user guide to see if it has an EDBG and which UART from the microcontroller is connected to the virtual COM port. The user guide for the SAM4N board shows that pins PA10 and PA9 are used for virtual COM port connections. UART0 is shown to connect to these pins in the ATSAM4N16C datasheet.

Terminal Emulator Software

Terminal emulator software such as Tera Term for Windows will be needed to test this project and communicate over the virtual COM port. The zipped version of Tera Term can be downloaded and opened and the folder inside extracted to a convenient location on the PC. Inside the folder find and run ttermppro.exe to start the terminal emulator.

Creating the ASF Standard I/O UART Project

This project basically provides the same functionality as the Serial Standard I/O (stdio) Example ASF example project which can be found in Atmel Studio by selecting File → New → Example Project... from the top menu bar. The difference is that this project is built from scratch using a user board ASF template and the steps to build the project are described below.

Start a New ASF Project in Atmel Studio

Create a new ASF project called stdio_uart in Atmel Studio as explained in the new ASF project quick start checklist.

Adding ASF Modules

Add the IOPORT service ASF module and the Standard serial I/O (stdio) driver module to the project. It is necessary to add the IOPORT module to be able to configure the microcontroller pins to use the UART.

ASF Modules used in the Stdio UART Project
ASF Modules used in the Stdio UART Project

Hardware Definitions and Configuration (conf_board.h and conf_uart_serial.h)

Add the definition in conf_board.h for the UART that will be used for stdio. This is UART0 on the SAM4N Xplained Pro board.

\src\config\conf_board.h

#ifndef CONF_BOARD_H
#define CONF_BOARD_H

#define CONSOLE_UART                UART0

// clock resonators
#define BOARD_FREQ_SLCK_XTAL        (32768U)
#define BOARD_FREQ_SLCK_BYPASS      (32768U)
#define BOARD_FREQ_MAINCK_XTAL      (12000000U)
#define BOARD_FREQ_MAINCK_BYPASS    (12000000U)
#define BOARD_MCK                   CHIP_FREQ_CPU_MAX
#define BOARD_OSC_STARTUP_US        15625

#endif // CONF_BOARD_H

The conf_uart_serial.h file is added to the project when the Standard serial I/O (stdio) ASF driver module is added to the project. Uncomment the USART settings in this file and change them to the desired values. Be sure to set the UART name (CONF_UART) to point to the correct UART for the board.

\src\config\conf_uart_serial.h

#ifndef CONF_USART_SERIAL_H
#define CONF_USART_SERIAL_H

/* A reference setting for USART */
/** USART Interface */
#define CONF_UART              CONSOLE_UART
/** Baudrate setting */
#define CONF_UART_BAUDRATE     115200
/** Character length setting */
#define CONF_UART_CHAR_LENGTH  US_MR_CHRL_8_BIT
/** Parity setting */
#define CONF_UART_PARITY       US_MR_PAR_NO
/** Stop bits setting */
#define CONF_UART_STOP_BITS    US_MR_NBSTOP_1_BIT

#endif/* CONF_USART_SERIAL_H_INCLUDED */

Hardware Initialization (init.c)

Pins PA9 and PA10 are set to use internal peripheral A which is UART0 by calling ioport_set_port_mode(). These two UART pins are then disabled as I/O pins by calling ioport_disable_port() which dedicates them to the UART.

\src\ASF\common\boards\user_board\init.c

#include <asf.h>
#include <board.h>
#include <conf_board.h>

void board_init(void)
{
    WDT->WDT_MR = WDT_MR_WDDIS;         // disable watchdog
    ioport_init();                      // call before using IOPORT service
    
    // configure UART pins
    ioport_set_port_mode(IOPORT_PIOA, PIO_PA9A_URXD0 | PIO_PA10A_UTXD0, IOPORT_MODE_MUX_A);
    ioport_disable_port(IOPORT_PIOA, PIO_PA9A_URXD0 | PIO_PA10A_UTXD0);

}

Application Code (main.c)

A usart_serial_options_t structure is set up in main() which is actually a USART initialization structure but can be used with the UART. The structure is initialized with the UART settings defined in conf_uart_serial.h.

stdio_serial_init() is called to initialize the UART and to set it up as the standard I/O device. Standard I/O functions such as printf() and scanf() can then be used in the project as shown in the code in main().

An initial message is written to the terminal emulator. scanf() is then used to check for characters from the terminal emulator which are echoed back to the terminal emulator using printf().

\src\main.c

#include <asf.h>

int main (void)
{
    char in_char;
    
    const usart_serial_options_t usart_serial_options = {
        .baudrate     = CONF_UART_BAUDRATE,
        .charlength   = CONF_UART_CHAR_LENGTH,
        .paritytype   = CONF_UART_PARITY,
        .stopbits     = CONF_UART_STOP_BITS
    };
    
    sysclk_init();
    board_init();
    
    stdio_serial_init(CONF_UART, &usart_serial_options);
    
    printf("\r\nHello, world!\r\n");

    while (1) {
        scanf("%c", &in_char);
        
        if (in_char) {
            printf("%c\r\n", in_char);
        }
    }
}