curiosity nano default clock rate?

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

Hi All,

 

I am working with a curiosity nano (with atmega4809).  LED blinking w/ delays seems to indicate that the clock rate is not 16 MHz or 20 MHz.

The nano literature indicates that the 4809 is being operated at 3.3 V.  

The 4809-48 data sheet says the CPU clock max frequency can be 10 MHz at room temperature.

The 0-series datasheet indicates MCLKCTRLB resets the clock to divide by 6.

The best I can guess is that if the osc rate is 16 MHz, the CPU clock starts at 2.666 MHz, of if osc at 20 MHz the CPU clock starts at 3.333 MHz.

 

Does anyone know what this is? 

 

My next step would be to go off and write code to toggle a pin and hook up a scope.

 

Thanks,

Matt

Last Edited: Mon. Sep 9, 2019 - 12:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After power-on reset, the prescaler starts at DIV6 to ensure operation over any voltage range.
It must be set to the desired clock by your program.

I use the following code:

    // Clock setting 10MHz(20/2)
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, !CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSC20M_gc);

 

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

Thanks.  I don't know if the oscillator is 16 or 20 MHz.   This is apparently a fuse setting which I can't read right now (on my linux box).

 

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

So the second line of my code selects 20MHz.
This does not matter what the fuse is set to.

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

As I read it, CLKCTRLA does not determine whether the internal osc is running at 16 MHz or 20 MHz

 

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

Oh, sorry. Fuse setting is required.
Below is an example of my fuse setting code. OSCCFG specifies 20MHz.

 

// FUSE Settings
FUSES = {
	.WDTCFG		= FUSE_WDT_WINDOW_OFF_gc | FUSE_WDT_PERIOD_OFF_gc,
	.BODCFG		= FUSE_BOD_LVL_2V60_gc | FUSE_BOD_SAMPFREQ_1KHZ_gc | FUSE_BOD_ACTIVE_ENABLED_gc | FUSE_BOD_SLEEP_SAMPLED_gc,
	.OSCCFG		= FUSE_OSC_OSCLOCK_OFF_gc | FUSE_OSC_FREQSEL_20MHZ_gc,
	.SYSCFG1	= FUSE_SYS1_SUT_0MS_gc,
	.APPEND		= 0,
	.BOOTEND	= 0,
	.SYSCFG0	= FUSE_SYS0_CRCSRC_NOCRC_gc | FUSE_SYS0_RSTPINCFG_GPIO_gc | FUSE_SYS0_EESAVE_OFF_gc,
	.SYSCFG0	= FUSE_SYS0_RESERVED_bm | FUSE_SYS0_CRCBOOT_OFF_gc | FUSE_SYS0_CRCAPP_OFF_gc | FUSE_SYS0_TOUTDIS_OFF_gc | FUSE_SYS0_RSTPINCFG_UPDI_gc | FUSE_SYS0_EESAVE_OFF_gc,
};

 

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

So I ended up writing a small program to toggle the LED pin (PF5) and put a scope on it to find  1.627 kHz.

1.627 kHz * 2 * 1024 * 6 * 1MHz/1000kHz = 19.993 MHz

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

ISR(TCA0_CMP0_vect) {
  PORTF.DIRTGL = PIN5_bm;
  TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP0_bm;
}

int main(void) {
  PORTF.DIRSET = PIN5_bm;		/* set LED/PF5 as output */
  PORTF.DIRSET = PIN2_bm;		/* set PF2 as output */

  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc;

  TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_FRQ_gc;
  TCA0.SINGLE.CMP0H = 50/256;
  TCA0.SINGLE.CMP0L = 50%256;

  TCA0.SINGLE.INTCTRL = TCA_SINGLE_CMP0EN_bm;

  TCA0.SINGLE.CTRLA |= 1;
  sei();

  while (1) { }
}

EDIT: Need to revisit math.   I was changing numbers.

Last Edited: Mon. Sep 9, 2019 - 12:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kabasan wrote:
It must be set to the desired clock by your program.

 

Question, In Studio7 under Tools>Device Programming I can go into the fuses and set up the oscillator and SUT as well as other parameters.  What is does not provide is any ability to enable/disable the divide by 6 which I think is not configurable.  Would it not be more accurate to say that the clock can be changed in ones program?

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Agree.   But programmer needs to be aware of  the AVR supply voltage for safety.

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

Of course, I was asking for clarity of kabasan's comment that the clock frequency must be done in a program, when it's also possible to set the frequency in the part programming stage.

 

Cheers,

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

As an example, here is a 1Hz LED blink code.
If you use an elf file, fuse settings are included, so there is no need to set the fuses manually.
I hope it's a useful reference.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#define F_CPU   10000000UL

volatile uint16_t tick_volatile;    // 1ms tick counter

// FUSE Settings
FUSES = {
    .WDTCFG     = FUSE_WDTCFG_DEFAULT,
    .BODCFG     = FUSE_BODCFG_DEFAULT,
    .OSCCFG     = FUSE_OSCCFG_DEFAULT,  // FREQSEL Default = 20MHz
    .SYSCFG0    = FUSE_SYSCFG0_DEFAULT,
    .SYSCFG1    = FUSE_SYSCFG1_DEFAULT,
    .APPEND     = FUSE_APPEND_DEFAULT,
    .BOOTEND    = FUSE_BOOTEND_DEFAULT,
};

// 1ms tick
void tick_init(void) {
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        TCB0_CCMP = F_CPU / 1000;
    }
    TCB0.CTRLB  = TCB_CNTMODE_INT_gc;
    TCB0.CTRLA  = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm;
    TCB0.INTCTRL = TCB_CAPT_bm;
}

ISR(TCB0_INT_vect) {
    tick_volatile++;        // Increase every 1ms.
    TCB0.INTFLAGS = TCB_CAPT_bm;
}

int main(void) {
    uint16_t tick_start = 0;
    uint16_t tick_now;

    // Clock setting 10MHz(20/2)
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, !CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSC20M_gc);

    PORTF.DIRSET = PIN5_bm;     /* set LED/PF5 as output */

    tick_start = 0;
    tick_volatile = 0;
    tick_init();
    sei();

    while (1) {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
            tick_now = tick_volatile;
        }
        if (tick_now - tick_start >= 500) {
            // LED Toggle every 500ms(1Hz blink)
            tick_start += 500;
            PORTF.OUTTGL = PIN5_bm;
        }
    }
}

 

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

On the Mega0 (and Xtiny) chips, the chip ALWAYS runs on the internal clock divided by 6.  Even if you have an external oscillator that you want to use for the normal clock.
You then have to manipulate the clock controller to select the final target speed.  You shouldn't think of this as just turning off the divider (although that might be what you do.)  You're configuring the clock for your application.  The 4809 doesn't have a high speed crystal oscillator, and the Curiosity 4809 Nano doesn't have an external clock connected, so you don't really have too many choices, but ... you might have!

 

This prevents "bricking" the chip by configuring fuses for external clock (or crystal) when there isn't one present, which has bitten the users of older AVRs relatively frequently.

This is, incidentally, common procedure on modern 32bit micros.  They all start up using some modest internal oscillator, and need significant amounts of configuration to start up crystal oscillators, configure DPLLs, and so on, before they'll  run at the high clock rates that most people expect.

 

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

I didn't know about the fuses.  I will make habit of having chip start-up section.   Off to clean this up ...

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

Working to add fuses and scale spec in startup.  I believe the correct setting for 20 MHz is FREQSEL = 2, but there is an odd detail in the 48 pit sheet intidating FREQSEL = 1.   Am I right?

 

From AVR 0-series data sheet:

 

From 4809 - 48 pin data sheet:

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

Here is link for related thread: https://www.avrfreaks.net/forum/easiest-blinky-ever-making-mega4809-nano-blink-using-codevision?skey=4809%20nano

 

I'm using the copy main.hex to /media/mattrw/CURIOSITY to get the program loaded onto the board and running.

 

I don't think it's possible to change FUSE settings this say.  (See the above thread.)

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

I think you can change fuses when copying a hexfile onto the curiosity as long as they are in your hexfile.  Look at location 0x820000 and you might find them?

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

mraardvark wrote:
I think you can change fuses when copying a hexfile onto the curiosity as long as they are in your hexfile.  Look at location 0x820000 and you might find them?
Surely that depends on which compiler and programming tool you are using? Most programming software faced with a .hex file that has a record at 0x820000 will simply think it is an ENORMOUS code image.

 

Remember that in #15 the link given is about using 4809 with Codevision. That does not, as far as I know, handle Harvard with 0x8Nxxxx offsets.

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

The "data" at 0x800000 gets mapped to the end of text, I believe.   But not sure how the board is supposed to know where it is.  Here is the ldscript for mega4809:

/* Default linker script, for normal executables */
/* Copyright (C) 2014-2019 Free Software Foundation, Inc.
   Copying and distribution of this script, with or without modification,
   are permitted in any medium without royalty provided the copyright
   notice and this notice are preserved.  */
OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:103)
__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
__RODATA_PM_OFFSET__ = DEFINED(__RODATA_PM_OFFSET__) ? __RODATA_PM_OFFSET__ : 0x8000;
MEMORY
{
  text   (rx)   : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
  data   (rw!x) : ORIGIN = 0x802000, LENGTH = __DATA_REGION_LENGTH__
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
}
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  .hash          : { *(.hash)		}
  .dynsym        : { *(.dynsym)		}
  .dynstr        : { *(.dynstr)		}
  .gnu.version   : { *(.gnu.version)	}
  .gnu.version_d   : { *(.gnu.version_d)	}
  .gnu.version_r   : { *(.gnu.version_r)	}
  .rel.init      : { *(.rel.init)		}
  .rela.init     : { *(.rela.init)	}
  .rel.text      :
    {
      *(.rel.text)
      *(.rel.text.*)
      *(.rel.gnu.linkonce.t*)
    }
  .rela.text     :
    {
      *(.rela.text)
      *(.rela.text.*)
      *(.rela.gnu.linkonce.t*)
    }
  .rel.fini      : { *(.rel.fini)		}
  .rela.fini     : { *(.rela.fini)	}
  .rel.rodata    :
    {
      *(.rel.rodata)
      *(.rel.rodata.*)
      *(.rel.gnu.linkonce.r*)
    }
  .rela.rodata   :
    {
      *(.rela.rodata)
      *(.rela.rodata.*)
      *(.rela.gnu.linkonce.r*)
    }
  .rel.data      :
    {
      *(.rel.data)
      *(.rel.data.*)
      *(.rel.gnu.linkonce.d*)
    }
  .rela.data     :
    {
      *(.rela.data)
      *(.rela.data.*)
      *(.rela.gnu.linkonce.d*)
    }
  .rel.ctors     : { *(.rel.ctors)	}
  .rela.ctors    : { *(.rela.ctors)	}
  .rel.dtors     : { *(.rel.dtors)	}
  .rela.dtors    : { *(.rela.dtors)	}
  .rel.got       : { *(.rel.got)		}
  .rela.got      : { *(.rela.got)		}
  .rel.bss       : { *(.rel.bss)		}
  .rela.bss      : { *(.rela.bss)		}
  .rel.plt       : { *(.rel.plt)		}
  .rela.plt      : { *(.rela.plt)		}
  /* Internal text space or external memory.  */
  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    /* PR 13812: Placing the trampolines here gives a better chance
       that they will be in range of the code that uses them.  */
    . = ALIGN(2);
    __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
    *(.trampolines*)
    __trampolines_end = . ;
    /* avr-libc expects these data to reside in lower 64K. */
    *libprintf_flt.a:*(.progmem.data)
    *libc.a:*(.progmem.data)
    *(.progmem.*)
    . = ALIGN(2);
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
    *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we do not bother about whether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
    *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))
    *(.fini8)
    KEEP (*(.fini8))
    *(.fini7)
    KEEP (*(.fini7))
    *(.fini6)  /* C++ destructors.  */
    KEEP (*(.fini6))
    *(.fini5)
    KEEP (*(.fini5))
    *(.fini4)
    KEEP (*(.fini4))
    *(.fini3)
    KEEP (*(.fini3))
    *(.fini2)
    KEEP (*(.fini2))
    *(.fini1)
    KEEP (*(.fini1))
    *(.fini0)  /* Infinite loop after program termination.  */
    KEEP (*(.fini0))
    /* For code that needs not to reside in the lower progmem.  */
    *(.hightext)
    *(.hightext*)
    *(.progmemx.*)
    . = ALIGN(2);
    /* For tablejump instruction arrays.  We do not relax
       JMP / CALL instructions within these sections.  */
    *(.jumptables)
    *(.jumptables*)
    _etext = . ;
  }  > text
  .rodata  ADDR(.text) + SIZEOF (.text) + __RODATA_PM_OFFSET__    :
  {
    *(.rodata)
     *(.rodata*)
    *(.gnu.linkonce.r*)
  } AT> text
  .data          :
  {
     PROVIDE (__data_start = .) ;
    *(.data)
     *(.data*)
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
     _edata = . ;
     PROVIDE (__data_end = .) ;
  }  > data AT> text
  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
  {
     PROVIDE (__bss_start = .) ;
    *(.bss)
     *(.bss*)
     *(COMMON)
     PROVIDE (__bss_end = .) ;
  }  > data
   __data_load_start = LOADADDR(.data);
   __data_load_end = __data_load_start + SIZEOF(.data);
  /* Global data not cleared after reset.  */
  .noinit  ADDR(.bss) + SIZEOF (.bss)  :  AT (ADDR (.noinit))
  {
     PROVIDE (__noinit_start = .) ;
    *(.noinit*)
     PROVIDE (__noinit_end = .) ;
     _end = . ;
     PROVIDE (__heap_start = .) ;
  }  > data
  .eeprom  :
  {
    /* See .data above...  */
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eeprom
  .fuse  :
  {
    KEEP(*(.fuse))
    KEEP(*(.lfuse))
    KEEP(*(.hfuse))
    KEEP(*(.efuse))
  }  > fuse
  .lock  :
  {
    KEEP(*(.lock*))
  }  > lock
  .signature  :
  {
    KEEP(*(.signature*))
  }  > signature
  /* Stabs debugging sections.  */
  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
  .note.gnu.build-id   : { *(.note.gnu.build-id) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }
  /* DWARF Extension.  */
  .debug_macro    0 : { *(.debug_macro) }
  .debug_addr     0 : { *(.debug_addr) }
}

 

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

With this in main:

FUSES = {  
  .OSCCFG = 0xf,
};

 

I see this in the .elf file (using avr-objdump -D):

00820000 <__fuse>:
  820000:       00 00           nop
  820002:       0f 00           .word   0x000f  ; ????
  820004:       00 00           nop
  820006:       00 00           nop