/** * \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; }
/** * \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; }
/** * \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; }
/** * \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; }
/** * \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; }
/** * \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; }
/** * \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; }
/** * \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]; }
/** * \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; }
/** * \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; }
/** * \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; }
/** * \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; }