LUFA – First Steps Part 1

Introduction

This week I used the LUFA framework to implement a simple USB-Serial device. USB isn’t at the trivial end of the embedded system development spectrum and LUFA goes a long way to ease the pain but getting started can be difficult. Here goes the first blog post…

The starting point for my little project was a need to debug the message exchange between nodes in an XpressNet bus. XpressNet is a model railway control bus developed by Lenz Elektronik GMBH. It uses RS-485 level signals with 9-bit characters over an asynchronous serial line. One node, the controller, operates as the bus master. All other nodes operate as bus slaves and wait until polled before becoming active on the bus.

To monitor the bus the RS-485 level signal is routed through a level converter, a TI 75176, and then into an AVR ATMEGA32U4 microcontroller. The microcontroller attaches to the monitoring computer using USB. This article focuses on using the open source LUFA framework to bring XpressNet messages into the PC over a USB serial channel.

LUFA Sample Code

LUFA is an acronym for Lightweight USB Framework for AVRs and was written by Dean Camera. You install it into Atmel Studio, the Atmel IDE, using the Studio Extension Manager. Once installed the LUFA extensions become available through the ASF wizard. I’m no ASF expert but it appears to function as a large cut and paste database.

A good way to get started with LUFA is to create the USB to Serial example and read through the code. Start with File->New->Example Project…, expand the item “Four Walled Cubicle…” and select “USB to Serial Converter – AVR8 Architecture”. This creates a new project structure and copies all the required LUFA files into the selected directory. A quick note, Atmel Studio doesn’t like directory names with embedded spaces.

At this point it is possible to compile the sample code and download it to a suitable AVR device, in my case an ATMEGA32U4 breakout from Sparkfun. Am happy to report that it worked first time. Whilst I recommend reading the sample code it can be a little daunting, there is a lot of code and it can be difficult to know where to start.

The Monitor Project

I could have started with the Serial Converter example and changed it to fit my needs. However, this doesn’t really answer the question of how to add LUFA support. More importantly it doesn’t tell me what I need to do to get LUFA working with the minimal amount of code.

So step one was to create a new project using the New Project tool. In my case a C language executable targeting the ATMEGA32U4. Once created I then applied the ASF Wizard to add LUFA support. This can be a little tricky, the ASF Wizard will complain about a missing board. I found that by either cancelling the board dialog or accepting a board of ‘None’ would allow me to progress. You then need to select the FourWalledCubicle extension and then ‘Add’ the ‘LUFA USB Driver (driver)’ module. Clicking the ‘Apply’ button copies the relevant LUFA code to your project. You should have your main C source file in the project root plus the LUFA directory ‘src’. Clicking the ‘Build Solution’ button should result in compilation failure due to some undefined symbols (F_CPU and F_USB).

The LUFA documentation discusses a build system based on Make. I found I could configure the project using the standard Studio settings without resorting to a custom makefile and wonder whether Dean has done a better job of Studio integration that his documentation leads you to believe.

I got the project to compile successfully by defining the following symbols under the project properties (Toolchain->AVR/GNU C Compiler->Symbols):

  1. DEBUG
  2. USE_LUFA_CONFIG_HEADER
  3. F_CPU=16000000
  4. F_USB=16000000
  5. ARCH=ARCH_AVR8

From memory, items 1 & 2 were created by the ASF Wizard. The effect of USE_LUFA_CONFIG_HEADER is discussed in the next section. Items 3 & 4 must be added. The value here is the clock frequency in Hertz; the Sparkfun board comes fitted with a 16MHz crystal. The ARCH symbol isn’t strictly necessary, I found it defaults to ARCH_AVR8 somewhere in the LUFA framework. I prefer to specify these type of things upfront as it makes things a little easier to understand.

At this point the project should build cleanly.

LUFA Configuration

The monitoring project is designed to operate as a USB device, over a fullspeed, i.e. 12Mb/s, connection. It logs a serial data stream so I decided to implement it as a communications device. The USB terminology is Communications Device Class or CDC device for short.

LUFA itself is designed to support multiple Atmel micro controller families and USB modes. Defining the symbol USE_LUFA_CONFIG_HEADER forces the LUFA framework to take its global settings from the configuration file src/Config/LUFAConfig.h. The sample below is abbreviated, anything not mentioned is to be assumed irrelevant and has been commented out the source file. Further information is found in the LUFA documentation under “Developing with LUFA/Summary of Compile Tokens”.


/*
LUFA Library
Copyright (C) Dean Camera, 2014.

dean [at] fourwalledcubicle [dot] com
http://www.lufa-lib.org
*/

/** \file
* \brief LUFA Library Configuration Header File (Template)
*
* This is a header file which can be used to configure LUFA's
* compile time options, as an alternative to the compile time
* constants supplied through a makefile. To use this configuration
* header, copy this into your project's root directory and supply
* the \c USE_LUFA_CONFIG_HEADER token to the compiler so that it is
* defined in all compiled source files.
*
* For information on what each token does, refer to the LUFA
* manual section "Summary of Compile Tokens".
*/

#ifndef __LUFA_CONFIG_H__
#define __LUFA_CONFIG_H__

#if (ARCH == ARCH_AVR8)

#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
#define USB_DEVICE_ONLY

#define USE_FLASH_DESCRIPTORS
#define FIXED_CONTROL_ENDPOINT_SIZE 8
#define DEVICE_STATE_AS_GPIOR 0
#define FIXED_NUM_CONFIGURATIONS 1
#define INTERRUPT_CONTROL_ENDPOINT

#elif (ARCH == ARCH_XMEGA)
... SNIP ...
#else

#error Unsupported architecture for this LUFA configuration file.

#endif
#endif

LUFA Options

Setting Description
USE_STATIC_OPTIONS

Hardcodes the USB_Init function parameter.

USB_DEVICE_OPT_FULLSPEED
Allows USB Fullspeed operation
USB_OPT_REG_ENABLED
Enables the on-chip 3.3V regulator
USB_OPT_AUTO_PLL
Lets the LUFA code figure out the PLL setting automagically
USB_DEVICE_ONLY LUFA supports USB hosts and devices. The monitor operates as a USB device, only include that part of the framework.
USE_FLASH_DESCRIPTORS Device descriptors are data structures used to control USB operation. See Part 2 for descriptor discussion. Placing the descriptors in program Flash makes them read-only but saves on RAM.
FIXED_CONTROL_ENDPOINT_SIZE Controls the buffer size allocated to the control endpoint (Endpoint 0)
DEVICE_STATE_AS_GPIOR Some AVR microcontrollers provide user controlled registers in their IO map. Selects GPIO register 0 to hold the USB state
FIXED_NUM_CONFIGURATIONS Only one USB configuration exists
INTERRUPT_CONTROL_ENDPOINT Allows the function USB_USBTask() call to be managed be the LUFA framework. User does not need to call

Continue with Part 2…

Advertisements
This entry was posted in AVR, Microcontroller, USB. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s