Example #1
0
File: gclk.c Project: Gussy/sam0
/**
 * \brief Retrieves the clock frequency of a Generic Clock generator.
 *
 * Determines the clock frequency (in Hz) of a specified Generic Clock
 * generator, used as a source to a Generic Clock Channel module.
 *
 * \param[in] generator  Generic Clock Generator index
 *
 * \return The frequency of the generic clock generator, in Hz.
 */
uint32_t system_gclk_gen_get_hz(
		const uint8_t generator)
{
	while (system_gclk_is_syncing(generator)) {
		/* Wait for synchronization */
	};

	system_interrupt_enter_critical_section();

	/* Get the frequency of the source connected to the GCLK generator */
	uint32_t gen_input_hz = system_clock_source_get_hz(
			(enum system_clock_source)GCLK->GENCTRL[generator].bit.SRC);

	uint8_t divsel = GCLK->GENCTRL[generator].bit.DIVSEL;
	uint32_t divider = GCLK->GENCTRL[generator].bit.DIV;

	system_interrupt_leave_critical_section();

	/* Check if the generator is using fractional or binary division */
	if (!divsel && divider > 1) {
		gen_input_hz /= divider;
	} else if (divsel) {
		gen_input_hz >>= (divider+1);
	}

	return gen_input_hz;
}
Example #2
0
/**
 * \brief Enables a Generic Clock Generator that was previously configured.
 *
 * Starts the clock generation of a Generic Clock Generator that was previously
 * configured via a call to \ref system_gclk_gen_set_config().
 *
 * \param[in] generator  Generic Clock Generator index to enable
 */
void system_gclk_gen_enable(
		const uint8_t generator)
{
	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};

	system_interrupt_enter_critical_section();

	/* Select the requested generator */
	*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};

	/* Enable generator */
	GCLK->GENCTRL.reg |= GCLK_GENCTRL_GENEN;

	system_interrupt_leave_critical_section();
}
Example #3
0
/**
 * \brief Disables a Generic Clock Generator that was previously enabled.
 *
 * Stops the clock generation of a Generic Clock Generator that was previously
 * started via a call to \ref system_gclk_gen_enable().
 *
 * \param[in] generator  Generic Clock Generator index to disable
 */
void system_gclk_gen_disable(
		const uint8_t generator)
{
	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};

	system_interrupt_enter_critical_section();

	/* Select the requested generator */
	*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};

	/* Disable generator */
	GCLK->GENCTRL.reg &= ~GCLK_GENCTRL_GENEN;
	while (GCLK->GENCTRL.reg & GCLK_GENCTRL_GENEN) {
		/* Wait for clock to become disabled */
	}

	system_interrupt_leave_critical_section();
}
Example #4
0
File: gclk.c Project: Gussy/sam0
/**
 * \brief Enables a Generic Clock Generator that was previously configured.
 *
 * Starts the clock generation of a Generic Clock Generator that was previously
 * configured via a call to \ref system_gclk_gen_set_config().
 *
 * \param[in] generator  Generic Clock Generator index to enable
 */
void system_gclk_gen_enable(
		const uint8_t generator)
{
	while (system_gclk_is_syncing(generator)) {
		/* Wait for synchronization */
	};

	system_interrupt_enter_critical_section();

	/* Enable generator */
	GCLK->GENCTRL[generator].reg |= GCLK_GENCTRL_GENEN;

	system_interrupt_leave_critical_section();
}
Example #5
0
/**
 * \brief Writes a Generic Clock Generator configuration to the hardware module.
 *
 * Writes out a given configuration of a Generic Clock Generator configuration
 * to the hardware module.
 *
 * \note Changing the clock source on the fly (on a running
 *       generator) can take additional time if the clock source is configured
 *       to only run on-demand (ONDEMAND bit is set) and it is not currently
 *       running (no peripheral is requesting the clock source). In this case
 *       the GCLK will request the new clock while still keeping a request to
 *       the old clock source until the new clock source is ready.
 *
 * \note This function will not start a generator that is not already running;
 *       to start the generator, call \ref system_gclk_gen_enable()
 *       after configuring a generator.
 *
 * \param[in] generator  Generic Clock Generator index to configure
 * \param[in] config     Configuration settings for the generator
 */
void system_gclk_gen_set_config(
		const uint8_t generator,
		struct system_gclk_gen_config *const config)
{
	/* Sanity check arguments */
	Assert(config);

	/* Cache new register configurations to minimize sync requirements. */
	uint32_t new_genctrl_config = (generator << GCLK_GENCTRL_ID_Pos);
	uint32_t new_gendiv_config  = (generator << GCLK_GENDIV_ID_Pos);

	/* Select the requested source clock for the generator */
	new_genctrl_config |= config->source_clock << GCLK_GENCTRL_SRC_Pos;

	/* Configure the clock to be either high or low when disabled */
	if (config->high_when_disabled) {
		new_genctrl_config |= GCLK_GENCTRL_OOV;
	}

	/* Configure if the clock output to I/O pin should be enabled. */
	if (config->output_enable) {
		new_genctrl_config |= GCLK_GENCTRL_OE;
	}

	/* Set division factor */
	if (config->division_factor > 1) {
		/* Check if division is a power of two */
		if (((config->division_factor & (config->division_factor - 1)) == 0)) {
			/* Determine the index of the highest bit set to get the
			 * division factor that must be loaded into the division
			 * register */

			uint32_t div2_count = 0;

			uint32_t mask;
			for (mask = (1UL << 1); mask < config->division_factor;
						mask <<= 1) {
				div2_count++;
			}

			/* Set binary divider power of 2 division factor */
			new_gendiv_config  |= div2_count << GCLK_GENDIV_DIV_Pos;
			new_genctrl_config |= GCLK_GENCTRL_DIVSEL;
		} else {
			/* Set integer division factor */

			new_gendiv_config  |=
					(config->division_factor) << GCLK_GENDIV_DIV_Pos;

			/* Enable non-binary division with increased duty cycle accuracy */
			new_genctrl_config |= GCLK_GENCTRL_IDC;
		}

	}

	/* Enable or disable the clock in standby mode */
	if (config->run_in_standby) {
		new_genctrl_config |= GCLK_GENCTRL_RUNSTDBY;
	}

	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};

	system_interrupt_enter_critical_section();

	GCLK->GENDIV.reg  = new_gendiv_config;

	while (system_gclk_is_syncing()) {
		/* Wait for synchronization */
	};
	GCLK->GENCTRL.reg = new_genctrl_config | (GCLK->GENCTRL.reg & GCLK_GENCTRL_GENEN);

	system_interrupt_leave_critical_section();
}