ATSAM4S

Ring oscillator with ATSAM4S

This ring oscillator runs on the ATSAM4S MCU using the XPlained Pro Dev Kit. The ATSAM4S has an ARM Cortex-M4 running with a max speed of 120 MHz. C code for the oscillator is available here, or visible below.


#include <asf.h>

int main (void)
{
	PMC->PMC_PCER0 = 1 << ID_PIOA; //enable PIOA peripheral clock

	//MAINCK OPTIONS: A) External, B) Internal
	/*
	//with 12 MHz external crystal for MAINCK
	REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN;
	//wait for crystal to become ready
	while (!(REG_PMC_SR & PMC_SR_MOSCXTS));
	//select crystal for main clock
	REG_CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
	//master clock source selection - choose main clock
	REG_PMC_MCKR |= PMC_MCKR_CSS_MAIN_CLK;
	//wait until main clock ready
	while (!(REG_PMC_SR & PMC_SR_MCKRDY));
	//select processer prescaler (0 - no divisor, 12 MHz)
	REG_PMC_MCKR |= PMC_MCKR_PRES_CLK_1;
	//select processer prescaler (div 4) 12mhz/4 = 3mhz
	//REG_PMC_MCKR |= PMC_MCKR_PRES_CLK_4;
	//wait until main clock ready
	while (!(REG_PMC_SR & PMC_SR_MCKRDY));

	//configure PLLB for 114MHz = (12 MHz / 4) * ( 37+1 )
	//all faster speeds result in a slower ring oscillator
	//REG_CKGR_PLLBR |= CKGR_PLLBR_MULB(37) | CKGR_PLLBR_DIVB(4);
	//REG_CKGR_PLLBR |= CKGR_PLLBR_MULB(82) | CKGR_PLLBR_DIVB(2);
	*/

	//or use 4 MHz internal oscillator for MAINCK
	// 106 MHz = ( 4 MHz / 2 ) * (52 + 1)
	//strange that any faster produced a slower ring...
	REG_CKGR_PLLBR |= CKGR_PLLBR_MULB(52) | CKGR_PLLBR_DIVB(2);


	REG_PMC_MCKR |= PMC_MCKR_CSS_PLLB_CLK; //choose PLLB for master clock source

	REG_PIOA_PER |= PIO_PER_P24 | PIO_PER_P25; //enable PIO controller on PA25 and PA26, PIO_PER_P25 = 1<<25,  PIO_PER_P26 = 1<<26
	REG_PIOA_OER = PIO_PER_P24; //set PA25 as output
	REG_PIOA_ODR = PIO_PER_P25; //set PA26 as input
	
	//v1 with asf
	//ioport_set_pin_dir(EXT1_PIN_5, IOPORT_DIR_INPUT);
	//ioport_set_pin_dir(EXT1_PIN_6, IOPORT_DIR_OUTPUT);

	while (1) {
		//v1 with asf
		//ioport_set_pin_level(EXT1_PIN_6, !ioport_get_pin_level(EXT1_PIN_5)); //ring
		
		if (REG_PIOA_PDSR & PIO_PDSR_P25){
			REG_PIOA_CODR = PIO_PER_P24; //if pin26 is high, set pin 25 low
		} else {
			REG_PIOA_SODR = PIO_PER_P24; //if pin26 is low, set pin 25 high
		}
	}
}

The system clock is sensitive near its maximum with the ring frequency decreasing dramatically if a threshold is exceeded for the system clock. Strangely enough, the fastest ring oscillators occured for system clocks of less than 120 MHz. The code above shows how to use both the internal oscillator to feed the PLL, as well as a 12 MHz external oscillator.

The code also shows how to use the Atmel software framework calls. This runs roughly half as fast as the direct port manipulation.

Back