SAMD10 Xplained Mini, questions and experiences... (clocking, transitioning to pinmux...)

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

The SAMD10 examples that come with ASF currently use the default 8MHz internal clock.\

I thought I should run it at the max 48MHz rate.  After all, that's one reason why you use an ARM, right?

 

Apparently, for an ASF-based program, the preferred way to configure the chip/board clocks is to modify the conf_clocks.h file, which is include and acted on by the ASF clock_init() function.  OK...

 

Is conf_clocks.h DOCUMENTED anywhere?  It's a lot more complex than I would have liked.  The ASF documentation describes the functions that clock_init() will end up calling, but not (as far as I found) how conf_clocks.h is laid out.  :-(

 

Why, oh why, is ARM clock configuration so complex and so poorly "abstracted" by vendor libraries?  In an environment where they seem to think that coders need a function "port_pin_set_output_level" instead of "PORTPINNAME = n", why can't I just say that I have an 8M crystal and want to run at 48MHz, without having to learn about the details of whether I want a PLL or an FLL, multipliers, clock source choices, and so on?  (And it's not just Atmel!)

 

Aside from that not being a legal configuration, apparently.  Max input frequency for the FLL is 33kHz, and for the PLL is 2MHz, so it looks like I can't generate 48MHz from an 8MHz crystal.  That seems ... annoying.  And it took me a long time to figure that out, considering that there is clock_config_check.h that is supposed to check the validity of conf_clocks.h

(I guess it's included from chip-independent code (sam0, anyway), so maybe it doesn't know about these limits?  Not very useful :-( )

 

Now, the D10 Xplained mini doesn't actually have an 8MHz crystal; it has an 8MHz clcok from the mdebug chip feeding into Xin.   I guess that's useless unless I want to run at 8MHz?  Sigh.  (no, wait.  Can I divide the external clock before it gets to the input of the FLL?)

 

Now, I'm still confused about how, if I configure one GCLK as the reference frequency for the FLL, how I manage to get the cpu and all the peripherals/buses to use a different GCLK?

Perhaps I'm just confused about the whole clock system for the SAMD; is there a document somewhere that describes it ... differently ... than the datasheet?

 

Last Edited: Thu. Oct 15, 2015 - 11:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can I divide the external clock before it gets to the input of the FLL?

Hah!  Apparently I can!  It helps if I actually toggle the pin I'm looking at, and not ... some other pin.

 

heh.  "Blink" is about 2200 bytes.  About 1200 bytes of that is ASF Clock Initialization functions!

 

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

I went through a similar experience last night with a samd20 xplained board (thanks Braemac/matthew!).
The default setting was 8MHz so i wanted max speed. HTF do i do that? A quick google landed me at an Atmel page that had the settings and a quick rundown. Without reference to the datasheet all i know is the clock system is a bunch of Lego blocks you need to assemble correctly. Aaand you need to set the flash wait states to 1, otherwise things don't work. That was about an hour of fiddling.
Timers are next.

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

A quick google landed me at an Atmel page that had the settings and a quick rundown.

 Link?  I kept ending up on UC3 pages, which didn't match the D10 at all.  (and the ASF documentation that said "system_clock_init() sets up the clocks as per conf_clocks.h" without describing the conf_clocks.h format.

 

 

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

The irony here, is that if you read the datasheet and don't use ASF, it's not actually that hard to configure whichever clock you want and my clock configuration probably took 20 bytes. I think I had 2 wait states to run the FLL at 48MHz using the 32k crystal as reference. 

edit - my bad, was 1 wait state for 48MHz, see code below

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

Last Edited: Fri. Jul 31, 2015 - 10:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah; it was certainly starting to look like configuring the clock on my own would have been easier (the datasheet is at least complete!)

Kartman's link is somewhat helpful, and not something that I found in my own searches.

I lot of the ASF code is (re)setting things to their default state, and/or some new default state.  I can slightly appreciate that from some sort of "always correct" viewpoint, but it's not something that comes up in practice very often.  At least, not for me.

 

Can you share your clock code?

 

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

Sure thing, here is my main clock setup function:

 

void SetupMainClock(void)
{
	//Enable the 32.768 khz external crystal oscillator
	REG_SYSCTRL_XOSC32K = (SYSCTRL_XOSC32K_ENABLE);
	REG_SYSCTRL_XOSC32K |= (SYSCTRL_XOSC32K_STARTUP(5) | SYSCTRL_XOSC32K_AAMPEN | SYSCTRL_XOSC32K_EN32K | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_ENABLE);
	
	//Wait for the crystal oscillator to start up
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_XOSC32KRDY)) == 0);
	
	//Configure GCLK Generator 1 to use the 32k crystal as input, and feed this clock to the DFLL48M FLL
	REG_GCLK_GENDIV = ((1 << GCLK_GENDIV_DIV_Pos) | (1 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((1 << GCLK_GENCTRL_ID_Pos) | (GCLK_GENCTRL_SRC_XOSC32K) | (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK1) | (GCLK_CLKCTRL_CLKEN) | (GCLK_CLKCTRL_ID(0))) ;
	
	//Configure the FDLL48MHz FLL, we will use this to provide a clock to the CPU
	//Set the course and fine step sizes, these should be less than 50% of the values used for the course and fine values (P150)
	REG_SYSCTRL_DFLLCTRL = (SYSCTRL_DFLLCTRL_ENABLE); //Enable the DFLL
	REG_SYSCTRL_DFLLMUL = (SYSCTRL_DFLLMUL_CSTEP(5) | SYSCTRL_DFLLMUL_FSTEP(10)); 	
	REG_SYSCTRL_DFLLMUL |= (SYSCTRL_DFLLMUL_MUL(1465)); //1465 * 32768 is approx 48MHZ
	REG_SYSCTRL_DFLLCTRL |= (SYSCTRL_DFLLCTRL_MODE);
	
	//Wait and see if the DFLL output is good . . .
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_DFLLLCKC)) == 0);
	
	//Set flash wait state to 1, which we need to do at 48MHz
	REG_NVMCTRL_CTRLB |= (NVMCTRL_CTRLB_RWS(1));
	
	//For generic clock generator 0, select the DFLL48 Clock as input
	REG_GCLK_GENDIV = ((1 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((0 << GCLK_GENCTRL_ID_Pos) | (GCLK_GENCTRL_SRC_DFLL48M) | (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK0) | (GCLK_CLKCTRL_CLKEN)) ;
}

 

 

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Thanks!   Here it is, modified to work with the D10 Xplained Mini 8MHz external clock.  (I think.  It seems to work.)  (and sure enough, the resulting binary is over 1K shorter!)

void system_clock_init()
{
	#define EXTCLK_FREQ 8000000  /* External clock freq on SAMD10 Xplained mini */
	#define EXTCLK_DIV 250	     /* Divisor to get clock within range for FLL input */
	
	//Enable the 8MHz oscillator input
	REG_SYSCTRL_XOSC = (SYSCTRL_XOSC_ENABLE);
	
	//Wait for the crystal oscillator to start up
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_XOSCRDY)) == 0);
	
	//Configure GCLK Generator 1 to use a divided external osc as input, and feed this clock to the DFLL48M FLL
	REG_GCLK_GENDIV = ((EXTCLK_DIV << GCLK_GENDIV_DIV_Pos) | (1 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((1 << GCLK_GENCTRL_ID_Pos) | (GCLK_GENCTRL_SRC_XOSC) | (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK1) | (GCLK_CLKCTRL_CLKEN) | (GCLK_CLKCTRL_ID(0))) ;
	
	//Configure the FDLL48MHz FLL, we will use this to provide a clock to the CPU
	//Set the course and fine step sizes, these should be less than 50% of the values used for the course and fine values (P150)
	REG_SYSCTRL_DFLLCTRL = (SYSCTRL_DFLLCTRL_ENABLE); //Enable the DFLL
	REG_SYSCTRL_DFLLMUL = (SYSCTRL_DFLLMUL_CSTEP(5) | SYSCTRL_DFLLMUL_FSTEP(10));
	REG_SYSCTRL_DFLLMUL |= (SYSCTRL_DFLLMUL_MUL(48000000/(EXTCLK_FREQ/EXTCLK_DIV)));
	REG_SYSCTRL_DFLLCTRL |= (SYSCTRL_DFLLCTRL_MODE);
	
	//Wait and see if the DFLL output is good . . .
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_DFLLLCKC)) == 0);
	
	//Set flash wait state to 1, which we need to do at 48MHz
	REG_NVMCTRL_CTRLB |= (NVMCTRL_CTRLB_RWS(1));
	
	//For generic clock generator 0, select the DFLL48 Clock as input
	REG_GCLK_GENDIV = ((1 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((0 << GCLK_GENCTRL_ID_Pos) | (GCLK_GENCTRL_SRC_DFLL48M) | (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK0) | (GCLK_CLKCTRL_CLKEN)) ;
}

 

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

westfw wrote:
Why, oh why, is ARM (sic) clock configuration so complex

Note that this has nothing whatsoever to do with ARM - it is entirely Atmel stuff, and completely separate from the ARM core.

 

In fact, I think the clocking scheme is pretty much the same as found on AVR32 ?

 

and so poorly "abstracted"

Actually, I found that even the datasheet description was not that great: terms like "clocks" and "sources" and "channels" were used but not clearly defined - and sometimes, apparently, used inconsistently.

 

angry

 

This is certainly somewhere where a graphical configuration tool - showing the paths from oscillators through GCLKs etc to peripherals - would help.

 

I certainly found it helpful to draw it out as a diagram ...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Sun. Aug 2, 2015 - 08:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why, oh why, is ARM (sic) clock configuration so complex

You (and I) say "complex" - no doubt Atmel say "flexible".

 

That's always going to be the trouble - "complexity" and "flexibility" are 2 sides of the same coin. 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this has nothing whatsoever to do with ARM - it is entirely Atmel stuff

Perhaps.  But the complexity seems to be common to ARM chips from many different vendors, not just Atmel.

 

At the moment, I'm trying to figure out why there are both FLL and PLL clock sources in the same chip.  They seem to do about the same thing and have similar input and output requirements, and neither one provides a very generalized frequency multiplier.  (FLL has output frequency of 48MHz.  PLL has output frequency of 48 to 96MHz.)   Is the FLL particularly low-power compared to the PLL?  I couldn't find a number for it in the datasheet.  Does the PLL offer many frequencies up to 48MHz by permitting fractional multipliers yielding 48-96MHz, which then get divided by prescalers to yield the system clock?  (ie if I want 32 MHz given an 8MHz clock input, I'd divide by 8 (=1MHz), multiply by 64, and then divide by 2?  (huh.  Didn't even require fractions...))

 

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

As an aside, I was fiddling with clock rates last night. Since we need to run 1 wait state on the flash at 48MHz, I pondered if 24MHz and 0 wait states would be the same (assuming most instructions are 1 clock). I had code that output a sawtooth wave to the DAC and viewed this on a 'scope. The results were that 24MHz and 0 wait states were half the speed of 48MHz and 1 wait state. Not sure what to make of this - there seems to be a little magic happening behind the scenes.

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

The reason we use 48MHz with 1 wait state is that on the ARM, code can be run from the RAM. I agree though that it's odd that for most code, 48MHz with 1WS is not equal to 24MHz with 0WS. Maybe someone more knowledgeable on processor architecture can explain that one to us.

 

edit - I wonder if maybe it is because with THUMB instructions, the CPU can load more than one instruction at a time from the flash, in that case, 48MHz will be twice as fast as 24MHz ???

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

Last Edited: Sun. Aug 2, 2015 - 09:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm suspecting it is something like that. Maybe i should've experimented with more wait states to get a better idea. Frequently the internal flash data path is wider to get some extra performance.

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

Kartman wrote:
Frequently the internal flash data path is wider to get some extra performance ...

 ... and is separate from the RAM data path - so code fetches don't have to share the RAM data path's bandwidth with data fetches.

 

Also, manufacturers often have clever "acceleration" tricks with the Flash.

 

All of which means that there may be little or no gain in practice in running from RAM. These parts are optimised to run from Flash.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

this has nothing whatsoever to do with ARM - it is entirely Atmel stuff

Perhaps.

 

No "perhaps" - it is for sure!

 

But the complexity seems to be common to ARM chips from many different vendors, not just Atmel.

As already noted, it is also found in AVR32; so it's not just ARM - it's general to these "advanced" processors.

(I've never looked at PIC32 so dunno whether they follow the pattern).

 

Again, it's the 'flexibility' <=> 'complexity' thing.

 

At the moment, I'm trying to figure out why there are both FLL and PLL clock sources in the same chip.  They seem to do about the same thing and have similar input and output requirements

I'd agree with you there - manufacturers could help a lot in explaining the pros & cons of all the options!

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No "perhaps" - it is for sure!

I'm still not sure I'm convinced.  ARM gets to defined "The CPU and the Bus controller and the memory and the peripherals all have different clock inputs", the the actual chip manufacturers feel compelled to make them be individually configurable, whether or not it makes much sense (especially in a CM0-class chip.)  OTOH, I guess the original CM3 chips (Luminary micro) had really awful power consumption specs, so maybe the separate clocks WERE needed to help solve those issues.  (I never dove into those early chips deeply enough to notice whether they had similarly complex clock circuits...)

 

Does the PLL offer many frequencies up to 48MHz by permitting fractional multipliers yielding 48-96MHz, which then get divided by prescalers to yield the system clock?

 This seems to be the case.  Using conf_clocks.h and ASF, I got my LED blinking at a couple of intermediate rates (20Mz, 30MHz, 40MHz)...

Now to see if I can get the PLL working without ASF...

 

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

westfw wrote:
the actual chip manufacturers feel compelled to make them be individually configurable

Yes - it's entirely a decision of the actual chip manufacturers - nothing whatsoever to do with ARM.

 

Again, they feel that "flexibility" is the Big Thing - and, therefore, that the resulting complexity is worth the price.

 

And again, you see the same in AVR32.

 

whether or not it makes much sense

I guess it makes sense for them as manufacturers - whether we as users agree that the pain is worth it is another question ...

 

maybe the separate clocks WERE needed to help solve those issues

Yes, flexibility of clocking is a Big Thing for power optimisation.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, here is my non-working attempt at a non-ASF PLL-based clock configuration.   As far as I can tell, it sets up the assorted sysctl registers the same as the ASF-based version (which DOES work.)

It hangs waiting for the PLL clock to be "good".   Any ideas what could be wrong?  It looks to me like the PLL should be slightly easier to use than the FLL, because the PLL can use the (divided) XOSC clock directly (via ...REF1), rather than needing to configure one of the generic clocks to use as an input.  Perhaps there is some other dependency that I'm missing?

void system_clock_init()
{
	//Enable the 8MHz oscillator input from SAMD10 XMini
	REG_SYSCTRL_XOSC = (SYSCTRL_XOSC_ENABLE);
	
	//Wait for the crystal oscillator to start up
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_XOSCRDY)) == 0);
		
	//Set flash wait state to 1, which we need to do at 48MHz
	REG_NVMCTRL_CTRLB |= (NVMCTRL_CTRLB_RWS(1));
	
	//Configure the DPLL

	SYSCTRL->DPLLCTRLA.reg =
		(1UL << SYSCTRL_DPLLCTRLA_ONDEMAND_Pos) |
		(0UL << SYSCTRL_DPLLCTRLA_RUNSTDBY_Pos);

	SYSCTRL->DPLLRATIO.reg =
		SYSCTRL_DPLLRATIO_LDRFRAC(0) |
		SYSCTRL_DPLLRATIO_LDR(480);  /* Refclock will be 100kHz, this should give 48MHz */

	SYSCTRL->DPLLCTRLB.reg =
		SYSCTRL_DPLLCTRLB_DIV(39) /* Refclock divider */ | 
		SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);

	SYSCTRL->DPLLCTRLA.reg |= SYSCTRL_DPLLCTRLA_ENABLE;
	
	while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL))
	   /* HANGS HERE */;
	
	//For generic clock generator 0, select the DPLL Clock as input, divide by 2
	REG_GCLK_GENDIV = ((2 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((0 << GCLK_GENCTRL_ID_Pos) | (SYSTEM_CLOCK_SOURCE_DPLL) | (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK0) | (GCLK_CLKCTRL_CLKEN)) ;
}

 

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

Can you confirm that 

SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);

equates to (1 << 4), I don't have the SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC on my system ?

 

Can you also check what 

while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL))
	   /* HANGS HERE */;

actually does ? I assume it would just check the lock bit in the status register ?

 

Am I correct in assuming that your board uses a crystal oscillator, and not just a crystal ?

 

I see the PCLKSR register also contains a few bits for checking the status of the DPLL, worth having a look at these with your debugger.

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

Last Edited: Tue. Aug 4, 2015 - 02:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);

equates to (1 << 4), I don't have the SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC on my system ?

 It certainly seems to.  I guess I have a sort of mishmash of ASF and chip-level definitions in this code.   Something to clean up when it's working?

 

I end up with:

                        ASF     Bare metal
PLLCTRLA 0x80000844:   0x82     0x82
PLLRATIO 0x80000848:   0x1DF    0x1DE  (479 or 480, to muliply by 100kHz)
PLLCTRLB 0x8000084C:  0x270010  0x270010  (0x27 = 39, to get 100kHz from 8MHz)
PLLSTAT  0x80000850:   0xF      0x8 (not enabled, not ready, not locked :-( )
 --
 PCLKSR  0x8000080C   0xDA11    0x5819  (I don't have brownout enabled.)
 XOSSC   0x80000810   0xF882    0x2   (Hmm.  "2" is enabled.  All the rest is
                                       for the crystal stuff I'm not using.)
system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL)

Ends up doing:

		return ((SYSCTRL->DPLLSTATUS.reg &
				(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)) ==
				(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK));

your board uses a crystal oscillator, and not just a crystal ?

Yep.  It's a SAMD10 Xplained Mini, so the meDBG chip provides an 8MHz clock to Xin.

 

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

I think I've got it, your code sets the ONDEMAND bit in Control Register A, but is there a peripheral that uses DPLL as input ? From datasheet P200:

 

Bit 7 – ONDEMAND: On Demand Clock Activation
0: The DPLL is always on when enabled.
1: The DPLL is activated only when a peripheral request the DPLL as a source clock. The DPLLCTRLA.ENABLE
bit must be one to validate that operation, otherwise the peripheral request has no effect.

 

Try it without this and let me know.

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Yes, that seems to take it beyond the clock initialization.

No blinking, though.  I suspect GPIO needs a clock.  (although, the working FLL code didn't give it one.  Perhaps it defaults to GENCLK1)

 

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

Yeah, that is weird then, the output of GCLK0 is the clock for the CPU, so if the only thing you change is whether the source of GCLK0 is the FLL or DPLL, you would think the  rest of your program should run exactly the same.

 

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Ahh.  I seem to have problems with the "source" for GCLK0.

It seems that the project includes *two* version of gclk.h.

 

There is C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.8.1443\CMSIS_Atmel\Device\ATMEL\samd10\include\component\gclk.h

Which has clock source definitions that need to be shifted into place:

#define   GCLK_GENCTRL_SRC_XOSC32K_Val    0x5ul  /**< \brief (GCLK_GENCTRL) XOSC32K oscillator output */
#define   GCLK_GENCTRL_SRC_OSC8M_Val      0x6ul  /**< \brief (GCLK_GENCTRL) OSC8M oscillator output */
#define   GCLK_GENCTRL_SRC_DFLL48M_Val    0x7ul  /**< \brief (GCLK_GENCTRL) DFLL48M output */
#define   GCLK_GENCTRL_SRC_FDPLL_Val      0x8ul  /**< \brief (GCLK_GENCTRL) FDPLL output */

 

And then there is C:\Documents and Settings\Bill\My Documents\Atmel Studio\D10-LED_TOGGLE0\D10-LED_TOGGLE0\src\ASF\sam0\utils\cmsis\samd10\include\component\gclk.h

Which has clock source definitions that have already been shifted into place (and doesn't include the PLL!):

#define GCLK_GENCTRL_SRC_OSC32K     (GCLK_GENCTRL_SRC_OSC32K_Val   << GCLK_GENCTRL_SRC_Pos)
#define GCLK_GENCTRL_SRC_XOSC32K    (GCLK_GENCTRL_SRC_XOSC32K_Val  << GCLK_GENCTRL_SRC_Pos)
#define GCLK_GENCTRL_SRC_OSC8M      (GCLK_GENCTRL_SRC_OSC8M_Val    << GCLK_GENCTRL_SRC_Pos)
#define GCLK_GENCTRL_SRC_DFLL48M    (GCLK_GENCTRL_SRC_DFLL48M_Val  << GCLK_GENCTRL_SRC_Pos)

(Oh wait, there's a 3rd one: C:\Documents and Settings\Bill\My Documents\Atmel Studio\D10-LED_TOGGLE0\D10-LED_TOGGLE0\src\ASF\sam0\utils\cmsis\samd10\include\instance\gclk.h)

 

That's really... rather depressing.  I wonder which files are including which includes?

 

The fll code (included in the main program) seems to be getting its definition from the 2nd location (which doesn't have a PLL value.)

I am not having much luck substituting in known constants :-(

 

The datasheet keeps saying that the gclk can have an input source selected from 8 choices.  The PLL is the 9th. :-(  I'm not feeling warm and fuzzy.

 

I guess tomorrow I'll trace through the ASF code more carefully, and see what it does.

 

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

The datasheet for the  SAMR21 has 5 bits to select the source, so, no problem selecting the 9th source. Haven't actually tried it yet though. Let me know what you find in the ASF.

 

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Interesting, just reading through the GCLK code, mine also says it can run from one of eight sources:

 

Each generic clock generator (GCLKGEN) can be set to run from one of eight different clock sources except 
GCLKGEN[1] which can be set to run from one of seven sources. GCLKGEN[1] can act as source to the other generic 
clock generators but can not act as source to itself.

 

Let me know if you figure out how the ASF is doing it.

 

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Today, things I didn't think were working seem to be mysteriously working.

ASF seemed to be writing the same values I thought I was trying to write to the REG_GCLK registers, but calculates them at runtime, but has a lot of "while (system_gclk_is_syncing()) ;" and critical section stuff.

 

Hmmph.  Now I don't know why it wasn't working before. :-(

 

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

Current state-of-the-code (seems to be working for a broad (beyond spec!) range of F_CPU targets from 16MHz to 55MHz...

 

#define USEPLL 1
	#define F_CPU 30000000		/* Desired target frequency */
	#define EXTCLK_FREQ 8000000  /* External clock freq on SAMD10 Xplained mini */
	#define F_INTERM 32000		 /* Intermediate frequency.  <33KHz for FLL, <2MHz for PLL */

void system_clock_init()
{
#ifdef USEPLL
#define EXTCLK_DIV ((EXTCLK_FREQ/(2*F_INTERM)) - 1)
	//Enable the 8MHz oscillator input from SAMD10 XMini
	REG_SYSCTRL_XOSC = (SYSCTRL_XOSC_ENABLE);
	
	//Wait for the crystal oscillator to start up
	while((REG_SYSCTRL_PCLKSR & (SYSCTRL_PCLKSR_XOSCRDY)) == 0);
		
	//Set flash wait state to 1, which we need to do at 48MHz
	REG_NVMCTRL_CTRLB |= (NVMCTRL_CTRLB_RWS(1));
	
	//Configure the DPLL

	/*
	 * The output of DPLL is supposed to be between 48MHz and 96MHz.
	 * By setting the PLL output to 2*F_CPU, we have easy acess to
	 * most of the "interesting" frequencies between 24MHz and 48MHz
	 * Lower F_CPU can be obtained by increasing the GCLK0 divisor.
	 */
	SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(2*F_CPU/F_INTERM);
	SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_DIV(EXTCLK_DIV) | /* Refclock divider */
		SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);
	SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;
	
	while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL));

	//For generic clock generator 0, select the DPLL Clock as input, divide by 2
	REG_GCLK_GENDIV = ((2 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));
	REG_GCLK_GENCTRL = ((0 << GCLK_GENCTRL_ID_Pos) | (8 << GCLK_GENCTRL_SRC_Pos)| (GCLK_GENCTRL_GENEN));
	REG_GCLK_CLKCTRL = ((GCLK_CLKCTRL_GEN_GCLK0) | (GCLK_CLKCTRL_CLKEN)) ;
#endif /* USEPLL */
}

 

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

I got a response from Atmel re my wait state conundrum - they implement a small cache so that with linear code the wait state does not affect the performance.

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

Random observation:  Code that accesses a structure-like definition of peripheral registers via a base address, like:

	SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(2*F_CPU/F_INTERM);
	SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_DIV(EXTCLK_DIV) | /* Refclock divider */
	         SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);
	SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;

Well end up slightly smaller than code that accesses the same registers individually, like:

    REG_SYSCTRL_DFLLCTRL = (SYSCTRL_DFLLCTRL_ENABLE); //Enable the DFLL
    REG_SYSCTRL_DFLLMUL = (SYSCTRL_DFLLMUL_CSTEP(5) | SYSCTRL_DFLLMUL_FSTEP(10));
    REG_SYSCTRL_DFLLMUL |= (SYSCTRL_DFLLMUL_MUL(48000000/(EXTCLK_FREQ/EXTCLK_DIV)));
    REG_SYSCTRL_DFLLCTRL |= (SYSCTRL_DFLLCTRL_MODE);

This is because the compiler doesn't seem to be quite smart enough to notice that one constant pointer reference is withing "indexing" range of a previous pointer reference, and will reload the pointer for each of the latter example's register, while only loading a pointer once for the first example.

 

Last Edited: Thu. Aug 6, 2015 - 03:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is that something that is likely to happen anyway by changing the compiler optimization level ? 

If you're using ASF, neither of us know what your code is really doing :)
Have I just solved your problem ? My bitcoin address: 1EpGuPa2VtUVWjGmgWRmFicNKMFZSGhfLr

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

Apparently not.   This is a result of code with both, compiled with -O3:

 

// (Note that R2 already has &SYSCTRL from previous statements.)
//
    SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(2*F_CPU/F_INTERM);
 2b6:	6490      	str	r0, [r2, #72]	; 0x48
    SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_DIV(EXTCLK_DIV) | /* Refclock divider */
 2b8:	64d1      	str	r1, [r2, #76]	; 0x4c
        SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);
    SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;
 2ba:	5513      	strb	r3, [r2, r4]

;----------------------------------------------------

    REG_SYSCTRL_DPLLRATIO  = SYSCTRL_DPLLRATIO_LDR(2*F_CPU/F_INTERM);
 2bc:	4c0d      	ldr	r4, [pc, #52]	; (2f4 <system_clock_init+0x64>)
 2be:	6020      	str	r0, [r4, #0]
    REG_SYSCTRL_DPLLCTRLB = SYSCTRL_DPLLCTRLB_DIV(EXTCLK_DIV) | /* Refclock divider */
 2c0:	480d      	ldr	r0, [pc, #52]	; (2f8 <system_clock_init+0x68>)
 2c2:	6001      	str	r1, [r0, #0]
        SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);
    REG_SYSCTRL_DPLLCTRLA = SYSCTRL_DPLLCTRLA_ENABLE;
 2c4:	490d      	ldr	r1, [pc, #52]	; (2fc <system_clock_init+0x6c>)
 2c6:	700b      	strb	r3, [r1, #0]
    

(The use of different registers for each loaded address in the 2nd case is "interesting."  I guess the register allocator is working harder than it really needs to.)

 

Edit:  the range of indexing off of a base register is "not very much" (0..124 for words, 0..31 for bytes), so larger peripherals may be "interesting."

 

Last Edited: Thu. Aug 6, 2015 - 05:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm.  I'm not seeing, anywhere in either the virgin SAMD10 Xplained LED Toggle project or in my modified version, anything that sets PA08 configuration to be an external clock input.

And glancing through the datasheet, I don't see anything in the pinmux descriptions to enable external clock or external crystal oscillator.  I guess enabling that via System Control bypasses and obviates the pinmux stuff?   I don't know if I consider that particularly convenient ("old fashioned", even), or horribly inconsistent with what I thought was the new way of doing things.

 

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

well thanks to this post i got the samd21 chomping along at 48mhz ish ... i dont have a scope to get a good measurement but i figured it out via systick iterations . much appreciated.