http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/a280628a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tc/tc_sam_d_r/tc.c ---------------------------------------------------------------------- diff --git a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tc/tc_sam_d_r/tc.c b/hw/mcu/atmel/samd21xx/src/sam0/drivers/tc/tc_sam_d_r/tc.c deleted file mode 100755 index 546c36c..0000000 --- a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tc/tc_sam_d_r/tc.c +++ /dev/null @@ -1,685 +0,0 @@ -/** - * \file - * - * \brief SAM TC - Timer Counter Driver - * - * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> - */ - -#include "tc.h" - -#if TC_ASYNC == true -# include "tc_interrupt.h" -# include <system_interrupt.h> - -/** \internal - * Converts a given TC index to its interrupt vector index. - */ -# define _TC_INTERRUPT_VECT_NUM(n, unused) \ - SYSTEM_INTERRUPT_MODULE_TC##n, -#endif - -#if !defined(__DOXYGEN__) -# define _TC_GCLK_ID(n,unused) TPASTE3(TC,n,_GCLK_ID) , -# define _TC_PM_APBCMASK(n,unused) TPASTE2(PM_APBCMASK_TC,n) , - -# define TC_INST_GCLK_ID { MRECURSION(TC_INST_NUM, _TC_GCLK_ID, TC_INST_MAX_ID) } -# define TC_INST_PM_APBCMASK { MRECURSION(TC_INST_NUM, _TC_PM_APBCMASK, TC_INST_MAX_ID) } - -#endif - -/** - * \internal Find the index of given TC module instance. - * - * \param[in] TC module instance pointer - * - * \return Index of the given TC module instance. - */ -uint8_t _tc_get_inst_index( - Tc *const hw) -{ - /* List of available TC modules. */ - Tc *const tc_modules[TC_INST_NUM] = TC_INSTS; - - /* Find index for TC instance. */ - for (uint32_t i = 0; i < TC_INST_NUM; i++) { - if (hw == tc_modules[i]) { - return i; - } - } - - /* Invalid data given. */ - Assert(false); - return 0; -} - - -/** - * \brief Initializes a hardware TC module instance. - * - * Enables the clock and initializes the TC 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 TC hardware module - * \param[in] config Pointer to the TC 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, or the - * hardware module is configured in 32-bit - * slave mode - */ -enum status_code tc_init( - struct tc_module *const module_inst, - Tc *const hw, - const struct tc_config *const config) -{ - /* Sanity check arguments */ - Assert(hw); - Assert(module_inst); - Assert(config); - - /* Temporary variable to hold all updates to the CTRLA - * register before they are written to it */ - uint16_t ctrla_tmp = 0; - /* Temporary variable to hold all updates to the CTRLBSET - * register before they are written to it */ - uint8_t ctrlbset_tmp = 0; - /* Temporary variable to hold all updates to the CTRLC - * register before they are written to it */ - uint8_t ctrlc_tmp = 0; - /* Temporary variable to hold TC instance number */ - uint8_t instance = _tc_get_inst_index(hw); - - /* Array of GLCK ID for different TC instances */ - uint8_t inst_gclk_id[] = TC_INST_GCLK_ID; - /* Array of PM APBC mask bit position for different TC instances */ - uint16_t inst_pm_apbmask[] = TC_INST_PM_APBCMASK; - - struct system_pinmux_config pin_config; - struct system_gclk_chan_config gclk_chan_config; - -#if TC_ASYNC == true - /* Initialize parameters */ - for (uint8_t i = 0; i < TC_CALLBACK_N; i++) { - module_inst->callback[i] = NULL; - } - module_inst->register_callback_mask = 0x00; - module_inst->enable_callback_mask = 0x00; - - /* Register this instance for callbacks*/ - _tc_instances[instance] = module_inst; -#endif - - /* Associate the given device instance with the hardware module */ - module_inst->hw = hw; - -#if SAMD09 || SAMD10 || SAMD11 - /* Check if even numbered TC modules are being configured in 32-bit - * counter size. Only odd numbered counters are allowed to be - * configured in 32-bit counter size. - */ - if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && - !((instance + TC_INSTANCE_OFFSET) & 0x01)) { - Assert(false); - return STATUS_ERR_INVALID_ARG; - } -#else - /* Check if odd numbered TC modules are being configured in 32-bit - * counter size. Only even numbered counters are allowed to be - * configured in 32-bit counter size. - */ - if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && - ((instance + TC_INSTANCE_OFFSET) & 0x01)) { - Assert(false); - return STATUS_ERR_INVALID_ARG; - } -#endif - - /* Make the counter size variable in the module_inst struct reflect - * the counter size in the module - */ - module_inst->counter_size = config->counter_size; - - if (hw->COUNT8.CTRLA.reg & TC_CTRLA_SWRST) { - /* We are in the middle of a reset. Abort. */ - return STATUS_BUSY; - } - - if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) { - /* Module is used as a slave */ - return STATUS_ERR_DENIED; - } - - if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) { - /* Module must be disabled before initialization. Abort. */ - return STATUS_ERR_DENIED; - } - - /* Set up the TC PWM out pin for channel 0 */ - if (config->pwm_channel[0].enabled) { - system_pinmux_get_config_defaults(&pin_config); - pin_config.mux_position = config->pwm_channel[0].pin_mux; - pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; - system_pinmux_pin_set_config( - config->pwm_channel[0].pin_out, &pin_config); - } - - /* Set up the TC PWM out pin for channel 1 */ - if (config->pwm_channel[1].enabled) { - system_pinmux_get_config_defaults(&pin_config); - pin_config.mux_position = config->pwm_channel[1].pin_mux; - pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; - system_pinmux_pin_set_config( - config->pwm_channel[1].pin_out, &pin_config); - } - - /* Enable the user interface clock in the PM */ - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, - inst_pm_apbmask[instance]); - - /* Enable the slave counter if counter_size is 32-bit */ - if ((config->counter_size == TC_COUNTER_SIZE_32BIT)) - { - /* Enable the user interface clock in the PM */ - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, - inst_pm_apbmask[instance + 1]); - } - - /* Setup clock for module */ - system_gclk_chan_get_config_defaults(&gclk_chan_config); - gclk_chan_config.source_generator = config->clock_source; - system_gclk_chan_set_config(inst_gclk_id[instance], &gclk_chan_config); - system_gclk_chan_enable(inst_gclk_id[instance]); - - /* Set ctrla register */ - ctrla_tmp = - (uint32_t)config->counter_size | - (uint32_t)config->wave_generation | - (uint32_t)config->reload_action | - (uint32_t)config->clock_prescaler; - - if (config->run_in_standby) { - ctrla_tmp |= TC_CTRLA_RUNSTDBY; - } - - /* Write configuration to register */ - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - hw->COUNT8.CTRLA.reg = ctrla_tmp; - - /* Set ctrlb register */ - if (config->oneshot) { - ctrlbset_tmp = TC_CTRLBSET_ONESHOT; - } - - if (config->count_direction) { - ctrlbset_tmp |= TC_CTRLBSET_DIR; - } - - /* Clear old ctrlb configuration */ - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - hw->COUNT8.CTRLBCLR.reg = 0xFF; - - /* Check if we actually need to go into a wait state. */ - if (ctrlbset_tmp) { - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - /* Write configuration to register */ - hw->COUNT8.CTRLBSET.reg = ctrlbset_tmp; - } - - /* Set ctrlc register*/ - ctrlc_tmp = config->waveform_invert_output; - for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { - if (config->enable_capture_on_channel[i] == true) { - ctrlc_tmp |= (TC_CTRLC_CPTEN(1) << i); - } - } - - /* Write configuration to register */ - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - hw->COUNT8.CTRLC.reg = ctrlc_tmp; - - /* Write configuration to register */ - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - /* Switch for TC counter size */ - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT8.COUNT.reg = - config->counter_8_bit.value; - - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT8.PER.reg = - config->counter_8_bit.period; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT8.CC[0].reg = - config->counter_8_bit.compare_capture_channel[0]; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT8.CC[1].reg = - config->counter_8_bit.compare_capture_channel[1]; - - return STATUS_OK; - - case TC_COUNTER_SIZE_16BIT: - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT16.COUNT.reg - = config->counter_16_bit.value; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT16.CC[0].reg = - config->counter_16_bit.compare_capture_channel[0]; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT16.CC[1].reg = - config->counter_16_bit.compare_capture_channel[1]; - - return STATUS_OK; - - case TC_COUNTER_SIZE_32BIT: - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT32.COUNT.reg - = config->counter_32_bit.value; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT32.CC[0].reg = - config->counter_32_bit.compare_capture_channel[0]; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - hw->COUNT32.CC[1].reg = - config->counter_32_bit.compare_capture_channel[1]; - - return STATUS_OK; - } - - Assert(false); - return STATUS_ERR_INVALID_ARG; -} - -/** - * \brief Sets TC module count value. - * - * Sets the current timer count value of a initialized TC module. The - * specified TC module may be started or stopped. - * - * \param[in] module_inst Pointer to the software module instance struct - * \param[in] count New timer count value to set - * - * \return Status of the count update procedure. - * - * \retval STATUS_OK The timer count was updated successfully - * \retval STATUS_ERR_INVALID_ARG An invalid timer counter size was specified - */ -enum status_code tc_set_count_value( - const struct tc_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*/ - Tc *const tc_module = module_inst->hw; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - /* Write to based on the TC counter_size */ - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - tc_module->COUNT8.COUNT.reg = (uint8_t)count; - return STATUS_OK; - - case TC_COUNTER_SIZE_16BIT: - tc_module->COUNT16.COUNT.reg = (uint16_t)count; - return STATUS_OK; - - case TC_COUNTER_SIZE_32BIT: - tc_module->COUNT32.COUNT.reg = (uint32_t)count; - return STATUS_OK; - - default: - return STATUS_ERR_INVALID_ARG; - } -} - -/** - * \brief Get TC module count value. - * - * Retrieves the current count value of a TC module. The specified TC module - * may be started or stopped. - * - * \param[in] module_inst Pointer to the software module instance struct - * - * \return Count value of the specified TC module. - */ -uint32_t tc_get_count_value( - const struct tc_module *const module_inst) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - - /* Get a pointer to the module's hardware instance */ - Tc *const tc_module = module_inst->hw; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - /* Read from based on the TC counter size */ - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - return (uint32_t)tc_module->COUNT8.COUNT.reg; - - case TC_COUNTER_SIZE_16BIT: - return (uint32_t)tc_module->COUNT16.COUNT.reg; - - case TC_COUNTER_SIZE_32BIT: - return tc_module->COUNT32.COUNT.reg; - } - - Assert(false); - return 0; -} - -/** - * \brief Gets the TC module capture value. - * - * Retrieves the capture value in the indicated TC 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 tc_get_capture_value( - const struct tc_module *const module_inst, - const enum tc_compare_capture_channel channel_index) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - - /* Get a pointer to the module's hardware instance */ - Tc *const tc_module = module_inst->hw; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - /* Read out based on the TC counter size */ - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - return tc_module->COUNT8.CC[channel_index].reg; - } - - case TC_COUNTER_SIZE_16BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - return tc_module->COUNT16.CC[channel_index].reg; - } - - case TC_COUNTER_SIZE_32BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - return tc_module->COUNT32.CC[channel_index].reg; - } - } - - Assert(false); - return 0; -} - -/** - * \brief Sets a TC module compare value. - * - * Writes a compare value to the given TC module compare/capture channel. - * - * \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 - */ -enum status_code tc_set_compare_value( - const struct tc_module *const module_inst, - const enum tc_compare_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 */ - Tc *const tc_module = module_inst->hw; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - /* Read out based on the TC counter size */ - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - tc_module->COUNT8.CC[channel_index].reg = - (uint8_t)compare; - return STATUS_OK; - } - - case TC_COUNTER_SIZE_16BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - tc_module->COUNT16.CC[channel_index].reg = - (uint16_t)compare; - return STATUS_OK; - } - - case TC_COUNTER_SIZE_32BIT: - if (channel_index < - NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { - tc_module->COUNT32.CC[channel_index].reg = - (uint32_t)compare; - return STATUS_OK; - } - } - - return STATUS_ERR_INVALID_ARG; -} - -/** - * \brief Resets the TC module. - * - * Resets the TC module, restoring all hardware module registers to their - * default values and disabling the module. The TC module will not be - * accessible while the reset is being performed. - * - * \note When resetting a 32-bit counter only the master TC module's instance - * structure should be passed to the function. - * - * \param[in] module_inst Pointer to the software module instance struct - * - * \return Status of the procedure. - * \retval STATUS_OK The module was reset successfully - * \retval STATUS_ERR_UNSUPPORTED_DEV A 32-bit slave TC module was passed to - * the function. Only use reset on master - * TC - */ -enum status_code tc_reset( - const struct tc_module *const module_inst) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - - /* Get a pointer to the module hardware instance */ - TcCount8 *const tc_module = &(module_inst->hw->COUNT8); - - if (tc_module->STATUS.reg & TC_STATUS_SLAVE) { - return STATUS_ERR_UNSUPPORTED_DEV; - } - - /* Disable this module if it is running */ - if (tc_module->CTRLA.reg & TC_CTRLA_ENABLE) { - tc_disable(module_inst); - while (tc_is_syncing(module_inst)) { - /* wait while module is disabling */ - } - } - - /* Reset this TC module */ - tc_module->CTRLA.reg |= TC_CTRLA_SWRST; - - return STATUS_OK; -} - -/** - * \brief Set the timer TOP/period value. - * - * For 8-bit counter size this function writes the top value to the period - * register. - * - * For 16- and 32-bit counter size this function writes the top value to - * Capture Compare register 0. The value in this register can not be used for - * any other purpose. - * - * \note This function is designed to be used in PWM or frequency - * match modes only, when the counter is set to 16- or 32-bit counter - * size. In 8-bit counter size it will always be possible to change the - * top value even in normal mode. - * - * \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 The configured TC module counter size in the - * module instance is invalid - */ -enum status_code tc_set_top_value ( - const struct tc_module *const module_inst, - const uint32_t top_value) -{ - Assert(module_inst); - Assert(module_inst->hw); - Assert(top_value); - - Tc *const tc_module = module_inst->hw; - - while (tc_is_syncing(module_inst)) { - /* Wait for sync */ - } - - switch (module_inst->counter_size) { - case TC_COUNTER_SIZE_8BIT: - tc_module->COUNT8.PER.reg = (uint8_t)top_value; - return STATUS_OK; - - case TC_COUNTER_SIZE_16BIT: - tc_module->COUNT16.CC[0].reg = (uint16_t)top_value; - return STATUS_OK; - - case TC_COUNTER_SIZE_32BIT: - tc_module->COUNT32.CC[0].reg = (uint32_t)top_value; - return STATUS_OK; - - default: - Assert(false); - return STATUS_ERR_INVALID_ARG; - } -}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/a280628a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tcc/tcc.c ---------------------------------------------------------------------- diff --git a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tcc/tcc.c b/hw/mcu/atmel/samd21xx/src/sam0/drivers/tcc/tcc.c deleted file mode 100755 index a75d541..0000000 --- a/hw/mcu/atmel/samd21xx/src/sam0/drivers/tcc/tcc.c +++ /dev/null @@ -1,1597 +0,0 @@ -/** - * \file - * - * \brief SAM TCC - Timer Counter for Control Applications Driver - * - * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> - */ - -#include "tcc.h" - -#if TCC_ASYNC == true -# include "tcc_callback.h" -# include <system_interrupt.h> - -/** \internal - * Converts a given TCC index to its interrupt vector index. - */ -# define _TCC_INTERRUPT_VECT_NUM(n, unused) \ - SYSTEM_INTERRUPT_MODULE_TCC##n, -#endif - -#define _SIZE_MAX(size) ((size==32u) ? 0xFFFFFFFF : ( \ - (1u << size) - 1)) - -#define _SIZE_MAX_WITH_DITHER 0x03FFFFFF - -/* Extension support mapping bits */ -#define _TCC_DITHERING_B 16u -#define _TCC_PG_B 8u -#define _TCC_SWAP_B 4u -#define _TCC_DTI_B 2u -#define _TCC_OTMX_B 1u - -#if !defined(__DOXYGEN__) - -# define _TCC_GCLK_ID(n,unused) TPASTE3(TCC,n,_GCLK_ID), -# if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) -# define _TCC_APBCMASK(n,unused) TPASTE2(MCLK_APBCMASK_TCC,n), -# else -# define _TCC_APBCMASK(n,unused) TPASTE2(PM_APBCMASK_TCC,n), -# endif - -# define _TCC_SIZE(n,unused) TPASTE3(TCC,n,_SIZE), -# define _TCC_MAX(n,unused) _SIZE_MAX(TPASTE3(TCC,n,_SIZE)), -# define _TCC_EXT(n,unused) TPASTE3(TCC,n,_EXT), -# define _TCC_CC_NUM(n,unused) min(TPASTE3(TCC,n,_CC_NUM),TCC_NUM_CHANNELS), -# define _TCC_OW_NUM(n,unused) min(TPASTE3(TCC,n,_OW_NUM),TCC_NUM_WAVE_OUTPUTS), - -# define TCC_GCLK_IDS { MREPEAT(TCC_INST_NUM, _TCC_GCLK_ID, 0) } -# define TCC_APBCMASKS { MREPEAT(TCC_INST_NUM, _TCC_APBCMASK, 0) } - -# define TCC_SIZES { MREPEAT(TCC_INST_NUM, _TCC_SIZE, 0) } -# define TCC_MAXS { MREPEAT(TCC_INST_NUM, _TCC_MAX, 0) } -# define TCC_EXTS { MREPEAT(TCC_INST_NUM, _TCC_EXT, 0) } -# define TCC_CC_NUMS { MREPEAT(TCC_INST_NUM, _TCC_CC_NUM, 0) } -# define TCC_OW_NUMS { MREPEAT(TCC_INST_NUM, _TCC_OW_NUM, 0) } - -#endif - -/* List of available TCC modules. */ -const Tcc *const tcc_modules[TCC_INST_NUM] = TCC_INSTS; - -/* List of TCC GCLK IDs */ -const uint8_t _tcc_gclk_ids[TCC_INST_NUM] = TCC_GCLK_IDS; - -/* List of TCC APBC Masks */ -const uint32_t _tcc_apbcmasks[TCC_INST_NUM] = TCC_APBCMASKS; - -/* List of extension support of TCC modules. */ -const uint8_t _tcc_exts[TCC_INST_NUM] = TCC_EXTS; - -/* List of sizes support of TCC modules. */ -const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; - -/* List of maximumvalues supported of TCC modules. */ -const uint32_t _tcc_maxs[TCC_INST_NUM] = TCC_MAXS; - -/* List of available channel number of TCC modules. */ -const uint8_t _tcc_cc_nums[TCC_INST_NUM] = TCC_CC_NUMS; - -/* List of available output number of TCC modules. */ -const uint8_t _tcc_ow_nums[TCC_INST_NUM] = TCC_OW_NUMS; - -/** - * \internal Find the index of the given TCC module instance. - * - * \param[in] The TCC module instance pointer - * - * \return Index of the given TCC module instance. - */ -uint8_t _tcc_get_inst_index( - Tcc *const hw) -{ - /* Find index for TCC instance. */ - for (uint32_t i = 0; i < TCC_INST_NUM; i++) { - if (hw == tcc_modules[i]) { - return i; - } - } - - /* Invalid data given. */ - Assert(false); - return 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; - -#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER - config->counter.dma_trigger_mode = TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_CONTINUE; -#endif - - /* 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; -} - - -/** - * \brief Build CTRLA register value from configuration. - * - * \param[in] module_index The software module instance index - * \param[in] config Pointer to the TCC configuration options struct - * \param[out] value_buffer Pointer to the buffer to fill with built value - * - * \return Configuration validation status. - * - * \retval STATUS_OK Configuration values are good and register - * value built and save to buffer - * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: - * assigned dither mode is invalid for module; - * used capture channel is invalid for module - */ -static inline enum status_code _tcc_build_ctrla( - const uint8_t module_index, - const struct tcc_config *const config, - uint32_t *value_buffer) -{ - uint32_t ctrla = 0; - - int i; - for (i = 0; i < TCC_NUM_CHANNELS; i ++) { - if (config->capture.channel_function[i] == - TCC_CHANNEL_FUNCTION_CAPTURE) { - - if (i > _tcc_cc_nums[module_index]) { - /* Channel not supported */ - return STATUS_ERR_INVALID_ARG; - } - ctrla |= (TCC_CTRLA_CPTEN0 << i); - } - } - - if (config->run_in_standby) { - ctrla |= TCC_CTRLA_RUNSTDBY; - } - ctrla |= config->counter.reload_action << TCC_CTRLA_PRESCSYNC_Pos; - ctrla |= config->counter.clock_prescaler << TCC_CTRLA_PRESCALER_Pos; - - *value_buffer = ctrla; - return STATUS_OK; -} - -/** - * \brief Build CTRLB register value from configuration. - * - * \param[in] module_index The software module instance index - * \param[in] config Pointer to the TCC configuration options struct - * \param[out] value_buffer Pointer to the buffer to fill with built value - */ -static inline void _tcc_build_ctrlb( - const uint8_t module_index, - const struct tcc_config *const config, - uint8_t *value_buffer) -{ - uint8_t ctrlb = 0; - - if (config->counter.oneshot) { - ctrlb |= TCC_CTRLBSET_ONESHOT; - } - if (config->counter.direction == TCC_COUNT_DIRECTION_DOWN) { - ctrlb |= TCC_CTRLBSET_DIR; - } - - *value_buffer = ctrlb; -} - -/** - * \brief Build FAULTs register values from configuration. - * - * \param[in] module_index The software module instance index - * \param[in] config Pointer to the TCC configuration options struct - * \param[out] value_buffer Pointer to the buffer to fill with built values - * - * \retval STATUS_OK Configuration values are good and register - * value built and save to buffer - * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned fault - * capture channel is invalid; assigned filter - * value is invalid - */ -static inline enum status_code _tcc_build_faults( - const uint8_t module_index, - const struct tcc_config *const config, - uint32_t *value_buffer) -{ - struct tcc_recoverable_fault_config *cfg; - uint8_t cc_num = _tcc_cc_nums[module_index]; - uint32_t fault; - int i; - for (i = 0; i < TCC_NUM_FAULTS; i ++) { - cfg = (struct tcc_recoverable_fault_config *) - &config->wave_ext.recoverable_fault[i]; - if (cfg->capture_channel >= cc_num) { - return STATUS_ERR_INVALID_ARG; - } - if (cfg->filter_value > 0xF) { - return STATUS_ERR_INVALID_ARG; - } - fault = TCC_FCTRLA_FILTERVAL(cfg->filter_value) - | TCC_FCTRLA_BLANKVAL(cfg->blanking_cycles) - | (cfg->restart ? TCC_FCTRLA_RESTART : 0) - | (cfg->keep ? TCC_FCTRLA_KEEP : 0) - | (cfg->qualification ? TCC_FCTRLA_QUAL : 0) - | TCC_FCTRLA_SRC(cfg->source) - | TCC_FCTRLA_BLANK(cfg->blanking) - | TCC_FCTRLA_HALT(cfg->halt_action) - | TCC_FCTRLA_CAPTURE(cfg->capture_action) - | TCC_FCTRLA_CHSEL(cfg->capture_channel); - value_buffer[i] = fault; - } - return STATUS_OK; -} - -/** - * \brief Build DRVCTRL register values from configuration. - * - * \param[in] module_index The software module instance index - * \param[in] config Pointer to the TCC configuration options struct - * \param[out] value_buffer Pointer to the buffer to fill with built value - * - * \retval STATUS_OK Configuration values are good and register - * value built and save to buffer - * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line - * is invalid; filter value is invalid - */ -static inline enum status_code _tcc_build_drvctrl( - const uint8_t module_index, - const struct tcc_config *const config, - uint32_t *value_buffer) -{ - uint32_t i; - uint8_t ow_num = _tcc_ow_nums[module_index]; - uint32_t drvctrl; - - drvctrl = 0; - - for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) { - if (config->wave_ext.invert[i]) { - if (i >= ow_num) { - return STATUS_ERR_INVALID_ARG; - } - drvctrl |= (TCC_DRVCTRL_INVEN0 << i); - } - if (config->wave_ext.non_recoverable_fault[i].output != - TCC_FAULT_STATE_OUTPUT_OFF) { - if (i >= ow_num) { - return STATUS_ERR_INVALID_ARG; - } - if (config->wave_ext.non_recoverable_fault[i].output == - TCC_FAULT_STATE_OUTPUT_1) { - drvctrl |= (TCC_DRVCTRL_NRE0 | TCC_DRVCTRL_NRV0) << i; - } else { - drvctrl |= (TCC_DRVCTRL_NRE0) << i; - } - } - } - *value_buffer = drvctrl; - return STATUS_OK; -} - -/** - * \brief Build WAVE & WAVEB register values from configuration. - * - * \param[in] module_index The software module instance index - * \param[in] config Pointer to the TCC configuration options struct - * \param[out] value_buffer Pointer to the buffer to fill with built value - * - * \retval STATUS_OK Configuration values are good and register - * value built and save to buffer - * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line - * is invalid; circular and double buffering - * conflict; assigned function not supported by - * module - */ -static inline enum status_code _tcc_build_waves( - const uint8_t module_index, - const struct tcc_config *const config, - uint32_t *value_buffer) -{ - int n; - - uint8_t cc_num = _tcc_cc_nums[module_index]; - struct tcc_match_wave_config const *wav_cfg = &config->compare; - - uint32_t wave; - - wave = TCC_WAVE_RAMP(wav_cfg->wave_ramp) | - TCC_WAVE_WAVEGEN(wav_cfg->wave_generation); - - for (n = 0; n < TCC_NUM_CHANNELS; n++) { - if (wav_cfg->wave_polarity[n]) { - if (n >= cc_num) { - return STATUS_ERR_INVALID_ARG; - } - wave |= (TCC_WAVE_POL0 << n); - } - } - - value_buffer[0] = wave; - - 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 The 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 The 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) && (!SAML22) - 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) && (!SAML22) - 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) && (!SAML22) - 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 Enables the TCC module event input or output. - * - * Enables one or more input or output events to or from the TCC module. - * See \ref tcc_events for a list of events this module supports. - * - * \note Events cannot be altered while the module is enabled. - * - * \param[in] module_inst Pointer to the software module instance struct - * \param[in] events Struct containing flags of events to enable or - * configure - * - * \return Status of the events setup procedure. - * - * \retval STATUS_OK The module was initialized successfully - * \retval STATUS_INVALID_ARG An invalid configuration option or argument - * was supplied - */ -enum status_code tcc_enable_events( - struct tcc_module *const module_inst, - struct tcc_events *const events) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - Assert(events); - - Tcc *const tcc_module = module_inst->hw; - - /* Check if it's enabled or resetting. */ - if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) { - return STATUS_ERR_DENIED; - } - - uint32_t evctrl = tcc_module->EVCTRL.reg; - - /* Setup event output action */ - if (events->output_config.modify_generation_selection) { - evctrl &= ~ TCC_EVCTRL_CNTSEL_Msk; - switch(events->output_config.generation_selection) { - case TCC_EVENT_GENERATION_SELECTION_START: - evctrl |= TCC_EVCTRL_CNTSEL_START; - break; - case TCC_EVENT_GENERATION_SELECTION_END: - evctrl |= TCC_EVCTRL_CNTSEL_END; - break; - case TCC_EVENT_GENERATION_SELECTION_BETWEEN: - evctrl |= TCC_EVCTRL_CNTSEL_BETWEEN; - break; - case TCC_EVENT_GENERATION_SELECTION_BOUNDARY: - evctrl |= TCC_EVCTRL_CNTSEL_BOUNDARY; - break; - default: - Assert(false); - /* Wrong configuration */ - return STATUS_ERR_INVALID_ARG; - } - } - /* Setup input event0 */ - if (events->on_input_event_perform_action[0]) { - evctrl |= TCC_EVCTRL_TCEI0; - } - if (events->input_config[0].invert) { - evctrl |= TCC_EVCTRL_TCINV0; - } - if (events->input_config[0].modify_action) { - evctrl &= ~ TCC_EVCTRL_EVACT0_Msk; - switch(events->input_config[0].action) { - case TCC_EVENT0_ACTION_OFF: - evctrl |= TCC_EVCTRL_EVACT0_OFF; - break; - case TCC_EVENT0_ACTION_RETRIGGER: - evctrl |= TCC_EVCTRL_EVACT0_RETRIGGER; - break; - case TCC_EVENT0_ACTION_COUNT_EVENT: - evctrl |= TCC_EVCTRL_EVACT0_COUNTEV; - break; - case TCC_EVENT0_ACTION_START: - evctrl |= TCC_EVCTRL_EVACT0_START; - break; - case TCC_EVENT0_ACTION_INCREMENT: - evctrl |= TCC_EVCTRL_EVACT0_INC; - break; - case TCC_EVENT0_ACTION_COUNT_DURING_ACTIVE: - evctrl |= TCC_EVCTRL_EVACT0_COUNT; - break; - case TCC_EVENT0_ACTION_NON_RECOVERABLE_FAULT: - evctrl |= TCC_EVCTRL_EVACT0_FAULT; - break; - default: - Assert(false); - /* Wrong configuration */ - return STATUS_ERR_INVALID_ARG; - } - } - /* Setup input event1 */ - if (events->on_input_event_perform_action[1]) { - evctrl |= TCC_EVCTRL_TCEI1; - } - if (events->input_config[1].invert) { - evctrl |= TCC_EVCTRL_TCINV1; - } - if (events->input_config[1].modify_action) { - evctrl &= ~ TCC_EVCTRL_EVACT1_Msk; - switch(events->input_config[1].action) { - case TCC_EVENT1_ACTION_OFF: - evctrl |= TCC_EVCTRL_EVACT1_OFF; - break; - case TCC_EVENT1_ACTION_RETRIGGER: - evctrl |= TCC_EVCTRL_EVACT1_RETRIGGER; - break; - case TCC_EVENT1_ACTION_DIR_CONTROL: - evctrl |= TCC_EVCTRL_EVACT1_DIR; - break; - case TCC_EVENT1_ACTION_STOP: - evctrl |= TCC_EVCTRL_EVACT1_STOP; - break; - case TCC_EVENT1_ACTION_DECREMENT: - evctrl |= TCC_EVCTRL_EVACT1_DEC; - break; - case TCC_EVENT1_ACTION_PERIOD_PULSE_WIDTH_CAPTURE: - evctrl |= TCC_EVCTRL_EVACT1_PPW | - TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1; - break; - case TCC_EVENT1_ACTION_PULSE_WIDTH_PERIOD_CAPTURE: - evctrl |= TCC_EVCTRL_EVACT1_PWP | - TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1; - break; - case TCC_EVENT1_ACTION_NON_RECOVERABLE_FAULT: - evctrl |= TCC_EVCTRL_EVACT1_FAULT; - break; - default: - Assert(false); - /* Wrong configuration */ - return STATUS_ERR_INVALID_ARG; - } - } - uint32_t ch; - for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) { - if (events->generate_event_on_channel[ch]) { - evctrl |= (TCC_EVCTRL_MCEO(1) << ch); - } - if (events->on_event_perform_channel_action[ch]) { - evctrl |= (TCC_EVCTRL_MCEI(1) << ch); - } - } - if (events->generate_event_on_counter_overflow) { - evctrl |= TCC_EVCTRL_OVFEO; - } - if (events->generate_event_on_counter_retrigger) { - evctrl |= TCC_EVCTRL_TRGEO; - } - if (events->generate_event_on_counter_event) { - evctrl |= TCC_EVCTRL_CNTEO; - } - - tcc_module->EVCTRL.reg = evctrl; - - return STATUS_OK; -} - -/** - * \brief Disables the event input or output of a TCC instance. - * - * Disables one or more input or output events for the given TCC module. - * See \ref tcc_events for a list of events this module supports. - * - * \note Events cannot be altered while the module is enabled. - * - * \param[in] module_inst Pointer to the software module instance struct - * \param[in] events Struct containing flags of events to disable - */ -void tcc_disable_events( - struct tcc_module *const module_inst, - struct tcc_events *const events) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - Assert(events); - - Tcc *const tcc_module = module_inst->hw; - - /* Check if it's enabled or resetting. */ - if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) { - return; - } - - - uint32_t evctrl = 0; - uint32_t ch; - for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) { - if (events->generate_event_on_channel[ch]) { - evctrl |= (TCC_EVCTRL_MCEO(1) << ch); - } - if (events->on_event_perform_channel_action[ch]) { - evctrl |= (TCC_EVCTRL_MCEI(1) << ch); - } - } - if (events->generate_event_on_counter_overflow) { - evctrl |= TCC_EVCTRL_OVFEO; - } - if (events->generate_event_on_counter_retrigger) { - evctrl |= TCC_EVCTRL_TRGEO; - } - if (events->generate_event_on_counter_event) { - evctrl |= TCC_EVCTRL_CNTEO; - } - if (events->on_input_event_perform_action[0]) { - evctrl |= TCC_EVCTRL_TCEI0; - } - if (events->on_input_event_perform_action[1]) { - evctrl |= TCC_EVCTRL_TCEI1; - } - if (events->input_config[0].invert) { - evctrl |= TCC_EVCTRL_TCINV0; - } - if (events->input_config[1].invert) { - evctrl |= TCC_EVCTRL_TCINV1; - } - - tcc_module->EVCTRL.reg &= ~evctrl; -} - - - -/** - * \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 Get count value of the given TCC module. - * - * Retrieves the current count value of a TCC module. The specified TCC module - * can remain running or stopped. - * - * \param[in] module_inst Pointer to the software module instance struct - * - * \return Count value of the specified TCC module. - */ -uint32_t tcc_get_count_value( - const struct tcc_module *const module_inst) -{ - /* 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; - uint32_t last_cmd; - - /* Wait last command done */ - do { - while (tcc_module->SYNCBUSY.bit.CTRLB) { - /* Wait for sync */ - } - last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; - if (TCC_CTRLBSET_CMD_NONE == last_cmd) { - /* Issue read command and break */ - tcc_module->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val; - break; - } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) { - /* Command have been issued */ - break; - } - } while (1); - - while (tcc_module->SYNCBUSY.bit.COUNT) { - /* Wait for sync */ - } - return (tcc_module->COUNT.reg); -} - - - -/** - * \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 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) - tcc_module->CCBUF[channel_index].reg = compare; -#else - 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 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_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] 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); - - return _tcc_set_compare_value(module_inst, channel_index, compare, - module_inst->double_buffering_enabled); -} - -/** - * \brief Sets a TCC module compare value and buffer value. - * - * Writes compare value and buffer to the given TCC module compare/capture - * channel. Usually as preparation for double buffer or circulared double buffer - * (circular buffer). - * - * \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 - * \param[in] compare_buffer New compare buffer 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_double_buffer_compare_values( - struct tcc_module *const module_inst, - const enum tcc_match_capture_channel channel_index, - const uint32_t compare, const uint32_t compare_buffer) -{ - /* Sanity check arguments */ - Assert(module_inst); - - enum status_code status; - status = _tcc_set_compare_value(module_inst, channel_index, compare, false); - if (status != STATUS_OK) { - return status; - } - return _tcc_set_compare_value(module_inst, channel_index, compare_buffer, - true); -} - - -/** - * \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) || (SAML22) - 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 Set the timer TOP/PERIOD value. - * - * This function writes the given value to the PER/PERB register. - * - * If double buffering is enabled it always write to the buffer - * register (PERB). 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. - * - * When using MFRQ, the top value is defined by the CC0 register value and the - * PER value is ignored, so - * \ref tcc_set_compare_value (module,channel_0,value) must be used instead of - * this function to change the actual top value in that case. - * 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 value to be loaded into the PER/PERB register - * - * \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); - - return _tcc_set_top_value(module_inst, top_value, - module_inst->double_buffering_enabled); -} - -/** - * \brief Set the timer TOP/PERIOD value and buffer value. - * - * This function writes the given value to the PER and PERB register. Usually as - * preparation for double buffer or circulared double buffer (circular buffer). - * - * When using MFRQ, the top values are defined by the CC0 and CCB0, the PER and - * PERB values are ignored, so - * \ref tcc_set_double_buffer_compare_values (module,channel_0,value,buffer) must - * be used instead of this function to change the actual top values in that - * case. For all other waveforms operation the top values are defined by PER and - * PERB registers values. - * - * \param[in] module_inst Pointer to the software module instance struct - * \param[in] top_value New value to be loaded into the PER register - * \param[in] top_buffer_value New value to be loaded into the PERB register - * - * \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_double_buffer_top_values( - const struct tcc_module *const module_inst, - const uint32_t top_value, const uint32_t top_buffer_value) -{ - /* Sanity check arguments */ - Assert(module_inst); - - enum status_code status; - status = _tcc_set_top_value(module_inst, top_value, false); - if (status != STATUS_OK) { - return status; - } - return _tcc_set_top_value(module_inst, top_buffer_value, true); -} - - -/** - * \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) || (SAML22) - 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; -} - -/** - * \brief Retrieves the current module status. - * - * Retrieves the status of the module, giving overall state information. - * - * \param[in] module_inst Pointer to the TCC software instance struct - * - * \return Bitmask of \c TCC_STATUS_* flags. - * - * \retval TCC_STATUS_CHANNEL_MATCH_CAPTURE(n) Channel n match/capture has occured - * \retval TCC_STATUS_CHANNEL_OUTPUT(n) Channel n match/capture output state - * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) Non-recoverable fault x has occured - * \retval TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) Recoverable fault n has occured - * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) Non-recoverable fault x input present - * \retval TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) Recoverable fault n input present - * \retval TCC_STATUS_SYNC_READY None of register is syncing - * \retval TCC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed - * \retval TCC_STATUS_COUNTER_EVENT Timer counter event has occurred - * \retval TCC_STATUS_COUNT_OVERFLOW Timer count value has overflowed - * \retval TCC_STATUS_COUNTER_RETRIGGERED Timer counter has been retriggered - * \retval TCC_STATUS_STOP Timer counter has been stopped - * \retval TCC_STATUS_RAMP_CYCLE_INDEX Wave ramp index for cycle - */ -uint32_t tcc_get_status( - struct tcc_module *const module_inst) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - - uint32_t int_flags = module_inst->hw->INTFLAG.reg; - uint32_t status_flags = module_inst->hw->STATUS.reg; - uint32_t status = 0; - int i; - - /* SYNC */ - if (module_inst->hw->SYNCBUSY.reg == 0) { - status |= TCC_STATUS_SYNC_READY; - } - - /* Channels */ - for (i = 0; i < TCC_NUM_CHANNELS; i++) { - if (int_flags & TCC_INTFLAG_MC(i)) { - status |= TCC_STATUS_CHANNEL_MATCH_CAPTURE(i); - } - if (status_flags & TCC_STATUS_CMP(i)) { - status |= TCC_STATUS_CHANNEL_OUTPUT(i); - } - } - /* Non-recoverable fault state */ - if ((int_flags & TCC_INTFLAG_FAULT1) || - (status_flags & TCC_STATUS_FAULT1)) { - status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1); - } - if ((int_flags & TCC_INTFLAG_FAULT0) || - (status_flags & TCC_STATUS_FAULT0)) { - status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0); - } - /* Non-recoverable fault inputs */ - if (status_flags & TCC_STATUS_FAULT0IN) { - status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0); - } - if (status_flags & TCC_STATUS_FAULT1IN) { - status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(1); - } - /* Recoverable fault state */ - if ((int_flags & TCC_INTFLAG_FAULTB) || - (status_flags & TCC_STATUS_FAULTB)) { - status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1); - } - if ((int_flags & TCC_INTFLAG_FAULTA) || - (status_flags & TCC_STATUS_FAULTA)) { - status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0); - } - /* Recoverable fault inputs */ - if (status_flags & TCC_STATUS_FAULTAIN) { - status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(0); - } - if (status_flags & TCC_STATUS_FAULTBIN) { - status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(1); - } - - /* Check for TCC capture overflow */ - if (int_flags & TCC_INTFLAG_ERR) { - status |= TCC_STATUS_CAPTURE_OVERFLOW; - } - /* Check for TCC count counter */ - if (int_flags & TCC_INTFLAG_CNT) { - status |= TCC_STATUS_COUNTER_EVENT; - } - /* Check for TCC count retrigger */ - if (int_flags & TCC_INTFLAG_TRG) { - status |= TCC_STATUS_COUNTER_RETRIGGERED; - } - /* Check for TCC count overflow */ - if (int_flags & TCC_INTFLAG_OVF) { - status |= TCC_STATUS_COUNT_OVERFLOW; - } - /* Check for TCC count stop */ - if (status_flags & TCC_STATUS_STOP) { - status |= TCC_STATUS_STOPPED; - } - return status; -} - -/** - * \brief Clears a module status flag. - * - * Clears the given status flag of the module. - * - * \param[in] module_inst Pointer to the TCC software instance struct - * \param[in] status_flags Bitmask of \c TCC_STATUS_* flags to clear - */ -void tcc_clear_status( - struct tcc_module *const module_inst, - const uint32_t status_flags) -{ - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - - uint32_t int_clr = 0; - uint32_t status_clr = 0; - int i; - - /* Channels */ - for (i = 0; i < TCC_NUM_CHANNELS; i++) { - if (status_flags & TCC_STATUS_CHANNEL_MATCH_CAPTURE(i)) { - int_clr |= TCC_INTFLAG_MC(i); - } - } - /* Faults */ - if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1)) { - int_clr |= TCC_INTFLAG_FAULT1; - status_clr |= TCC_STATUS_FAULT1; - } - if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0)) { - int_clr |= TCC_INTFLAG_FAULT0; - status_clr |= TCC_STATUS_FAULT0; - } - if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1)) { - int_clr |= TCC_INTFLAG_FAULTB; - status_clr |= TCC_STATUS_FAULTB; - } - if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0)) { - int_clr |= TCC_INTFLAG_FAULTA; - status_clr |= TCC_STATUS_FAULTA; - } - /* Check for TCC capture overflow */ - if (status_flags & TCC_STATUS_CAPTURE_OVERFLOW) { - int_clr |= TCC_INTFLAG_ERR; - } - /* Check for TCC count counter */ - if (status_flags & TCC_STATUS_COUNTER_EVENT) { - int_clr |= TCC_INTFLAG_CNT; - } - /* Check for TCC count retrigger */ - if (status_flags & TCC_STATUS_COUNTER_RETRIGGERED) { - int_clr = TCC_INTFLAG_TRG; - } - /* Check for TCC count overflow */ - if (status_flags & TCC_STATUS_COUNT_OVERFLOW) { - int_clr |= TCC_INTFLAG_OVF; - } - /* Clear status flag */ - module_inst->hw->STATUS.reg = status_clr; - /* Clear interrupt flag */ - module_inst->hw->INTFLAG.reg = int_clr; -} - -/** - * \brief Enable circular option for double buffered compare values. - * - * Enable circular option for the double buffered channel compare values. - * On each UPDATE condition, the contents of CCBx and CCx are switched, meaning - * that the contents of CCBx are transferred to CCx and the contents of CCx are - * transferred to CCBx. - * - * \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_enable_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 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; -}