XMEGA clock setting

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

Hi Guys,
I have migrated from atmega to xmega128a1, adjusted all the code... but I am not able to fix the simple one: delay.
I do believe is a matter of clock setting.
Could you please help me with the following:
1. just testing led blinking on PORTH pin PH7
2. I have an external clock, about 18Mhz
3. I am optimizing the code with -O1
4. and I wrote the following code:

int main (void){

OSC.CTRL=OSC_XOSCEN_bm;
CLK.PSCTRL=0x00;
CLK.CTRL=0x03;

//blink_test;
PORTH_OUT=0x80;
_delay_ms(1000);
PORTH_OUT=0x00;
_delay_ms(1000);
PORTH_OUT=0x80;
_delay_ms(1000);
PORTH_OUT=0x00;
_delay_ms(1000);
PORTH_OUT=0x80;
_delay_ms(1000);
PORTH_OUT=0x00;

as result I have the led on and turn off after ~45sec... instead of blinking 3 times on every other second.
Thanks

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

I don't see the CCP register being set before your attempts to change CLK or OSC. Since both CLK and OSC are I/O Protected Registers, you must set CCP to 0xD8 before each change.

Also each change must occur within 4 clock cycles of setting CCP. To accomplish this in GCC, that section of code must be compiled with the -Os optimization level. The _delay_ms function also prefers to be compiled with -Os.

The math still doesn't quite work out - 45 seconds is 5X off from the expected 9 seconds I would expect from telling _delay_ms that FCPU=18000000UL and the default 2 MHz that the Xmega is running. Maybe someone else has an idea.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

Thanks stu_san,
fixed the blinking... and the timing.
OSC doesn't need the CCP.

Following code doesn't work, CPP switch back before the CLK setting:

	CCP=0xD8;
	OSC.CTRL=OSC_XOSCEN_bm;
	CLK.CTRL=0x03;

But following one is correct:

	OSC.CTRL=OSC_XOSCEN_bm;	
	CCP=0xD8;
	CLK.CTRL=0x03;

Thanks

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

bmarcello wrote:
Following code doesn't work, CPP switch back before the CLK setting...
Yup. When you are required to set something "within 4 clock cycles" of something else, the two settings should be one after another in the C code. Also, I will repeat that you must compile with at least -O1 (I think) or preferably -Os to make the resulting code happen withing 4 clock cycles.

Glad I helped!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

Hi all,

I am having the same problem here with my atxmega128a1. I have tried everything mentioned in this thread, but I cannot change the clock setting to internal 32Mhz.
Code, compiled with WinAVR 20090313:

int main(void)
{
CCP = 0xd8;
CLK.CTRL = 0x01;
while(1){}
}

I can see with the debugger the CCP register changing to 0x01, but it dissapears when stepped to the next instruction and CLK.CTRL stays at 0x00 (2Mhz operation). I have -Os optimization. What could I be missing?

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

Got it. 32Mhz clock wasn't enabled. Somewhat confusing since the enable register is a sub-register of the OSC module instead of the CLK module.

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

What was your solution?

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

Hi, i get the same problem here, and i can't solve it.
I'm trying to enable the 32Mhz internal oscillator.

OSC.CTRL = OSC_RC32MEN_bm; //enable 32MHz oscillator
while(!(OSC.STATUS & OSC_RC32MRDY_bm));	//wait for stability
CCP = CCP_IOREG_gc; //secured access
CLK.CTRL = 0x01; //choose this osc source as clk

When i use the debugger, i can see that it gets stuck on the line : "CLK.CTRL = 0x01;"

Can someone help me please?

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

Use -Os when you compile. You have a 4 cycle window to do anything. (from memory)

If you are intentionally using zero optimisation, there is an app note that gives you a specific CCP setting function. AVR1003 clksys-driver.c

David.

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

optimization is already active, and i do into as soon as possible, i don't know if it's more than 4 cycles because it's C code... any other idea?

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

up!

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

I'd try inline-assembler and/or have a look at the assembly which comes out of the compiler

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

Ok here's the asm i got after compiling:

void init_clock(void)
{
	
	OSC.CTRL = OSC_RC32MEN_bm; //enable 32MHz oscillator
 234:	e0 e5       	ldi	r30, 0x50	; 80
 236:	f0 e0       	ldi	r31, 0x00	; 0
 238:	82 e0       	ldi	r24, 0x02	; 2
 23a:	80 83       	st	Z, r24
	while(!OSC.STATUS & OSC_RC32MRDY_bm);	
 23c:	81 81       	ldd	r24, Z+1	; 0x01
	CCP = CCP_IOREG_gc; //Security Signature to modify clock register	
 23e:	88 ed       	ldi	r24, 0xD8	; 216
 240:	84 bf       	out	0x34, r24	; 52
	CLK.CTRL = 0x01; //clock at 32MHz selected
 242:	81 e0       	ldi	r24, 0x01	; 1
 244:	80 93 40 00 	sts	0x0040, r24
}
 248:	08 95       	ret

I'm not an asm expert, but it seems like the 4 cycles are respected here.

What i've thought also : could the problem come from the change of clock? I mean, i'm using the debugger through jtag which i guess works at a specific clock with the atxmega. When i change the clock, maybe the link is broken between the debugger and the atxmega because of the higher speed?

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

Ok i found the solution myself, i post it in case it might help someone else stuck with the same problem:

The code i wrote was good, but i thought the debugger was stuck because of the compilation optimisation. After my clock initialization function, there was nothing much in my code but a while(1) and a i++ inside the while loop. The compilation optimized it, and since the while and i++ were useless, it deleted it. Hence, in the debugger, there was no more step to go to, and it got stuck on the last line of the clock init function.

I hope this explanation is clear...

Don't underestimate your compilator... mine is smarter than me !

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

I have a similar issue to the first poster. I'm trying to view the external clock and see something else but 2 MHz. Here is my code to try to change the clock:

   CLK.CTRL   = 0x03;      // sets external clock out
   PORTCFG.CLKEVOUT = 0x03;
   OSC_XOSCCTRL = 0xCB;    // 12 to 16 MHz; external clk

   OSC.CTRL=OSC_XOSCEN_bm; // gets 0x08 
   CCP = CCP_IOREG_gc;     // secured access 

What am i missing?

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

I figured it out. Had the wrong order:

  PORTCFG.CLKEVOUT = 0x03;

   OSC_XOSCCTRL = 0xC0;    // 12 to 16 MHz; external clk
   OSC.CTRL = 0x08;        // gets 0x08 
   PORTC.DIRSET = 0xFF;
   do {PORTC.OUT = ~(OSC.STATUS); _delay_ms(200); PORTC.OUT = 0xFF; _delay_ms(200);} while ((OSC.STATUS & 0x08) == 0x00);   //wait for stability 
   CCP = 0xD8,             // IO Register Protection
   CLK.CTRL   = 0x03;      // sets external clock out 
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi again!
i got a strange problem with the 32MHz clock. I got it to work, but when i download my latest programm in the xmega in debug mode, it will go with a 2mhz clock. If i reset it and try a step by step, i see that it goes in the ini_32mhz function, and then the clock is correctly set at 32MHz. Does anyone have an explanation?

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

If something works when you step it but not when you run it that suggests a timing problem. Perhaps there's some condition you are not waiting for it to complete?

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

you're probably right. Here's my code (posted earlier)

OSC.CTRL = OSC_RC32MEN_bm; //enable 32MHz oscillator
while(!(OSC.STATUS & OSC_RC32MRDY_bm));   //wait for stability
CCP = CCP_IOREG_gc; //secured access
CLK.CTRL = 0x01; //choose this osc source as clk 

i thought the "4 cycles" security was the only condition. Is there another timing to respect for it to work?
Thanks!

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

Well my money would be on something wrong in that while() statement. I don't know Xmega - is it the right register or the right bit mask that's being used there?

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

wow, sometimes i wish i could beat my stupidity to death...
anyway, this was just a syntax error from me, i had removed the bracket of

while(!(OSC.STATUS & OSC_RC32MRDY_bm));

which made

while(!OSC.STATUS & OSC_RC32MRDY_bm);

so the while loop was wrong, and i didn't see it in the step by step mode, as you pointed out!
Thank you so much for opening my eyes on this error!

This forum is awesome and full of awesome people!

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

Hello
you must enable new and old clock source.
it means that if you are using 2Mhz you must write

//ENABLE 32MHZ and 2MHz
OSC.CTRL=3;

nduhamel wrote:
Hi, i get the same problem here, and i can't solve it.
I'm trying to enable the 32Mhz internal oscillator.

OSC.CTRL = OSC_RC32MEN_bm; //enable 32MHz oscillator
while(!(OSC.STATUS & OSC_RC32MRDY_bm));	//wait for stability
CCP = CCP_IOREG_gc; //secured access
CLK.CTRL = 0x01; //choose this osc source as clk

When i use the debugger, i can see that it gets stuck on the line : "CLK.CTRL = 0x01;"

Can someone help me please?

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

nduhamel wrote:
you're probably right. Here's my code (posted earlier)

OSC.CTRL = OSC_RC32MEN_bm; //enable 32MHz oscillator
while(!(OSC.STATUS & OSC_RC32MRDY_bm));   //wait for stability
CCP = CCP_IOREG_gc; //secured access
CLK.CTRL = 0x01; //choose this osc source as clk 

i thought the "4 cycles" security was the only condition. Is there another timing to respect for it to work?
Thanks!

Reading from avr1003 it doesn't mention anything but that:

The procedure for changing system clock and prescalers is as follows:
1. Load the Protect IO Register signature (byte value 0xD8) into the Configuration Change Protection register (CCP). This will automatically disable all interrupts for
the next four CPU instruction cycles.
2. Set the desired configuration for the prescaler or the system clock.
Note that writing the signature to the CCP register only leaves time for reconfiguring either the prescaler or the system clock. Repeat the CCP write if both needs reconfiguration. Study the example software for details.

I'm also having troubles and, whether I'm not asm expert, this code here seems to be correctly within the 4 clock cycles:

        /*
         * Set Regirester Protection signature
         */
   CCP=CCP_IOREG_gc; //0xD8;
     dde:       84 bf           out     0x34, r24       ; 52
        /*
         * Selecting Clock source;
         * Equivalent to
         * CCPWrite(&CLK.CTRL, CLK_SCLKSEL1_bm);
         */
   CLK.CTRL = CLK_SCLKSEL0_bm;
     de0:       81 e0           ldi     r24, 0x01       ; 1
     de2:       80 93 40 00     sts     0x0040, r24

Nevertheless I don't see the clock switching.
By the way, is there a reason for using CLK_SCLKSEL1_bm instead of CLK_SCLKSEL_RC32M_gc (or viceversa) ?

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

clawson wrote:
Well my money would be on something wrong in that while() statement. I don't know Xmega - is it the right register or the right bit mask that's being used there?

The while is required for the OSC to stabilize.
I'll post my 2 cents:

/*
		* From avr1003 (doc8072.pdf)
		* There are five internal clock sources (including the internal PLL),
		* ranging from an ultra low-power 32 kHz RC oscillator to a 32 MHz 
		* factory-calibrated ring oscillator with auto-calibration features.
		* All but one can be used for the main system clock.
		*/
		OSC.CTRL |=OSC_RC32MEN_bm;
		/*
		* Wait for OSC to stabilize
		*/
		while(   !( (OSC.STATUS) & OSC_RC32MRDY_bm)   );
		/*
		* Set Regirester Protection signature
		*/
		CCP=CCP_IOREG_gc; //0xD8;
		/* 
		* Possible prescaler config: 
		* 0x00 = NO prescaler
		* CLK_PSADIVx_bm | CLK_PSBCDIVy_bm;
		* x = A prescaler config: 0, 1, 2, 3, 4;
		* y = B & C prescaler config: 0, 1;
		* 
		* Now Disabling prescaler
		*/
		CLK.PSCTRL = 0x00;
		/*
		* Previous instruction takes 3 clk cycles with -Os option
		* we need another clk cycle before we can reuse it.
		*/
		nop();
		/*
		* Set Regirester Protection signature
		*/
		CCP=CCP_IOREG_gc; //0xD8;
		/*
		* Selecting Clock source
		* Equivalent to CCPWrite(&CLK.CTRL, CLK_SCLKSEL0_bm);
		*/
		CLK.CTRL = CLK_SCLKSEL0_bm;

This code works for me with the "-Os" compile flag.
In my case I had troubles with the fact that the prescaler config took 3 clock cycles only. Therefore I was trying to reload the protection signature on the 4th clock cycle which is probably not an option. Therefore I could not switch clock source.
Placing a nop() in beteen the two instructions did solve the issue.
I figured it out by looking at the assembly generated instructions with:

avr-objdump  -DsxS app.elf > app.dis

which showed:

                CLK.PSCTRL = 0x00;
     e88:       e0 e4           ldi     r30, 0x40       ; 64
     e8a:       f0 e0           ldi     r31, 0x00       ; 0
     e8c:       11 82           std     Z+1, r1 ; 0x01

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

I'm Portuguese. :)

Esta é uma possivél solução para activar o oscilador de 32MHz do XMEGA.
(This is a possible solution to enable the 32MHz oscillator for XMEGA.)

//Inicializar o oscilador de 32MHz
OSC.CTRL |= OSC_RC32MEN_bm;

//Verificar se o oscilador está preparado
do {} while ((OSC.STATUS & OSC_RC32MRDY_bm)==0);
//ou
//while(!(OSC.STATUS & OSC_RC32MRDY_bm));

//Escrever  Security Signature, para poder modificar o clock 
CCP = CCP_IOREG_gc;				 

//Define o oscilador de 32MHz como fonte para "System Clock"
CLK.CTRL = CLK_SCLKSEL_RC32M_gc;

Esta solução só funcionou com o nível de optimização abaixo indicado!!! :o
(This solution will only work with the level of optimization indicated below!!!)

No "AVR Studio 5.0" configurar "Optimization level" --> "Optimize for size (-Os)"

Agradeço pela ajuda que ja aqui existia.
(Thanks for the help that already existed here.)

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

Remember to disable interrupts too, otherwise one might trigger within the 4 cycle time-limit.

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

mojo-chan wrote:
Remember to disable interrupts too, otherwise one might trigger within the 4 cycle time-limit.

This shouldn't be necessary. According to the AU main manual section 3.12 (CPU->CCP): "Once the correct signature is written by the CPU, interrupts will be ignored for the duration of the configuration change enable period." This should apply to all xmega variants as it is a core feature.

Given the way the text is organized, it isn't totally clear that the disabling of interrupts applies to both kinds of CCP signatures (it's placed under the section for enabling SPM/LPM), but it makes sense for it to apply to both.

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

The 3 of you are responding to an almost 2 year old thread . :(

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

This is what i use without any problems.

OSC.CTRL|=OSC_RC32MEN_bm;
while((OSC.STATUS & OSC_RC32MRDY_bm)==0);
n=(CLK.CTRL & (~CLK_SCLKSEL_gm)) | CLK_SCLKSEL_RC32M_gc;
CPU.CCP=CCP_IOREG_gc;
CLK.CTRL=n;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My first time using an xmega,

none of the macro works to set those protected registers, I tried -O1, and -O2 and nothing. After struggle, I decided to actualy write this part in assembly, and wola`, worked. I want to share mine, hope it helps somebody else having this problem.

void Initialize_CPUclocks(void)
{
	// SELECT the external crystal, range 12 to 16MHz, start up time 16Kclk
	// OSC_XOSCCTRL = 0b11011011;
	asm("LDI R31,0x00"      ); // R30 & R31 are the 16bits pointer register Z, since I am loading a 8bits address load R31 = null
	asm("LDI R18,0b11011011"); // load R18 whit the data to write to OSC_XOSCCTRL reg (0x0052)
	asm("LDI R30,0x52"      ); // load R30 with the pointer to OSC_XOSCCTRL reg (0x0052)
	asm("STD Z+0,R18"       ); // store R18 data to the OSC_XOSCCTRL reg (0x0052)
	
	// enable the XOSCEN
	OSC_CTRL     = 0b00001001;
	while ((OSC_STATUS & 0b00001000)!= 0b00001000) { /*wait until XOSCRDY is true*/; }
	
	// system clock prescaler A to 6, and 1_1 on prescaler B, and C
	// CCP = 0xD8;
	asm("LDI R31,0x00" ); // R30 & R31 are the 16bits pointer register Z, since I am loading a 8bits address load R31 = null
	asm("LDI R18,0xD8" ); // load R18 with the data to write to the register address 0x0034 (CCP reg.)
	asm("LDI R30,0x34" ); // load the register address 0x0034 (CCP)
	asm("STD Z+0,R18"  ); // store R18 data to the CCP register
	// CLK_PSCTRL = 0b00001100;
	asm("LDI R18,0b00001100"); // load R18 whit the data to write to CLK_PSCTRL reg (0x0041)
	asm("LDI R30,0x41"      ); // load R30 with the pointer to CLK_PSCTRL reg (0x0041)
	asm("STD Z+0,R18"       ); // store R18 data to the CLK_PSCTRL reg (0x0041)

	// select the external clock as the PLL clock source, and set the start up time to 16Kclk
	//CCP          = 0x9D;
	OSC_PLLCTRL  = 0b11000110;
	
	// now enable the PLL
	//CCP          = 0x9D;
	OSC_CTRL     = 0b00011001;
	while ((OSC_STATUS & 0b00010000)!= 0b00010000) { /*wait until PLL is ready*/; }
	
	// now switch cpu clock source from the internal 2MHz osc, to the PLL
	// CCP = 0xD8;
	asm("LDI R31,0x00" ); // R30 & R31 are the 16bits pointer register Z, since I am loading a 8bits address load R31 = null
	asm("LDI R18,0xD8" ); // load R18 with the data to write to the register address 0x0034 (CCP reg.)
	asm("LDI R30,0x34" ); // load the register address 0x0034 (CCP)
	asm("STD Z+0,R18"  ); // store R18 data to the CCP register
	// CLK_CTRL = 0b00000100;
	asm("LDI R18,0b00000100"); // load R18 whit the data to write to CLK_CTRL reg (0x0040)
	asm("LDI R30,0x40"      ); // load R30 with the pointer to CLK_CTRL reg (0x0040)
	asm("STD Z+0,R18"       ); // store R18 data to the CLK_CTRL reg (0x0040)
	
	// Disable the internal 2MHz oscillator, since not longer needed
	OSC_CTRL = 0b00011000;
}

 

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

Hello, 

 

Does this work?