我正在尝试将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()函数。
答案 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()中完成的相关步骤是:
相关代码行(假设您的电路板安装了外部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 */
}