Monday, November 24, 2014

XMega - The Clock Examples


The Clock Examples

The clock can be a tricky configuration with lots of trial and error. Without external test equipment it's hard to verify what the result of your work has been. Let's start by reviewing the capabilities.

The Main Clock systems in the XMega are:
  • ClkRTC - Real-Time Counter (Covered in a separate post.)
  • ClkSYS - Feeds the prescaler only
  • ClkCPU  - CPU operating speed 
  • ClkPER - Peripheral operating speed
    • AES, RTC, Event System, DMA, AC, ADC, DAC, Timers, SPI, USART, TWI, XCL
  • ClkPER2 - Clk-PER2 (can be configured at 2 x ClkPER)
    • EBI
  • ClkPER4 - ClkPER4 (can be configured at 4 x ClkPER)
    • HIRES

The main clock has 4 potential sources
  1. Internal 32 kHz Oscillator (+/- 1% accurate)
  2. Internal 2 MHz Oscillator (+/- 1% accurate)
  3. Internal 32 MHz Oscillator (+/- 1% accurate)
  4. External Oscillator (generally 200 ppm accurate)

Phase Locked Loop (PLL)

Internal PLL
  1. PLL depends on one of the above oscillator types
  2. A little more involved configuration
  3. Cannot use 32 kHz oscillator
PLL is not an actual oscillator source; it is a way to modify the frequency based on one of the other oscillators either internal or external. The maximum supported external Crystal is 16 MHz but the common CPU speed is 32 MHz. PLL will take the 16 MHz Crystal and multiply it by two to create the 32 MHz speed.

How do I use all of this information?

There is clearly a lot of technical information available on these clocks. The following provides some practical examples.

Once set to match the board, the user_board.h file should not be modified to change operating frequencies. In my examples, the external crystal is 8 MHz. The settings are not needed when using the Internal oscillator, I generally choose to comment them out to make it clear they are not actively used.

Operating at slower speeds is useful to reduce power usage, higher speeds may require some form of cooling.  Operating at speeds in excess of 32 MHz is really only applicable to peripherals that need it. The CPU can operate at a maximum of 32 MHz.

Generally invalid values will either lock up the CPU or they are ignored and will leave the frequency set to the 2 MHz internal oscillator.

The following line has some opportunities in advanced situations where the peripherals can operate at speeds faster than the CPU speed, Unless you know what sub systems need which speeds, I would encourage leaving this line alone in all of the examples below.

#define CONFIG_SYSCLK_PSBCDIV  SYSCLK_PSBCDIV_1_1

Decide which of the following options make sense for your application. If you are unsure, start with the 2 MHz Internal Oscillator option and get to solving your problem. Come back and check this list if your needs change. 

2 MHz - Internal Oscillator

This is a quick and easy way to get started. It is the default configuration, so in a new project no settings need to be modified. In case these settings have been modified and need to be restored here they are. 

\src\ASF\common\boards\user_board\init.c
Comment out any "#define BOARD_xxxxxxxx" lines that occur there.

\src\config\conf_clock.h
There should only be the following CONFIG_SYSCLK lines of code left uncommented
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC2MHZ
#define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1
#define CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC OSC_ID_RC32KHZ

32 MHz - Internal Oscillator

When 2 MHz isn't enough or early in development when it's not clear what speed is needed, 32 MHz is a safe bet. Implementing delay and sleep routines will provide some timing flexibility.

The following code is very similar to the 2 MHz version.
\src\ASF\common\boards\user_board\init.c
Comment out any "#define BOARD_xxxxxxxx" lines that occur there. 

\src\config\conf_clock.h
There should only be the following CONFIG_SYSCLK lines of code uncommented
#define CONFIG_SYSCLK_SOURCE                SYSCLK_SRC_RC32MHZ
#define CONFIG_SYSCLK_PSADIV                SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV               SYSCLK_PSBCDIV_1_1
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC  OSC_ID_RC32KHZ

Other less than 32 MHz - Internal Oscillator

There are many different needs and everybody will have their own reasons. Here is the easiest way to set up some different frequencies. 

The first few lines are similar to the above, but the lines that are different are described below
\src\ASF\common\boards\user_board\init.c
Comment out any "#define BOARD_xxxxxxxx" lines that occur there. 

\src\config\conf_clock.h
There should only be the following CONFIG_SYSCLK lines of code left uncommented:
#define CONFIG_SYSCLK_SOURCE               SYSCLK_SRC_RC32MHZ
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_RC32KHZ
#define CONFIG_SYSCLK_PSBCDIV              SYSCLK_PSBCDIV_1_1

To run at speeds less than 32 MHz, use one of the following lines:
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_1 // 32 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_2 // 16 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_4 // 8 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_8 // 4 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_16 // 2 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_32 // 1 MHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_64 // 500 kHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_128 // 250 kHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_256 // 125 kHz
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_512 // 62.5 kHz

Other greater than and less than 32 MHz - Internal Oscillator

The following configuration uses the PLL with either of the MHz internal oscillators. This would be useful to obtain many alternate speeds without using an external crystal.

\src\ASF\common\boards\user_board\init.c
Comment out any "#define BOARD_xxxxxxxx" lines that occur there.

\src\config\conf_clock.h

#define CONFIG_SYSCLK_SOURCE    SYSCLK_SRC_PLL
#define CONFIG_SYSCLK_PSADIV    SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV   SYSCLK_PSBCDIV_1_1
#define CONFIG_PLL0_DIV         0

Once the initial settings are done, the frequency fun begins. Note that when using the 32 MHz internal oscillator with PLL it is automatically divided by 4. So, our real base value is 8 MHz. Lets quickly define the limits: 1 is an invalid multiplier, 2, 3 and 4 are always safe values for the multiplier. To use a multiplier higher than 4, the prescaler divider B and C must be used.

The max valid multiplier and therefore maximum performance with the internal oscillator is
#define CONFIG_PLL0_MUL       16
#define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_2_2
Results:
  • ClkCPU: 32 MHz
  • ClkPer: 32 MHz
  • ClkPer2: 64 MHz
  • ClkPer4: 128 MHz
This is fast, but it's using the internal oscillator,  so it's still kind of "sloppy". Be careful, while my "open air" experiments did not cause the microcontroller to get warm, it could still generate heat in a small sealed enclosure and require either a heat sink or fan to maintain this level of performance. 

16 MHz from the internal clock:
#define CONFIG_SYSCLK_PSADIV   SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV  SYSCLK_PSBCDIV_1_1
#define CONFIG_PLL0_SOURCE     PLL_SRC_RC32MHZ
#define CONFIG_PLL0_MUL        2

The following examples reset some of the values above. Using the 2 MHz internal oscillator to drive the PLL has a few different limitations and features. Interestingly, the minimum multiplication factor is 5 with an output of 10 MHz.

#define CONFIG_PLL0_SOURCE  PLL_SRC_RC2MHZ
#define CONFIG_PLL0_MUL     3

In comparing the 2 MHz and 32 MHz source, for accuracy, I couldn't confirm one was better than the other, especially when considering variations in manufacturing. So, the reason to pick one over the other is really about the goal frequency.

These are the available frequencies without using the prescaler A divisor:
2 MHz = 10 MHz, 12 MHz, 14 MHz, 16 MHz, 18 MHz, 20 MHz, 22 MHz, 24 MHz, 26 MHz, 28 MHz, 30 MHz, 32 MHz
32 MHz = 16 MHz, 24 MHz, 32 MHz

## MHz - External Crystal

If an external crystal is available lets use it at it's most accurate and natural speed. The configuration is a little more involved so just follow along. My boards have an 8 MHz Crystal so that is what I will be using.

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

#define BOARD_XOSC_HZ          8000000
#define BOARD_XOSC_TYPE        XOSC_TYPE_XTAL
#define BOARD_XOSC_STARTUP_US  XOSC_STARTUP_16384

\src\config\conf_clock.h

#define CONFIG_SYSCLK_SOURCE   SYSCLK_SRC_XOSC
#define CONFIG_SYSCLK_PSADIV   SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV  SYSCLK_PSBCDIV_1_1

## MHz - External Resonator

I'm very sorry I don't have a board to test this code, so I won't be posting this example. I believe the only difference is the "Start-up time". I leave this combination as an exercise for the reader. 

## MHz less than External Oscillator

This is the case when the Crystal is faster than needed. Maybe 16 MHz crystals are cheaper or late in the design cycle it is discovered that an accurate 2 MHz operating speed is all that is needed.
Reminder: I have an 8 MHz Crystal, adjust as needed.

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

#define BOARD_XOSC_HZ          8000000
#define BOARD_XOSC_TYPE        XOSC_TYPE_XTAL
#define BOARD_XOSC_STARTUP_US  XOSC_STARTUP_16384

\src\config\conf_clock.h

#define CONFIG_SYSCLK_SOURCE   SYSCLK_SRC_XOSC
#define CONFIG_SYSCLK_PSBCDIV  SYSCLK_PSBCDIV_1_1

To run at other speeds less than the crystal, use one of the following lines:
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_1 // 8 MHz (installed crystal)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_2 // 4 MHz (installed crystal / 2)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_4 // 2 MHz (installed crystal / 4)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_8 // 1 MHz (installed crystal / 8)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_16 // 500 kHz (installed crystal / 16)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_32 // 250 kHz (installed crystal / 32)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_64 // 125 kHz (installed crystal / 64)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_128 // 62.5 kHz (installed crystal / 128)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_256 // 31.25 kHz (installed crystal / 256)
#define CONFIG_SYSCLK_PSADIV  SYSCLK_PSADIV_512 // 15.625 kHz (installed crystal / 512)

## MHz  greater than and less than External Oscillator

This one is a little more involved. In order to operate the peripherals at a frequency higher than the external crystal requires use of the PLL. Reminder: I have an 8 MHz Crystal, adjust as needed.


\src\ASF\common\boards\user_board\user_board.h

#define BOARD_XOSC_HZ          8000000
#define BOARD_XOSC_TYPE        XOSC_TYPE_XTAL
#define BOARD_XOSC_STARTUP_US  XOSC_STARTUP_16384

\src\config\conf_clock.h

#define CONFIG_SYSCLK_SOURCE   SYSCLK_SRC_PLL
#define CONFIG_SYSCLK_PSADIV   SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV  SYSCLK_PSBCDIV_1_1
#define CONFIG_PLL0_MUL        (16000000UL / BOARD_XOSC_HZ)
#define CONFIG_PLL0_DIV        1

This is the part where it gets interesting. Any multiplier from 2 to 31 (1 is documented but not recommended) combined with the standard prescaler choices makes for a lot of options. Mine you, the PLL Multiplier can easily create values that are too high and/or invalid for the peripherals so be careful!

Instead of defining all of the valid values for every crystal frequency, lets talk about the limits. The peripheral and CPU need to be 32 MHz or slower. In some cases this can be managed by using Prescaler B and C.

Common Crystal Frequencies and their supported multiplication factor maximum:
4 MHz = 2, 3, 4, 5, 6, 7, 8
8 MHz = 2, 3, 4
16 MHz = 2

USB

This is a very special use case because it needs to run the USB peripheral at a speed of either 6 MHz or 48 MHz. There is much more to the topic of USB, so I'll address this at a future time.

XMega - Table of Contents

XMega - Table of contents

The XMega series of articles will be a long one. Some concepts build on each other so this sequence may be helpful.

  1. The Clock - Covers the basics of how to set up the System Clock
    1. The Clock Examples - This is a collection of code samples for different clock configurations.
  2. The Clock is Dynamic covers the changing of the system clock at any time while your program is running. 
  3. Let's Blink an LED - Simple Input and Output
  4. Interrupts
  5. Timers
  6. RTC or Real Time Counter
  7. The Serial Ports (USART)
  8. Power Reduction and Sleep

Also of interest 
  • The Background - Details about my environment and my goals.
  • Tips - A collection of tidbits that were published, which are useful alone.

Sunday, November 23, 2014

XMega - Tips

XMega - Tips

This is a collection of tips that were part of individual articles but may be easier to find in one place. 

Hardware Debugger 

  1. During most of the debug process, the frequency counter showed 1,000,038 or 1,000,039. It is very accurate so I doubt it is an internal clock. Since it showed those values when the Crystal wasn't used, I think it's a clock from the debugger.
  2. It appears that when the debugger is connected and not in debug mode it's probably holding the microcontroller in reset, since the frequency counter shows 0.

Optimization

  1.  Optimization level defaults to -O1 which is a good start when your talking about shipping a product with firmware. While developing especially with a stepping debugger, strange behavior can occur. I suggest turning optimizations off for DEBUG builds. It will be helpful if prototype boards have a larger Flash than the final product.
    The optimization setting is found in the Project Properties -> Toolchain -> AVR/GNU C Compiler -> Optimization -> Optimization Level = None

ASF Coding Style

A quick note about C code for the XMega: there are lots of great constants that make the code a bit more readable than the common practice of "magic" values in Hex, Decimal or Binary. The suffix of these constants have additional meaning:
  • _bm is a BitMask. It is generally a Hex Value like 0x80 which specifies Bit 7 (0 to 7)
    • It can also be represented by Left Bit shifting a 1 into the specified position
  • _bp is a Bit Position it is generally a single digit number like 7 which also specifies Bit 7
  • _gc
  • _gm Group Mask 
  • _gp Group Position

Warnings 

Many people especially when they start out, don't take compiler warnings very seriously, they expect/hope the compiler will create code that does what they intended. While many times this is true, it is not true all of the time. I recommend treating the warnings as errors and working through them. This has the added benefit of more predicable code behavior, especially when Optimizations are turned on. It is also a great way to learn the details of the C language. 

Saturday, November 22, 2014

XMega - The Clock

The Clock

Most of the time the first tutorial article is the classic "Hello World" application, usually blinking an LED for microcontroller applications. This time, I want to start a little lower, I've found the Clock system to be especially difficult to understand when using the ASF (Atmel Software Framework). There are several steps in different areas and there are #define statements that are like bad magic because they either work or they don't. I also want to learn how to better use some test equipment that I've picked up. I buy cool tools but don't always use them to their best advantage.

XMega Programmer

  • Atmel-ICE Basic - Supports Hardware Debugging 
    • $49 - Pretty Case (The one I'm using)
    • $32 - Circuit Board (Less expensive alternative)

Test Equipment Used

  • Frequency Counter - Tektronix CFC250 100 MHz (circa 1988)

Experiment

As you can see my tools aren't expensive or fancy. 

The code for this first experiment will be pretty minimal. Just setting up a built-in feature that takes the System Clock and places its output on a physical pin. Adjust the code as needed depending on which pins are available on your board.

The Code

I'm not going to get caught up in the step by step. For this example, I created a new project with the "GCC C ASF Board Project" template and then selected my MicroController, then the "User Board template".
The files  to edit are a little scattered, so here are the changes I made.

src\ASF\common\boards\user_board\user_board.h
Add Line:  
#define FREQ_OUT  IOPORT_CREATE_PIN(PORTC, 7)
src\ASF\common\boards\user_board\init.c
inside the board_init function, add this line: 
ioport_set_pin_dir  (FREQ_OUT, IOPORT_DIR_OUTPUT);
src\main.c
Replace entire main()
int main(void)
{
     // Specifies that the Clock frequency is sent out on PortC Pin7.
     PORTCFG.CLKEVOUT = PORTCFG_CLKOUT_PC7_gc;
     sysclk_init();

     for (;;){}
}

The Result

The Frequency Counter* showed fluctuations between 2,033,386 and 2,032,973 Hz

What do those results really mean?

We have two different versions of accuracy.
  1. Frequency isn't exactly 2 MHz
  2. Variation between the high and low value
So how far off from 2 MHz is it?
Accuracy = (Measured Frequency - Expected Frequency) / Expected Frequency

0.0166 =  (2,033,386 - 2,000,000) / 2,000,000 = 1.66%
0.0168  = (2,032,973 - 2,000,000) / 2,000,000 = 1.68%

That's a bit sloppy. We can do better as we will see, but that is good information.

Next up is the "wiggle". Since we calculated the percentage for both the high and low value, we can subtract to find the difference 0.0002 or 0.02% which is a good number for a built in oscillator. 

How important is the accuracy?

If we are talking about buttons and LED's it is nothing. If we are talking about communication, it is very important. 

How to Improve Accuracy

The XMega includes a built in calibration feature. Lets see how much closer we can get to our goal.

\src\config\conf_clock.h
Add Line (or uncomment)
 
#define CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC   OSC_ID_RC32KHZ
With that done the frequency counter is now showing 1,998,172 to 1,997,508.  Using the above formula:

0.001461 = (1,997,078 - 2,000,000) / 2,000,000 = 0.14%
0.001300 = (1,997,401 - 2,000,000) / 2,000,000 = 0.13%

While the frequency is now below 2,000,000 it is closer with a variation of 0.13% compared to 1.66%, which is a great improvement. The variation between the tested values is 0.01% which is a small change in the right direction compared to the 0.02% without the Calibration setting.

32 MHz Internal Oscillator

Here are some quick stats doing the same tests at 32 MHz.

Observed Values High: 32,449,486 and Low: 32,308,628.

0.009644 = (32,308,628 - 32,000,000) / 32,000,000 = 0.96%
0.014046 = (32,449,486 - 32,000,000) / 32,000,000 = 1.40%

Wiggle: 0.014046 - 0.009644 = 0.44%

32 MHZ Internal Oscillator w/Calibration 
\src\config\conf_clock.h
Add Line (or uncomment)
 
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC  OSC_ID_RC32KHZ

Observed Values High: 31,932,746 and Low: 31,911,475.

0.002766 = (31,911,475 - 32,000,000) / 32,000,000 = 0.27%
0.002101 = (31,932,746 - 32,000,000) / 32,000,000 = 0.21%

Wiggle: 0.002766 - 0.002101 = 0.066%

Remember that manufacturing tolerances will affect these settings, so while this chip seems to have a more accurate 32 MHz oscillator that may not always be true.

See a future post for more examples, including external crystals!

Additional observations

During most of the debug process, the frequency counter showed 1,000,038 or 1,000,039. The frequency counter reading is very accurate so I doubt it's an internal clock. Since it showed those values when the Crystal wasn't used, I think it's a clock from the debugger.

It appears that when the debugger is connected and not in debug mode it's probably holding the microcontroller in reset, since the frequency counter shows 0.

*Frequency Counter Accuracy - It's not calibrated against anything official. I did compare the output of my 4 digit Function Generator and the 8 digits on the frequency counter and the first 4 digits match at 2 MHz so FG 2000 = FC _2000214. 

XMega - The Background

The Background

I like the size, feature set, and pricing of the Atmel XMega line of chips. I used one model in a retail product when the classic ATMega328P didn't have enough I/O pins.

One of my struggles with using the XMega series of microcontrollers is that the documentation while good it's not always helpful. My plan here is to provide code and practical examples.

My Development Process

There are several language options for programming the XMega, primarily assembly and c. The Atmel Software Framework (ASF) is a great solution for creating C code that is more portable between all Atmel Microcontrollers especially if you stay within the XMega product line, moving to a new model is pretty easy. The downside is that all of the documentation is really dry and generic, so figuring out how to apply the code to solve my problem has been a bit of a challenge.

Some programmers feel that it makes the code "bloated". I wont argue what is bloated and what isn't. I will say that it has worked well enough for me, it either compiles to a binary that fits in FLASH or just a few optimizations will get it there. Code on this site will generally be C primarily using the ASF.

Atmel Studio is based on Visual Studio which is a professional level IDE. Some might say overkill for such a little chip but once you have more than a couple of hundred lines of code, it's nice to have an editor that makes it easy to break your project into smaller more manageable pieces. The alternative is a couple of source files that just keep getting longer and longer. I'll be using Atmel Studio for nearly everything.


I'll be using multiple boards for development and testing, some from 3rd parties some that I design myself. If it's relevant I may specify where a similar board can be purchased. Some will clearly be better for certain tasks. If the board isn't specified it's probably not important which one.

Math

While I am good at math I don't read formula's well so most math here will be what I would call Calculator math. Written so it's easy to punch in to the calculator of your choice. 

The Audience

Many other tutorials are more helpful if you are just starting out. I make some assumptions that you've written some microcontroller code before and about your knowledge of Atmel Studio,  Many of these posts will build on each other some code snippets can be used on their own.