ATmega4809 - Switching to external crystal oscillator in code or FUSE-bits

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

Hi,
I am writing a program which will be uploaded to an atmega4809 microcontroller. The environment the device will be operating in could be of high temperature and I need to switch to an external crystal oscillator.
A 32.768 kHz Crystal Oscillator is already connected to the pins 34 and 35 (PF0, TOSC1 and PF1, TOSC2) and it is the one I want to use instead of the internal clock on the microcontroller.

 

Background:
I am using visual studio micro to create the Program.ino.hex file. Then I program the microcontroller from a Raspberry Pi4 8GB via UPDI with the pymcuprog library in python.
In visual micro the settings is set to:

  • Board: ATmega4809 (MegaCoreX-master_4809)
  • Option1: Clock Internal 20MHz

The datasheet for atmega4809: http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega4808-4809-Data-Sheet-DS40002173A.pdf

I have never done this before and my attempts after reading everything I can find on the internet (including the datasheet) have failed. At first I tried to switch to the external crystal oscillator during startup. The code I used is the following and I call it from startup():

 

void activateExternalClk() {
    // Enable the external clock on TOSC1/TOSC2
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL.XOSC32KCTRLA | 0x01);

    // I also tried to activate RUNSTDBY before switching to the crystal clock
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL.XOSC32KCTRLA | (1 << 1));

    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL.MCLKCTRLA | CLKCTRL_CLKSEL_XOSC32K_gc);

    // Here I have tried different registers to read to controll if 
    // the crystal clock is stable, but nothing I tried have worked. 
    // For example: 
    while (~(CLKCTRL.MCLKSTATUS & (1 << 6))) {
	;
    }

}

 

After several attempts I tried to set the FUSE-bits. I can only manage to set the fusebit-settings for the internal clock. I have tried to choose "Option1: External clock 20MHz" and connected 20MHz to the EXT_CLK pin ( and can't even switch to the external clock at the EXTCLK pin PA0.

 

Is it possible to switch to the crystal ocillator in the software or do I have a problem when I am writing the program in arduino code? When I read the datasheet as it should be possible, but I am unsure how.

If you know a way to do this, I would really appreciate your reply!

Thanks in advance.

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

10.5.4 Main Clock Status

Name: MCLKSTATUS

 

Bit 5 – OSC32KS OSCULP32K Status
The Status bit will only be available if the source is requested as the main clock or by another module. If the oscillator
RUNSTDBY bit is set but the oscillator is unused/not requested, this bit will be 0.

So you MIUST request the 32KHz clock for some purpose.

 

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

After several attempts I tried to set the FUSE-bits.

You only have 2 choices for fuse bits with regards to intial clock- 20MHz or 16MHz, either will have the clock prescaler set to div6. So at power up you will get either 2.66MHz or 3.33MHz, and to change to something else requires dealing with CLKCTRL at runtime.

 

 

A simple program that runs on a mega4809 board (correctly), and as shown there is not much to do-

 

//mega4809 curiosity nano
#include <avr/io.h>

static void ledToggle(){ PORTF.DIRSET = 1<<5; PORTF.OUTTGL = 1<<5; }

int main(){

    _PROTECTED_WRITE( CLKCTRL.XOSC32KCTRLA, 1 );    //ENABLE xosc32k
    _PROTECTED_WRITE( CLKCTRL.MCLKCTRLA, 2 );       //main clock source XOSC32K

 

    //if the switch is not made, SOSC will be set and remain set until the switch is made

    //and no further clock switching until this one completed (if ever),

    //in the meantime you still have your current clock

 

    //while( CLKCTRL.MCLKSTATUS & 1 ){}             //optional, wait for the switch
 

    _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, 0 );       //no clock prescale, PEN = 0

 

    while(1){
        __builtin_avr_delay_cycles( 32768/2 );      //2Hz toggle, 1Hz blink
        ledToggle();                                //it is blinking, 1Hz, so we have a 32khz clock
    }
}

 

 

 

The following is not a great idea, probably harmless in this case since the previous register value is most likely 0-

_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL.MCLKCTRLA | CLKCTRL_CLKSEL_XOSC32K_gc);

You need to clear out the previous CLKSEL bits before setting the new CLKSEL bits value. In this case, I doubt there is a need to preserve the CLKOUT bit as you most likely know what it needs to be, so just write the whole register value when you can.

 

 

This is your real problem-

   while (~(CLKCTRL.MCLKSTATUS & (1 << 6))) {
	;
    }

CLKCTRL.MCLKSTATUS & (1 << 6) is either 0x00 or 0x40. So ~0x00 is 0xFF and ~0x40 is 0xBF. Both cases are true so you wait forever. I would assume you wanted to use ! instead of ~

 

 

 

edit-

A long winded way to say 'replace ~ with !'.

Last Edited: Fri. Jun 24, 2022 - 08:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Thank you really much! This helped a lot, great explanations! 

 

I did succeed to change to the crystal oscillator. 

 

Thanks again.