Problems to configure clock at SAMC21

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys, I am having a set of problems trying to make my ATSAMC21E18A run at 48Mhz. To start off I have a custom board and an external XT of 16Mhz. I know it is not possible to directly feed the DPLL with 16Mhz so I tried to prescale its output using one of the GCLKlines and feed it to the DPLL, but it did not work.

 

I also have tried to use the internal 48Mhz RC with no DPLL to run the micro at 48Mhz but it did not work out, even with the biggest start up time and the clock have never got stable.

Here are some samples of my code:

 

void externalXtClock(void){
	struct system_clock_source_xosc_config xosc_conf;
	system_clock_source_xosc_get_config_defaults(&xosc_conf);

	xosc_conf.external_clock    = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL;
	xosc_conf.startup_time      = CONF_CLOCK_XOSC_STARTUP_TIME;
	xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL;
	xosc_conf.frequency         = 16000000UL;
	xosc_conf.on_demand         = CONF_CLOCK_XOSC_ON_DEMAND;
	xosc_conf.run_in_standby    = CONF_CLOCK_XOSC_RUN_IN_STANDBY;
	xosc_conf.clock_failure_detector_prescaler = CONF_CLOCK_XOSC_FAILURE_DETECTOR_PRE;
	xosc_conf.enable_clock_failure_detector    = CONF_CLOCK_XOSC_FAILURE_DETECTOR_ENABLE;
	xosc_conf.enable_clock_failure_detector_event_outut = CONF_CLOCK_XOSC_FAILURE_DETECTOR_EVENT_OUTPUT_ENABLE;
	xosc_conf.enable_clock_switch_back = CONF_CLOCK_XOSC_FAILURE_SWITCH_BACK_ENABLE;

	system_clock_source_xosc_set_config(&xosc_conf);
	system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC);
			
	Assert(CONF_CLOCK_XOSC_ENABLE);

	struct system_gclk_gen_config config_gclock_gen;
	system_gclk_gen_get_config_defaults(&config_gclock_gen);
	config_gclock_gen.source_clock = SYSTEM_CLOCK_SOURCE_XOSC;
	config_gclock_gen.division_factor = 16;
	system_gclk_gen_set_config(GCLK_GENERATOR_0, &config_gclock_gen);
}
void rc48MhzClock(void){
// 	struct system_clock_source_osc48m_config osc48m_conf;
// 	system_clock_source_osc48m_get_config_defaults(&osc48m_conf);
	OSCCTRL->OSC48MSTUP.reg = 0x07;
	OSCCTRL->OSC48MDIV.reg = OSCCTRL_OSC48MDIV_DIV(SYSTEM_OSC48M_DIV_1);		//by 1 does not work, by 2 it does
	while(OSCCTRL->OSC48MSYNCBUSY.reg);
	
// 	struct system_gclk_gen_config config_gclock_gen;
// 	system_gclk_gen_get_config_defaults(&config_gclock_gen);
// 	config_gclock_gen.source_clock = SYSTEM_CLOCK_SOURCE_OSC48M;
// 	config_gclock_gen.division_factor = 1;
// 	system_gclk_gen_set_config(GCLK_GENERATOR_0, &config_gclock_gen);
}
void dpll48MhzClock(void){
		struct system_clock_source_dpll_config dpll_config;
		system_clock_source_dpll_get_config_defaults(&dpll_config);
		
		dpll_config.on_demand        = true;
		dpll_config.run_in_standby   = true;
		dpll_config.lock_bypass      = CONF_CLOCK_DPLL_LOCK_BYPASS;
		dpll_config.wake_up_fast     = CONF_CLOCK_DPLL_WAKE_UP_FAST;
		dpll_config.low_power_enable = CONF_CLOCK_DPLL_LOW_POWER_ENABLE;

		dpll_config.filter           = CONF_CLOCK_DPLL_FILTER;

		dpll_config.reference_clock     = SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK;
		dpll_config.reference_frequency = 1000000;
		dpll_config.reference_divider   = 1;
		dpll_config.output_frequency    = 48000000;
		dpll_config.prescaler           = SYSTEM_CLOCK_SOURCE_DPLL_DIV_1;
		
		
		system_clock_source_dpll_set_config(&dpll_config);
		
// 		OSCCTRL->DPLLCTRLB.reg &= 0x‭F800FFFF‬;
// 		OSCCTRL->DPLLCTRLB.reg |= 0x‭00030000‬;
		
		system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DPLL);
		while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL)); //
		
// 		struct system_gclk_gen_config config_gclock_gen;
// 		system_gclk_gen_get_config_defaults(&config_gclock_gen);
// 		config_gclock_gen.source_clock = SYSTEM_CLOCK_SOURCE_DPLL;
// 		config_gclock_gen.division_factor = 1;
// 		system_gclk_gen_set_config(GCLK_GENERATOR_0, &config_gclock_gen);
}

 

I would appreciate any help.

Regards!
FS.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog_jr have posted one solution to configure the internal RC for 48Mhz without ASF. I am posting it here in case anyone looks in this topic needing help:

 

void ClocksInit(void) {
    // Set flash wait states for operation at 48 MHz @ 5V
    NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS(1) | NVMCTRL_CTRLB_MANW;        //
     while ((OSCCTRL->STATUS.reg & OSCCTRL_STATUS_OSC48MRDY) == 0 );       // Wait until ready
 
    // Default setting for OSC48M
    OSCCTRL->OSC48MCTRL.reg = OSCCTRL_OSC48MCTRL_ONDEMAND | OSCCTRL_OSC48MCTRL_ENABLE;
    OSCCTRL->OSC48MDIV.reg = OSCCTRL_OSC48MDIV_DIV(1 - 1) | OSCCTRL_OSC48MCTRL_RUNSTDBY;   // 48MHz

    REG_OSCCTRL_OSC48MSTUP = 0x07;              // ~21uS startup
    while (OSCCTRL->OSC48MSYNCBUSY.reg);        // Wait until synced
    while ((OSCCTRL->STATUS.reg & OSCCTRL_STATUS_OSC48MRDY) == 0 );        // Wait until ready

    // Default setting for GEN0 (DIV => 0 & 1 are both 1)
    GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC_OSC48M | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1);    // 48MHz
    GCLK->GENCTRL[2].reg = GCLK_GENCTRL_SRC_OSC48M | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(6);    // 8MHz
}

 

 

Regards!
FS.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is not possible to connect directly 16MHz to DPLL since input clock can be up to 2MHz (maximal perscale is 4).

The only way is to drive 16MHz to general clock (GLCK) and prescale it there.

Then you can set GCLK as DPLL input.

Last Edited: Tue. Nov 20, 2018 - 12:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS(1) | NVMCTRL_CTRLB_MANW;        //

The datasheet has 2 wait states for 48Mhz.

/Lars