An Introduction to EMB-ZRF212 and XMega256a3 platforms

jacopo mondi
Suggestions, corrections, everything: jacopo.mondi[AT]gmail[DOT]com

Introduction

About this doc

This document provides some basic hints and examples on how to getting started with the Xmega256a3 MCU that is embedded into the Embit EMB-ZRF212 EVB.
The target of the examples is the low level interfacing with the MCU sub-systems, not the ZigBee stack nor the radio communication interface.

Either if you are just interested in the development of higher level ZigBee compliant applications, sooner or later you'll have to read/write an IO port, handle some sort of communications or interface with external sensors.
Those operations are the target of this documents and associated software.

This documents provides an introduction to the available documentation about the Xmega256a3 MCU (micro-controller unit) and the custom EMB-ZRF212 EVB (Evaluation Board) available in Wireless System Lab @CS unibo.
It also provides some useful pointers (links, tips and so on) for developers that are completely new to firmware development or are used to older ATMEL devices, or other manufacturer's devices.

The default way to specify actions and commands in the document is supposed to be a default terminal emulator running in a Linux (or similar *NIX) development box.

If you want to use some integrated development environment (IDE), such as the official ATMEL AVR Studio IDE, you have to switch to a Windows box, and consult the official ATMEL documentation freely available on-line.

Also, if you are just interested working with the ATMEL BitCloud ZigBee stack this documents will not help you in any way.
Refer instead to the documentation provided in the CD-ROMs and on-line by both ATMEL and EMBIT.

The software is provided 'as it is' since it does nothing particularly useful. No license of any-kind is applied, so do what you want with it.

XMega Series

The AVR ATXMega series from ATMEL introduces many new features and capabilities, that lead to new abstractions and (sometimes obscure) software mechanisms, providing a sensible shift of code complexity and modularity respect the well known AVR ATMega series.

The provided (very simple) examples introduce some 'hands-on' techniques for manipulating low level functions such as USART and ADC.
The included Makefile also provide an introduction on how software for AVR ATMEL gets build and uploaded to the board.

Preliminary

To fully understand how this software works, gets build and uploaded, some preliminary readings are quite mandatory.

Basics

If you are very new to microcontrollerdome (that is, for the record, the obscure land of memory and resource severely constrained processors), it could be useful reading some pages from the arduino web page since some high-level concepts (Serial communication, ADC, gpio handling etc) are common to all the platforms.

Here you'll find many tutorials, about basic and more advanced topics and typical MCU operations.
A good understanding of basic I/O (both digital and analog), serial communication protocols (USART, SPI, I2C), Analog to Digital Converters (ADC), is the bare minimum to start with a more advanced processor like Xmega256a3 is.

WARNING: ignore the code examples in the arduino wiki. You will have nothing like Arduino libraries or Arduino IDE for this platforms, just ANSI C and a bunch of registers.

EMBIT Doc

Technical documentation provided by EMBIT, the EMB-ZRF212 board manufacturer, can be found under the Doc/ directory in the included CD-ROM, providing an introduction to the board design and layout.
A complete list of board connectors and installed peripherals can be found in the "EMB-ZRF2xx-EVB.pdf" document, while technical characteristics, such as size, electrical characteristics, pin associations between board and MCU can be found in the "EMB-ZRF2xx.pdf" document.
An overview on the board programming model and pre-installed bootloader information are also included in the "EMB-ZRF2xx-Programming-Guide.pdf" document.

ATMEL DOC

The datasheets provided by ATMEL (available under the Datasheet/ dir) features the new datasheet style for XMega series.
A general datasheet for all the family is provided (called "ATXMEGA256A3.pdf").
This documents describes the MCU pin layout and alternate pin functions, common to all the XMega series. It also briefly introduces the available peripherals and buses, in a very short and descriptive way.

A manual specific to the XMega256a3 is also included, called "ATXMEGA256A3-Reference Manual.pdf".
This document is quite longer and fully describes all the functionality and possible configurations for this specific device (this one is the real datasheet).
The antenna datasheets are also included.

ATMEL also provides an impressive collection of on-line documentation, with software examples and documents specific to single processor's subsystems (such as "Getting started with ATXMega ADC" and so on).
Those documents are used to guide the developers in the transition from the ATMega series to the new XMega one.

You can find everything here:
This documentation is not all mandatory, but some readings are anyway recommended.

In particular:


	"Atmel AVR1927: XMEGA-A1 Xplained Getting Started Guide"
"AVR1000: Getting Started Writing C-code for XMEGA"
"AVR1005: Getting started with XMEGA"
Some articles also describes some (very) advanced features such as DMA, Event System, Clock Subsystem, DAC, that are not mandatory but could be useful to improve your firmware development skills.

Tips (and tricks)

Building

In order to successfully build software programs for XMega processor you will need a fully working installation of the avr-gcc tool-chain.
As any other cross-compiling tool-chain the avr-gcc suite includes a compiler, a linker, an object handler and many other tools such as profilers and debuggers, all targeted to the AVR architecture.
A binary packaged version of the tool-chain is provided in many Linux distributions (usually called avr-gcc or similar).
However some versions of the pre-built tool-chain do not support the XMega family.
You can verify this checking the 'Known MCU names' section in the
$ avr-gcc --target-help
command output.

If no ATXMega device is mentioned, so you have to compile your own version of the tool-chain.
This operation could be automatized using the 'Bingo scripts' you can find here.

Carefully read the instructions and proceed compiling, then verify that the chosen install directory is included in your default system path. After compiling the tool-chain, remove the default avr-gcc package and try
$ which avr-gcc.
If nothing it's found, then add the install path (default one is /usr/local/avr/) to your .bashrc or .zshrc...

Coding

As the ATMEL provided documentation suggests, the XMega series introduces a totally new coding style in firmware development process.

The header files (specifically the 'iox256a3.h') introduce a new name convention for bit-fields groups and masks.
Two different macros are now associated to each bit in a register , one that specify the position (BITNAME_bp) and one that specify the bit-shifting operation used to handle the bit (BITNAME_bm). The same happens for bit-groups, but corresponding macros end with the _gm and _gp suffixes.

In the simplest provided example (src/blink.c) you'll find some example macros following this new coding style.
This enables the developers to speed up the bit groups selection and bit setting or clearing.
It is suggested to open and consult the IO header file ('iox256a3.h') while writing code, to fully exploits the new _bm, _bp, _gm, _gp macros.

 
				/*=== from blink.c ===*/
				#define LED1_bm (1<<0)
				#define LED2_bm (1<<1)
				#define LED3_bm (1<<2)
				#define LED1_bp 0
				#define LED2_bp 1
				#define LED3_bp 2

				/*=== from iox256a3.h ===*/
				/* ADC_CH.MUXCTRL  bit masks and bit positions */
				#define ADC_CH_MUXPOS_gm  0x78  /* Positive Input Select group mask. */
				#define ADC_CH_MUXPOS_gp  3  /* Positive Input Select group position. */
				#define ADC_CH_MUXPOS0_bm  (1<<3)  /* Positive Input Select bit 0 mask. */
				#define ADC_CH_MUXPOS0_bp  3  /* Positive Input Select bit 0 position. */
				#define ADC_CH_MUXPOS1_bm  (1<<4)  /* Positive Input Select bit 1 mask. */
				#define ADC_CH_MUXPOS1_bp  4  /* Positive Input Select bit 1 position. */
				#define ADC_CH_MUXPOS2_bm  (1<<5)  /* Positive Input Select bit 2 mask. */
				#define ADC_CH_MUXPOS2_bp  5  /* Positive Input Select bit 2 position. */
				#define ADC_CH_MUXPOS3_bm  (1<<6)  /* Positive Input Select bit 3 mask. */
				#define ADC_CH_MUXPOS3_bp  6  /* Positive Input Select bit 3 position. */
	
Also the I/O ports handling model has changed, since now every ports has many registers that could be used to manipulate a single pin operations.
Please refer to chapter 13 of the atxmega256a3 manual, particularly section 13.14 to get a full description of the new registers' functions.


				/*=== XMEGA ===*/
				/*set direction*/
				PORTB_DIRSET |= LED1_bm;
				/*set the bit*/
				PORTB_OUTSET |= LED1_bm;
				/*clear the bit*/
				PORTB_OUTCLR |= LED1_bm;
				

				/*=== ATMEGA ===*/
				/*set direction*/
				DDRB |= _BV(DDRB1);
				/*set the bit*/
				PORTB |= _BV(PORTB1);
				/*clear the bit*/
				PORTB &= ~_BV(PORTB1);
				

The newly introduced modular device design (check on-line ATMEL documentation to know further about) enables the developers to map the processor's registers used for configuring peripherals and input/output ports into plain C structures, and access sub-register and bit fields in an "object oriented" coding style.
This features dramatically speeds up development process, since all the registers related to a specific subsystem are tightly coupled into a single data structure.
This structure could be directly manipulated or reassigned if another instance of the same subsystem has to be used (now you can switch from one USART interface to another simply changing a pointer value).

To understand how this feature can be exploited two different examples are provided.
usart.c handles the USARTD0 interface in the 'old fashioned' way, while usart_with_structs.c uses the new memory mapping functionality.
To understand why the new coding style is much more flexible, try to switch from using USARTD0 (the rs232 port on EMB-ZRF212) to USARTD1 (the USB one on EMB-ZRF212) in the previously mentioned files.


/*==== from usart.c ====*/


int main(...){
	...
	/*zero control registers*/
	USARTD0_CTRLA = 0x00;
	USARTD0_CTRLB = 0x00;
	USARTD0_CTRLC = 0x00;
	/*setup USARTD0 baudrate*/
	USARTD0_BAUDCTRLA = baud;
	USARTD0_BAUDCTRLB = (0x0f&(baud>>8));
	/*set 8bit word size*/
	USARTD0_CTRLC = (USART_CHSIZE0_bm | USART_CHSIZE1_bm);
	/*enable TX RX*/
	USARTD0_CTRLB = USART_TXEN_bm | USART_RXEN_bm;
	....
}
				

/*=== from usart_with_structs.c ===*/
#define	USART  USARTD0 /*<--- CHANGE THIS TO SWITCH INTERFACE*/

int main(...){
...
	/*zero control registers*/
	USART.CTRLA = 0x00;
	USART.CTRLB = 0x00;
	USART.CTRLC = 0x00;
	/*setup USART baudrate*/
	USART.BAUDCTRLA = baud;
	USART.BAUDCTRLB = (0x0f&(baud>>8));
	/*set 8bit word size*/
	USART.CTRLC = (USART_CHSIZE0_bm | USART_CHSIZE1_bm);
	/*enable TX RX*/
	USART.CTRLB = USART_TXEN_bm | USART_RXEN_bm;
....
}
				

Many operations could be speed up with a minimal knowledge of AVR assembly.
This enables the developers to exploit new AVR assembly features, such as the indirect access with post/pre decrement, or efficient memory mapped I/O.

To reduce the produced code size could also be useful to learn how efficiently use variables data type, and how their definition and use produce different assembly code.

The following loops, functionally equivalent, produce code of different size (assembly code is specified after each C instruction).

from "AVR035: Efficient C Coding for 8-bit AVR microcontrollers"

unsigned char count8 = 5; 
// LDI R16,5 ;init variable


/* Decrement loop counter and check for zero */
do{
}while(--count8);
//?0004:DEC R16 ;decrement
//BRNE ?0004 ;branch if not equal

				

	unsigned int count16 = 6; 
	// LDI R24,LOW(6) ;Init variable, low byte
	// LDI R25,0 ;Init variable, high byte

	/* Decrement loop counter and check for zero*/
	do{
	}while(--count16);
	//?0004:SBIW R24,LWRD(1) ;Subtract 16-bit value
	//BRNE ?0004 ;Branch if not equal
				
The loop using the 8bit counter reduce to 6 byte of produced code, the one using the 16bit counter to 8byte.
This could seems not a big deal, but when handling lot of global variables their definition and data types could lead to very different object code size.

All that features are fully described in the "AVR035: Efficient C Coding for 8-bit AVR microcontrollers" document provided by ATMEL on-line reference.

Testing the examples

To compile and upload the examples, simply go to the src/ directory and type
$ make
to build the executable (.hex extension), and
$ make upload
to flash the firmware on the device.
Refer to "EMB-ZRF2xx-Programming-Guide.pdf" to know how to restart the board in programming mode.

To change the example file you are building, edit the src/Makefile SOURCE variable.
You will find binaries into the bin/ directory.
Remember to clean up with
$ make clean
when you are done.

Before uploading the built file to the board verify that the selected port in the src/Makefile PORT variable matches the port the board is attached to.
You can find it out connecting the USB cable (both ends) and powering the board up.
Type
$ dmesg |grep tty
and check the last entry mentioning the FTDI keyword. Edit the Makefile accordingly.

Source Code

The src/ directory contains:

	blink.c
blink 2 led. Learn the new _bm and _bp macro style, and the new OUTSET OUTCLR registry.

usart.c
setup a serial communication the "old fashioned" way, manipulating the single registers.

usart_with_structs.c
setup a serial communication the new way, using the flexible memory mapped IO model.

adc.c
setup ADCA and read from channel 4 (connected to a trimmer on EMB-ZRF212 board). The resulting value is then sent out on the USARTD0 channel.

With the firmware examples, a simple test program it's also provided (src/read_serial.c).
This application shows how to open and setup a serial communication with the board.
This example is tested with the adc.c firmware and displays messages incoming from the MCU (the voltage generate by the on-board variable resistor).

Conclusions

You can download the whole archive with source code here

If you want to contribute to this page, with corrections, new code examples etc, please let me know!