mega3208 - Prescaler always on?

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

I'm using a mega3208 and trying to understand the main clock, and prescaler activity.

I would like the main clock to run at 20Mhz, so my fuses are thus:

 

Fuses, fused, and unfused. Just fuses really. Why are you reading this?

 

So, FREQSEL is 20Mhz and OSCLOCK is clear.

Then my startup code looks like this:

CLKCTRL.MCLKLOCK = 0; // Ensure clock-lock is clear.
CLKCTRL.MCLKCTRLB = 0; // Switch off the pre-scaler.
uart_init(0, 115200UL);

Then uart_init(...) like this: (F_PER is: #define F_PER 20000000)

void uart_init(uint8_t uart, uint32_t baud)
{
	if(uart >= UART_MAX_UARTS) // sanity check.
	{
		return;
	}

	// First set up the ring buffers for this UART
	ring_buffer_init(&uart_rx_rb[uart], &uart_rx_buffer[uart][0], UART_RX_BUFF_SIZE);
	ring_buffer_init(&uart_tx_rb[uart], &uart_tx_buffer[uart][0], UART_TX_BUFF_SIZE);

	// Now configure the registers for this uart
	if(uart==0)
	{
		PORTA_DIRSET = (1<<0);	// TX on PA0
		PORTA_DIRCLR = (1<<1);	// RX on PA1

		PORTA_OUTSET = (1<<0); // set TX high.

		// Baud
		USART0_BAUD = ((64*F_PER) / (16*baud));

		// RX Interrupt enable
		USART0_CTRLA = USART_RXCIE_bm;

		// Transmitter / receiver enable
		USART0_CTRLB = USART_RXEN_bm | USART_TXEN_bm;
	}
}

 

And then I send 0x55 out of uart, and check it with my oscilloscope, thus:

No pron here.

 

Which is clearly 19200 bps, not 115200 bps.

But - that is exactly 1/6th of the desired rate, which is what the default clock prescaler is. But that should be off, as per my startup code.

 

No matter what I do with the PEN bit of MCLKCTRLB, the baudrate remains the same. It does not change either way.

 

What have I missed?

 

SpiderKenny
@spiderelectron
www.spider-e.com

 

Last Edited: Fri. Jul 20, 2018 - 09:52 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1/6th seems an "odd" division. Scalers usually work in binary multiples. I could understand 1/4 or 1/8 perhaps but not 1/6th ??

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

 

Ah yes, but the 3208 is a remarkable beast with fractional prescalers in various places. See 0x08 above.

SpiderKenny
@spiderelectron
www.spider-e.com

 

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

 

And the default prescaler is: 0x08 (which is 1/6th).

SpiderKenny
@spiderelectron
www.spider-e.com

 

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

I notice from reading the datasheet:

 

Yet I don't see CCB in your code ?

 

EDIT oh and what's more:

So the curious /6 is the power on default. So you simply aren't writing to this register!

Last Edited: Fri. Jul 20, 2018 - 10:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Am I not? What does this do then:

(As per my OP) :

CLKCTRL.MCLKLOCK = 0; // Ensure clock-lock is clear.
CLKCTRL.MCLKCTRLB = 0; // Switch off the pre-scaler.
uart_init(0, 115200UL);

 

SpiderKenny
@spiderelectron
www.spider-e.com

 

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

You do know what CCP is don't you? You can't just do:

CLKCTRL.MCLKCTRLB = 0; // Switch off the pre-scaler.

The write will be ignored because you have not enabled configuration change protection.

 

What's more CCP requires that you write the magic key value to the CCP register THEN you make the write to the register that is protected WITHIN FOUR MACHINE CYCLES. This may or may not be achievable in plain. I think most libraries provide some kind of hand crafted macro writing in inline Asm that does the CCP write then the SFR write in a guaranteed less than 4 cycles.

 

Datasheet words about CCP:

 

also...

Last Edited: Fri. Jul 20, 2018 - 10:18 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah right - sorry _ i get it now.]

I need to write to CCP first... d'oh!

 

I do know about CCP, I just missed the subtle clue int he doc.

 

Thanks!

SpiderKenny
@spiderelectron
www.spider-e.com

 

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

Not sure if you are using GCC but I just found something I never knew existed (I don't remember seeing this documented in the user manual):

D:\atmel_avr\avr8-gnu-toolchain\avr\include\avr>type xmega.h
/* Copyright (c) 2012 Joerg Wunsch
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. */

/* $Id$ */

/*
 * This file is included by <avr/io.h> whenever compiling for an Xmega
 * device.  It abstracts certain features common to the Xmega device
 * families.
 */

#ifndef _AVR_XMEGA_H
#define _AVR_XMEGA_H

#ifdef __DOXYGEN__
/**
 \def _PROTECTED_WRITE
 \ingroup avr_io

 Write value \c value to IO register \c reg that is protected through
 the Xmega configuration change protection (CCP) mechanism.  This
 implements the timed sequence that is required for CCP.

 Example to modify the CPU clock:
 \code
 #include <avr/io.h>

 _PROTECTED_WRITE(CLK_PSCTRL, CLK_PSADIV0_bm);
 _PROTECTED_WRITE(CLK_CTRL, CLK_SCLKSEL0_bm);
 \endcode
 */
#define _PROTECTED_WRITE(reg, value)
#else  /* !__DOXYGEN__ */
#define _PROTECTED_WRITE(reg, value)                            \
  __asm__ __volatile__("out %[ccp], %[ccp_ioreg]" "\n\t"        \
                       "sts %[ioreg], %[val]"                   \
                       :                                        \
                       : [ccp] "I" (_SFR_IO_ADDR(CCP)),         \
                         [ccp_ioreg] "d" ((uint8_t)CCP_IOREG_gc),       \
                         [ioreg] "n" (_SFR_MEM_ADDR(reg)),      \
                         [val] "r" ((uint8_t)value))
#endif /* DOXYGEN */

#endif /* _AVR_XMEGA_H */

So PROTECTED_WRITE() would seem to be the "official" way to handle this.

 

EDIT: Oh I see, xmega.h is included when you use <avr/io.h> if you are building for Xmega (and I assume that also mean XTiny):

#if __AVR_ARCH__ >= 100
#  include <avr/xmega.h>
#endif

but despite it having Doxygen I'm still not seeing where this is mentioned in the AVR-LibC manual??

Last Edited: Fri. Jul 20, 2018 - 10:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In Studio 7 the following code:

CPU_CCP = CCP_IOREG_gc;
CLKCTRL.MCLKCTRLB = 0;

Compiles as:

  d0:	88 ed       	ldi	r24, 0xD8	; 216
  d2:	84 bf       	out	0x34, r24	; 52
  d4:	10 92 61 00 	sts	0x0061, r1	; 0x800061 

So that fits into the 4-cycle limit.

 

**EDIT** But I'll use PROTECTED_WRITE anyway.

 

Thanks again.

SpiderKenny
@spiderelectron
www.spider-e.com

 

Last Edited: Fri. Jul 20, 2018 - 10:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think I am Xmega or Xtiny, it's one of the new 0-Series.

 

SpiderKenny
@spiderelectron
www.spider-e.com

 

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

Yeah, they are effectively Xmega's in sheep's clothing. So things Xmega apply a lot more to them than anything to do with traditional Tiny or Mega AVRs. In fact the CCP thing is a case in point - it was added when Xmega were born and is characteristic of Xmega family chips. Also the very fact that the C compiler sees these as

__AVR_ARCH__ >= 100

shows that it, too, sees them as effectively Xmega.

 

The only people unable to admit this seems to Microchip's marketing/naming department.

 

It is a source of some confusion as people with "mega" experience are going to come to these thinking they are just like all previous mega when they are really a radically different design. In the old days mega UARTs had register with names like UCSRA but now you have USART0_CTRLA etc.

 

No existing "mega" ever had anything like this either...

 

Last Edited: Fri. Jul 20, 2018 - 11:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what I have done for the M4809 to run @20MHz. (sorry for the bad language used.... cheeky)

; Select 20 MHz internal oscillator
	clr		temp
	ldi		temp1, CPU_CCP_IOREG_gc
	sts		CPU_CCP, temp1
	sts		CLKCTRL_MCLKCTRLA, temp

; This disables the divisor and allows chip to run at full spped
	clr		temp
	ldi		temp1, CPU_CCP_IOREG_gc
	sts		CPU_CCP, temp1
	sts		CLKCTRL_MCLKCTRLB, temp		; Clear CLKCTRL_PEN_bm

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

You guys have been very helpful once again.

I should have guessed it would be CCP, and once it was pointed out it was obvious!

Guess I couldn't see the woods for the trees.

 

BTW, I'm loving the 0-Series, they are a great fit for my products. Especially having 3 UARTS and pin-swapping. What a great little device.

SpiderKenny
@spiderelectron
www.spider-e.com