Use External Crystals on Atmel ARM Cortex Microcontroller ASF Project

Created on: 16 May 2016

Part 6 of the ASF ARM Tutorial

Enable the internal oscillators of Atmel ARM Cortex microcontrollers to use external crystals for their timing in an ASF project.

The ATSAM4N16C microcontroller on the Atmel SAM4N Xplained Pro board has two external crystals connected to its oscillator pins. Default Atmel Studio ASF projects use the internal RC oscillators instead of the external crystals. This part of the ARM Cortex ASF tutorial shows how to enable and use the external crystals with the oscillators.

A 12MHz crystal and 32.768kHz crystal are used for the main clock and slow clock respectively. A 100MHz system clock is derived from the internal oscillator using the 12MHz crystal by feeding the 12MHz clock through the PLL. A 32.768kHz slow clock is derived from the internal oscillator using the 32.768kHz crystal.

Creating the ASF Project

Start by creating a new user board ASF project as done in previous parts of this tutorial. I am calling this project ext_xtal.

In Atmel Studio:

  • Select File → New → Project... from the top menu.
  • In the New Project dialog box choose GCC C ASF Board Project and name the new project ext_xtal.
  • In the Board Selection dialog box filter for the ARM microcontroller on the board. This is ATSAM4N16C for the SAM4N Xplained board.
  • Still in the Board Selection dialog box, select the User Board Template. For the SAM4N Xplained board it is called User Board Template - ATSAM4N16C.
  • In the new project, open main.c and add a while(1) loop at the bottom of the main() function.

If the new project is compiled and loaded to the board it will not use the external 12MHz crystal, but rather the internal RC oscillator. This can be verified by probing the crystal pins with an oscilloscope.

Enabling the External Crystal to be used with the Main Clock Oscillator

The following steps show how to use the 12MHz external crystal instead of the internal RC oscillator for the main clock.

1. Add the System Clock Control ASF Module to the Project

Before ASF functions can be used to set up the clock source for a microcontroller, the System Clock Control service ASF module must be added to the project.

  • Open the ASF Wizard using ASF → ASF Wizard from the top menu.
  • Filter the available modules by searching for clock.
  • Use the ASF Wizard to add the System Clock Control (service) module to the project.

2. Call sysclk_init() in main()

The sysclk_init() function becomes available after adding the System Clock Control ASF module. Call sysclk_init() at the top of main().

main.c

#include <asf.h>

int main (void)
{
    sysclk_init();
    board_init();

    while(1) {
    }
}

3. Set the Clock Source and Configuration

After adding the System Clock Control ASF module, conf_clock.h is added to the project in src\config\. Open this file for editing.

Current system clock configuration can be found in conf_clock.h and the current clock settings are shown in the comments at the bottom of the file. As can be seen in the image below, the system clock is set up to run at 100MHz using the internal 8MHz RC oscillator.

ASF System Clock Settings
ASF System Clock Settings

We still want to get the clock source from the PLL and use a prescaler value of two, so leave the first two definitions in conf_clock.h at their default settings.

CONFIG_PLL0_SOURCE must change from PLL_SRC_MAINCK_8M_RC to OSC_MAINCK_XTAL to change from using the internal RC oscillator to using the crystal attached to the external oscillator pins.

On the SAM4N Xplained Pro, the main crystal is 12MHz. The values of the PLL multiplication and division factors must change in order to derive a 100MHz system clock from the 12MHz crystal. This is done by changing the division to 3 which divides 12MHz by 3 to get 4MHz. A multiplication factor or 50 is then used to change the PLL frequency to 4MHz × 50 = 200MHz. The prescaler division of 2 brings this frequency down to 100MHz.

The modified conf_clock.h file is shown below with the commented out options removed and the comments at the bottom of the file updated.

conf_clock.h

#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED

#define CONFIG_SYSCLK_SOURCE        SYSCLK_SRC_PLLACK

// ===== System Clock (MCK) Prescaler Options   (Fmck = Fsys / (SYSCLK_PRES))
#define CONFIG_SYSCLK_PRES          SYSCLK_PRES_2

// ===== PLL0 (A) Options   (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL0_SOURCE          OSC_MAINCK_XTAL
#define CONFIG_PLL0_MUL             50
#define CONFIG_PLL0_DIV             3

// ===== Target frequency (System clock)
// - External Xtal frequency: 12MHz
// - System clock source: PLLA
// - System clock prescaler: 2 (divided by 2)
// - PLLA source: 12MHz
// - PLLA output: 12MHz * 50 / 3
// - System clock: 12MHz * 50 / 3 / 2 = 100MHz

#endif /* CONF_CLOCK_H_INCLUDED */

Note: When writing the multiplication factor directly to the PLL configuration register, one would normally be subtracted from this value to make the multiplication work correctly. This is not necessary in the above settings because the function that uses this value subtracts one from it. The multiplication factor for this example can therefore be 50 and not 49 to get the PLL to multiply by 50.

4. Define the Crystal Values

Values for the crystals on the board must be defined in conf_board.h as we have done in previous projects in this tutorial series. These values were defined in previous projects to prevent compiler warnings rather than use the external crystals. All previous projects used the internal 8MHz RC oscillator as the clock source which was ramped up to 100MHz by the PLL.

conf_board.h

#ifndef CONF_BOARD_H
#define CONF_BOARD_H

#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

Building the Project

The project can now be built and loaded to the board. An oscilloscope can be used to check the pins of the external 12MHz crystal to see that it is being used by the oscillator. A 12MHz clock should be seen on the oscilloscope.

Enabling the Slow Clock Oscillator to use the External 32.768KHz Crystal

Two lines of code must be added to the project at the top of main() to enable the slow clock oscillator to use the external 32.768kHz crystal. The code is shown below.

main.c

#include <asf.h>

int main (void)
{
    pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL);   // enable external 32.768kHz crystal
    while (!pmc_osc_is_ready_32kxtal());        // wait until oscillator is ready
    
    sysclk_init();
    board_init();

    while(1) {
        
    }
}

The first line of code enables the slow clock to use the 32.768kHz external crystal. The second line of code waits for the slow clock oscillator to stabilize.

The project can be built again and loaded to the board. An oscilloscope can be used to check the pins of the 32.768kHz crystal which should show a 32.768kHz clock pulse.