Home arrow Tutorials arrow Software arrow Getting Started With The ATXMega - The ATXMega Test Library
Getting Started With The ATXMega - The ATXMega Test Library | Print |
Written by Akiba   
Tuesday, 06 July 2010

The ATXMega is an upgraded version of the popular AVR microcontroller from Atmel. It still contains the basic AVR core but has a huge amount of enhancements to both the core and the peripherals. Basically, you can think of it like an AVR on steroids…a whole lot of steroids. Switching from the ATMega to the ATXMega series is a bit overwhelming because there are so many new features and improvements. Consequently, there is also a lot of new documentation which shows how to use the new features and the old ones. Because of the potential register shock to people that try out the ATXMega, I decided to put together a library of the Atmel drivers and some example functions. And of course, all the functions are ported and tested. Some of the examples may seem trivial, but they’re not designed for evaluation purposes. Their real purpose is to serve as a reference on how to access and use the peripherals, now that the register set is different.

Bootloader

One of the first things I always do with a new microcontroller board is load a bootloader on it. I prefer developing with bootloaders whenever possible because its much easier than pulling out the JTAG debugger. It’s also handy for on-location development where all you need is a USB cable.

Atmel did a very nice thing and released the source code to their serial debugger for the ATXMega and I’ve ported it to the board and included the package in this post along with the binary hex file. The bootloader comes pre-loaded on to all of the boards, but if it ever gets wiped, ie: you’re debugging with a JTAG debugger, then all you need to do is re-load it on to the board. The port to AVR-GCC is thanks to damien_d from the AVRFreaks forum:

Bootloader Source Code Link

The first thing you'll want to do is to build the ATXMega test files by extracting all of the files into a directory. To do that, just go into the directory where the test files are and type:

make 

Next is to connect the USB to the target board and turn the board on. You'll need to figure out which COM port the board is on. The boards use an FTDI USB to serial converter which is very standard and supported on Windows, Linux, and Mac platforms. If you have any problems with the driver, you can find your platform here and download the driver . Once you figure out the COM port, you’ll need to go into the makefile and configure AVRDUDE with that COM port.
Look for this line:

AVRDUDE_PORT = com2    # programmer connected to serial device

and change it to whichever COM port the board is on.

Once that’s done, you follow the same sequence as with the other FreakLabs MCU boards, where you push and hold down the BOOT button while pressing and releasing the RESET button. If this sequence seems bizarre to you, check out my bootloader tutorial. The board should now be in bootloader mode and ready to accept new code.

The AVRDude program is used to program the boards. AVRDude is an open source firmware downloader for AVRs and is included in WinAVR for Windows and CrossPack for Mac. For Linux, you can either download the program directly here , or use a package manager and download it using the name "avrdude". Support for downloading via AVRDude is already integrated into the makefile.

After the correct COM port is set in the makefile and the board is connected and in bootloader mode, you can simply download by typing 

make program 

You should see something like this:

And finally, you can then get a command prompt when you open up your terminal program that looks like this:

You can ignore the "Command not recognized" message at the top. You need to press Enter to trigger the command shell to re-print the prompt when you first connect via terminal. 

ATXMega Test Library

Now it's time to get into the nitty-gritty. I've put together example functions and integrated them into a command line shell. The test code is not really comprehensive, since the ATXMega feature set is too huge. However it should be enough to get people started working with the ATXMega and get a feel for how to migrate from an ATMega to the ATXMega. The test code currently consists of example functions that use the following:

  • External Bus Interface (EBI)
  • I2C
  • SPI
  • RTC
  • PLL
  • EEPROM 
I'm hoping to add more to it later on as time allows or if others are interested to contribute, that'd be awesome.

External Memory Bus
Although it’s not a new feature, the ATXMega-A1 family has an external memory bus which allows the user to add SRAM or SDRAM to the chip. For wireless applications, SDRAM is usually not a good idea because of the charge leakage from the memory cells. If you ever wondered why SDRAM needs to be refreshed, its because the charge gradually degrades in each memory cell. SDRAM uses a simple memory architecture which allows it to be manufactured cheaply and in high densities, but the power leakage is no good for battery operation.

For the FreakLabs ATXMega-A1 boards, I populated them with 32 kB of external SRAM. SRAM is a much better alternative to SDRAM because of the charge leakage issue, although it’s also more expensive. The boards actually support up to 512 kB of SRAM, however there’s a 64 kB limit on AVR-GCC for the total RAM space. Since 16 kB of RAM is taken up by internal peripherals and memory, there’s only 48 kB of available external RAM space that can be used. I was faced with the decision of using 128 kB of SRAM (64 kB SRAM is very uncommon and expensive) or 32 kB SRAM. I decided to use the 32 kB chips to keep the board costs down and also because over half of the 128 kB RAM would go unused because of the compiler limitations. Along with the 8 kB of internal RAM, that should be enough for most applications.

I also put together some simple commands to read and write the external RAM. It’s not super useful to read and write single bytes of RAM from the command line, but the functions can be used as a reference if you ever need to access the external RAM directly.

For reading a byte from external memory address, type:

rd <addr>

Ex: “rd 3” will read address 3 of the external RAM. The address is a hex value and address 0 is the bottom of external memory. When you call this function, it’ll print out the value at the specified address on the command line.

For writing a byte to external memory, type:

wr <addr> <data>

Ex: wr 3 ff
This writes a value of 0xFF to address 3 of the external RAM. Both the address and data are in hex.

I’ve also put together a memory test which will test the complete 32 kB external memory space. It starts by seeding a pseudo-random number generator and writing random numbers into each address in memory. It then re-seeds the random number generator with the same starting value which will generate the same sequence of random numbers. It’ll then read out each address in memory, compare it with the expected value, and flag any differences it finds.

To perform the memory test, type:

memtest

One last thing I did for the external memory bus was to create a large 32 kB array and locate it in external RAM:

// create large array and locate it in external SRAM.
// this assumes that a memory section has been created in the makefile
// called ".extsram" . Check makefile for an example of how to do this.
#define BIG_ASS_ARRAY_SZ 32000
static U8 big_ass_array[BIG_ASS_ARRAY_SZ] __attribute__((section(".extsram")))= {0};

This was done as a demonstration of how to locate structures and arrays in external memory. I’ll probably do a post later on about other ways to use external RAM, but this is a pretty efficient way to do things for protocol stacks. The reason is because in protocol stacks, you usually have some type of managed memory which consists of a single large array that serves as a memory pool. This memory pool is used for dynamic allocation of memory for things like routing table entries and usually has some type of logic to prevent memory fragmentation which plagues communication stacks. Anyhoo, I made this example to show how a large managed memory pool can be created in external RAM. I also wrote a function similar to the memory test, but instead does a memtest on the array rather than the individual memory addresses. To call the function, type:

bigtest

SPI

One of the nice things about the ATXMega is that it has 4 independent SPI ports. The FreakLabs board uses two independent SPI ports on each of the peripheral connectors. This is nice because you don’t have to worry about switching between different SPI modes if you have SPI peripherals hanging off each of the connectors. This is actually fairly common issue if you’re using a wireless radio and an SPI-based peripheral since both use SPI and may require different SPI modes.

I put together two commands to read and write a byte to the SPI interface. It may seem trivial, but it should help make porting existing drivers for SPI-based devices much easier.

To perform an SPI read, type:

sr <addr>

Where the address is in hex. It will print out the value at that address to the command line.

To perform an SPI write, type:

sw <addr> <data> 

Where both the address and data are in hex. 

For the ATXMega-A1 board, the SPI driver is targeted to the top connector, H2. If you want to use the bottom serial peripheral connector, you’ll need to make a slight modification to the source code.

I2C

The ATXMega also generously provides four separate I2C buses which makes it possible to have separate I2C buses for each peripheral port on the board. This isn’t really necessary since I2C is an addressable bus, but it does make things nicer. Plus, if any device is overly chatty, you won’t have to worry about it hogging the I2C bus completely.

One thing that’s always bugged me about I2C is that the software to access it is actually slightly complicated, at least compared to SPI. Atmel provides an I2C driver library for the ATXMega, but it’s somewhat bizarre. It mostly consists of a single generic function which handles reads and writes. To understand how to use it requires a bit of knowledge about I2C.

Because of this, I put together a couple of reference functions to demonstrate how the library is used. There are actually four functions altogether: an 8-bit I2C read, 16-bit I2C read, 8-bit I2C write, and 16-bit I2C write. They are accessible from the command line so if you plug in an I2C device, you’ll be able to access it immediately without having to write any code. Well, actually you’ll first need to set the device address in the main() file. Just look for this and change it to whatever address is being used by the device you’re hooking onto the connector:

#define I2C_DEV_ADDR    0x18

As for the actual command line functions, they’re:

ir8 <address>
ir16 <address>
iw8 <address> <value>
iw16 <address> <value>

The address and values are always in hex format and an “ir” command signifies an I2C read while an “iw” command signifies an I2C write.

PLL

One of the more interesting new features about the ATXMega is that they’ve integrated a configurable PLL to generate the clock frequency and even integrated the clock source. There’s now a 2 MHz internal clock source that you can configure to feed the PLL. From there, you can multiply the clock up to 32 MHz. The implications are quite interesting from a wireless point of view because we’re always worrying about the power consumption of the chips we’re using. The power consumption is also proportional to the clock frequency. Hence it’s now possible to change the clock frequency higher when a lot of computing needs to be done (like sensor data processing), and then go back to a low frequency for normal tasks. It’s also possible to configure the chip to run off its internal 32 kHz oscillator for extremely low power operations without putting the chip to sleep.

For playing with the PLL, I wrote a simple command to toggle between 2 MHz and 32 MHz operation. To toggle the clock frequency, type:

pll

There are no arguments and it will print out a message at the command line saying what the current clock frequency is.

Here's a quick video on doing a memory test at two different clock speeds. You can see that the speed difference between the test at 2 MHz and 32 MHz is quite significant:

EEPROM

I put together two functions on reading and writing to the internal EEPROM of the chip. The EEPROM is very useful for storing things like node addresses, configuration information, and funny messages. The latter is the most interesting so in my command line EEPROM write function, you can actually write a text message and store it in the EEPROM. It doesn’t serve a very useful purpose but it does give an example of how to read and write to the EEPROM since you can’t use the standard eeprom functions in avrlibc.

To write to the EEPROM, type:

eew <eeprom start address> <text string>

Ex: eew 0 I really need to get out more or at least exercise

To read from the EEPROM, type:

eer <eeprom start address>

The read function will automatically know how long the text string is because of the string terminator (‘/0’) I tack on to the end of the text message when you write to the memory.

Real Time Clock

One of the big issues when you have sensor arrays is synchronizing the data samples. Say you have 50 samples from 3 different nodes. You won’t really know if those data samples are aligned unless they’re timestamped and the clocks are synchronized. That’s when the real time clock (RTC) starts becoming important. A real time clock is very useful in a sensor network for timestamping purposes so that when you read out the sensor data from different nodes, you’ll know how the samples line up for processing or visualization.

The ATXMega actually has an internal 32.768 kHz RTC source on-chip but I decided to use an external 32.768 kHz crystal on the FreakLabs boards. This was because accuracy is important and the on-chip oscillator’s frequency output was temperature dependent. Having an external crystal allows much higher accuracy (or much lower drift between nodes) and temperature stability.

I wrote a function that toggles the RTC on and off. When the RTC is enabled, it prints out a message every second showing the elapsed time since it was turned on. To toggle the RTC, type:

rtc

 

That's it for the test code at this moment. I'm hoping to add other functions later on as I test out some of the new features on the ATXMega. So far, the platform looks very promising for wireless sensor networks and seems to be an excellent choice for a WSN node on an 8-bit platform.  

ATXmega Test Code Link

Hits: 32018
Trackback(0)
Comments (2)Add Comment
cheap coach bags, Lowly rated comment [Show]
This tutorial doesn't work for beginners
written by MSU Grad Student, February 22, 2011
The bootloader source code (which is step 1 in this tutorial) doesn't compile. I extracted it in a folder and ran make, but that generated a lot of errors, including the following:
unknown MCU 'atxmega128a1' specified
...
eeprom_driver.c: In function 'EEPROM_WriteByte':
eeprom_driver.c:78:2: error: 'NVM' undeclared (first use in this function)
...(many more eeprom_driver.c errors)...
eeprom_driver.c: In function 'EEPROM_ReadByte':
eeprom_driver.c:129:1: warning: control reaches end of non-void function
make: *** [eeprom_driver.o] Error 1

I have avr-gcc version 4.5.1 (Fedora 4.5.1-2.fc14.1). My computer is Fedora 14 x86_64.

report abuse
vote down
vote up
Votes: +0

Write comment

busy
  No Comments.

Discuss...
< Prev   Next >