コード例 #1
0
/**
 * \brief Disable circular option for double buffered compare values.
 *
 * Stop circularing the double buffered compare values.
 *
 * \param[in] module_inst     Pointer to the TCC software instance struct
 * \param[in] channel_index   Index of the compare channel to set up to
 *
 * \retval STATUS_OK           The module was initialized successfully
 * \retval STATUS_INVALID_ARG  An invalid channel index is supplied
 */
enum status_code tcc_disable_circular_buffer_compare(
		struct tcc_module *const module_inst,
		enum tcc_match_capture_channel channel_index)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	/* Check index */
	if (channel_index > 3) {
		return STATUS_ERR_INVALID_ARG;
	}
	if (channel_index >= _tcc_cc_nums[module_index]) {
		return STATUS_ERR_INVALID_ARG;
	}

	tcc_module->WAVE.reg &= ~(TCC_WAVE_CICCEN0 << channel_index);

	return STATUS_OK;
}
コード例 #2
0
/**
 * \brief Sets count value for the given TCC module.
 *
 * Sets the timer count value of an initialized TCC module. The
 * specified TCC module can remain running or stopped.
 *
 * \param[in] module_inst  Pointer to the software module instance struct
 * \param[in] count        New timer count value to set
 *
 * \return Status which indicates whether the new value is set.
 *
 * \retval STATUS_OK               The timer count was updated successfully
 * \retval STATUS_ERR_INVALID_ARG  An invalid timer counter size was specified
 */
enum status_code tcc_set_count_value(
		const struct tcc_module *const module_inst,
		const uint32_t count)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance*/
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	uint32_t max_count = _tcc_maxs[module_index];

	if (count > max_count) {
		return STATUS_ERR_INVALID_ARG;
	}

	while (tcc_module->SYNCBUSY.bit.COUNT) {
		/* Wait for sync */
	}

	/* Write to based on the TCC dithering */
	tcc_module->COUNT.reg = (count);

	return STATUS_OK;
}
コード例 #3
0
/**
 * \brief Set the timer TOP/PERIOD value.
 *
 * This function writes the top value.
 *
 * If double buffering is enabled, it always write to the buffer register.
 * The value will then be updated immediately by calling
 * \ref tcc_update_buffered_values, or be updated when the lock update bit
 * is cleared and the update condition happen.
 *
 * When using MFRQ, the top value is defined by the CC0 register value, for all
 * other waveforms operation the top value is defined by PER register value.
 *
 * \param[in]  module_inst   Pointer to the software module instance struct
 * \param[in]  top_value     New timer TOP value to set
 *
 * \return Status of the TOP set procedure.
 *
 * \retval STATUS_OK              The timer TOP value was updated successfully
 * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
 *                                top/period value exceed resolution
 */
enum status_code tcc_set_top_value(
		const struct tcc_module *const module_inst,
		const uint32_t top_value)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	uint32_t max_count = _tcc_maxs[module_index];

	/* Check compare value */
	if (top_value > max_count) {
		return STATUS_ERR_INVALID_ARG;
	}

	while(tcc_module->SYNCBUSY.reg  & TCC_SYNCBUSY_PER) {
		/* Sync wait */
	}
	tcc_module->PER.reg = top_value;

	return STATUS_OK;
}
コード例 #4
0
/**
 * \brief Sets a TCC module compare value.
 *
 * Writes a compare value to the given TCC module compare/capture channel.
 *
 * If double buffering is enabled, it always write to the buffer register.
 * The value will then be updated immediately by calling
 * \ref tcc_update_buffered_values, or be updated when the lock update bit
 * is cleared and the update condition happen.
 *
 * \param[in]  module_inst    Pointer to the software module instance struct
 * \param[in]  channel_index  Index of the compare channel to write to
 * \param[in]  compare        New compare value to set
 *
 * \return Status of the compare update procedure.
 *
 * \retval  STATUS_OK               The compare value was updated successfully
 * \retval  STATUS_ERR_INVALID_ARG  An invalid channel index was supplied or
 *                                  compare value exceed resolution
 */
enum status_code tcc_set_compare_value(
		const struct tcc_module *const module_inst,
		const enum tcc_match_capture_channel channel_index,
		const uint32_t compare)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	/* Check index */
	if (channel_index >= _tcc_cc_nums[module_index]) {
		return STATUS_ERR_INVALID_ARG;
	}

	uint32_t max_count = _tcc_maxs[module_index];

	/* Check compare value */
	if (compare > max_count) {
		return STATUS_ERR_INVALID_ARG;
	}

	while(tcc_module->SYNCBUSY.reg  & (TCC_SYNCBUSY_CC0 << channel_index)) {
		/* Sync wait */
	}
	tcc_module->CC[channel_index].reg = compare;

	return STATUS_OK;
}
コード例 #5
0
/**
 * \brief Initializes config with predefined default values.
 *
 * This function will initialize a given TCC configuration structure to
 * a set of known default values. This function should be called on
 * any new instance of the configuration structures before being
 * modified by the user application.
 *
 * The default configuration is as follows:
 *  \li Don't run in standby
 *  \li The base timer/counter configurations:
 *      \li GCLK generator 0 (GCLK main) clock source
 *      \li No prescaler
 *      \li GCLK reload action
 *      \li Count upward
 *      \li Don't perform one-shot operations
 *      \li Counter starts on 0
 *      \li Period/top value set to maximum of counting
 *  \li The match/capture configurations:
 *      \li All Capture compare channel value set to 0
 *      \li No capture enabled (all channels use compare function)
 *      \li Normal frequency wave generation
 *      \li Waveform generation polarity set to 0
 *      \li Don't perform ramp on waveform
 *  \li The waveform extension configurations:
 *      \li No inversion of waveform output
 *  \li No channel output enabled
 *  \li No PWM pin output enabled
 *  \li Pin and Mux configuration not set
 *
 * \param[out]  config  Pointer to a TCC module configuration structure to set
 * \param[in]   hw      Pointer to the TCC hardware module
 *
 */
void tcc_get_config_defaults(
		struct tcc_config *const config,
		Tcc *const hw)
{
	/* TCC instance index */
	uint8_t module_index = _tcc_get_inst_index(hw);

	/* Base counter defaults */
	config->counter.count                  = 0;

	config->counter.period                 = _tcc_maxs[module_index];

	config->counter.clock_source           = GCLK_GENERATOR_0;
	config->counter.clock_prescaler        = TCC_CLOCK_PRESCALER_DIV1;
	config->counter.reload_action          = TCC_RELOAD_ACTION_GCLK;

	config->counter.direction              = TCC_COUNT_DIRECTION_UP;
	config->counter.oneshot                = false;

	/* Match/Capture defaults */
#  define _TCC_CHANNEL_MATCH_VALUE_INIT(n, value) \
		config->compare.match[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
		_TCC_CHANNEL_MATCH_VALUE_INIT, 0)
#  undef _TCC_CHANNEL_MATCH_VALUE_INIT

#  define _TCC_CHANNEL_WAVE_POLARITY_INIT(n, value) \
		config->compare.wave_polarity[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
		_TCC_CHANNEL_WAVE_POLARITY_INIT, TCC_WAVE_POLARITY_0)
#  undef _TCC_CHANNEL_WAVE_POLARITY_INIT

	config->compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ;
	config->compare.wave_ramp       = TCC_RAMP_RAMP1;

#  define _TCC_CHANNEL_FUNCTION_INIT(n, value) \
		config->compare.channel_function[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
			_TCC_CHANNEL_FUNCTION_INIT, TCC_CHANNEL_FUNCTION_COMPARE)
#  undef _TCC_CHANNEL_FUNCTION_INIT

#  define _TCC_OUT_INVERT_INIT(n, value) \
		config->wave_ext.invert[n] = value;
	MREPEAT(TCC_NUM_WAVE_OUTPUTS,
		_TCC_OUT_INVERT_INIT, false)
#  undef _TCC_OUT_INVERT_INIT

#define _TCC_CHANNEL_OUT_PIN_INIT(n, dummy) \
		config->pins.enable_wave_out_pin[n]                          = false;\
		config->pins.wave_out_pin[TCC_WAVE_OUTPUT_##n]     = 0;   \
		config->pins.wave_out_pin_mux[TCC_WAVE_OUTPUT_##n] = 0;
	MREPEAT(TCC_NUM_WAVE_OUTPUTS,
		_TCC_CHANNEL_OUT_PIN_INIT, 0)
#undef _TCC_CHANNEL_OUT_PIN_INIT

	config->run_in_standby          = false;
}
コード例 #6
0
/**
 * \brief Sets the TCC module waveform output pattern.
 *
 * Force waveform output line to generate specific pattern (0, 1, or as is).
 *
 * If double buffering is enabled it always write to the buffer
 * register. The value will then be updated immediately by calling
 * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit
 * is cleared and the UPDATE condition happen.
 *
 * \param[in]  module_inst Pointer to the software module instance struct
 * \param[in]  line_index  Output line index
 * \param[in]  pattern     Output pattern to use (\ref tcc_output_pattern)
 *
 * \return Status of the pattern set procedure.
 *
 * \retval  STATUS_OK               The PATT register is updated successfully
 * \retval  STATUS_ERR_INVALID_ARG  An invalid line index was supplied
 */
enum status_code tcc_set_pattern(
		const struct tcc_module *const module_inst,
		const uint32_t line_index,
		const enum tcc_output_pattern pattern)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);
	/* Get number of output lines */
	uint8_t ow_num = _tcc_ow_nums[module_index];

	/* Check if line number is OK */
	if (line_index >= ow_num) {
		return STATUS_ERR_INVALID_ARG;
	}

	uint32_t patt_value;

	while(tcc_module->SYNCBUSY.reg  & TCC_SYNCBUSY_PATT) {
		/* Sync wait */
	}
	patt_value = tcc_module->PATT.reg;
	if (TCC_OUTPUT_PATTERN_DISABLE == pattern) {
		patt_value &= ~(TCC_PATT_PGE0 << line_index);
	} else if (TCC_OUTPUT_PATTERN_0 == pattern) {
		patt_value &= ~(TCC_PATT_PGV0 << line_index);
		patt_value |=  (TCC_PATT_PGE0 << line_index);
	} else {
		patt_value |=  ((TCC_PATT_PGE0 | TCC_PATT_PGV0) << line_index);
	}

	if (module_inst->double_buffering_enabled) {
#if (SAML21) || (SAMC20) || (SAMC21)
		tcc_module->PATTBUF.reg = patt_value;
#else
		while(tcc_module->SYNCBUSY.reg  & TCC_SYNCBUSY_PATTB) {
			/* Sync wait */
		}
		tcc_module->PATTB.reg = patt_value;
#endif
	} else {
		tcc_module->PATT.reg = patt_value;
	}
	return STATUS_OK;
}
コード例 #7
0
ファイル: tcc.c プロジェクト: csz-cmy/rt-thread
/**
 * \internal
 * \brief Sets a TCC module compare value/buffer.
 *
 * Writes a compare value to the given TCC module compare/capture channel or
 * buffer one.
 *
 * \param[in]  module_inst    Pointer to the software module instance struct
 * \param[in]  channel_index  Index of the compare channel to write to
 * \param[in]  compare        New compare value/buffer value to set
 * \param[in]  double_buffering_enabled Set to \c true to write to CCBx
 *
 * \return Status of the compare update procedure.
 *
 * \retval  STATUS_OK               The compare value was updated successfully
 * \retval  STATUS_ERR_INVALID_ARG  An invalid channel index was supplied or
 *                                  compare value exceed resolution
 */
static enum status_code _tcc_set_compare_value(
		const struct tcc_module *const module_inst,
		const enum tcc_match_capture_channel channel_index,
		const uint32_t compare,
		const bool double_buffering_enabled)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	/* Check index */
	if (channel_index >= _tcc_cc_nums[module_index]) {
		return STATUS_ERR_INVALID_ARG;
	}

	uint32_t max_count = _tcc_maxs[module_index];

	/* Check compare value */
	if (compare > max_count) {
		return STATUS_ERR_INVALID_ARG;
	}

	if (double_buffering_enabled) {
#if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30)
		tcc_module->CCBUF[channel_index].reg = compare;
#else
		while(tcc_module->STATUS.reg  &
				(TCC_STATUS_CCBV0 << channel_index)) {
			/* Valid check */
		}
		while(tcc_module->SYNCBUSY.reg  &
				(TCC_SYNCBUSY_CCB0 << channel_index)) {
			/* Sync wait */
		}
		tcc_module->CCB[channel_index].reg = compare;
#endif
	} else {
		while(tcc_module->SYNCBUSY.reg  & (TCC_SYNCBUSY_CC0 << channel_index)) {
			/* Sync wait */
		}
		tcc_module->CC[channel_index].reg = compare;
	}
	return STATUS_OK;
}
コード例 #8
0
/**
 * \brief Disables callback
 *
 * Disables the callback function registered by the \ref
 * tcc_register_callback, and the callback will not be called from the
 * interrupt routine. The function will also disable the appropriate
 * interrupts.
 *
 * \param[in]     module Pointer to TCC software instance struct
 * \param[in]     callback_type Callback type given by an enum
 */
void tcc_disable_callback(
		struct tcc_module *const module,
		const enum tcc_callback callback_type)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(module->hw);

	/* Disable interrupts for this TCC module */
	system_interrupt_enable(_tcc_interrupt_get_interrupt_vector(
			_tcc_get_inst_index(module->hw)));

	/* Disable channel or other callbacks */
	module->enable_callback_mask &= ~_tcc_intflag[callback_type];
	module->hw->INTENCLR.reg = _tcc_intflag[callback_type];
}
コード例 #9
0
/**
 * \brief Gets the TCC module capture value.
 *
 * Retrieves the capture value in the indicated TCC module capture channel.
 *
 * \param[in]  module_inst    Pointer to the software module instance struct
 * \param[in]  channel_index  Index of the Compare Capture channel to read
 *
 * \return Capture value stored in the specified timer channel.
 */
uint32_t tcc_get_capture_value(
		const struct tcc_module *const module_inst,
		const enum tcc_match_capture_channel channel_index)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	Assert(channel_index < _tcc_cc_nums[_tcc_get_inst_index(module_inst->hw)]);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;

	while(tcc_module->SYNCBUSY.reg  & (TCC_SYNCBUSY_CC0 << channel_index)) {
		/* Sync wait */
	}

	return tcc_module->CC[channel_index].reg;
}
コード例 #10
0
/**
 * \internal
 * \brief Set the timer TOP/PERIOD buffer/value.
 *
 * This function writes the given value to the PER/PERB register.
 *
 * \param[in] module_inst   Pointer to the software module instance struct
 * \param[in] top_value     New value to be loaded into the PER/PERB register
 * \param[in] double_buffering_enabled Set to \c true to write to PERB
 *
 * \return Status of the TOP set procedure.
 *
 * \retval STATUS_OK              The timer TOP value was updated successfully
 * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
 *                                top/period value exceed resolution
 */
static enum status_code _tcc_set_top_value(
		const struct tcc_module *const module_inst,
		const uint32_t top_value,
		const bool double_buffering_enabled)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(module_inst->hw);

	/* Get a pointer to the module's hardware instance */
	Tcc *const tcc_module = module_inst->hw;
	/* Get a index of the module */
	uint8_t module_index = _tcc_get_inst_index(tcc_module);

	uint32_t max_count = _tcc_maxs[module_index];

	/* Check compare value */
	if (top_value > max_count) {
		return STATUS_ERR_INVALID_ARG;
	}

	if (double_buffering_enabled) {
#if (SAML21) || (SAMC20) || (SAMC21)
		tcc_module->PERBUF.reg = top_value;
#else
		while(tcc_module->SYNCBUSY.reg  & TCC_SYNCBUSY_PERB) {
			/* Sync wait */
		}
		tcc_module->PERB.reg = top_value;
#endif
	} else {
		while(tcc_module->SYNCBUSY.reg  & TCC_SYNCBUSY_PER) {
			/* Sync wait */
		}
		tcc_module->PER.reg = top_value;
	}
	return STATUS_OK;
}
コード例 #11
0
/**
 * \brief Initializes a hardware TCC module instance.
 *
 * Enables the clock and initializes the given TCC module, based on the given
 * configuration values.
 *
 * \param[in,out] module_inst  Pointer to the software module instance struct
 * \param[in]     hw           Pointer to the TCC hardware module
 * \param[in]     config       Pointer to the TCC configuration options struct
 *
 * \return Status of the initialization procedure.
 *
 * \retval STATUS_OK           The module was initialized successfully
 * \retval STATUS_BUSY         Hardware module was busy when the
 *                             initialization procedure was attempted
 * \retval STATUS_INVALID_ARG  An invalid configuration option or argument
 *                             was supplied
 * \retval STATUS_ERR_DENIED   Hardware module was already enabled
 */
enum status_code tcc_init(
		struct tcc_module *const module_inst,
		Tcc *const hw,
		const struct tcc_config *const config)
{
	int i;

	/* Sanity check arguments */
	Assert(hw);
	Assert(module_inst);
	Assert(config);

	/* TCC instance index */
	uint8_t module_index = _tcc_get_inst_index(hw);

	/* Enable the user interface clock for TCC */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
			_tcc_apbcmasks[module_index]);

	/* Check if it's enabled. */
	if (hw->CTRLA.reg & TCC_CTRLA_ENABLE) {
		return STATUS_ERR_DENIED;
	}
	/* Check if it's resetting */
	if (hw->CTRLA.reg & TCC_CTRLA_SWRST) {
		return STATUS_ERR_DENIED;
	}

	enum status_code status;

	/* Check COUNT, PER, CCx */
	uint32_t count_max  = _tcc_maxs[module_index];

	/* Check all counter values */
	if ((config->counter.count > count_max)
		|| (config->counter.period > count_max)
		) {
		return STATUS_ERR_INVALID_ARG;
	}

	/* Check all channel values */
	for (i = 0; i < TCC_NUM_CHANNELS; i ++) {
		if ((config->compare.match[i] > count_max)
			) {
			return STATUS_ERR_INVALID_ARG;
		}
	}

	/* Check all outputs */
	for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) {
		if (!config->pins.enable_wave_out_pin[i]) {
			continue;
		}
		/* Output line is not supported */
		if (i >= _tcc_ow_nums[module_index]) {
			return STATUS_ERR_INVALID_ARG;
		}
	}

	/* CTRLA settings */
	uint32_t ctrla = 0;
	status = _tcc_build_ctrla(module_index, config, &ctrla);
	if (STATUS_OK != status) {
		return status;
	}

	/* CTRLB settings */
	uint8_t ctrlb;
	_tcc_build_ctrlb(module_index, config, &ctrlb);

	/* FAULTs settings */
	uint32_t faults[TCC_NUM_FAULTS];

	status = _tcc_build_faults(module_index, config, faults);
	if (STATUS_OK != status) {
		return status;
	}

	/* DRVCTRL */
	uint32_t drvctrl = 0;

	status = _tcc_build_drvctrl(module_index, config, &drvctrl);
	if (STATUS_OK != status) {
		return status;
	}

	/* WAVE */
	uint32_t waves[1];

	status = _tcc_build_waves(module_index, config, waves);
	if (STATUS_OK != status) {
		return status;
	}

	/* Initialize module */
#if TCC_ASYNC
	/* Initialize parameters */
	for (i = 0; i < TCC_CALLBACK_N; i ++) {
		module_inst->callback[i] = NULL;
	}
	module_inst->register_callback_mask = 0;
	module_inst->enable_callback_mask = 0;
	_tcc_instances[module_index] = module_inst;
#endif

	module_inst->hw = hw;

	module_inst->double_buffering_enabled = config->double_buffering_enabled;

	/* Setup clock for module */
	struct system_gclk_chan_config gclk_chan_config;
	system_gclk_chan_get_config_defaults(&gclk_chan_config);
	gclk_chan_config.source_generator = config->counter.clock_source;
	system_gclk_chan_set_config(_tcc_gclk_ids[module_index], &gclk_chan_config);
	system_gclk_chan_enable(_tcc_gclk_ids[module_index]);

	/* Initialize pins */
	struct system_pinmux_config pin_config;
	for (i = 0; i <  _tcc_ow_nums[module_index]; i ++) {
		if (!config->pins.enable_wave_out_pin[i]) {
			continue;
		}

		system_pinmux_get_config_defaults(&pin_config);
		pin_config.mux_position = config->pins.wave_out_pin_mux[i];
		pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
		system_pinmux_pin_set_config(
				config->pins.wave_out_pin[i], &pin_config);
	}

	/* Write to registers */

	hw->CTRLA.reg = ctrla;
	while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
		/* Wait for sync */
	}

	hw->CTRLBCLR.reg = 0xFF;
	while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
		/* Wait for sync */
	}
	hw->CTRLBSET.reg = ctrlb;

	hw->FCTRLA.reg = faults[0];
	hw->FCTRLB.reg = faults[1];

	hw->DRVCTRL.reg = drvctrl;

#if (!SAML21) && (!SAMC20) && (!SAMC21)
	while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_WAVE | TCC_SYNCBUSY_WAVEB)) {
		/* Wait for sync */
	}
#endif
	hw->WAVE.reg = waves[0];

	while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) {
		/* Wait for sync */
	}
	hw->COUNT.reg = config->counter.count;

#if (!SAML21) && (!SAMC20) && (!SAMC21)
	while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_PER | TCC_SYNCBUSY_PERB)) {
		/* Wait for sync */
	}
#endif
	hw->PER.reg = (config->counter.period);

	for (i = 0; i <  _tcc_cc_nums[module_index]; i ++) {
#if (!SAML21) && (!SAMC20) && (!SAMC21)
		while (hw->SYNCBUSY.reg & (
			(TCC_SYNCBUSY_CC0 | TCC_SYNCBUSY_CCB0) << i)) {
			/* Wait for sync */
		}
#endif
		hw->CC[i].reg = (config->compare.match[i]);
	}

	return STATUS_OK;
}
コード例 #12
0
/**
 * \brief Initializes config with predefined default values.
 *
 * This function will initialize a given TCC configuration structure to
 * a set of known default values. This function should be called on
 * any new instance of the configuration structures before being
 * modified by the user application.
 *
 * The default configuration is as follows:
 *  \li Don't run in standby
 *  \li When setting top,compare or pattern by API, do double buffering write
 *  \li The base timer/counter configurations:
 *     - GCLK generator 0 clock source
 *     - No prescaler
 *     - GCLK reload action
 *     - Count upward
 *     - Don't perform one-shot operations
 *     - Counter starts on 0
 *     - Period/top value set to maximum
 *  \li The match/capture configurations:
 *     - All Capture compare channel value set to 0
 *     - No capture enabled (all channels use compare function)
 *     - Normal frequency wave generation
 *     - Waveform generation polarity set to 0
 *     - Don't perform ramp on waveform
 *  \li The waveform extension configurations:
 *     - No recoverable fault is enabled, fault actions are disabled, filter
 *          is set to 0
 *     - No non-recoverable fault state output is enabled and filter is 0
 *     - No inversion of waveform output
 *  \li No channel output enabled
 *  \li No PWM pin output enabled
 *  \li Pin and MUX configuration not set
 *
 * \param[out]  config  Pointer to a TCC module configuration structure to set
 * \param[in]   hw      Pointer to the TCC hardware module
 *
 */
void tcc_get_config_defaults(
		struct tcc_config *const config,
		Tcc *const hw)
{
	/* TCC instance index */
	uint8_t module_index = _tcc_get_inst_index(hw);

	/* Base counter defaults */
	config->counter.count                  = 0;

	config->counter.period                 = _tcc_maxs[module_index];

	config->counter.clock_source           = GCLK_GENERATOR_0;
	config->counter.clock_prescaler        = TCC_CLOCK_PRESCALER_DIV1;
	config->counter.reload_action          = TCC_RELOAD_ACTION_GCLK;

	config->counter.direction              = TCC_COUNT_DIRECTION_UP;
	config->counter.oneshot                = false;

	/* Match/Capture defaults */
#  define _TCC_CHANNEL_MATCH_VALUE_INIT(n, value) \
		config->compare.match[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
		_TCC_CHANNEL_MATCH_VALUE_INIT, 0)
#  undef _TCC_CHANNEL_MATCH_VALUE_INIT

	/* Wave polarity defaults */
#  define _TCC_CHANNEL_WAVE_POLARITY_INIT(n, value) \
		config->compare.wave_polarity[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
		_TCC_CHANNEL_WAVE_POLARITY_INIT, TCC_WAVE_POLARITY_0)
#  undef _TCC_CHANNEL_WAVE_POLARITY_INIT

	config->compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ;
	config->compare.wave_ramp       = TCC_RAMP_RAMP1;

#  define _TCC_CHANNEL_FUNCTION_INIT(n, value) \
		config->compare.channel_function[n] = value;
	MREPEAT(TCC_NUM_CHANNELS,
			_TCC_CHANNEL_FUNCTION_INIT, TCC_CHANNEL_FUNCTION_COMPARE)
#  undef _TCC_CHANNEL_FUNCTION_INIT

	/* Recoverable fault defaults */
#  define _TCC_FAULT_FUNCTION_INIT(n, dummy) \
		config->wave_ext.recoverable_fault[n].filter_value = 0;      \
		config->wave_ext.recoverable_fault[n].blanking_cycles = 0;   \
		config->wave_ext.recoverable_fault[n].restart = false;       \
		config->wave_ext.recoverable_fault[n].keep = false;          \
		config->wave_ext.recoverable_fault[n].qualification = false; \
		config->wave_ext.recoverable_fault[n].source = TCC_FAULT_SOURCE_DISABLE;           \
		config->wave_ext.recoverable_fault[n].blanking = TCC_FAULT_BLANKING_DISABLE;       \
		config->wave_ext.recoverable_fault[n].halt_action = TCC_FAULT_HALT_ACTION_DISABLE; \
		config->wave_ext.recoverable_fault[n].capture_action = TCC_FAULT_CAPTURE_DISABLE;  \
		config->wave_ext.recoverable_fault[n].capture_channel = TCC_FAULT_CAPTURE_CHANNEL_0;
	MREPEAT(TCC_NUM_FAULTS, _TCC_FAULT_FUNCTION_INIT, 0)
#  undef _TCC_FAULT_FUNCTION_INIT

	/* Non-recoverable fault defaults */
#  define _TCC_NRF_FUNCTION_INIT(n, dummy) \
		config->wave_ext.non_recoverable_fault[n].filter_value = 0; \
		config->wave_ext.non_recoverable_fault[n].output = TCC_FAULT_STATE_OUTPUT_OFF;
	MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_NRF_FUNCTION_INIT, 0)
#  undef _TCC_NRF_FUNCTION_INIT

	/* Output inversion defaults */
#  define _TCC_OUT_INVERT_INIT(n, value) \
		config->wave_ext.invert[n] = value;
	MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_OUT_INVERT_INIT, false)
#  undef _TCC_OUT_INVERT_INIT

#  define _TCC_CHANNEL_OUT_PIN_INIT(n, dummy) \
		config->pins.enable_wave_out_pin[n]                = false;\
		config->pins.wave_out_pin[TCC_WAVE_OUTPUT_##n]     = 0;    \
		config->pins.wave_out_pin_mux[TCC_WAVE_OUTPUT_##n] = 0;
	MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_CHANNEL_OUT_PIN_INIT, 0)
#  undef _TCC_CHANNEL_OUT_PIN_INIT

	config->double_buffering_enabled  = true;
	config->run_in_standby            = false;
}