XMEGA16E5 32 Mhz Internal Oscillator input to PLL and per4x per2x per1x outputs

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

I've been putting together the clock configuration routines for a project and have ran into some inconsistencies with the manual for the xmega16e.

 

On page 95 of the manual (Rev Atmel–42005E–AVR–XMEGA E–11/2014 which I'm 99.9% is the most recent), the clock system diagram indicates that the output from the 32 Mhz internal oscillator can be selected as an input clock for the PLL AFTER passing through a divide by four counter.  There's a couple of other places in the manual that mention this as well.  I have my clocks setup and working, but there is absolutely no evidence that this /4 is happening.

 

If all multiplier and dividers between the 32 Mhz internal oscillator and the system clock output are set to one, I get 32 Mhz on PINC7.  I would expect to get 8 (32/4). 

 

Does anyone know if this is a bug or some kind of error in the datasheet? 

 

Which brings me to my second question, clock output to a pin.  I have pinc7 configured to output the system clock (assume clk1x for now) All of my observations have been based on the output of this pin.

 

Given I have the following, and it's working:

 

32Mhz Int. Osc (Running @ 36 Mhz). ->36 Mhz-> PLL *2/2 ->36Mhz->Prescale A (/1) -> 36 Mhz->Prescale B(/2)->18 Mhz->Prescale C (/2)-> 9 Mhz -> Clkper Clkcpu

 

Peripheral clocks 4x, 2x and 1x should be 36 Mhz, 18 Mhz and 9 Mhz respectively.

 

With

 

    ; Output RTC Clock on PORTC, PIN6.  Output system clock on PC7, Clkper
    ldi r31, PORTCFG_RTCCLKOUT_PC6_gc | PORTCFG_CLKOUT_PC7_gc | PORTCFG_CLKOUTSEL_CLK1X_gc
    sts PORTCFG_CLKOUT,r31

 

I measure 9Mhz on PC7, which is what I would expect

 

    ; Output RTC Clock on PORTC, PIN6.  Output system clock on PC7, Clkper
    ldi r31, PORTCFG_RTCCLKOUT_PC6_gc | PORTCFG_CLKOUT_PC7_gc | PORTCFG_CLKOUTSEL_CLK2X_gc
    sts PORTCFG_CLKOUT,r31

 

I get NOTHING on PC7, but uC is operating just fine, still responding to USART I/O, etc.  I would expect 18 Mhz

 

    ; Output RTC Clock on PORTC, PIN6.  Output system clock on PC7, Clkper
    ldi r31, PORTCFG_RTCCLKOUT_PC6_gc | PORTCFG_CLKOUT_PC7_gc | PORTCFG_CLKOUTSEL_CLK4X_gc
    sts PORTCFG_CLKOUT,r31

 

I measure 9Mhz on PC7, I would expect 36 Mhz

 

Does anyone know if this is a bug too???

 

Or if I've missing some configuration somewhere?

This topic has a solution.
Last Edited: Tue. Sep 12, 2017 - 01:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The output of RC32M goes through a divide-by-four prescaler prior to driving the PLL, but F_CPU = 32MHz.  The PER2 and PER4 clock are for specific peripherals that can be clocked faster than the CPU.  At the moment, the only ones I can think of are the EBI and the HIRES thingy.  So you can clock the EBI at 64MHz (PER2) and the HIRES at 128MHz (PER4).  

 

EDIT:

 

This is wrong:

 ->36 Mhz-> PLL *2/2 ->36Mhz->

it should be: ->->->36 Mhz-> PLL *2/4 ->18Mhz->->->->

 

 

EDIT2:

 

Where is the code that sets prescalers B and C?

 

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

Last Edited: Fri. Sep 8, 2017 - 02:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greg, I think we could do with seeing the code you use to set up the oscillators and clock settings.

 

The XMEGA clocks can be a bit fiddly sometimes, so what I normally do is use the _delay_ms() function to create a simple square wave, say 1 Hz. That's really easy to measure on a 'scope and will tell you what the CPU is running at without having to worry about if the clock output port override is working.

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

 Actually, this is correct: ->36 Mhz-> PLL *2/2 ->36Mhz->

 

There is a divide by two (PLLDIV Bit in PLLCTRL register) which will divide the output of the PLL by two.  I enabled it as a work around for the apparent lack of /4 at the input of the PLL.  My objective is (was) to generate a tweakable (via COMP) CPU clock of 27 Mhz and output that clock (via PINC7) to the master clock of an Audio Codec.  Fortunately for my purposes that's doable, although not how I had originally planned.

 

I'm familiar with the Hi-Res extension, but what is EBI?  I couldn't find anything the manual about it.

 

I am learning the xmega as I develop this project, and I found it concerning that the device wasn't behaving how I expected based on the manual

 

Code that sets prescalers:

 

            ;System Clock Prescalar Configuration
                clr r31

                ;CLK_PSCTRL is write protected if the bit LOCK has been set in the LOCK register.
                ;Default is no prescaling (Divisor is 1 for all prescalars)
    
                ;Prescalar A
                ; Prescaler A Division Factor
                ;.equ CLK_PSADIV_1_gc = (0x00<<2) ; Divide by 1
                ;.equ CLK_PSADIV_2_gc = (0x01<<2) ; Divide by 2
                ;.equ CLK_PSADIV_4_gc = (0x03<<2) ; Divide by 4
                ;.equ CLK_PSADIV_8_gc = (0x05<<2) ; Divide by 8
                ;.equ CLK_PSADIV_16_gc = (0x07<<2) ; Divide by 16
                ;.equ CLK_PSADIV_32_gc = (0x09<<2) ; Divide by 32
                ;.equ CLK_PSADIV_64_gc = (0x0B<<2) ; Divide by 64
                ;.equ CLK_PSADIV_128_gc = (0x0D<<2) ; Divide by 128
                ;.equ CLK_PSADIV_256_gc = (0x0F<<2) ; Divide by 256
                ;.equ CLK_PSADIV_512_gc = (0x11<<2) ; Divide by 512
                ;.equ CLK_PSADIV_6_gc = (0x13<<2) ; Divide by 6
                ;.equ CLK_PSADIV_10_gc = (0x15<<2) ; Divide by 10
                ;.equ CLK_PSADIV_12_gc = (0x17<<2) ; Divide by 12
                ;.equ CLK_PSADIV_24_gc = (0x19<<2) ; Divide by 24
                ;.equ CLK_PSADIV_48_gc = (0x1B<<2) ; Divide by 48

                ;ldi r31,[Desired Division Factor for Prescalar A] ; See Table 7-2 on page 102 of manual for values for various division factors
                ori r31,CLK_PSADIV_1_gc        ; No Prescaling
                
                ;Prescalar B and C
                ; Prescaler B and C Division Factor
                ;.equ CLK_PSBCDIV_1_1_gc = (0x00<<0) ; Divide B by 1 and C by 1
                ;.equ CLK_PSBCDIV_1_2_gc = (0x01<<0) ; Divide B by 1 and C by 2
                ;.equ CLK_PSBCDIV_4_1_gc = (0x02<<0) ; Divide B by 4 and C by 1
                ;.equ CLK_PSBCDIV_2_2_gc = (0x03<<0) ; Divide B by 2 and C by 2
                ;ldi r31,[Desired Division Factor for Prescalar B] ; See Table 7-3 on page 102 of manual for values for various division factors
                ori r31,CLK_PSBCDIV_2_2_gc        ; No Prescaling
                
                sts CLK_PSCTRL,r31

 

I'm attaching the full code for clock initialization.  It's too wordy to post...  It's based on a template I put together which includes a sizable amount of the manual and the .equ from the .inc file.  It's handy, feel free to use it.

 

The attached code represents a very close approximation of my final configuration (speeds and outputs are correct).

 

Summarized, it looks like this:  INT32MRC -> 36 Mhz -> PLL *3 -> 108 Mhz -> A /1 -> 108 Mhz -> B /2 -> 54 Mhz -> C /2 -> 27 Mhz -> CPU

 

However, I still get the same behavior when setting PORTCFG_CLKOUTSEL_CLKnx_gc in PORTCFG_CLKOUT

 

PORTCFG_CLKOUTSEL_CLK1x_gc = 27 Mhz on Scope   (Correct)

PORTCFG_CLKOUTSEL_CLK2x_gc = 0 Hz on scope (Flat line - Should be 54 Mhz, no?)

PORTCFG_CLKOUTSEL_CLK4x_gc = 27 Mhz on Scope   (Should be 108 Mhz?!?!)

 

Attachment(s): 

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

Greg, I think we could do with seeing the code you use to set up the oscillators and clock settings.

 

The following results in F_PER4 = 128MHz, F_PER2 = 64MHz, F_PER = F_CPU = 32MHz:

// enable RC32M and wait for ready
OSC.CTRL |= OSC_RC32MEN_bm;
while (!(OSC.STATUS & OSC_RC32MRDY_bm));

// configure/enable PLL and wait for ready
OSC.PLLCTRL = OSC_PLLSRC_RC32M_gc | 16;	// 8MHz * 16 = 128MHz
OSC.CTRL |= OSC_PLLEN_bm;
while (!(OSC.STATUS & OSC_PLLRDY_bm));

// FIRST, set prescalers
PROTECTED_WRITE(&CLK.PSCTRL, CLK_PSADIV_1_gc | CLK_PSBCDIV_2_2_gc);

// THEN, switch clock sources
PROTECTED_WRITE(&CLK.CTRL, CLK_SCLKSEL_PLL_gc);

// turn off RC2M
OSC.CTRL &= ~OSC_RC2MEN_bm;

 

I'm familiar with the Hi-Res extension, but what is EBI?  I couldn't find anything the manual about it.

Whoops, I forgot we're talking about the XMEGA E series.  The External Bus Interface (EBI) is for attaching attaching external SRAM/SDRAM and is only available in the XMEGA A series.

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

Last Edited: Fri. Sep 8, 2017 - 08:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Summarized, it looks like this:  INT32MRC -> 36 Mhz -> PLL *3 -> 108 Mhz -> A /1 -> 108 Mhz -> B /2 -> 54 Mhz -> C /2 -> 27 Mhz -> CPU

I don't think so.  How about this: INT32MRC -> 36 Mhz  (/4) -> 9MHz -> PLL *3 -> 27 Mhz -> A /1 -> 27 Mhz -> B /2 -> 13.5 Mhz -> C /2 -> 6.75 Mhz -> CPU 

 

You have seen the following, have you not?

 

EDIT: the above is Figure 7.1 from the XMEGA E Manual.

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

Last Edited: Fri. Sep 8, 2017 - 08:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a more sophisticated version (it took multiples tries to find it...).  It does some build-time analysis to select a few of the clock parameters.

void sysclk_init(void)
{

#ifdef SIMULATION

	OSC.CTRL = OSC_RC2MEN_bm | OSC_RC32MEN_bm;
	while (!(OSC.STATUS & OSC_RC32MRDY_bm));
	CLK.PSCTRL = CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc;
	_PROTECTED_WRITE(CLK.CTRL, CLK_SCLKSEL_RC32M_gc);

#else	//  #ifdef SIMULATION

# if defined(XOSC_FREQ_HZ)

#  if (XOSC_FREQ_HZ == 32768UL)

	OSC.XOSCCTRL = OSC_XOSCSEL_32KHz_gc;

#  elif (400000UL <= XOSC_FREQ_HZ) && (XOSC_FREQ_HZ <= 2000000UL)

	OSC.XOSCCTRL = OSC_FRQRANGE_04TO2_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;

#  elif (XOSC_FREQ_HZ <= 9000000UL)

	OSC.XOSCCTRL = OSC_FRQRANGE_2TO9_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;

#  elif (XOSC_FREQ_HZ <= 12000000UL)

	OSC.XOSCCTRL = OSC_FRQRANGE_9TO12_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;

#  elif (XOSC_FREQ_HZ <= 16000000UL)

	OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;;

#  else

#   error Invalid External Oscillator Frequency.  Must be  0.4MHz to 16MHz.

#  endif

	OSC.CTRL = OSC_RC2MEN_bm | OSC_RC32MEN_bm | OSC_XOSCEN_bm;
	while (~OSC.STATUS & (OSC_RC2MRDY_bm | OSC_RC32MRDY_bm | OSC_XOSCRDY_bm));

# else

	OSC.CTRL = OSC_RC2MEN_bm | OSC_RC32MEN_bm;
	while (~OSC.STATUS & (OSC_RC2MRDY_bm | OSC_RC32MRDY_bm));

#  endif

# ifdef CONFIG_ENABLE_EBI

	OSC.PLLCTRL = OSC_PLLSRC_RC32M_gc | 8;
	OSC.CTRL |= OSC_PLLEN_bm;
	while (!(OSC.STATUS & OSC_PLLRDY_bm));
	CLK.PSCTRL = CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc;
	_PROTECTED_WRITE(CLK.CTRL, CLK_SCLKSEL_PLL_gc);

# else

	CLK.PSCTRL = CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc;
	_PROTECTED_WRITE(CLK.CTRL, CLK_SCLKSEL_RC32M_gc);

# endif

#endif

	_PROTECTED_WRITE(CLK.LOCK, CLK_LOCK_bm);

}

 

EDIT: This appears to be the undebugged version, as the while() loops 2 and 3 are wrong.

 

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

Last Edited: Sat. Sep 9, 2017 - 04:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This looks better for the while() loops in question:

#
#
#  endif

	OSC.CTRL = OSC_RC2MEN_bm | OSC_RC32MEN_bm | OSC_XOSCEN_bm;
	while ((OSC.STATUS & (OSC_RC2MRDY_bm | OSC_RC32MRDY_bm | OSC_XOSCRDY_bm)) != \
			(OSC_RC2MRDY_bm | OSC_RC32MRDY_bm | OSC_XOSCRDY_bm));

# else

	OSC.CTRL = OSC_RC2MEN_bm | OSC_RC32MEN_bm;
	while ((OSC.STATUS & (OSC_RC2MRDY_bm | OSC_RC32MRDY_bm)) != \
			(OSC_RC2MRDY_bm | OSC_RC32MRDY_bm));

#  endif

# ifdef CONFIG_ENABLE_EBI
#
#
#

 

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

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

I am indeed familiar with the clock schematic.  I agree with you 100% that this is what should be happening:

 

Greg_Muth wrote:

 

INT32MRC -> 36 Mhz  (/4) -> 9MHz -> PLL *3 -> 27 Mhz -> A /1 -> 27 Mhz -> B /2 -> 13.5 Mhz -> C /2 -> 6.75 Mhz -> CPU 

 

 

However, all my observations indicate this is not the case.  My CPU clock is running at 27 Mhz.  My scope measures 27 Mhz.  I have USARTC configured based on 27 Mhz and it operates perfectly.  I have the DFLL COMP registers set for 36 Mhz per the datasheet and CALB adjusted appropriately

 

; === PLL Control ===
	
	clr r31

	; PLL Clock Source
		;The PLLSRC bits select the input source for the PLL according to Table 7-7, page 107 of manual
		;
		; PLL Clock Source
		;.equ OSC_PLLSRC_RC2M_gc = (0x00<<6) ; Internal 2 MHz RC Oscillator
		;.equ OSC_PLLSRC_RC8M_gc = (0x01<<6) ; Internal 8 MHz RC Oscillator
		;.equ OSC_PLLSRC_RC32M_gc = (0x02<<6) ; Internal 32 MHz RC Oscillator
		;.equ OSC_PLLSRC_XOSC_gc = (0x03<<6) ; External Oscillator
		ori r31, OSC_PLLSRC_RC32M_gc			; 0x00 is Reset Default Value

	;PLL Output Division - PLLDIV, Bit 5
		;Setting this bit will divide the output from the PLL by 2.
		;
		;.equ OSC_PLLDIV_bm = 0x20 ; Divide by 2 bit mask
		;
		ori r31,0x00			; 0x00 is Reset Default Value

	;PLL Multiplication Factor
		; 
		;Bit 4:0 – PLLFAC[4:0]: Multiplication Factor
		;These bits select the multiplication factor for the PLL. The multiplication factor can be in the range of from 1x to
		;31x.
		ori r31, 3			; 0x00 is Reset Default Value

	; Write new configuration to OSC_PLLCTRL
	sts OSC_PLLCTRL, r31

	;Enable PLL, leaving previously enabled oscillators as they are
	ldi r31,OSC_RC32MEN_bm | OSC_RC2MEN_bm | OSC_XOSCEN_bm | OSC_PLLEN_bm
	sts OSC_CTRL,r31

; Wait for PLL to be ready before proceeding
WAIT_OSC_PLLRDY:
		lds r31,OSC_STATUS
		sbrs r31,OSC_PLLRDY_bp
		rjmp WAIT_OSC_PLLRDY
            
; COMP
    ldi r31, 0x54
    sts DFLLRC32M_COMP1,r31	; COMP1 is LSB
    ldi r31, 0x89
    sts DFLLRC32M_COMP2,r31 ; COMP2 is MSB

; Calibration
    ;Nominal DFLL32M COMP Values for Different Output Frequencies
    ;
    ;Oscillator frequency [MHz]		COMP value (ClkRC32MCREF = 1.024kHz)
    ;30.0							0x7270
    ;32.0							0x7A12
    ;34.0							0x81B3
    ;36.0							0x8954
    ldi r31,0x40	;42 is the production value I read from the user signature row.  From what I gather reading the manual, CALA is the one that is automatically
                    ; adjusted.  I think CALAB is not...  It kinda sets the baseline.  
    sts DFLLRC32M_CALA,r31
    
    ldi r31,0x0D	;0A is the production value I read from the user signature row
                    ;A larger value is required for auto calibration of 36 Mhz to keep CALA near a middle value

    sts DFLLRC32M_CALB,r31

 

I've monitored CALA to ensure automatic calibration is happening, and it is.  I can observe CALA being dynamically adjusted in the range of 0x38 to 0x42.  It moves when the chip is touched, warmed up, etc.

 

If the /4 where actually happening, I don't believe it would even be possible to get a 27 Mhz CPU clock with my configuration as INT32MRC would have to be running at 144 Mhz, which is outside of it's range, or the PLL multiplication factor would have to be larger (12)

 

INT32MRC -> 144 Mhz  (/4) -> 36 MHz -> PLL *3 -> 108 Mhz -> A /1 -> 108 Mhz -> B /2 -> 57 Mhz -> C /2 -> 27 Mhz -> CPU 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found the problem.  Although the XMEGA E manual neglects to indicate the CLK_PSCTRL is CCP_protected, it is.  When I run the following (your attachment above minus comments) in the simulator, this is what I see.  Note the prescaler setting indicated.

 

 

When I include the CCP code, this is was I get.  Again, note the prescaler setting indicated.

 

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

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

Messed up the CCP code slightly.  This is better:

 

	clr r31
	ori r31,CLK_PSADIV_1_gc
	ori r31,CLK_PSBCDIV_2_2_gc
	ldi r30,CCP_IOREG_gc		// observe CCP protocol
	sts CPU_CCP,r30			// observe CCP protocol
	sts CLK_PSCTRL,r31

 

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

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

Although the XMEGA E manual neglects to indicate the CLK_PSCTRL is CCP_protected, it is.  

I've said before how much I dis-like having TWO separate manuals for the Xmega chips...

 

The manual does state that the Configuration Change Protection process is required for changing the Xmega clocks, but one has to look closely to find it, (second paragraph, below)...

 

An example of my XmegaE5 clock setup is shown below, albeit in Basic.

The theory, however, is the same.

Sorry for the "magic numbers", they are, however, explained in the code's notes.

 

I've not had any problems with the X5 clock.

 

JC

 

 

Clockopt5:
   'Set up the Xmega Clock.
   'Run at 32 MHz from the Internal 32 MHz Osc.
   'Xmega runs on Int 2 MHz Osc on Startup.
   'This turns on the Int 32 MHz Osc, awaits it being ready, and switches to it.
   'Don't forget the Configuration Change Register Protection Trigger before
   'changing the uC's Clock Source.
   'First turn ON the 32 MHz Int Osc:
   'Then wait until the Int 32 MHz Osc is ready to be used.
  
   Osc_ctrl = 2                     'Int 32 MHz Osc ON
   Rvbit = 0                        'Clear flag
   While Rvbit = 0
      'Read the Int 32 MHz Osc Status
      Regdata = Osc_status          'Status of all Int Osc Sources
      Rvbit = Regdata.1             'Int 32 MHz Osc Status, 1 = Ready
   Wend
   Cpu_ccp = 216                    'Config Change Protection
   Clk_ctrl = 1                     'Use Int 32 MHz Osc
   Return

 

Edit: Typo

  

Last Edited: Sun. Sep 10, 2017 - 06:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Greg and others!

 

The problem was indeed the CCP system on the CLK_PSCTRL.  Okay so it wasn't the CCP system that was really the problem, it was me!

I'm now getting:

 

108 Mhz on PC7 with PORTCFG_CLKOUTSEL_CLK4x_gc

0 Mhz on PC7 with PORTCFG_CLKOUTSEL_CLK2x_gc (<<  That is not a typo, it's still inexplicably happening!)

27 Mhz on PC7 with PORTCFG_CLKOUTSEL_CLK1x_gc

 

As expected