SAMD21时钟配置

时间:2017-02-03 13:41:15

标签: configuration arm clock atmel cortex-m

我正在尝试将SAMD21时钟配置为尽可能快。因此,我使用内部8 MHz振荡器为通用时钟发生器1(预分频器为8)供电,以生成通用时钟,为数字锁相环供电,从而为通用时钟发生器0(我的主时钟)供电。应该为CPU提供时钟,但微型运行速度非常慢,我在哪里犯了错误? 我遵循了本指南http://borkedlabs.com/2014/08/21/asf-samd21-dpll-for-internal-clock-from-internal-8mhz/,但它不起作用。这是我的代码:

void system_clock_init(void)
{
    SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET | SYSCTRL_INTFLAG_DFLLRDY;

    /* switch off all peripheral clocks to save power */
    //_switch_peripheral_gclk();

    /* configure and enable generic clock generator 1 (GENCTRL and GENDIV registers of GCLK module) */
    struct system_gclk_gen_config gclk_gen_config1;
    system_gclk_gen_get_config_defaults(&gclk_gen_config1);
    gclk_gen_config1.source_clock = SYSTEM_CLOCK_SOURCE_OSC8M;
    gclk_gen_config1.division_factor = 8;
    gclk_gen_config1.output_enable = false;
    system_gclk_gen_set_config(GCLK_GENERATOR_1,&gclk_gen_config1);
    system_gclk_gen_enable(GCLK_GENERATOR_1);

    /* configure and enable generic clock for DPLL (CLKCTRL of GCLK module) */
    struct system_gclk_chan_config gclk_chan_config;
    system_gclk_chan_get_config_defaults(&gclk_chan_config);
    gclk_chan_config.source_generator = GCLK_GENERATOR_1;
    system_gclk_chan_set_config(SYSCTRL_GCLK_ID_FDPLL,&gclk_chan_config);
    system_gclk_chan_enable(SYSCTRL_GCLK_ID_FDPLL);

    /* configure and enable clock source: DPLL (SYSCTRL registers) */
    struct system_clock_source_dpll_config dpll_config;
    system_clock_source_dpll_get_config_defaults(&dpll_config);
    dpll_config.reference_clock = SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK;
    dpll_config.reference_divider = 1;
    dpll_config.reference_frequency = 1000000;
    dpll_config.output_frequency = 30000000;
    system_clock_source_dpll_set_config(&dpll_config);
    system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DPLL);

    /* set NVM wait states */
    system_flash_set_waitstates(2);

    /* configure and enable generic clock 0 (GCLK_MAIN) */
    struct system_gclk_gen_config gclk_gen_config0;
    system_gclk_gen_get_config_defaults(&gclk_gen_config0);
    gclk_gen_config0.source_clock = SYSTEM_CLOCK_SOURCE_DPLL;
    gclk_gen_config0.division_factor = 1;
    system_gclk_gen_set_config(GCLK_GENERATOR_0,&gclk_gen_config0);
    system_gclk_gen_enable(GCLK_GENERATOR_0);
}

我更新了conf_clocks.h标头以反映更改(我不知道这些宏是否在其他地方被引用,以防万一)并且我更改了从system_init()调用的system_clock_init()函数。

2 个答案:

答案 0 :(得分:1)

我从来不喜欢使用Atmel的ASF因为你从来没有真正做过你想做的事。 我建议你更多地查看数据表,因为这样的成本减少了完成任务然后潜伏在ASF中的时间。 Atmel数据表甚至还有一个"初始化"这一章是对如何做的一步一步的解释。

启用OSC8基本上是5个代码行:

/* Various bits in the INTFLAG register can be set to one at startup.
This will ensure that these bits are cleared */
SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET | SYSCTRL_INTFLAG_DFLLRDY;

/* OSC8M Internal 8MHz Oscillator */
SYSCTRL->OSC8M.bit.PRESC = SYSTEM_OSC8M_DIV_1;
SYSCTRL->OSC8M.bit.ONDEMAND = CONF_CLOCK_OSC8M_ON_DEMAND;
SYSCTRL->OSC8M.bit.RUNSTDBY = CONF_CLOCK_OSC8M_RUN_IN_STANDBY;

/* Enable OSC8M */
SYSCTRL->OSC8M.reg |= SYSCTRL_OSC8M_ENABLE;

其余步骤仅用于使用已启用的OSC8M配置dpll寄存器,OSC8M也只是少数代码行。 (写入GCLK.GENDIV / GENCTRL和CLKCTRL寄存器以及写入SYSCTRL.DPLL寄存器。

答案 1 :(得分:1)

要配置SAMD21 CPU使其以其支持的最大频率(48 MHz)运行,我不使用ASF,而是使用取自Arduino SAMD内核的代码;您可以在https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/startup.c的SystemInit()函数中找到它的作用。引用该文件中的注释,在SystemInit()中完成的相关步骤是:

  • 启用XOSC32K时钟(板载外部32.768Hz振荡器),将用作DFLL48M参考
  • 将XOSC32K用作通用时钟生成器1
  • 将通用时钟发生器1用作通用时钟多路复用器0(DFLL48M参考)的源
  • 启用DFLL48M时钟
  • 将通用时钟发生器0切换到DFLL48M。 CPU将以48MHz运行

相关代码行(假设您的电路板安装了外部32.768 kHz晶振):

/* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val ;

/* Turn on the digital interface clock */
PM->APBAMASK.reg |= PM_APBAMASK_GCLK ;

/* Enable XOSC32K clock (External on-board 32.768Hz oscillator) */
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */
                       SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K ;
SYSCTRL->XOSC32K.bit.ENABLE = 1 ; /* separate call, as described in chapter 15.6.3 */
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 )
{
  /* Wait for oscillator stabilization */
}

/* Software reset the module to ensure it is re-initialized correctly */
GCLK->CTRL.reg = GCLK_CTRL_SWRST ;
while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) )
{
  /* Wait for reset to complete */
}

/* Put XOSC32K as source of Generic Clock Generator 1 */
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) ; // Generic Clock Generator 1
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
  /* Wait for synchronization */
}

/* Write Generic Clock Generator 1 configuration */
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC32K ) | // Generic Clock Generator 1
                    GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator
//                  GCLK_GENCTRL_OE | // Output clock to a pin for tests
                    GCLK_GENCTRL_GENEN ;
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
  /* Wait for synchronization */
}

/* Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) */
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0
                  GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source
                  GCLK_CLKCTRL_CLKEN ;
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
  /* Wait for synchronization */
}

/* Enable DFLL48M clock */  
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
{
  /* Wait for synchronization */
}
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value
                       SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value
                       SYSCTRL_DFLLMUL_MUL( (VARIANT_MCK + VARIANT_MAINOSC/2) / VARIANT_MAINOSC ) ; // External 32KHz is the reference
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
{
  /* Wait for synchronization */
}

/* Write full configuration to DFLL control register */
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */
                         SYSCTRL_DFLLCTRL_WAITLOCK |
                         SYSCTRL_DFLLCTRL_QLDIS ; /* Disable Quick lock */
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
{
  /* Wait for synchronization */
}

/* Enable the DFLL */
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ;
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 ||
        (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 )
{
  /* Wait for locks flags */
}
while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 )
{
  /* Wait for synchronization */
}

/* Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. */
GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ) ; // Generic Clock Generator 0
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
  /* Wait for synchronization */
}

/* Write Generic Clock Generator 0 configuration */
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0
                    GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz
//                  GCLK_GENCTRL_OE | // Output clock to a pin for tests
                    GCLK_GENCTRL_IDC | // Set 50/50 duty cycle
                    GCLK_GENCTRL_GENEN ;
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
{
  /* Wait for synchronization */
}