diff --git a/.vs/TE_Controller/v14/.atsuo b/.vs/TE_Controller/v14/.atsuo
index 6513e8e..1b9756a 100644
Binary files a/.vs/TE_Controller/v14/.atsuo and b/.vs/TE_Controller/v14/.atsuo differ
diff --git a/TE_Controller/TE_Controller.cproj b/TE_Controller/TE_Controller.cproj
index e58519a..209b33d 100644
--- a/TE_Controller/TE_Controller.cproj
+++ b/TE_Controller/TE_Controller.cproj
@@ -30,319 +30,330 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
com.atmel.avrdbg.tool.atmeliceJ41800067100
@@ -383,6 +394,8 @@
SYSTICK_MODEADC_CALLBACK_MODE=trueDAC_CALLBACK_MODE=true
+ TCC_ASYNC=false
+ TC_ASYNC=true
@@ -431,6 +444,9 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_hOptimize for size (-Os)
@@ -498,9 +514,12 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h
- -DARM_MATH_CM0PLUS=true -DBOARD=SAMD21_XPLAINED_PRO -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21J18A__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true
+ -DARM_MATH_CM0PLUS=true -DBOARD=SAMD21_XPLAINED_PRO -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21J18A__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true -DTCC_ASYNC=false -DTC_ASYNC=true../src
@@ -547,6 +566,9 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h
@@ -574,6 +596,8 @@
SYSTICK_MODEADC_CALLBACK_MODE=trueDAC_CALLBACK_MODE=true
+ TCC_ASYNC=false
+ TC_ASYNC=true
@@ -623,6 +647,9 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h-fdata-sections
@@ -691,10 +718,13 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_hDefault (-g)
- -DARM_MATH_CM0PLUS=true -DBOARD=USER_BOARD -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21E16B__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true
+ -DARM_MATH_CM0PLUS=true -DBOARD=USER_BOARD -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21E16B__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true -DTCC_ASYNC=false -DTC_ASYNC=true../src
@@ -741,6 +771,9 @@
../src/ASF/sam0/drivers/adc/adc_sam_d_r_h../src/ASF/sam0/drivers/dac../src/ASF/sam0/drivers/dac/dac_sam_d_c_h
+ ../src/ASF/sam0/drivers/tcc
+ ../src/ASF/sam0/drivers/tc
+ ../src/ASF/sam0/drivers/tc/tc_sam_d_r_hDefault (-Wa,-g)
@@ -799,6 +832,12 @@
+
+
+
+
+
+
@@ -886,6 +925,33 @@
compile
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+
+
+ compile
+ compile
@@ -949,9 +1015,6 @@
compile
-
- compile
- compile
@@ -1681,15 +1744,39 @@
compile
+
+ compile
+
+
+ compile
+ compile
+
+ compile
+
+
+ compile
+
+
+ compile
+ compile
+
+ compile
+ compile
+
+ compile
+
+
+ compile
+ compile
@@ -1699,15 +1786,39 @@
compile
+
+ compile
+
+
+ compile
+ compile
+
+ compile
+
+
+ compile
+
+
+ compile
+ compile
+
+ compile
+ compile
+
+ compile
+
+
+ compile
+ compile
diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc.h b/TE_Controller/src/ASF/sam0/drivers/tc/tc.h
new file mode 100644
index 0000000..2ed1f48
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc.h
@@ -0,0 +1,1788 @@
+/**
+ * \file
+ *
+ * \brief SAM TC - Timer Counter Driver
+ *
+ * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#ifndef TC_H_INCLUDED
+#define TC_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_sam0_tc_group SAM Timer/Counter (TC) Driver
+ *
+ * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration
+ * and management of the timer modules within the device, for waveform
+ * generation and timing operations. The following driver API modes are covered
+ * by this manual:
+ *
+ * - Polled APIs
+ * \if TC_CALLBACK_MODE
+ * - Callback APIs
+ * \endif
+ *
+ *
+ * The following peripheral is used by this module:
+ * - TC (Timer/Counter)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ * - Atmel | SMART SAM HA1
+ * - Atmel | SMART SAM R30
+ * - Atmel | SMART SAM R34
+ * - Atmel | SMART SAM R35
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_tc_prerequisites
+ * - \ref asfdoc_sam0_tc_module_overview
+ * - \ref asfdoc_sam0_tc_special_considerations
+ * - \ref asfdoc_sam0_tc_extra_info
+ * - \ref asfdoc_sam0_tc_examples
+ * - \ref asfdoc_sam0_tc_api_overview
+ *
+ *
+ * \section asfdoc_sam0_tc_prerequisites Prerequisites
+ *
+ * There are no prerequisites for this module.
+ *
+ *
+ * \section asfdoc_sam0_tc_module_overview Module Overview
+ *
+ * The Timer/Counter (TC) module provides a set of timing and counting related
+ * functionality, such as the generation of periodic waveforms, the capturing
+ * of a periodic waveform's frequency/duty cycle, and software timekeeping for
+ * periodic operations. TC modules can be configured to use an 8-, 16-, or
+ * 32-bit counter size.
+ *
+ * This TC module for the SAM is capable of the following functions:
+ *
+ * - Generation of PWM signals
+ * - Generation of timestamps for events
+ * - General time counting
+ * - Waveform period capture
+ * - Waveform frequency capture
+ *
+ * \ref asfdoc_sam0_tc_block_diagram "The diagram below" shows the overview
+ * of the TC module design.
+ *
+ * \anchor asfdoc_sam0_tc_block_diagram
+ * \image html overview.svg "Basic Overview of the TC Module"
+ *
+ *
+ * \subsection asfdoc_sam0_tc_features Driver Feature Macro Definition
+ *
+ *
+ *
Driver Feature Macro
+ *
Supported devices
+ *
+ *
+ *
FEATURE_TC_DOUBLE_BUFFERED
+ *
SAM L21/L22/C20/C21/R30/R34/R35
+ *
+ *
+ *
FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2
+ *
SAM L21/L22/C20/C21/R30/R34/R35
+ *
+ *
+ *
FEATURE_TC_STAMP_PW_CAPTURE
+ *
SAM L21/L22/C20/C21/R30/R34/R35
+ *
+ *
+ *
FEATURE_TC_READ_SYNC
+ *
SAM L21/L22/C20/C21/R30/R34/R35
+ *
+ *
+ *
FEATURE_TC_IO_CAPTURE
+ *
SAM L21/L22/C20/C21/R30/R34/R35
+ *
+ *
+ *
FEATURE_TC_GENERATE_DMA_TRIGGER
+ *
SAM L21/L22/R30/R34/R35
+ *
+ *
+ * \note The specific features are only available in the driver when the
+ * selected device supports those features.
+ *
+ * \subsection asfdoc_sam0_tc_module_overview_func_desc Functional Description
+ * Independent of the configured counter size, each TC module can be set up
+ * in one of two different modes; capture and compare.
+ *
+ * In capture mode, the counter value is stored when a configurable event
+ * occurs. This mode can be used to generate timestamps used in event capture,
+ * or it can be used for the measurement of a periodic input signal's
+ * frequency/duty cycle.
+ *
+ * In compare mode, the counter value is compared against one or more of the
+ * configured channel compare values. When the counter value coincides with a
+ * compare value an action can be taken automatically by the module, such as
+ * generating an output event or toggling a pin when used for frequency or
+ * Pulse Width Modulation (PWM) signal generation.
+ *
+ * \note The connection of events between modules requires the use of the
+ * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)"
+ * to route output event of one module to the input event of another.
+ * For more information on event routing, refer to the event driver
+ * documentation.
+ *
+ * \subsection asfdoc_sam0_tc_module_overview_tc_size Timer/Counter Size
+ * Each timer module can be configured in one of three different counter
+ * sizes; 8-, 16-, and 32-bit. The size of the counter determines the maximum
+ * value it can count to before an overflow occurs and the count is reset back
+ * to zero. \ref asfdoc_sam0_tc_count_size_vs_top "The table below" shows the
+ * maximum values for each of the possible counter sizes.
+ *
+ * \anchor asfdoc_sam0_tc_count_size_vs_top
+ *
+ *
Timer Counter Sizes and Their Maximum Count Values
+ *
+ *
Counter size
+ *
Max. (hexadecimal)
+ *
Max. (decimal)
+ *
+ *
+ *
8-bit
+ *
0xFF
+ *
255
+ *
+ *
+ *
16-bit
+ *
0xFFFF
+ *
65,535
+ *
+ *
+ *
32-bit
+ *
0xFFFFFFFF
+ *
4,294,967,295
+ *
+ *
+ *
+ * When using the counter in 16- or 32-bit count mode, Compare Capture
+ * register 0 (CC0) is used to store the period value when running in PWM
+ * generation match mode.
+ *
+ * When using 32-bit counter size, two 16-bit counters are chained together
+ * in a cascade formation. Except in SAM D09/D10/D11. Even numbered TC modules
+ * (e.g. TC0, TC2) can be configured as 32-bit counters. The odd numbered
+ * counters will act as slaves to the even numbered masters, and will not
+ * be reconfigurable until the master timer is disabled. The pairing of timer
+ * modules for 32-bit mode is shown in \ref asfdoc_sam0_tc_module_ms_pairs
+ * "the table below".
+ *
+ * \anchor asfdoc_sam0_tc_module_ms_pairs
+ *
+ *
TC Master and Slave Module Pairings
+ *
+ *
Master TC module
+ *
Slave TC module
+ *
+ *
+ *
TC0
+ *
TC1
+ *
+ *
+ *
TC2
+ *
TC3
+ *
+ *
+ *
...
+ *
...
+ *
+ *
+ *
TCn-1
+ *
TCn
+ *
+ *
+ *
+ * In SAM D09/D10/D11, odd numbered TC modules (e.g. TC1) can be configured as 32-bit
+ * counters. The even numbered (e.g. TC2) counters will act as slaves to the odd
+ * numbered masters.
+ *
+ * \subsection asfdoc_sam0_tc_module_overview_clock Clock Settings
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_clock_selection Clock Selection
+ * Each TC peripheral is clocked asynchronously to the system clock by a GCLK
+ * (Generic Clock) channel. The GCLK channel connects to any of the GCLK
+ * generators. The GCLK generators are configured to use one of the available
+ * clock sources on the system such as internal oscillator, external crystals,
+ * etc. See the \ref asfdoc_sam0_system_clock_group "Generic Clock driver"
+ *for
+ * more information.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_clock_prescaler Prescaler
+ * Each TC module in the SAM has its own individual clock prescaler, which
+ * can be used to divide the input clock frequency used in the counter. This
+ * prescaler only scales the clock used to provide clock pulses for the counter
+ * to count, and does not affect the digital register interface portion of
+ * the module, thus the timer registers will synchronize to the raw GCLK
+ * frequency input to the module.
+ *
+ * As a result of this, when selecting a GCLK frequency and timer prescaler
+ * value the user application should consider both the timer resolution
+ * required and the synchronization frequency, to avoid lengthy
+ * synchronization times of the module if a very slow GCLK frequency is fed
+ * into the TC module. It is preferable to use a higher module GCLK frequency
+ * as the input to the timer, and prescale this down as much as possible to
+ * obtain a suitable counter frequency in latency-sensitive applications.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_clock_reloading Reloading
+ * Timer modules also contain a configurable reload action, used when a
+ * re-trigger event occurs. Examples of a re-trigger event are the counter
+ * reaching the maximum value when counting up, or when an event from the event
+ * system tells the counter to re-trigger. The reload action determines if the
+ * prescaler should be reset, and when this should happen. The counter will
+ * always be reloaded with the value it is set to start counting from. The user
+ * can choose between three different reload actions, described in
+ * \ref asfdoc_sam0_tc_module_reload_act "the table below".
+ *
+ * \anchor asfdoc_sam0_tc_module_reload_act
+ *
+ *
TC Module Reload Actions
+ *
+ *
Reload action
+ *
Description
+ *
+ *
+ *
\ref TC_RELOAD_ACTION_GCLK
+ *
Reload TC counter value on next GCLK cycle. Leave prescaler
+ * as-is.
+ *
+ *
+ *
\ref TC_RELOAD_ACTION_PRESC
+ *
Reloads TC counter value on next prescaler clock. Leave prescaler
+ * as-is.
+ *
+ *
+ *
\ref TC_RELOAD_ACTION_RESYNC
+ *
Reload TC counter value on next GCLK cycle. Clear prescaler to
+ * zero.
+ *
+ *
+ *
+ * The reload action to use will depend on the specific application being
+ * implemented. One example is when an external trigger for a reload occurs; if
+ * the TC uses the prescaler, the counter in the prescaler should not have a
+ * value between zero and the division factor. The TC counter and the counter
+ * in the prescaler should both start at zero. When the counter is set to
+ * re-trigger when it reaches the maximum value on the other hand, this is not the
+ * right option to use. In such a case it would be better if the prescaler is
+ * left unaltered when the re-trigger happens, letting the counter reset on the
+ * next GCLK cycle.
+ *
+ * \subsection asfdoc_sam0_tc_module_overview_compare_match Compare Match Operations
+ * In compare match operation, Compare/Capture registers are used in comparison
+ * with the counter value. When the timer's count value matches the value of a
+ * compare channel, a user defined action can be taken.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_timer Basic Timer
+ *
+ * A Basic Timer is a simple application where compare match operations are used
+ * to determine when a specific period has elapsed. In Basic Timer operations,
+ * one or more values in the module's Compare/Capture registers are used to
+ * specify the time (as a number of prescaled GCLK cycles) when an action should
+ * be taken by the microcontroller. This can be an Interrupt Service Routine
+ * (ISR), event generator via the event system, or a software flag that is
+ * polled via the user application.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg Waveform Generation
+ *
+ * Waveform generation enables the TC module to generate square waves, or if
+ * combined with an external passive low-pass filter; analog waveforms.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_pwm Waveform Generation - PWM
+ *
+ * Pulse width modulation is a form of waveform generation and a signalling
+ * technique that can be useful in many situations. When PWM mode is used,
+ * a digital pulse train with a configurable frequency and duty cycle can be
+ * generated by the TC module and output to a GPIO pin of the device.
+ *
+ * Often PWM is used to communicate a control or information parameter to an
+ * external circuit or component. Differing impedances of the source generator
+ * and sink receiver circuits are less of an issue when using PWM compared to
+ * using an analog voltage value, as noise will not generally affect the
+ * signal's integrity to a meaningful extent.
+ *
+ * \ref asfdoc_sam0_tc_module_pwm_normal_diag "The figure below" illustrates
+ * operations and different states of the counter and its output when running
+ * the counter in PWM normal mode. As can be seen, the TOP value is unchanged
+ * and is set to MAX. The compare match value is changed at several points to
+ * illustrate the resulting waveform output changes. The PWM output is set to
+ * normal (i.e. non-inverted) output mode.
+ *
+ * \anchor asfdoc_sam0_tc_module_pwm_normal_diag
+ * \image html pwm_normal_ex.svg "Example of PWM in Normal Mode, and Different Counter Operations"
+ *
+ *
+ * In \ref asfdoc_sam0_tc_module_pwm_match_diag "the figure below", the
+ * counter is set to generate PWM in Match mode. The PWM output is inverted via
+ * the appropriate configuration option in the TC driver configuration
+ * structure. In this example, the counter value is changed once, but the
+ * compare match value is kept unchanged. As can be seen, it is possible to
+ * change the TOP value when running in PWM match mode.
+ *
+ * \anchor asfdoc_sam0_tc_module_pwm_match_diag
+ * \image html pwm_match_ex.svg "Example of PWM in Match Mode and Different Counter Operations"
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_freq Waveform Generation - Frequency
+ *
+ * Frequency Generation mode is in many ways identical to PWM
+ * generation. However, in Frequency Generation a toggle only occurs
+ * on the output when a match on a capture channels occurs. When the
+ * match is made, the timer value is reset, resulting in a variable
+ * frequency square wave with a fixed 50% duty cycle.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt Capture Operations
+ *
+ * In capture operations, any event from the event system or a pin change can
+ * trigger a capture of the counter value. This captured counter value can be
+ * used as a timestamp for the event, or it can be used in frequency and pulse
+ * width capture.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_event_capture Capture Operations - Event
+ *
+ * Event capture is a simple use of the capture functionality,
+ * designed to create timestamps for specific events. When the TC
+ * module's input capture pin is externally toggled, the current timer
+ * count value is copied into a buffered register which can then be
+ * read out by the user application.
+ *
+ * Note that when performing any capture operation, there is a risk that the
+ * counter reaches its top value (MAX) when counting up, or the bottom value
+ * (zero) when counting down, before the capture event occurs. This can distort
+ * the result, making event timestamps to appear shorter than reality; the
+ * user application should check for timer overflow when reading a capture
+ * result in order to detect this situation and perform an appropriate
+ * adjustment.
+ *
+ * Before checking for a new capture, \ref TC_STATUS_COUNT_OVERFLOW
+ * should be checked. The response to an overflow error is left to the user
+ * application, however it may be necessary to clear both the capture overflow
+ * flag and the capture flag upon each capture reading.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_pwc Capture Operations - Pulse Width
+ *
+ * Pulse Width Capture mode makes it possible to measure the pulse width and
+ * period of PWM signals. This mode uses two capture channels of the counter.
+ * This means that the counter module used for Pulse Width Capture can not be
+ * used for any other purpose. There are two modes for pulse width capture;
+ * Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture
+ * channel 0 is used for storing the pulse width and capture channel 1 stores
+ * the observed period. While in PPW mode, the roles of the two capture channels
+ * are reversed.
+ *
+ * As in the above example it is necessary to poll on interrupt flags to see
+ * if a new capture has happened and check that a capture overflow error has
+ * not occurred.
+ *
+ * \subsection asfdoc_sam0_tc_module_overview_oneshot One-shot Mode
+ *
+ * TC modules can be configured into a one-shot mode. When configured in this
+ * manner, starting the timer will cause it to count until the next overflow
+ * or underflow condition before automatically halting, waiting to be manually
+ * triggered by the user application software or an event signal from the event
+ * system.
+ *
+ * \subsubsection asfdoc_sam0_tc_module_overview_inversion Wave Generation Output Inversion
+ *
+ * The output of the wave generation can be inverted by hardware if desired,
+ * resulting in the logically inverted value being output to the configured
+ * device GPIO pin.
+ *
+ *
+ * \section asfdoc_sam0_tc_special_considerations Special Considerations
+ *
+ * The number of capture compare registers in each TC module is dependent on
+ * the specific SAM device being used, and in some cases the counter size.
+ *
+ * The maximum amount of capture compare registers available in any SAM
+ * device is two when running in 32-bit mode and four in 8- and 16-bit modes.
+ *
+ *
+ * \section asfdoc_sam0_tc_extra_info Extra Information
+ *
+ * For extra information, see \ref asfdoc_sam0_tc_extra. This includes:
+ * - \ref asfdoc_sam0_tc_extra_acronyms
+ * - \ref asfdoc_sam0_tc_extra_dependencies
+ * - \ref asfdoc_sam0_tc_extra_errata
+ * - \ref asfdoc_sam0_tc_extra_history
+ *
+ *
+ * \section asfdoc_sam0_tc_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_tc_exqsg.
+ *
+ * \section asfdoc_sam0_tc_api_overview API Overview
+ * @{
+ */
+
+#include
+#include
+#include
+#include
+
+/**
+ * Define port features set according to different device family
+ * @{
+*/
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)|| (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__)
+/** TC double buffered. */
+# define FEATURE_TC_DOUBLE_BUFFERED
+/** SYNCBUSY scheme version 2. */
+# define FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2
+/** TC time stamp capture and pulse width capture. */
+# define FEATURE_TC_STAMP_PW_CAPTURE
+/** Read synchronization of COUNT. */
+# define FEATURE_TC_READ_SYNC
+/** I/O pin edge capture. */
+# define FEATURE_TC_IO_CAPTURE
+#endif
+
+#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__)
+/** Generate Direct Memory Access (DMA) triggers. */
+# define FEATURE_TC_GENERATE_DMA_TRIGGER
+#endif
+/*@}*/
+
+#if !defined(__DOXYGEN__)
+#if SAMD20 || SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089)
+# define TC_INSTANCE_OFFSET 0
+#endif
+#if SAMD21 || SAMR21 || SAMDA1 || (SAMHA1) || (SAMHA0)
+# define TC_INSTANCE_OFFSET 3
+#endif
+#if SAMD09 || SAMD10 || SAMD11
+# define TC_INSTANCE_OFFSET 1
+#endif
+
+#if SAMD20
+# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC8_NUM
+#elif SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089)
+# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC_NUM
+#elif SAMD09 || SAMD10 || SAMD11
+# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC1_CC8_NUM
+#else
+# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC3_CC8_NUM
+ /* Same number for 8-, 16- or 32-bit TC and all TC instances */
+#endif
+
+/** TC Instance MAX ID Number. */
+#if SAMD20E || SAMD20G || SAMD21G || SAMD21E || SAMR21
+# if SAMD21GXXL || SAM_PART_IS_DEFINED(SAMD21G17AU) || SAM_PART_IS_DEFINED(SAMD21G18AU)
+# define TC_INST_MAX_ID 7
+# else
+# define TC_INST_MAX_ID 5
+# endif
+#elif SAML21 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089)
+# define TC_INST_MAX_ID 4
+#elif SAML22
+# define TC_INST_MAX_ID 3
+#elif SAMD09 || SAMD10 || SAMD11
+# define TC_INST_MAX_ID 2
+#else
+# define TC_INST_MAX_ID 7
+#endif
+
+#endif
+
+#if TC_ASYNC == true
+# include
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if TC_ASYNC == true
+/** Enum for the possible callback types for the TC module. */
+enum tc_callback {
+ /** Callback for TC overflow */
+ TC_CALLBACK_OVERFLOW,
+ /** Callback for capture overflow error */
+ TC_CALLBACK_ERROR,
+ /** Callback for capture compare channel 0 */
+ TC_CALLBACK_CC_CHANNEL0,
+ /** Callback for capture compare channel 1 */
+ TC_CALLBACK_CC_CHANNEL1,
+# if !defined(__DOXYGEN__)
+ /** Number of available callbacks */
+ TC_CALLBACK_N,
+# endif
+};
+#endif
+
+/**
+ * \name Module Status Flags
+ *
+ * TC status flags, returned by \ref tc_get_status() and cleared by
+ * \ref tc_clear_status().
+ *
+ * @{
+ */
+
+/** Timer channel 0 has matched against its compare value, or has captured a
+ * new value.
+ */
+#define TC_STATUS_CHANNEL_0_MATCH (1UL << 0)
+
+/** Timer channel 1 has matched against its compare value, or has captured a
+ * new value.
+ */
+#define TC_STATUS_CHANNEL_1_MATCH (1UL << 1)
+
+/** Timer register synchronization has completed, and the synchronized count
+ * value may be read.
+ */
+#define TC_STATUS_SYNC_READY (1UL << 2)
+
+/** A new value was captured before the previous value was read, resulting in
+ * lost data.
+ */
+#define TC_STATUS_CAPTURE_OVERFLOW (1UL << 3)
+
+/** The timer count value has overflowed from its maximum value to its minimum
+ * when counting upward, or from its minimum value to its maximum when
+ * counting downward.
+ */
+#define TC_STATUS_COUNT_OVERFLOW (1UL << 4)
+
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+/** Channel 0 compare or capture buffer valid. */
+#define TC_STATUS_CHN0_BUFFER_VALID (1UL << 5)
+/** Channel 1 compare or capture buffer valid. */
+#define TC_STATUS_CHN1_BUFFER_VALID (1UL << 6)
+/** Period buffer valid. */
+#define TC_STATUS_PERIOD_BUFFER_VALID (1UL << 7)
+#endif
+/** @} */
+
+/**
+ * \brief Index of the compare capture channels.
+ *
+ * This enum is used to specify which capture/compare channel to do
+ * operations on.
+ */
+enum tc_compare_capture_channel {
+ /** Index of compare capture channel 0 */
+ TC_COMPARE_CAPTURE_CHANNEL_0,
+ /** Index of compare capture channel 1 */
+ TC_COMPARE_CAPTURE_CHANNEL_1,
+};
+
+/**
+ * \name TC Wave Generation Mode
+ *
+ * @{
+ */
+#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089)
+/** TC wave generation mode: normal frequency. */
+#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_WAVE_WAVEGEN_NFRQ
+/** TC wave generation mode: match frequency. */
+#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_WAVE_WAVEGEN_MFRQ
+/** TC wave generation mode: normal PWM. */
+#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_WAVE_WAVEGEN_NPWM
+/** TC wave generation mode: match PWM. */
+#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_WAVE_WAVEGEN_MPWM
+#else
+/** TC wave generation mode: normal frequency. */
+#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_CTRLA_WAVEGEN_NFRQ
+/** TC wave generation mode: match frequency. */
+#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_CTRLA_WAVEGEN_MFRQ
+/** TC wave generation mode: normal PWM. */
+#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_CTRLA_WAVEGEN_NPWM
+/** TC wave generation mode: match PWM. */
+#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_CTRLA_WAVEGEN_MPWM
+#endif
+/** @} */
+
+/**
+ * \brief TC wave generation mode enum.
+ *
+ * This enum is used to select which mode to run the wave
+ * generation in.
+ *
+ */
+enum tc_wave_generation {
+ /** Top is maximum, except in 8-bit counter size where it is the PER
+ * register
+ */
+ TC_WAVE_GENERATION_NORMAL_FREQ = TC_WAVE_GENERATION_NORMAL_FREQ_MODE,
+
+ /** Top is CC0, except in 8-bit counter size where it is the PER
+ * register
+ */
+ TC_WAVE_GENERATION_MATCH_FREQ = TC_WAVE_GENERATION_MATCH_FREQ_MODE,
+
+ /** Top is maximum, except in 8-bit counter size where it is the PER
+ * register
+ */
+ TC_WAVE_GENERATION_NORMAL_PWM = TC_WAVE_GENERATION_NORMAL_PWM_MODE,
+
+ /** Top is CC0, except in 8-bit counter size where it is the PER
+ * register
+ */
+ TC_WAVE_GENERATION_MATCH_PWM = TC_WAVE_GENERATION_MATCH_PWM_MODE,
+};
+
+/**
+ * \brief Specifies if the counter is 8-, 16-, or 32-bit.
+ *
+ * This enum specifies the maximum value it is possible to count to.
+ */
+enum tc_counter_size {
+ /** The counter's maximum value is 0xFF, the period register is
+ * available to be used as top value
+ */
+ TC_COUNTER_SIZE_8BIT = TC_CTRLA_MODE_COUNT8,
+
+ /** The counter's maximum value is 0xFFFF. There is no separate
+ * period register, to modify top one of the capture compare
+ * registers has to be used. This limits the amount of
+ * available channels.
+ */
+ TC_COUNTER_SIZE_16BIT = TC_CTRLA_MODE_COUNT16,
+
+ /** The counter's maximum value is 0xFFFFFFFF. There is no separate
+ * period register, to modify top one of the capture compare
+ * registers has to be used. This limits the amount of
+ * available channels.
+ */
+ TC_COUNTER_SIZE_32BIT = TC_CTRLA_MODE_COUNT32,
+};
+
+/**
+ * \brief TC Counter reload action enum.
+ *
+ * This enum specify how the counter and prescaler should reload.
+ */
+enum tc_reload_action {
+ /** The counter is reloaded/reset on the next GCLK and starts
+ * counting on the prescaler clock
+ */
+ TC_RELOAD_ACTION_GCLK = TC_CTRLA_PRESCSYNC_GCLK,
+
+ /** The counter is reloaded/reset on the next prescaler clock
+ */
+ TC_RELOAD_ACTION_PRESC = TC_CTRLA_PRESCSYNC_PRESC,
+
+ /** The counter is reloaded/reset on the next GCLK, and the
+ * prescaler is restarted as well
+ */
+ TC_RELOAD_ACTION_RESYNC = TC_CTRLA_PRESCSYNC_RESYNC,
+};
+
+/**
+ * \brief TC clock prescaler values.
+ *
+ * This enum is used to choose the clock prescaler
+ * configuration. The prescaler divides the clock frequency of the TC
+ * module to make the counter count slower.
+ */
+enum tc_clock_prescaler {
+ /** Divide clock by 1 */
+ TC_CLOCK_PRESCALER_DIV1 = TC_CTRLA_PRESCALER(0),
+ /** Divide clock by 2 */
+ TC_CLOCK_PRESCALER_DIV2 = TC_CTRLA_PRESCALER(1),
+ /** Divide clock by 4 */
+ TC_CLOCK_PRESCALER_DIV4 = TC_CTRLA_PRESCALER(2),
+ /** Divide clock by 8 */
+ TC_CLOCK_PRESCALER_DIV8 = TC_CTRLA_PRESCALER(3),
+ /** Divide clock by 16 */
+ TC_CLOCK_PRESCALER_DIV16 = TC_CTRLA_PRESCALER(4),
+ /** Divide clock by 64 */
+ TC_CLOCK_PRESCALER_DIV64 = TC_CTRLA_PRESCALER(5),
+ /** Divide clock by 256 */
+ TC_CLOCK_PRESCALER_DIV256 = TC_CTRLA_PRESCALER(6),
+ /** Divide clock by 1024 */
+ TC_CLOCK_PRESCALER_DIV1024 = TC_CTRLA_PRESCALER(7),
+};
+
+/**
+ * \brief TC module count direction.
+ *
+ * Timer/Counter count direction.
+ */
+enum tc_count_direction {
+ /** Timer should count upward from zero to MAX */
+ TC_COUNT_DIRECTION_UP,
+
+ /** Timer should count downward to zero from MAX */
+ TC_COUNT_DIRECTION_DOWN,
+};
+
+/**
+ * \name Waveform Inversion Mode
+ *
+ * @{
+ */
+#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089)
+/** Waveform inversion CC0 mode. */
+#define TC_WAVEFORM_INVERT_CC0_MODE TC_DRVCTRL_INVEN(1)
+/** Waveform inversion CC1 mode. */
+#define TC_WAVEFORM_INVERT_CC1_MODE TC_DRVCTRL_INVEN(2)
+#else
+/** Waveform inversion CC0 mode. */
+#define TC_WAVEFORM_INVERT_CC0_MODE TC_CTRLC_INVEN(1)
+/** Waveform inversion CC1 mode. */
+#define TC_WAVEFORM_INVERT_CC1_MODE TC_CTRLC_INVEN(2)
+#endif
+
+/**
+ * \brief Waveform inversion mode.
+ *
+ * Output waveform inversion mode.
+ */
+enum tc_waveform_invert_output {
+ /** No inversion of the waveform output */
+ TC_WAVEFORM_INVERT_OUTPUT_NONE = 0,
+ /** Invert output from compare channel 0 */
+ TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_0 = TC_WAVEFORM_INVERT_CC0_MODE,
+ /** Invert output from compare channel 1 */
+ TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_1 = TC_WAVEFORM_INVERT_CC1_MODE,
+};
+
+/**
+ * \brief Action to perform when the TC module is triggered by an event.
+ *
+ * Event action to perform when the module is triggered by an event.
+ */
+enum tc_event_action {
+ /** No event action */
+ TC_EVENT_ACTION_OFF = TC_EVCTRL_EVACT_OFF,
+ /** Re-trigger on event */
+ TC_EVENT_ACTION_RETRIGGER = TC_EVCTRL_EVACT_RETRIGGER,
+ /** Increment counter on event */
+ TC_EVENT_ACTION_INCREMENT_COUNTER = TC_EVCTRL_EVACT_COUNT,
+ /** Start counter on event */
+ TC_EVENT_ACTION_START = TC_EVCTRL_EVACT_START,
+
+ /** Store period in capture register 0, pulse width in capture
+ * register 1
+ */
+ TC_EVENT_ACTION_PPW = TC_EVCTRL_EVACT_PPW,
+
+ /** Store pulse width in capture register 0, period in capture
+ * register 1
+ */
+ TC_EVENT_ACTION_PWP = TC_EVCTRL_EVACT_PWP,
+#ifdef FEATURE_TC_STAMP_PW_CAPTURE
+ /** Time stamp capture */
+ TC_EVENT_ACTION_STAMP = TC_EVCTRL_EVACT_STAMP,
+ /** Pulse width capture */
+ TC_EVENT_ACTION_PW = TC_EVCTRL_EVACT_PW,
+#endif
+};
+
+/**
+ * \brief TC event enable/disable structure.
+ *
+ * Event flags for the \ref tc_enable_events() and \ref tc_disable_events().
+ */
+struct tc_events {
+ /** Generate an output event on a compare channel match */
+ bool generate_event_on_compare_channel
+ [NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+ /** Generate an output event on counter overflow */
+ bool generate_event_on_overflow;
+ /** Perform the configured event action when an incoming event is signalled */
+ bool on_event_perform_action;
+ /** Specifies if the input event source is inverted, when used in PWP or
+ * PPW event action modes
+ */
+ bool invert_event_input;
+ /** Specifies which event to trigger if an event is triggered */
+ enum tc_event_action event_action;
+};
+
+/**
+ * \brief Configuration struct for TC module in 8-bit size counter mode.
+ */
+struct tc_8bit_config {
+ /** Initial timer count value */
+ uint8_t value;
+ /** Where to count to or from depending on the direction on the counter */
+ uint8_t period;
+ /** Value to be used for compare match on each channel */
+ uint8_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+};
+
+/**
+ * \brief Configuration struct for TC module in 16-bit size counter mode.
+ */
+struct tc_16bit_config {
+ /** Initial timer count value */
+ uint16_t value;
+ /** Value to be used for compare match on each channel */
+ uint16_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+};
+
+/**
+ * \brief Configuration struct for TC module in 32-bit size counter mode.
+ */
+struct tc_32bit_config {
+ /** Initial timer count value */
+ uint32_t value;
+ /** Value to be used for compare match on each channel */
+ uint32_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+};
+
+/**
+ * \brief Configuration struct for TC module in 32-bit size counter mode.
+ */
+struct tc_pwm_channel {
+ /** When \c true, PWM output for the given channel is enabled */
+ bool enabled;
+ /** Specifies pin output for each channel */
+ uint32_t pin_out;
+ /** Specifies Multiplexer (MUX) setting for each output channel pin */
+ uint32_t pin_mux;
+};
+
+/**
+ * \brief TC configuration structure.
+ *
+ * Configuration struct for a TC instance. This structure should be
+ * initialized by the \ref tc_get_config_defaults function before being
+ * modified by the user application.
+ */
+struct tc_config {
+ /** GCLK generator used to clock the peripheral */
+ enum gclk_generator clock_source;
+
+ /** When \c true the module is enabled during standby */
+ bool run_in_standby;
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ /** Run on demand */
+ bool on_demand;
+#endif
+ /** Specifies either 8-, 16-, or 32-bit counter size */
+ enum tc_counter_size counter_size;
+ /** Specifies the prescaler value for GCLK_TC */
+ enum tc_clock_prescaler clock_prescaler;
+ /** Specifies which waveform generation mode to use */
+ enum tc_wave_generation wave_generation;
+
+ /** Specifies the reload or reset time of the counter and prescaler
+ * resynchronization on a re-trigger event for the TC
+ */
+ enum tc_reload_action reload_action;
+
+ /** Specifies which channel(s) to invert the waveform on.
+ For SAM L21/L22/C20/C21, it's also used to invert I/O input pin. */
+ uint8_t waveform_invert_output;
+
+ /** Specifies which channel(s) to enable channel capture
+ * operation on
+ */
+ bool enable_capture_on_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+#ifdef FEATURE_TC_IO_CAPTURE
+ /** Specifies which channel(s) to enable I/O capture
+ * operation on
+ */
+ bool enable_capture_on_IO[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+#endif
+
+ /** When \c true, one-shot will stop the TC on next hardware or software
+ * re-trigger event or overflow/underflow
+ */
+ bool oneshot;
+
+ /** Specifies the direction for the TC to count */
+ enum tc_count_direction count_direction;
+
+ /** Specifies the PWM channel for TC */
+ struct tc_pwm_channel pwm_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
+
+ /** Access the different counter size settings through this configuration member. */
+ union {
+ /** Struct for 8-bit specific timer configuration */
+ struct tc_8bit_config counter_8_bit;
+ /** Struct for 16-bit specific timer configuration */
+ struct tc_16bit_config counter_16_bit;
+ /** Struct for 32-bit specific timer configuration */
+ struct tc_32bit_config counter_32_bit;
+ };
+
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+ /** Set to \c true to enable double buffering write. When enabled any write
+ * through \ref tc_set_top_value(), \ref tc_set_compare_value() and
+ * will direct to the buffer register as buffered
+ * value, and the buffered value will be committed to effective register
+ * on UPDATE condition, if update is not locked.
+ */
+ bool double_buffering_enabled;
+#endif
+};
+
+#if TC_ASYNC == true
+/** Forward Declaration for the device instance. */
+struct tc_module;
+
+/** Type of the callback functions. */
+typedef void (*tc_callback_t)(struct tc_module *const module);
+#endif
+
+/**
+ * \brief TC software device instance structure.
+ *
+ * TC software instance structure, used to retain software state information
+ * of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct tc_module {
+#if !defined(__DOXYGEN__)
+ /** Hardware module pointer of the associated Timer/Counter peripheral */
+ Tc *hw;
+
+ /** Size of the initialized Timer/Counter module configuration */
+ enum tc_counter_size counter_size;
+# if TC_ASYNC == true
+ /** Array of callbacks */
+ tc_callback_t callback[TC_CALLBACK_N];
+ /** Bit mask for callbacks registered */
+ uint8_t register_callback_mask;
+ /** Bit mask for callbacks enabled */
+ uint8_t enable_callback_mask;
+# endif
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+ /** Set to \c true to enable double buffering write */
+ bool double_buffering_enabled;
+#endif
+#endif
+};
+
+#if !defined(__DOXYGEN__)
+uint8_t _tc_get_inst_index(
+ Tc *const hw);
+#endif
+
+/**
+ * \name Driver Initialization and Configuration
+ * @{
+ */
+
+/**
+ * \brief Determines if the hardware module(s) are currently synchronizing to
+ * the bus.
+ *
+ * Checks to see if the underlying hardware peripheral module(s) are currently
+ * synchronizing across multiple clock domains to the hardware bus. This
+ * function can be used to delay further operations on a module until such time
+ * that it is ready, to prevent blocking delays for synchronization in the
+ * user application.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ *
+ * \return Synchronization status of the underlying hardware module(s).
+ *
+ * \retval false If the module has completed synchronization
+ * \retval true If the module synchronization is ongoing
+ */
+static inline bool tc_is_syncing(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ return (tc_module->SYNCBUSY.reg);
+#else
+ return (tc_module->STATUS.reg & TC_STATUS_SYNCBUSY);
+#endif
+}
+
+/**
+ * \brief Initializes config with predefined default values.
+ *
+ * This function will initialize a given TC 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 GCLK generator 0 (GCLK main) clock source
+ * \li 16-bit counter size on the counter
+ * \li No prescaler
+ * \li Normal frequency wave generation
+ * \li GCLK reload action
+ * \li Don't run in standby
+ * \li Don't run on demand for SAM L21/L22/C20/C21
+ * \li No inversion of waveform output
+ * \li No capture enabled
+ * \li No I/O capture enabled for SAM L21/L22/C20/C21
+ * \li No event input enabled
+ * \li Count upward
+ * \li Don't perform one-shot operations
+ * \li No event action
+ * \li No channel 0 PWM output
+ * \li No channel 1 PWM output
+ * \li Counter starts on 0
+ * \li Capture compare channel 0 set to 0
+ * \li Capture compare channel 1 set to 0
+ * \li No PWM pin output enabled
+ * \li Pin and MUX configuration not set
+ * \li Double buffer disabled (if have this feature)
+ *
+ * \param[out] config Pointer to a TC module configuration structure to set
+ */
+static inline void tc_get_config_defaults(
+ struct tc_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(config);
+
+ /* Write default config to config struct */
+ config->clock_source = GCLK_GENERATOR_0;
+ config->counter_size = TC_COUNTER_SIZE_16BIT;
+ config->clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
+ config->wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ;
+ config->reload_action = TC_RELOAD_ACTION_GCLK;
+ config->run_in_standby = false;
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ config->on_demand = false;
+#endif
+ config->waveform_invert_output = TC_WAVEFORM_INVERT_OUTPUT_NONE;
+ config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_0] = false;
+ config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_1] = false;
+#ifdef FEATURE_TC_IO_CAPTURE
+ config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_0] = false;
+ config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_1] = false;
+#endif
+
+ config->count_direction = TC_COUNT_DIRECTION_UP;
+ config->oneshot = false;
+
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].enabled = false;
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_out = 0;
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_mux = 0;
+
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].enabled = false;
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_out = 0;
+ config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_mux = 0;
+
+ config->counter_16_bit.value = 0x0000;
+ config->counter_16_bit.compare_capture_channel\
+ [TC_COMPARE_CAPTURE_CHANNEL_0] = 0x0000;
+ config->counter_16_bit.compare_capture_channel\
+ [TC_COMPARE_CAPTURE_CHANNEL_1] = 0x0000;
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+ config->double_buffering_enabled = false;
+#endif
+
+}
+
+enum status_code tc_init(
+ struct tc_module *const module_inst,
+ Tc *const hw,
+ const struct tc_config *const config);
+
+/** @} */
+
+/**
+ * \name Event Management
+ * @{
+ */
+
+/**
+ * \brief Enables a TC module event input or output.
+ *
+ * Enables one or more input or output events to or from the TC module.
+ * See \ref tc_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
+ */
+static inline void tc_enable_events(
+ struct tc_module *const module_inst,
+ struct tc_events *const events)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+ Assert(events);
+
+ Tc *const tc_module = module_inst->hw;
+
+ uint32_t event_mask = 0;
+
+ if (events->invert_event_input == true) {
+ event_mask |= TC_EVCTRL_TCINV;
+ }
+
+ if (events->on_event_perform_action == true) {
+ event_mask |= TC_EVCTRL_TCEI;
+ }
+
+ if (events->generate_event_on_overflow == true) {
+ event_mask |= TC_EVCTRL_OVFEO;
+ }
+
+ for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
+ if (events->generate_event_on_compare_channel[i] == true) {
+ event_mask |= (TC_EVCTRL_MCEO(1) << i);
+ }
+ }
+
+ tc_module->COUNT8.EVCTRL.reg |= event_mask | events->event_action;
+}
+
+/**
+ * \brief Disables a TC module event input or output.
+ *
+ * Disables one or more input or output events to or from the TC module.
+ * See \ref tc_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
+ */
+static inline void tc_disable_events(
+ struct tc_module *const module_inst,
+ struct tc_events *const events)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+ Assert(events);
+
+ Tc *const tc_module = module_inst->hw;
+
+ uint32_t event_mask = 0;
+
+ if (events->invert_event_input == true) {
+ event_mask |= TC_EVCTRL_TCINV;
+ }
+
+ if (events->on_event_perform_action == true) {
+ event_mask |= TC_EVCTRL_TCEI;
+ }
+
+ if (events->generate_event_on_overflow == true) {
+ event_mask |= TC_EVCTRL_OVFEO;
+ }
+
+ for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
+ if (events->generate_event_on_compare_channel[i] == true) {
+ event_mask |= (TC_EVCTRL_MCEO(1) << i);
+ }
+ }
+
+ tc_module->COUNT8.EVCTRL.reg &= ~event_mask;
+}
+
+/** @} */
+
+/**
+ * \name Enable/Disable/Reset
+ * @{
+ */
+
+enum status_code tc_reset(
+ const struct tc_module *const module_inst);
+
+/**
+ * \brief Enable the TC module.
+ *
+ * Enables a TC module that has been previously initialized. The counter will
+ * start when the counter is enabled.
+ *
+ * \note When the counter is configured to re-trigger on an event, the counter
+ * will not start until the start function is used.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_enable(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Enable TC module */
+ tc_module->CTRLA.reg |= TC_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Disables the TC module.
+ *
+ * Disables a TC module and stops the counter.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_disable(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Disbale interrupt */
+ tc_module->INTENCLR.reg = TC_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ tc_module->INTFLAG.reg = TC_INTFLAG_MASK;
+
+ /* Disable TC module */
+ tc_module->CTRLA.reg &= ~TC_CTRLA_ENABLE;
+}
+
+/** @} */
+
+/**
+ * \name Get/Set Count Value
+ * @{
+ */
+
+uint32_t tc_get_count_value(
+ const struct tc_module *const module_inst);
+
+enum status_code tc_set_count_value(
+ const struct tc_module *const module_inst,
+ const uint32_t count);
+
+/** @} */
+
+/**
+ * \name Start/Stop Counter
+ * @{
+ */
+
+/**
+ * \brief Stops the counter.
+ *
+ * This function will stop the counter. When the counter is stopped
+ * the value in the count value is set to 0 if the counter was
+ * counting up, or maximum if the counter was counting
+ * down when stopped.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_stop_counter(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Write command to execute */
+ tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_STOP_Val);
+}
+
+/**
+ * \brief Starts the counter.
+ *
+ * Starts or restarts an initialized TC module's counter.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_start_counter(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Make certain that there are no conflicting commands in the register */
+ tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE;
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Write command to execute */
+ tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_RETRIGGER_Val);
+}
+
+/** @} */
+
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+/**
+ * \name Double Buffering
+ * @{
+ */
+
+/**
+ * \brief Update double buffer.
+ *
+ * Update double buffer.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_update_double_buffer(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Make certain that there are no conflicting commands in the register */
+ tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE;
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Write command to execute */
+ tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_UPDATE_Val);
+}
+/** @} */
+#endif
+
+#ifdef FEATURE_TC_READ_SYNC
+/**
+ * \name Count Read Synchronization
+ * @{
+ */
+
+/**
+ * \brief Read synchronization of COUNT.
+ *
+ * Read synchronization of COUNT.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_sync_read_count(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Make certain that there are no conflicting commands in the register */
+ tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE;
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Write command to execute */
+ tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_READSYNC_Val);
+#if (SAMC20) || (SAMC21) || (SAML21) || (SAML22) || (SAMR30)
+ /* wait for the CMD bits in CTRLBSET to be cleared, meaning the CMD has been executed */
+ while(tc_module->CTRLBSET.reg & TC_CTRLBSET_CMD_READSYNC);
+#endif
+}
+/** @} */
+#endif
+
+#ifdef FEATURE_TC_GENERATE_DMA_TRIGGER
+/**
+ * \name Generate TC DMA Triggers Command
+ * @{
+ */
+
+/**
+ * \brief TC DMA Trigger.
+ *
+ * TC DMA trigger command.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tc_dma_trigger_command(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+ /* Make certain that there are no conflicting commands in the register */
+ tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE;
+
+ while (tc_is_syncing(module_inst)) {
+ /* Wait for sync */
+ }
+
+#if (SAMC20) || (SAMC21) || (SAML22) || (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ /* Write command to execute */
+ tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_DMAOS_Val);
+#endif
+}
+/** @} */
+#endif
+
+/**
+ * \name Get Capture Set Compare
+ * @{
+ */
+
+uint32_t tc_get_capture_value(
+ const struct tc_module *const module_inst,
+ const enum tc_compare_capture_channel channel_index);
+
+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_value);
+
+/** @} */
+
+/**
+ * \name Set Top Value
+ * @{
+ */
+
+enum status_code tc_set_top_value(
+ const struct tc_module *const module_inst,
+ const uint32_t top_value);
+
+/** @} */
+
+/**
+ * \name Status Management
+ * @{
+ */
+
+/**
+ * \brief Retrieves the current module status.
+ *
+ * Retrieves the status of the module, giving overall state information.
+ *
+ * \param[in] module_inst Pointer to the TC software instance struct
+ *
+ * \return Bitmask of \c TC_STATUS_* flags.
+ *
+ * \retval TC_STATUS_CHANNEL_0_MATCH Timer channel 0 compare/capture match
+ * \retval TC_STATUS_CHANNEL_1_MATCH Timer channel 1 compare/capture match
+ * \retval TC_STATUS_SYNC_READY Timer read synchronization has completed
+ * \retval TC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed
+ * \retval TC_STATUS_COUNT_OVERFLOW Timer count value has overflowed
+ * \retval TC_STATUS_CHN0_BUFFER_VALID Timer count channel 0 compare/capture buffer valid
+ * \retval TC_STATUS_CHN1_BUFFER_VALID Timer count channel 1 compare/capture buffer valid
+ * \retval TC_STATUS_PERIOD_BUFFER_VALID Timer count period buffer valid
+ */
+static inline uint32_t tc_get_status(
+ 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 */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ uint32_t int_flags = tc_module->INTFLAG.reg;
+
+ uint32_t status_flags = 0;
+
+ /* Check for TC channel 0 match */
+ if (int_flags & TC_INTFLAG_MC(1)) {
+ status_flags |= TC_STATUS_CHANNEL_0_MATCH;
+ }
+
+ /* Check for TC channel 1 match */
+ if (int_flags & TC_INTFLAG_MC(2)) {
+ status_flags |= TC_STATUS_CHANNEL_1_MATCH;
+ }
+
+#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2)
+ /* Check for TC read synchronization ready */
+ if (int_flags & TC_INTFLAG_SYNCRDY) {
+ status_flags |= TC_STATUS_SYNC_READY;
+ }
+#endif
+
+ /* Check for TC capture overflow */
+ if (int_flags & TC_INTFLAG_ERR) {
+ status_flags |= TC_STATUS_CAPTURE_OVERFLOW;
+ }
+
+ /* Check for TC count overflow */
+ if (int_flags & TC_INTFLAG_OVF) {
+ status_flags |= TC_STATUS_COUNT_OVERFLOW;
+ }
+#ifdef FEATURE_TC_DOUBLE_BUFFERED
+ uint8_t double_buffer_valid_status = tc_module->STATUS.reg;
+
+ /* Check channel 0 compare or capture buffer valid */
+ if (double_buffer_valid_status & TC_STATUS_CCBUFV0) {
+ status_flags |= TC_STATUS_CHN0_BUFFER_VALID;
+ }
+ /* Check channel 0 compare or capture buffer valid */
+ if (double_buffer_valid_status & TC_STATUS_CCBUFV1) {
+ status_flags |= TC_STATUS_CHN1_BUFFER_VALID;
+ }
+ /* Check period buffer valid */
+ if (double_buffer_valid_status & TC_STATUS_PERBUFV) {
+ status_flags |= TC_STATUS_PERIOD_BUFFER_VALID;
+ }
+#endif
+
+ return status_flags;
+}
+
+/**
+ * \brief Clears a module status flag.
+ *
+ * Clears the given status flag of the module.
+ *
+ * \param[in] module_inst Pointer to the TC software instance struct
+ * \param[in] status_flags Bitmask of \c TC_STATUS_* flags to clear
+ */
+static inline void tc_clear_status(
+ struct tc_module *const module_inst,
+ const uint32_t status_flags)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ /* Get a pointer to the module's hardware instance */
+ TcCount8 *const tc_module = &(module_inst->hw->COUNT8);
+
+ uint32_t int_flags = 0;
+
+ /* Check for TC channel 0 match */
+ if (status_flags & TC_STATUS_CHANNEL_0_MATCH) {
+ int_flags |= TC_INTFLAG_MC(1);
+ }
+
+ /* Check for TC channel 1 match */
+ if (status_flags & TC_STATUS_CHANNEL_1_MATCH) {
+ int_flags |= TC_INTFLAG_MC(2);
+ }
+
+#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2)
+ /* Check for TC read synchronization ready */
+ if (status_flags & TC_STATUS_SYNC_READY) {
+ int_flags |= TC_INTFLAG_SYNCRDY;
+ }
+#endif
+
+ /* Check for TC capture overflow */
+ if (status_flags & TC_STATUS_CAPTURE_OVERFLOW) {
+ int_flags |= TC_INTFLAG_ERR;
+ }
+
+ /* Check for TC count overflow */
+ if (status_flags & TC_STATUS_COUNT_OVERFLOW) {
+ int_flags |= TC_INTFLAG_OVF;
+ }
+
+ /* Clear interrupt flag */
+ tc_module->INTFLAG.reg = int_flags;
+}
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * \page asfdoc_sam0_tc_extra Extra Information for TC Driver
+ *
+ * \section asfdoc_sam0_tc_extra_acronyms Acronyms
+ * The table below presents the acronyms used in this module:
+ *
+ *
+ *
+ *
Acronym
+ *
Description
+ *
+ *
+ *
DMA
+ *
Direct Memory Access
+ *
+ *
+ *
TC
+ *
Timer Counter
+ *
+ *
+ *
PWM
+ *
Pulse Width Modulation
+ *
+ *
+ *
PWP
+ *
Pulse Width Period
+ *
+ *
+ *
PPW
+ *
Period Pulse Width
+ *
+ *
+ *
+ *
+ * \section asfdoc_sam0_tc_extra_dependencies Dependencies
+ * This driver has the following dependencies:
+ *
+ * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+ *
+ *
+ * \section asfdoc_sam0_tc_extra_errata Errata
+ * There are no errata related to this driver.
+ *
+ *
+ * \section asfdoc_sam0_tc_extra_history Module History
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in
+ * the table.
+ *
+ *
+ *
+ *
Changelog
+ *
+ *
+ *
Added support for SAM D21 and do some modifications as below:
+ * \li Clean up in the configuration structure, the counter size
+ * setting specific registers is accessed through the counter_8_bit,
+ * counter_16_bit, and counter_32_bit structures
+ * \li All event related settings moved into the tc_event structure
+ *
+ *
+ *
Added automatic digital clock interface enable for the slave TC
+ * module when a timer is initialized in 32-bit mode
+ *
+ *
+ *
Initial release
+ *
+ *
+ */
+
+/**
+ * \page asfdoc_sam0_tc_exqsg Examples for TC Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_tc_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that QSGs can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_sam0_tc_basic_use_case
+ * - \subpage asfdoc_sam0_tc_macth_freq_use_case
+ * \if TC_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_tc_timer_use_case
+ * - \subpage asfdoc_sam0_tc_callback_use_case
+ * \endif
+ * - \subpage asfdoc_sam0_tc_dma_use_case
+ *
+ * \page asfdoc_sam0_tc_document_revision_history Document Revision History
+ *
+ *
+ *
+ *
Doc. Rev.
+ *
Date
+ *
Comments
+ *
+ *
+ *
42123E
+ *
12/2015
+ *
Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21
+ *
+ *
+ *
42123D
+ *
12/2014
+ *
Added timer use case.
+ * Added support for SAM R21 and SAM D10/D11
+ *
+ *
+ *
42123C
+ *
01/2014
+ *
Added support for SAM D21
+ *
+ *
+ *
42123B
+ *
06/2013
+ *
Corrected documentation typos
+ *
+ *
+ *
42123A
+ *
06/2013
+ *
Initial document release
+ *
+ *
+ */
+
+#endif /* TC_H_INCLUDED */
diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c
new file mode 100644
index 0000000..3b54fee
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c
@@ -0,0 +1,189 @@
+/**
+ * \file
+ *
+ * \brief SAM TC - Timer Counter Callback Driver
+ *
+ * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#include "tc_interrupt.h"
+
+void *_tc_instances[TC_INST_NUM];
+
+void _tc_interrupt_handler(uint8_t instance);
+
+/**
+ * \brief Registers a callback.
+ *
+ * Registers a callback function which is implemented by the user.
+ *
+ * \note The callback must be enabled by \ref tc_enable_callback,
+ * in order for the interrupt handler to call it when the conditions for the
+ * callback type is met.
+ *
+ * \param[in] module Pointer to TC software instance struct
+ * \param[in] callback_func Pointer to callback function
+ * \param[in] callback_type Callback type given by an enum
+ */
+enum status_code tc_register_callback(
+ struct tc_module *const module,
+ tc_callback_t callback_func,
+ const enum tc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(callback_func);
+
+ /* Register callback function */
+ module->callback[callback_type] = callback_func;
+
+ /* Set the bit corresponding to the callback_type */
+ if (callback_type == TC_CALLBACK_CC_CHANNEL0) {
+ module->register_callback_mask |= TC_INTFLAG_MC(1);
+ }
+ else if (callback_type == TC_CALLBACK_CC_CHANNEL1) {
+ module->register_callback_mask |= TC_INTFLAG_MC(2);
+ }
+ else {
+ module->register_callback_mask |= (1 << callback_type);
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Unregisters a callback.
+ *
+ * Unregisters a callback function implemented by the user. The callback should be
+ * disabled before it is unregistered.
+ *
+ * \param[in] module Pointer to TC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+enum status_code tc_unregister_callback(
+ struct tc_module *const module,
+ const enum tc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Unregister callback function */
+ module->callback[callback_type] = NULL;
+
+ /* Clear the bit corresponding to the callback_type */
+ if (callback_type == TC_CALLBACK_CC_CHANNEL0) {
+ module->register_callback_mask &= ~TC_INTFLAG_MC(1);
+ }
+ else if (callback_type == TC_CALLBACK_CC_CHANNEL1) {
+ module->register_callback_mask &= ~TC_INTFLAG_MC(2);
+ }
+ else {
+ module->register_callback_mask &= ~(1 << callback_type);
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \internal ISR handler for TC
+ *
+ * Auto-generate a set of interrupt handlers for each TC in the device.
+ */
+#define _TC_INTERRUPT_HANDLER(n, m) \
+ void TC##n##_Handler(void) \
+ { \
+ _tc_interrupt_handler(m); \
+ }
+
+#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G)
+ _TC_INTERRUPT_HANDLER(0,0)
+ _TC_INTERRUPT_HANDLER(1,1)
+ _TC_INTERRUPT_HANDLER(4,2)
+#else
+ MRECURSION(TC_INST_NUM, _TC_INTERRUPT_HANDLER, TC_INST_MAX_ID)
+#endif
+
+
+/**
+ * \internal Interrupt Handler for TC module
+ *
+ * Handles interrupts as they occur, it will run the callback functions
+ * that are registered and enabled.
+ *
+ * \param[in] instance ID of the TC instance calling the interrupt
+ * handler
+ */
+void _tc_interrupt_handler(
+ uint8_t instance)
+{
+ /* Temporary variable */
+ uint8_t interrupt_and_callback_status_mask;
+
+ /* Get device instance from the look-up table */
+ struct tc_module *module
+ = (struct tc_module *)_tc_instances[instance];
+
+ /* Read and mask interrupt flag register */
+ interrupt_and_callback_status_mask = module->hw->COUNT8.INTFLAG.reg &
+ module->register_callback_mask &
+ module->enable_callback_mask;
+
+ /* Check if an Overflow interrupt has occurred */
+ if (interrupt_and_callback_status_mask & TC_INTFLAG_OVF) {
+ /* Invoke registered and enabled callback function */
+ (module->callback[TC_CALLBACK_OVERFLOW])(module);
+ /* Clear interrupt flag */
+ module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;
+ }
+
+ /* Check if an Error interrupt has occurred */
+ if (interrupt_and_callback_status_mask & TC_INTFLAG_ERR) {
+ /* Invoke registered and enabled callback function */
+ (module->callback[TC_CALLBACK_ERROR])(module);
+ /* Clear interrupt flag */
+ module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_ERR;
+ }
+
+ /* Check if an Match/Capture Channel 0 interrupt has occurred */
+ if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(1)) {
+ /* Invoke registered and enabled callback function */
+ (module->callback[TC_CALLBACK_CC_CHANNEL0])(module);
+ /* Clear interrupt flag */
+ module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(1);
+ }
+
+ /* Check if an Match/Capture Channel 1 interrupt has occurred */
+ if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(2)) {
+ /* Invoke registered and enabled callback function */
+ (module->callback[TC_CALLBACK_CC_CHANNEL1])(module);
+ /* Clear interrupt flag */
+ module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(2);
+ }
+}
diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h
new file mode 100644
index 0000000..0d3a0b0
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h
@@ -0,0 +1,169 @@
+/**
+ * \file
+ *
+ * \brief SAM TC - Timer Counter Callback Driver
+ *
+ * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#ifndef TC_INTERRUPT_H_INCLUDED
+#define TC_INTERRUPT_H_INCLUDED
+
+#include "tc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__DOXYGEN__)
+extern void *_tc_instances[TC_INST_NUM];
+
+# define _TC_INTERRUPT_VECT_NUM(n, unused) \
+ SYSTEM_INTERRUPT_MODULE_TC##n,
+/**
+ * \internal Get the interrupt vector for the given device instance
+ *
+ * \param[in] TC module instance number
+ *
+ * \return Interrupt vector for of the given TC module instance.
+ */
+static enum system_interrupt_vector _tc_interrupt_get_interrupt_vector(
+ uint32_t inst_num)
+{
+ static uint8_t tc_interrupt_vectors[TC_INST_NUM] =
+ {
+#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G)
+ SYSTEM_INTERRUPT_MODULE_TC0,
+ SYSTEM_INTERRUPT_MODULE_TC1,
+ SYSTEM_INTERRUPT_MODULE_TC4
+#else
+ MRECURSION(TC_INST_NUM, _TC_INTERRUPT_VECT_NUM, TC_INST_MAX_ID)
+#endif
+ };
+
+ return (enum system_interrupt_vector)tc_interrupt_vectors[inst_num];
+}
+#endif /* !defined(__DOXYGEN__) */
+
+/**
+ * \name Callback Management
+ * {@
+ */
+
+enum status_code tc_register_callback(
+ struct tc_module *const module,
+ tc_callback_t callback_func,
+ const enum tc_callback callback_type);
+
+enum status_code tc_unregister_callback(
+ struct tc_module *const module,
+ const enum tc_callback callback_type);
+
+/**
+ * \brief Enables callback.
+ *
+ * Enables the callback function registered by the \ref
+ * tc_register_callback. The callback function will be called from the
+ * interrupt handler when the conditions for the callback type are
+ * met. This function will also enable the appropriate interrupts.
+ *
+ * \param[in] module Pointer to TC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void tc_enable_callback(
+ struct tc_module *const module,
+ const enum tc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+
+ /* Enable interrupts for this TC module */
+ system_interrupt_enable(_tc_interrupt_get_interrupt_vector(_tc_get_inst_index(module->hw)));
+
+ /* Enable callback */
+ if (callback_type == TC_CALLBACK_CC_CHANNEL0) {
+ module->enable_callback_mask |= TC_INTFLAG_MC(1);
+ module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(1);
+ }
+ else if (callback_type == TC_CALLBACK_CC_CHANNEL1) {
+ module->enable_callback_mask |= TC_INTFLAG_MC(2);
+ module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(2);
+ }
+ else {
+ module->enable_callback_mask |= (1 << callback_type);
+ module->hw->COUNT8.INTENSET.reg = (1 << callback_type);
+ }
+}
+
+/**
+ * \brief Disables callback.
+ *
+ * Disables the callback function registered by the \ref
+ * tc_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 TC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void tc_disable_callback(
+ struct tc_module *const module,
+ const enum tc_callback callback_type){
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Disable callback */
+ if (callback_type == TC_CALLBACK_CC_CHANNEL0) {
+ module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(1);
+ module->enable_callback_mask &= ~TC_INTFLAG_MC(1);
+ }
+ else if (callback_type == TC_CALLBACK_CC_CHANNEL1) {
+ module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(2);
+ module->enable_callback_mask &= ~TC_INTFLAG_MC(2);
+ }
+ else {
+ module->hw->COUNT8.INTENCLR.reg = (1 << callback_type);
+ module->enable_callback_mask &= ~(1 << callback_type);
+ }
+}
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TC_INTERRUPT_H_INCLUDED */
diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c b/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c
new file mode 100644
index 0000000..766fd55
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c
@@ -0,0 +1,675 @@
+/**
+ * \file
+ *
+ * \brief SAM TC - Timer Counter Driver
+ *
+ * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#include "tc.h"
+
+#if TC_ASYNC == true
+# include "tc_interrupt.h"
+# include
+
+/** \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 || SAMHA1 || SAMHA0
+ /* 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;
+ }
+}
diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h
new file mode 100644
index 0000000..5acefad
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h
@@ -0,0 +1,139 @@
+/**
+ * \file
+ *
+ * \brief SAM TCC Driver Quick Start
+ *
+ * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+/**
+ * \page asfdoc_sam0_tcc_basic_use_case Quick Start Guide for TCC - Basic
+ *
+ * The supported board list:
+ * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro
+ *
+ * In this use case, the TCC will be used to generate a PWM signal. Here
+ * the pulse width is set to one quarter of the period.
+ * When the PWM signal connects to LED, LED will light. To see the waveform,
+ * you may need an oscilloscope.
+ * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead,
+ * so we can't see LED blink but only see the waveform from oscilloscope.
+ *
+ * The PWM output is set up as follows:
+ *
+ *
Board
Pin
Connect to
+ *
SAM D21 Xpro
PB30
LED0
+ *
SAM R21 Xpro
PA19
LED0
+ *
SAM L21 Xpro
PB10
LED0
+ *
SAM L22 Xpro
PC27
LED0
+ *
SAM DA1 Xpro
PB30
LED0
+ *
SAM C21 Xpro
PA15
LED0
+ *
SAM HA1G16A Xpro
PA04
NULL
+ *
+ *
+ * The TCC module will be set up as follows:
+ * - GCLK generator 0 (GCLK main) clock source
+ * - Use double buffering write when set top, compare, or pattern through API
+ * - No dithering on the counter or compare
+ * - Prescaler is set to 256
+ * - Single Slope PWM wave generation
+ * - GCLK reload action
+ * - Don't run in standby
+ * - No fault or waveform extensions
+ * - No inversion of waveform output
+ * - No capture enabled
+ * - Count upward
+ * - Don't perform one-shot operations
+ * - No event input enabled
+ * - No event action
+ * - No event generation enabled
+ * - Counter starts on 0
+ * - Counter top set to 0xFFFF
+ * - Capture compare channel 0 set to 0xFFFF/4
+ *
+ * \section asfdoc_sam0_tcc_basic_use_case_setup Quick Start
+ *
+ * \subsection asfdoc_sam0_tcc_basic_use_case_prereq Prerequisites
+ * There are no prerequisites for this use case.
+ *
+ * \subsection asfdoc_sam0_tcc_basic_use_case_setup_code Code
+ *
+ * Add to the main application source file, before any functions:
+ * \snippet conf_quick_start.h definition_pwm
+ *
+ * Add to the main application source file, outside of any functions:
+ * \snippet qs_tcc_basic.c module_inst
+ *
+ * Copy-paste the following setup code to your user application:
+ * \snippet qs_tcc_basic.c setup
+ *
+ * Add to user application initialization (typically the start of \c main()):
+ * \snippet qs_tcc_basic.c setup_init
+ *
+ * \subsection asfdoc_sam0_tcc_basic_use_case_setup_flow Workflow
+ * -# Create a module software instance structure for the TCC module to store
+ * the TCC driver state while it is in use.
+ * \snippet qs_tcc_basic.c module_inst
+ * \note This should never go out of scope as long as the module is in use.
+ * In most cases, this should be global.
+ *
+ * -# Configure the TCC module.
+ * -# Create a TCC module configuration struct, which can be filled out to
+ * adjust the configuration of a physical TCC peripheral.
+ * \snippet qs_tcc_basic.c setup_config
+ * -# Initialize the TCC configuration struct with the module's default values.
+ * \snippet qs_tcc_basic.c setup_config_defaults
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ *
+ * -# Alter the TCC settings to configure the counter width, wave generation
+ * mode, and the compare channel 0 value.
+ * \snippet qs_tcc_basic.c setup_change_config
+ * -# Alter the TCC settings to configure the PWM output on a physical device
+ * pin.
+ * \snippet qs_tcc_basic.c setup_change_config_pwm
+ * -# Configure the TCC module with the desired settings.
+ * \snippet qs_tcc_basic.c setup_set_config
+ * -# Enable the TCC module to start the timer and begin PWM signal generation.
+ * \snippet qs_tcc_basic.c setup_enable
+ *
+ *
+ * \section asfdoc_sam0_tcc_basic_use_case_main Use Case
+ *
+ * \subsection asfdoc_sam0_tcc_basic_use_case_main_code Code
+ * Copy-paste the following code to your user application:
+ * \snippet qs_tcc_basic.c main
+ *
+ * \subsection asfdoc_sam0_tcc_basic_use_case_main_flow Workflow
+ * -# Enter an infinite loop while the PWM wave is generated via the TCC module.
+ * \snippet qs_tcc_basic.c main_loop
+ */
diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h
new file mode 100644
index 0000000..b6038cc
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h
@@ -0,0 +1,145 @@
+/**
+ * \file
+ *
+ * \brief SAM TCC Driver Double Buffering Quick Start
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+/**
+ * \page asfdoc_sam0_tcc_buffering_use_case Quick Start Guide for TCC - Double Buffering and Circular
+ *
+ * The supported board list:
+ * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro
+ *
+ * In this use case, the TCC will be used to generate a PWM signal. Here
+ * the pulse width alters in one quarter and three quarter of the period.
+ * When the PWM signal connects to LED, LED will light. To see the waveform,
+ * you may need an oscilloscope.
+ * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead,
+ * so we can't see LED blink but only see the waveform from oscilloscope.
+ *
+ * The PWM output is set up as follows:
+ *
+ *
Board
Pin
Connect to
+ *
SAM D21 Xpro
PB30
LED0
+ *
SAM R21 Xpro
PA19
LED0
+ *
SAM L21 Xpro
PB10
LED0
+ *
SAM L22 Xpro
PC27
LED0
+ *
SAM DA1 Xpro
PB30
LED0
+ *
SAM C21 Xpro
PA15
LED0
+ *
SAM HA1G16A Xpro
PA04
NULL
+ *
+ *
+ * The TCC module will be set up as follows:
+ * - GCLK generator 0 (GCLK main) clock source
+ * - Use double buffering write when set top, compare, or pattern through API
+ * - No dithering on the counter or compare
+ * - Prescaler is set to 1024
+ * - Single Slope PWM wave generation
+ * - GCLK reload action
+ * - Don't run in standby
+ * - No fault or waveform extensions
+ * - No inversion of waveform output
+ * - No capture enabled
+ * - Count upward
+ * - Don't perform one-shot operations
+ * - No event input enabled
+ * - No event action
+ * - No event generation enabled
+ * - Counter starts on 0
+ * - Counter top set to 8000
+ * - Capture compare channel set to 8000/4
+ * - Capture compare channel buffer set to 8000*3/4
+ * - Circular option for compare channel is enabled so that the compare
+ * values keep switching on update condition
+ *
+ * \section asfdoc_sam0_tcc_buffering_use_case_setup Quick Start
+ *
+ * \subsection asfdoc_sam0_tcc_buffering_use_case_prereq Prerequisites
+ * There are no prerequisites for this use case.
+ *
+ * \subsection asfdoc_sam0_tcc_buffering_use_case_setup_code Code
+ *
+ * Add to the main application source file, before any functions:
+ * \snippet conf_quick_start_buffering.h definition_pwm
+ *
+ * Add to the main application source file, outside of any functions:
+ * \snippet qs_tcc_buffering.c module_inst
+ *
+ * Copy-paste the following setup code to your user application:
+ * \snippet qs_tcc_buffering.c setup
+ *
+ * Add to user application initialization (typically the start of \c main()):
+ * \snippet qs_tcc_buffering.c setup_init
+ *
+ * \subsection asfdoc_sam0_tcc_buffering_use_case_setup_flow Workflow
+ * -# Create a module software instance structure for the TCC module to store
+ * the TCC driver state while it is in use.
+ * \snippet qs_tcc_buffering.c module_inst
+ * \note This should never go out of scope as long as the module is in use.
+ * In most cases, this should be global.
+ *
+ * -# Configure the TCC module.
+ * -# Create a TCC module configuration struct, which can be filled out to
+ * adjust the configuration of a physical TCC peripheral.
+ * \snippet qs_tcc_buffering.c setup_config
+ * -# Initialize the TCC configuration struct with the module's default values.
+ * \snippet qs_tcc_buffering.c setup_config_defaults
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ *
+ * -# Alter the TCC settings to configure the counter width, wave generation
+ * mode, and the compare channel 0 value.
+ * \snippet qs_tcc_buffering.c setup_change_config
+ * -# Alter the TCC settings to configure the PWM output on a physical device
+ * pin.
+ * \snippet qs_tcc_buffering.c setup_change_config_pwm
+ * -# Configure the TCC module with the desired settings.
+ * \snippet qs_tcc_buffering.c setup_set_config
+ * -# Set to compare buffer value and enable circular of double buffered
+ * compare values.
+ * \snippet qs_tcc_buffering.c setup_set_buffering
+ * -# Enable the TCC module to start the timer and begin PWM signal generation.
+ * \snippet qs_tcc_buffering.c setup_enable
+ *
+ *
+ * \section asfdoc_sam0_tcc_buffering_use_case_main Use Case
+ *
+ * \subsection asfdoc_sam0_tcc_buffering_use_case_main_code Code
+ * Copy-paste the following code to your user application:
+ * \snippet qs_tcc_buffering.c main
+ *
+ * \subsection asfdoc_sam0_tcc_buffering_use_case_main_flow Workflow
+ * -# Enter an infinite loop while the PWM wave is generated via the TCC module.
+ * \snippet qs_tcc_buffering.c main_loop
+ */
diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h
new file mode 100644
index 0000000..d7fc301
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h
@@ -0,0 +1,275 @@
+/**
+ * \file
+ *
+ * \brief SAM TCC Driver Quick Start with DMA
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+/**
+ * \page asfdoc_sam0_tcc_dma_use_case Quick Start Guide for Using DMA with TCC
+ *
+ * The supported board list:
+ * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro
+ *
+ * In this use case, the TCC will be used to generate a PWM signal. Here
+ * the pulse width varies through the following values with the help of DMA
+ * transfer: one quarter of the period, half of the period, and three quarters
+ * of the period.
+ * The PWM output can be used to drive a LED. The waveform can also be
+ * viewed using an oscilloscope.
+ * The output signal is also fed back to another TCC channel by event system,
+ * the event stamps are captured and transferred to a buffer by DMA.
+ * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead,
+ * so we can't see LED blink but only see the waveform from oscilloscope.
+ *
+ * The PWM output is set up as follows:
+ *
+ *
Board
Pin
Connect to
+ *
SAM D21 Xpro
PB30
LED0
+ *
SAM R21 Xpro
PA19
LED0
+ *
SAM L21 Xpro
PB10
LED0
+ *
SAM L22 Xpro
PC27
LED0
+ *
SAM DA1 Xpro
PB30
LED0
+ *
SAM C21 Xpro
PA15
LED0
+ *
SAM HA1G16A Xpro
PA04
NULL
+ *
+ *
+ * The TCC module will be setup as follows:
+ * - GCLK generator 0 (GCLK main) clock source
+ * - Use double buffering write when set top, compare, or pattern through API
+ * - No dithering on the counter or compare
+ * - Prescaler is set to 1024
+ * - Single Slope PWM wave generation
+ * - GCLK reload action
+ * - Don't run in standby
+ * - No fault or waveform extensions
+ * - No inversion of waveform output
+ * - No capture enabled
+ * - Count upward
+ * - Don't perform one-shot operations
+ * - Counter starts on 0
+ * - Counter top set to 0x1000
+ * - Channel 0 (on SAM D21 Xpro) or 3 (on SAM R21 Xpro) is set to
+ * compare and match value 0x1000*3/4 and generate event
+ * - Channel 1 is set to capture on input event
+ *
+ * The event resource of EVSYS module will be setup as follows:
+ * - TCC match capture channel 0 (on SAM D21 Xpro) or 3 (on SAM R21 Xpro) is
+ * selected as event generator
+ * - Event generation is synchronous, with rising edge detected
+ * - TCC match capture channel 1 is the event user
+ *
+ * The DMA resource of DMAC module will be setup as follows:
+ * - Two DMA resources are used
+ * - Both DMA resources use peripheral trigger
+ * - Both DMA resources perform beat transfer on trigger
+ * - Both DMA resources use beat size of 16 bits
+ * - Both DMA resources are configured to transfer three beats and
+ * then repeat again in same buffer
+ * - On DMA resource which controls the compare value
+ * - TCC0 overflow triggers DMA transfer
+ * - The source address increment is enabled
+ * - The destination address is fixed to TCC channel 0 Compare/Capture
+ *register
+ * - On DMA resource which reads the captured value
+ * - TCC0 capture on channel 1 triggers DMA transfer
+ * - The source address is fixed to TCC channel 1 Compare/Capture register
+ * - The destination address increment is enabled
+ * - The captured value is transferred to an array in SRAM
+ *
+ * \section asfdoc_sam0_tcc_dma_use_case_setup Quick Start
+ *
+ * \subsection asfdoc_sam0_tcc_dma_use_case_prereq Prerequisites
+ * There are no prerequisites for this use case.
+ *
+ * \subsection asfdoc_sam0_tcc_dma_use_case_setup_code Code
+ *
+ * Add to the main application source file, before any functions, according to
+ * the kit used:
+ * - SAM D21 Xplained Pro
+ * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger
+ * - SAM R21 Xplained Pro
+ * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger
+ * - SAM L21 Xplained Pro
+ * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ * - SAM L22 Xplained Pro
+ * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ * - SAM DA1 Xplained Pro
+ * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger
+ * - SAM C21 Xplained Pro
+ * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_pwm
+ * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_feedback
+ * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger
+ *
+ * Add to the main application source file, outside of any functions:
+ * \snippet qs_tcc_dma.c module_inst
+ * \snippet qs_tcc_dma.c capture_variables
+ * \snippet qs_tcc_dma.c compare_variables
+ *
+ * Copy-paste the following setup code to your user application:
+ * \snippet qs_tcc_dma.c config_event_for_capture
+ * \snippet qs_tcc_dma.c config_dma_for_capture
+ * \snippet qs_tcc_dma.c config_dma_for_wave
+ * \snippet qs_tcc_dma.c setup
+ *
+ * Add to user application initialization (typically the start of \c main()):
+ * \snippet qs_tcc_dma.c setup_init
+ *
+ * \subsection asfdoc_sam0_tcc_dma_use_case_setup_flow Workflow
+ * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_tcc Configure the TCC
+ * -# Create a module software instance structure for the TCC module to store
+ * the TCC driver state while it is in use.
+ * \snippet qs_tcc_dma.c module_inst
+ * \note This should never go out of scope as long as the module is in use.
+ * In most cases, this should be global.
+ * -# Create a TCC module configuration struct, which can be filled out to
+ * adjust the configuration of a physical TCC peripheral.
+ * \snippet qs_tcc_dma.c setup_config
+ * -# Initialize the TCC configuration struct with the module's default values.
+ * \snippet qs_tcc_dma.c setup_config_defaults
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ * -# Alter the TCC settings to configure the counter width, wave generation
+ * mode, and the compare channel 0 value.
+ * \snippet qs_tcc_dma.c setup_change_config
+ * -# Alter the TCC settings to configure the PWM output on a physical device
+ * pin.
+ * \snippet qs_tcc_dma.c setup_change_config_pwm
+ * -# Configure the TCC module with the desired settings.
+ * \snippet qs_tcc_dma.c setup_set_config
+ * -# Configure and enable the desired events for the TCC module.
+ * \snippet qs_tcc_dma.c setup_events
+ * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_event Configure the Event System
+ * Configure the EVSYS module to wire channel 0 event to channel 1.
+ * -# Create an event resource instance.
+ * \snippet qs_tcc_dma.c capture_event_resource
+ * \note This should never go out of scope as long as the resource is in
+ * use. In most cases, this should be global.
+ *
+ * -# Create an event resource configuration struct.
+ * \snippet qs_tcc_dma.c event_setup_1
+ * -# Initialize the event resource configuration struct with default values.
+ * \snippet qs_tcc_dma.c event_setup_2
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ * -# Adjust the event resource configuration to desired values.
+ * \snippet qs_tcc_dma.c event_setup_3
+ * -# Allocate and configure the resource using the configuration structure.
+ * \snippet qs_tcc_dma.c event_setup_4
+ * -# Attach a user to the resource.
+ * \snippet qs_tcc_dma.c event_setup_5
+ * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_dma_capture Configure the DMA for Capture TCC Channel 1
+ * Configure the DMAC module to obtain captured value from TCC channel 1.
+ * -# Create a DMA resource instance.
+ * \snippet qs_tcc_dma.c capture_dma_resource
+ * \note This should never go out of scope as long as the resource is in
+ * use. In most cases, this should be global.
+ * -# Create a DMA resource configuration struct.
+ * \snippet qs_tcc_dma.c dma_setup_1
+ * -# Initialize the DMA resource configuration struct with default values.
+ * \snippet qs_tcc_dma.c dma_setup_2
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ * -# Adjust the DMA resource configurations.
+ * \snippet qs_tcc_dma.c dma_setup_3
+ * -# Allocate a DMA resource with the configurations.
+ * \snippet qs_tcc_dma.c dma_setup_4
+ * -# Prepare DMA transfer descriptor.
+ * -# Create a DMA transfer descriptor.
+ * \snippet qs_tcc_dma.c capture_dma_descriptor
+ * \note When multiple descriptors are linked, the linked item should
+ * never go out of scope before it is loaded (to DMA Write-Back
+ * memory section). In most cases, if more than one descriptors are
+ * used, they should be global except the very first one.
+ * -# Create a DMA transfer descriptor struct.
+ * -# Create a DMA transfer descriptor configuration structure, which can be
+ * filled out to adjust the configuration of a single DMA transfer.
+ * \snippet qs_tcc_dma.c dma_setup_5
+ * -# Initialize the DMA transfer descriptor configuration struct with
+ * default values.
+ * \snippet qs_tcc_dma.c dma_setup_6
+ * \note This should always be performed before using the configuration
+ * struct to ensure that all values are initialized to known default
+ * settings.
+ * -# Adjust the DMA transfer descriptor configurations.
+ * \snippet qs_tcc_dma.c dma_setup_7
+ * -# Create the DMA transfer descriptor with the given configuration.
+ * \snippet qs_tcc_dma.c dma_setup_8
+ * -# Start DMA transfer job with prepared descriptor.
+ * -# Add the DMA transfer descriptor to the allocated DMA resource.
+ * \snippet qs_tcc_dma.c dma_setup_10
+ * \note When adding multiple descriptors, the last one added is linked
+ * at the end of the descriptor queue. If ringed list is needed,
+ * just add the first descriptor again to build the circle.
+ * -# Start the DMA transfer job with the allocated DMA resource and
+ * transfer descriptor.
+ * \snippet qs_tcc_dma.c dma_setup_11
+ * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_dma_compare Configure the DMA for Compare TCC Channel 0
+ * Configure the DMAC module to update TCC channel 0 compare value.
+ * The flow is similar to last DMA configure step for capture.
+ * -# Allocate and configure the DMA resource.
+ * \snippet qs_tcc_dma.c compare_dma_resource
+ * \snippet qs_tcc_dma.c config_dma_resource_for_wave
+ * -# Prepare DMA transfer descriptor.
+ * \snippet qs_tcc_dma.c compare_dma_descriptor
+ * \snippet qs_tcc_dma.c config_dma_descriptor_for_wave
+ * -# Start DMA transfer job with prepared descriptor.
+ * \snippet qs_tcc_dma.c config_dma_job_for_wave
+ * -# Enable the TCC module to start the timer and begin PWM signal generation.
+ * \snippet qs_tcc_dma.c setup_enable
+ *
+ * \section asfdoc_sam0_tcc_dma_use_case_main Use Case
+ *
+ * \subsection asfdoc_sam0_tcc_dma_use_case_main_code Code
+ * Copy-paste the following code to your user application:
+ * \snippet qs_tcc_dma.c main
+ *
+ * \subsection asfdoc_sam0_tcc_dma_use_case_main_flow Workflow
+ * -# Enter an infinite loop while the PWM wave is generated via the TCC module.
+ * \snippet qs_tcc_dma.c main_loop
+ */
diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c
new file mode 100644
index 0000000..feed971
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c
@@ -0,0 +1,1598 @@
+/**
+ * \file
+ *
+ * \brief SAM TCC - Timer Counter for Control Applications Driver
+ *
+ * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#include "tcc.h"
+
+#if TCC_ASYNC == true
+# include "tcc_callback.h"
+# include
+
+/** \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) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+# 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) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089)
+ 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) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089)
+ 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) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089)
+ 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.reg & TCC_SYNCBUSY_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.reg & TCC_SYNCBUSY_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;
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ break;
+ } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) {
+ /* Command have been issued */
+ break;
+ }
+ } while (1);
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_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) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ 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 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) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ 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) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ 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;
+ }
+ /* Check for TCC RAMP index */
+ if (status_flags & TCC_STATUS_IDX) {
+ status |= TCC_STATUS_RAMP_CYCLE_INDEX;
+ }
+ 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;
+}
diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h
new file mode 100644
index 0000000..eae07f8
--- /dev/null
+++ b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h
@@ -0,0 +1,2487 @@
+/**
+ * \file
+ *
+ * \brief SAM TCC - Timer Counter for Control Applications Driver
+ *
+ * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#ifndef TCC_H_INCLUDED
+#define TCC_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_sam0_tcc_group SAM Timer Counter for Control Applications (TCC) Driver
+ *
+ * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration
+ * and management of the TCC module within the device, for waveform
+ * generation and timing operations. It also provides extended options for
+ * control applications.
+ *
+ * The following driver API modes are covered
+ * by this manual:
+ *
+ * - Polled APIs
+ * \if TCC_CALLBACK_MODE
+ * - Callback APIs
+ * \endif
+ *
+ * The following peripheral is used by this module:
+ * - TCC (Timer/Counter for Control Applications)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ * - Atmel | SMART SAM HA1
+ * - Atmel | SMART SAM R30
+ * - Atmel | SMART SAM R34
+ * - Atmel | SMART SAM R35
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_tcc_prerequisites
+ * - \ref asfdoc_sam0_tcc_module_overview
+ * - \ref asfdoc_sam0_tcc_special_considerations
+ * - \ref asfdoc_sam0_tcc_extra_info
+ * - \ref asfdoc_sam0_tcc_examples
+ * - \ref asfdoc_sam0_tcc_api_overview
+ *
+ * \section asfdoc_sam0_tcc_prerequisites Prerequisites
+ *
+ * There are no prerequisites for this module.
+ *
+ * \section asfdoc_sam0_tcc_module_overview Module Overview
+ *
+ * The Timer/Counter for Control Applications (TCC) module provides a set of
+ * timing and counting related functionality, such as the generation of periodic
+ * waveforms, the capturing of a periodic waveform's frequency/duty cycle,
+ * software timekeeping for periodic operations, waveform extension control,
+ * fault detection etc.
+ *
+ * The counter size of the TCC modules can be 16- or 24-bit depending on
+ * the TCC instance.
+ * Refer \ref asfdoc_sam0_tcc_special_considerations_tcc_d21 and
+ * \ref asfdoc_sam0_tcc_special_considerations_tcc_d11 for details on TCC instances.
+ *
+ * The TCC module for the SAM includes the following functions:
+ *
+ * - Generation of PWM signals
+ * - Generation of timestamps for events
+ * - General time counting
+ * - Waveform period capture
+ * - Waveform frequency capture
+ * - Additional control for generated waveform outputs
+ * - Fault protection for waveform generation
+ *
+ * \ref asfdoc_sam0_tcc_block_diagram "The diagram below" shows the overview
+ * of the TCC Module.
+ *
+ * \anchor asfdoc_sam0_tcc_block_diagram
+ * \image html overview.svg "Overview of the TCC Module"
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_parts Functional Description
+ * The TCC module consists of following sections:
+ * - Base Counter
+ * - Compare/Capture channels, with waveform generation
+ * - Waveform extension control and fault detection
+ * - Interface to the event system, DMAC, and the interrupt system
+ *
+ * The base counter can be configured to either count a prescaled generic
+ * clock or events from the event system.(TCEx, with event action configured
+ * to counting).
+ * The counter value can be used by compare/capture channels which can be
+ * set up either in compare mode or capture mode.
+ *
+ * In capture mode, the counter value is stored when a configurable event
+ * occurs. This mode can be used to generate timestamps used in event capture,
+ * or it can be used for the measurement of a periodic input signal's
+ * frequency/duty cycle.
+ *
+ * In compare mode, the counter value is compared against one or more of the
+ * configured channels' compare values. When the counter value coincides with a
+ * compare value an action can be taken automatically by the module, such as
+ * generating an output event or toggling a pin when used for frequency or PWM
+ * signal generation.
+ *
+ * \note The connection of events between modules requires the use of the
+ * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)"
+ * to route output event of one module to the the input event of another.
+ * For more information on event routing, refer to the event driver
+ * documentation.
+ *
+ * In compare mode, when output signal is generated, extended waveform controls
+ * are available, to arrange the compare outputs into specific formats.
+ * The Output matrix can change the channel output routing. Pattern generation
+ * unit can overwrite the output signal line to specific state.
+ * The Fault protection feature of the TCC supports recoverable and
+ * non-recoverable faults.
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_tc Base Timer/Counter
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_tc_size Timer/Counter Size
+ * Each TCC has a counter size of either 16- or 24-bits. The size of the
+ * counter determines the maximum value it can count to before an overflow
+ * occurs.
+ * \ref asfdoc_sam0_tcc_count_size_vs_top "The table below" shows the
+ * maximum values for each of the possible counter sizes.
+ *
+ * \anchor asfdoc_sam0_tcc_count_size_vs_top
+ *
+ *
Timer Counter Sizes and Their Maximum Count Values
+ *
+ *
Counter size
+ *
Max. (hexadecimal)
+ *
Max. (decimal)
+ *
+ *
+ *
16-bit
+ *
0xFFFF
+ *
65,535
+ *
+ *
+ *
24-bit
+ *
0xFFFFFF
+ *
16,777,215
+ *
+ *
+ *
+ * The period/top value of the counter can be set, to define counting period.
+ * This will allow the counter to overflow when the counter value reaches the
+ * period/top value.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_tc_clk Timer/Counter Clock and Prescaler
+ * TCC is clocked asynchronously to the system clock by a GCLK
+ * (Generic Clock) channel. The GCLK channel can be connected to any of the GCLK
+ * generators. The GCLK generators are configured to use one of the available
+ * clock sources in the system such as internal oscillator, external crystals,
+ * etc. See the \ref asfdoc_sam0_system_clock_group "Generic Clock driver" for
+ * more information.
+ *
+ * Each TCC module in the SAM has its own individual clock prescaler, which
+ * can be used to divide the input clock frequency used by the counter. This
+ * prescaler only scales the clock used to provide clock pulses for the counter
+ * to count, and does not affect the digital register interface portion of
+ * the module, thus the timer registers will be synchronized to the raw GCLK
+ * frequency input to the module.
+ *
+ * As a result of this, when selecting a GCLK frequency and timer prescaler
+ * value, the user application should consider both the timer resolution
+ * required and the synchronization frequency to avoid lengthy
+ * synchronization times of the module if a very slow GCLK frequency is fed
+ * into the TCC module. It is preferable to use a higher module GCLK frequency
+ * as the input to the timer, and prescale this down as much as possible to
+ * obtain a suitable counter frequency in latency-sensitive applications.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_tc_ctrl Timer/Counter Control Inputs (Events)
+ *
+ * The TCC can take several actions on the occurrence of an input event.
+ * The event actions are listed
+ * in \ref asfdoc_sam0_tcc_module_event_act "events action settings".
+ *
+ * \anchor asfdoc_sam0_tcc_module_event_act
+ *
+ *
TCC Module Event Actions
+ *
+ *
Event action
+ *
Description
+ *
Applied event
+ *
+ *
+ *
TCC_EVENT_ACTION_OFF
+ *
No action on the event input
+ *
All
+ *
+ *
+ *
TCC_EVENT_ACTION_RETRIGGER
+ *
Re-trigger Counter on event
+ *
All
+ *
+ *
+ *
TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT
+ *
Generate Non-Recoverable Fault on event
+ *
All
+ *
+ *
+ *
TCC_EVENT_ACTION_START
+ *
Counter start on event
+ *
EV0
+ *
+ *
+ *
TCC_EVENT_ACTION_DIR_CONTROL
+ *
Counter direction control
+ *
EV0
+ *
+ *
+ *
TCC_EVENT_ACTION_DECREMENT
+ *
Counter decrement on event
+ *
EV0
+ *
+ *
+ *
TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE
+ *
Capture pulse period and pulse width
+ *
EV0
+ *
+ *
+ *
TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURE
+ *
Capture pulse width and pulse period
+ *
EV0
+ *
+ *
+ *
TCC_EVENT_ACTION_STOP
+ *
Counter stop on event
+ *
EV1
+ *
+ *
+ *
TCC_EVENT_ACTION_COUNT_EVENT
+ *
Counter count on event
+ *
EV1
+ *
+ *
+ *
TCC_EVENT_ACTION_INCREMENT
+ *
Counter increment on event
+ *
EV1
+ *
+ *
+ *
TCC_EVENT_ACTION_COUNT_DURING_ACTIVE
+ *
Counter count during active state of asynchronous event
+ *
EV1
+ *
+ *
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_tc_reload Timer/Counter Reloading
+ *
+ * The TCC also has a configurable reload action, used when a
+ * re-trigger event occurs. Examples of a re-trigger event could be the counter
+ * reaching the maximum value when counting up, or when an event from the event
+ * system makes the counter to re-trigger. The reload action determines if the
+ * prescaler should be reset, and on which clock. The counter will
+ * always be reloaded with the value it is set to start counting. The user
+ * can choose between three different reload actions, described in
+ * \ref asfdoc_sam0_tcc_module_reload_act "the table below".
+ *
+ * \anchor asfdoc_sam0_tcc_module_reload_act
+ *
+ *
TCC Module Reload Actions
+ *
+ *
Reload action
+ *
Description
+ *
+ *
+ *
TCC_RELOAD_ACTION_GCLK
+ *
Reload TCC counter value on next GCLK cycle. Leave prescaler
+ * as-is.
+ *
+ *
+ *
TCC_RELOAD_ACTION_PRESC
+ *
Reloads TCC counter value on next prescaler clock. Leave prescaler
+ * as-is.
+ *
+ *
+ *
TCC_RELOAD_ACTION_RESYNC
+ *
Reload TCC counter value on next GCLK cycle. Clear prescaler to
+ * zero.
+ *
+ *
+ *
+ * The reload action to use will depend on the specific application being
+ * implemented. One example is when an external trigger for a reload occurs; if
+ * the TCC uses the prescaler, the counter in the prescaler should not have a
+ * value between zero and the division factor. The counter in the TCC module
+ * and the counter in the prescaler should both start at zero.
+ * If the counter is set to re-trigger when it reaches the maximum value,
+ * this is not the right option to use. In such a case it would be better if
+ * the prescaler is left unaltered when the re-trigger happens, letting the
+ * counter reset on the next GCLK cycle.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_tc_oneshot One-shot Mode
+ *
+ * The TCC module can be configured in one-shot mode. When configured in this
+ * manner, starting the timer will cause it to count until the next overflow
+ * or underflow condition before automatically halting, waiting to be manually
+ * triggered by the user application software or an event from the event
+ * system.
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_capt Capture Operations
+ *
+ * In capture operations, any event from the event system or a pin change can
+ * trigger a capture of the counter value. This captured counter value can be
+ * used as timestamps for the events, or it can be used in frequency and pulse
+ * width capture.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_capt_ev Capture Operations - Event
+ *
+ * Event capture is a simple use of the capture functionality,
+ * designed to create timestamps for specific events. When the input event
+ * appears, the current counter value is copied into the corresponding
+ * compare/capture register, which can then be read by the user application.
+ *
+ * Note that when performing any capture operation, there is a risk that the
+ * counter reaches its top value (MAX) when counting up, or the bottom value
+ * (zero) when counting down, before the capture event occurs. This can distort
+ * the result, making event timestamps to appear shorter than they really are.
+ * In this case, the user application should check for timer overflow when
+ * reading a capture result in order to detect this situation and perform an
+ * appropriate adjustment.
+ *
+ * Before checking for a new capture, \ref TCC_STATUS_COUNT_OVERFLOW
+ * should be checked. The response to an overflow error is left to the user
+ * application, however, it may be necessary to clear both the overflow
+ * flag and the capture flag upon each capture reading.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_capt_pulse Capture Operations - Pulse Width
+ *
+ * Pulse Width Capture mode makes it possible to measure the pulse width and
+ * period of PWM signals. This mode uses two capture channels of the counter.
+ * There are two modes for pulse width capture;
+ * Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture
+ * channel 0 is used for storing the pulse width and capture channel 1 stores
+ * the observed period. While in PPW mode, the roles of the two capture channels
+ * are reversed.
+ *
+ * As in the above example it is necessary to poll on interrupt flags to see
+ * if a new capture has happened and check that a capture overflow error has
+ * not occurred.
+ *
+ * Refer to \ref asfdoc_sam0_tcc_module_overview_tc_ctrl to set up the input
+ * event to perform pulse width capture.
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_mc Compare Match Operation
+ *
+ * In compare match operation, Compare/Capture registers are compared
+ * with the counter value. When the timer's count value matches the value of a
+ * compare channel, a user defined action can be taken.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_mc_timer Basic Timer
+ *
+ * A Basic Timer is a simple application where compare match operation is used
+ * to determine when a specific period has elapsed. In Basic Timer operations,
+ * one or more values in the module's Compare/Capture registers are used to
+ * specify the time (in terms of the number of prescaled GCLK cycles, or
+ * input events) at which
+ * an action should be taken by the microcontroller. This can be an Interrupt
+ * Service Routine (ISR), event generation via the event system, or a software
+ * flag that is polled from the user application.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave Waveform Generation
+ *
+ * Waveform generation enables the TCC module to generate square waves, or, if
+ * combined with an external passive low-pass filter, analog waveforms.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave_pwm Waveform Generation - PWM
+ *
+ * Pulse width modulation is a form of waveform generation and a signalling
+ * technique that can be useful in many applications. When PWM mode is used,
+ * a digital pulse train with a configurable frequency and duty cycle can be
+ * generated by the TCC module and output to a GPIO pin of the device.
+ *
+ * Often PWM is used to communicate a control or information parameter to an
+ * external circuit or component. Differing impedances of the source generator
+ * and sink receiver circuits is less of an issue when using PWM compared to
+ * using an analog voltage value, as noise will not generally affect the
+ * signal's integrity to a meaningful extent.
+ *
+ * \ref asfdoc_sam0_tcc_module_pwm_single_diag "The figure below" illustrates
+ * operations and different states of the counter and its output when using
+ * the timer in Normal PWM mode (Single Slope). As can be seen, the TOP/PERIOD
+ * value is
+ * unchanged and is set to MAX. The compare match value is changed at several
+ * points to illustrate the resulting waveform output changes. The PWM output is
+ * set to normal (i.e. non-inverted) output mode.
+ *
+ * \anchor asfdoc_sam0_tcc_module_pwm_single_diag
+ * \image html pwm_single_ex.svg "Example Of PWM In Single-Slope Mode, and Different Counter Operations"
+ *
+ * Several PWM modes are supported by the TCC module, refer to
+ * datasheet for the details on PWM waveform generation.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave_freq Waveform Generation - Frequency
+ *
+ * Normal Frequency Generation is in many ways identical to PWM generation.
+ * However, only in Frequency Generation, a toggle occurs on the output when a
+ * match on a compare channels occurs.
+ *
+ * When the Match Frequency Generation is used, the timer value is reset on
+ * match condition, resulting in a variable frequency square wave with a
+ * fixed 50% duty cycle.
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_ext Waveform Extended Controls
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_ext_pat Pattern Generation
+ *
+ * Pattern insertion allows the TCC module to change the actual pin output level
+ * without modifying the compare/match settings.
+ *
+ * \anchor asfdoc_sam0_tcc_module_pattern_gen
+ *
+ *
TCC Module Output Pattern Generation
+ *
+ *
Pattern
+ *
Description
+ *
+ *
+ *
TCC_OUTPUT_PATTERN_DISABLE
+ *
Pattern disabled, generate output as is
+ *
+ *
+ *
TCC_OUTPUT_PATTERN_0
+ *
Generate pattern 0 on output (keep the output LOW)
+ *
+ *
+ *
TCC_OUTPUT_PATTERN_1
+ *
Generate pattern 1 on output (keep the output HIGH)
+ *
+ *
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_ext_r_fault Recoverable Faults
+ *
+ * The recoverable faults can trigger one or several of following fault actions:
+ * -# *Halt* action: The recoverable faults can halt the TCC timer/counter,
+ * so that the final output wave is kept at a defined state. When the fault
+ * state is removed it is possible to recover the counter and waveform
+ * generation. The halt action is defined as:
+ * \anchor asfdoc_sam0_tcc_module_fault_halt_action
+ *
+ *
TCC Module Recoverable Fault Halt Actions
+ *
+ *
Action
+ *
Description
+ *
+ *
+ *
TCC_FAULT_HALT_ACTION_DISABLE
+ *
Halt action is disabled
+ *
+ *
+ *
TCC_FAULT_HALT_ACTION_HW_HALT
+ *
The timer/counter is halted as long as the corresponding fault is
+ * present
+ *
+ *
+ *
TCC_FAULT_HALT_ACTION_SW_HALT
+ *
The timer/counter is halted until the corresponding fault is removed
+ * and fault state cleared by software
+ *
+ *
+ *
TCC_FAULT_HALT_ACTION_NON_RECOVERABLE
+ *
Force all the TCC output pins to a pre-defined level, as what
+ * Non-Recoverable Fault do
+ *
+ *
+ * -# *Restart* action: When enabled, the recoverable faults can restart the TCC
+ * timer/counter.
+ * -# *Keep* action: When enabled, the recoverable faults can keep the
+ * corresponding channel output to zero when the fault condition is present.
+ * -# *Capture* action: When the recoverable fault occurs, the capture action can
+ * time stamps the corresponding fault. The following capture mode is
+ * supported:
+ * \anchor asfdoc_sam0_tcc_module_fault_capt_action
+ *
+ *
TCC Module Recoverable Fault Capture Actions
+ *
+ *
Action
+ *
Description
+ *
+ *
+ *
TCC_FAULT_CAPTURE_DISABLE
+ *
Capture action is disabled
+ *
+ *
+ *
TCC_FAULT_CAPTURE_EACH
+ *
Equivalent to standard capture operation, on each fault occurrence
+ * the time stamp is captured
+ *
+ *
+ *
TCC_FAULT_CAPTURE_MINIMUM
+ *
Get the minimum time stamped value in all time stamps
+ *
+ *
+ *
TCC_FAULT_CAPTURE_MAXIMUM
+ *
Get the maximum time stamped value in all time stamps
+ *
+ *
+ *
TCC_FAULT_CAPTURE_SMALLER
+ *
Time stamp the fault input if the value is smaller than last one
+ *
+ *
+ *
TCC_FAULT_CAPTURE_BIGGER
+ *
Time stamp the fault input if the value is bigger than last one
+ *
+ *
+ *
TCC_FAULT_CAPTURE_CHANGE
+ *
Time stamp the fault input if the time stamps changes its increment
+ * direction
+ *
+ *
+ *
+ * In TCC module, only the first two compare channels (CC0 and CC1) can work
+ * with recoverable fault inputs. The corresponding event inputs (TCCx MC0
+ * and TCCx MC1) are then used as fault inputs respectively.
+ * The faults are called Fault A and Fault B.
+ *
+ * The recoverable fault can be filtered or effected by corresponding channel
+ * output. On fault condition there are many other settings that can be chosen.
+ * Refer to data sheet for more details about the recoverable fault
+ * operations.
+ *
+ * \subsubsection asfdoc_sam0_tcc_module_overview_ext_n_fault Non-Recoverable Faults
+ *
+ * The non-recoverable faults force all the TCC output pins to a pre-defined
+ * level (can be forced to 0 or 1). The input control signal of non-recoverable
+ * fault is from timer/counter event (TCCx EV0 and TCCx EV1).
+ * To enable non-recoverable fault,
+ * corresponding TCEx event action must be set to non-recoverable fault action
+ * (\ref TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT).
+ * Refer to \ref asfdoc_sam0_tcc_module_overview_tc_ctrl to see the available
+ * event input action.
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_buffering Double and Circular Buffering
+ *
+ * The pattern, period, and the compare channels registers are double buffered.
+ * For these options there are effective registers (PATT, PER, and CCx) and
+ * buffer registers (PATTB, PERB, and CCx). When writing to the buffer
+ * registers, the values are buffered and will be committed to effective
+ * registers on UPDATE condition.
+ *
+ * Usually the buffered value is cleared after it is committed, but there is also
+ * an option to circular the register buffers. The period (PER) and four lowest
+ * compare channels register (CCx, x is 0 ~ 3) support this function. When
+ * circular buffer is used, on UPDATE the previous period or compare values are
+ * copied back into the corresponding period buffer and compare buffers.
+ * This way, the register value and its buffer register value is actually
+ * switched on UPDATE condition, and will be switched back on next UPDATE
+ * condition.
+ *
+ * For input capture, the buffer register (CCBx) and the corresponding capture
+ * channel register (CCx) act like a FIFO. When regular register (CCx) is empty
+ * or read, any content in the buffer register is passed to regular one.
+ *
+ * In TCC module driver, when the double buffering write is enabled, any
+ * write through \ref tcc_set_top_value(), \ref tcc_set_compare_value(), and
+ * \ref tcc_set_pattern() will be done to the corresponding buffer register.
+ * Then the value in the buffer register will be transferred to the regular
+ * register on the next UPDATE condition or by a force UPDATE using
+ * \ref tcc_force_double_buffer_update().
+ *
+ * \subsection asfdoc_sam0_tcc_module_overview_sleep Sleep Mode
+ *
+ * TCC modules can be configured to operate in any sleep mode, with its "run
+ * in standby" function enabled. It can wake up the device using interrupts or
+ * perform internal actions with the help of the Event System.
+ *
+ * \section asfdoc_sam0_tcc_special_considerations Special Considerations
+ *
+ * \subsection asfdoc_sam0_tcc_special_considerations_specific_features Driver Feature Macro Definition
+ * \ref asfdoc_sam0_tcc_feature_table "The table below" shows some specific features
+ * of the TCC Module.
+ *
+ * \anchor asfdoc_sam0_tcc_feature_table
+ *
+ *
TCC Module Specific Features
+ *
+ *
Driver Feature Macro
+ *
Supported devices
+ *
+ *
+ *
FEATURE_TCC_GENERATE_DMA_TRIGGER
+ *
SAM L21/L22/R30/R34/R35
+ *
+ *
+ *
+ * \note The specific features are only available in the driver when the
+ * selected device supports those features.
+ *
+ * \subsection asfdoc_sam0_tcc_special_considerations_tcc_feature Module Features
+ *
+ * The features of TCC, such as timer/counter size, number of compare capture
+ * channels, and number of outputs, are dependent on the TCC module instance being
+ * used.
+ *
+ * \subsubsection asfdoc_sam0_tcc_special_considerations_tcc_d21 SAM TCC Feature List
+ * For SAM D21/R21/L21/L22/DA1/C21/R30, the TCC features are:
+ * \anchor asfdoc_sam0_tcc_features_d21
+ *
+ *
TCC module features for SAM D21/R21/L21/L22/DA1/C21/R30
+ *
+ *
TCC#
+ *
Match/Capture channels
+ *
Wave outputs
+ *
Counter size [bits]
+ *
Fault
+ *
Dithering
+ *
Output matrix
+ *
Dead-Time insertion
+ *
SWAP
+ *
Pattern
+ *
+ *
+ *
0
+ *
4
+ *
8
+ *
24
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
+ *
+ *
1
+ *
2
+ *
4
+ *
24
+ *
Y
+ *
Y
+ *
+ *
+ *
+ *
Y
+ *
+ *
+ *
2
+ *
2
+ *
2
+ *
16
+ *
Y
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * \subsubsection asfdoc_sam0_tcc_special_considerations_tcc_d11 SAM D10/D11 TCC Feature List
+ * For SAM D10/D11, the TCC features are:
+ * \anchor asfdoc_sam0_tcc_features_d11
+ *
+ *
TCC Module Features For SAM D10/D11
+ *
+ *
TCC#
+ *
Match/Capture channels
+ *
Wave outputs
+ *
Counter size [bits]
+ *
Fault
+ *
Dithering
+ *
Output matrix
+ *
Dead-Time insertion
+ *
SWAP
+ *
Pattern
+ *
+ *
+ *
0
+ *
4
+ *
8
+ *
24
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
Y
+ *
+ *
+ *
+ * \subsection asfdoc_sam0_tcc_special_considerations_tcc_pin Channels vs. Pinouts
+ *
+ * As the TCC module may have more waveform output pins than the number of
+ * compare/capture channels, the free pins (with number higher than number of
+ * channels) will reuse the waveform generated by channels subsequently. E.g.,
+ * if the number of channels is four and the number of wave output pins is eight, channel
+ * 0 output will be available on out pin 0 and 4, channel 1 output
+ * on wave out pin 1 and 5, and so on.
+ *
+ * \section asfdoc_sam0_tcc_extra_info Extra Information
+ *
+ * For extra information, see \ref asfdoc_sam0_tcc_extra. This includes:
+ * - \ref asfdoc_sam0_tcc_extra_acronyms
+ * - \ref asfdoc_sam0_tcc_extra_dependencies
+ * - \ref asfdoc_sam0_tcc_extra_errata
+ * - \ref asfdoc_sam0_tcc_extra_history
+ *
+ *
+ * \section asfdoc_sam0_tcc_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_tcc_exqsg.
+ *
+ * \section asfdoc_sam0_tcc_api_overview API Overview
+ * @{
+ */
+
+#include
+#include
+#include
+#include
+
+/** Maximum number of channels supported by the driver
+ * (Channel index from 0 to \c TCC_NUM_CHANNELS - 1).
+ */
+#define TCC_NUM_CHANNELS 4
+
+/** Maximum number of wave outputs lines supported by the driver
+ * (Output line index from 0 to \c TCC_NUM_WAVE_OUTPUTS - 1).
+ */
+#define TCC_NUM_WAVE_OUTPUTS 8
+
+/** Maximum number of (recoverable) faults supported by the driver. */
+#define TCC_NUM_FAULTS 2
+
+#if TCC_ASYNC == true
+# include
+#endif
+
+/**
+ * \name Driver Feature Definition
+ * Define port features set according to different device family.
+ * @{
+*/
+#if (SAML21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__)
+/** Generate DMA triggers */
+# define FEATURE_TCC_GENERATE_DMA_TRIGGER
+#endif
+/*@}*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Generates a table enum list entry for a given type
+ and index (e.g. "TCC_CALLBACK_MC_CHANNEL_0,"). */
+#define _TCC_ENUM(n, type) TCC_##type##_##n,
+
+/** Generates table enum list entries for all channels of a
+ given type and channel number on TCC module. */
+#define _TCC_CHANNEL_ENUM_LIST(type) \
+ MREPEAT(TCC_NUM_CHANNELS, _TCC_ENUM, type##_CHANNEL)
+/** Generates table enum list entries for all output of a
+ given type and waveform output number on TCC module. */
+#define _TCC_WO_ENUM_LIST(type) \
+ MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_ENUM, type)
+
+
+#if TCC_ASYNC == true
+/** Enum for the possible callback types for the TCC module. */
+enum tcc_callback {
+ /** Callback for TCC overflow */
+ TCC_CALLBACK_OVERFLOW,
+ /** Callback for TCC Retrigger */
+ TCC_CALLBACK_RETRIGGER,
+ /** Callback for TCC counter event */
+ TCC_CALLBACK_COUNTER_EVENT,
+ /** Callback for capture overflow error */
+ TCC_CALLBACK_ERROR,
+ /** Callback for Recoverable Fault A */
+ TCC_CALLBACK_FAULTA,
+ /** Callback for Recoverable Fault B */
+ TCC_CALLBACK_FAULTB,
+ /** Callback for Non-Recoverable Fault 0 */
+ TCC_CALLBACK_FAULT0,
+ /** Callback for Non-Recoverable Fault 1 */
+ TCC_CALLBACK_FAULT1,
+
+# if defined(__DOXYGEN__)
+ /** Channel callback type table for TCC
+ *
+ * Each TCC module may contain several callback types for channels; each
+ * channel will have its own callback type in the table, with the channel
+ * index number substituted for "n" in the channel callback type
+ * (e.g. \c TCC_MATCH_CAPTURE_CHANNEL_0).
+ */
+ TCC_CALLBACK_CHANNEL_n = n,
+# else
+ /** Callbacks for Match/Capture channels, e.g., TCC_CALLBACK_CHANNEL_0 */
+ _TCC_CHANNEL_ENUM_LIST(CALLBACK)
+# endif
+
+# if !defined(__DOXYGEN__)
+ /** Number of available callbacks */
+ TCC_CALLBACK_N
+# endif
+};
+#endif /* #if TCC_ASYNC == true */
+
+/**
+ * \name Module Status Flags
+ *
+ * TCC status flags, returned by \ref tcc_get_status() and cleared by
+ * \ref tcc_clear_status().
+ *
+ * @{
+ */
+
+/** Timer channel \c ch (0 ~ 3) has matched against its compare value,
+ * or has captured a new value.
+ */
+#define TCC_STATUS_CHANNEL_MATCH_CAPTURE(ch) (1UL << (ch))
+/** Timer channel \c ch (0 ~ 3) match/compare output state. */
+#define TCC_STATUS_CHANNEL_OUTPUT(ch) (1UL << ((ch)+8))
+/** A Non-Recoverable Fault \c x (0 ~ 1) has occurred. */
+#define TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) (1UL << ((x)+16))
+/** A Recoverable Fault \c n (0 ~ 1 representing A ~ B) has occured. */
+#define TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) (1UL << ((n)+18))
+/** The Non-Recoverable Fault \c x (0 ~ 1) input is present. */
+#define TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) (1UL << ((x)+20))
+/** A Recoverable Fault \c n (0 ~ 1 representing A ~ B) is present. */
+#define TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) (1UL << ((n)+22))
+/** Timer registers synchronization has completed, and the synchronized count
+ * value may be read.
+ */
+#define TCC_STATUS_SYNC_READY (1UL << 23)
+/** A new value was captured before the previous value was read, resulting in
+ * lost data.
+ */
+#define TCC_STATUS_CAPTURE_OVERFLOW (1UL << 24)
+/** A counter event occurred. */
+#define TCC_STATUS_COUNTER_EVENT (1UL << 25)
+/** A counter retrigger occurred. */
+#define TCC_STATUS_COUNTER_RETRIGGERED (1UL << 26)
+/** The timer count value has overflowed from its maximum value to its minimum
+ * when counting upward, or from its minimum value to its maximum when
+ * counting downward.
+ */
+#define TCC_STATUS_COUNT_OVERFLOW (1UL << 27)
+/** Ramp period cycle index.
+ * In ramp operation, each two period cycles are marked as cycle A and B,
+ * the index 0 represents cycle A and 1 represents cycle B. */
+#define TCC_STATUS_RAMP_CYCLE_INDEX (1UL << 28)
+/** The counter has been stopped (due to disable, stop command, or one-shot). */
+#define TCC_STATUS_STOPPED (1UL << 29)
+
+/** @} */
+
+/**
+ * \brief Index of the match capture channels
+ *
+ * This enum is used to specify which capture/match channel to do
+ * operations on.
+ */
+enum tcc_match_capture_channel {
+# if defined(__DOXYGEN__)
+ /** Match capture channel index table for TCC
+ *
+ * Each TCC module may contain several match capture channels; each channel
+ * will have its own index in the table, with the index number substituted
+ * for "n" in the index name (e.g. \c TCC_MATCH_CAPTURE_CHANNEL_0).
+ */
+ TCC_MATCH_CAPTURE_CHANNEL_n = n,
+# else
+ /** Indexes of match capture channels, e.g., TCC_MATCH_CAPTURE_CHANNEL_0 */
+ _TCC_CHANNEL_ENUM_LIST(MATCH_CAPTURE)
+# endif
+# if !defined(__DOXYGEN__)
+ /** Number of supported channels */
+ TCC_MATCH_CAPTURE_CHANNEL_N
+# endif
+};
+
+/**
+ * \brief Index of the wave outputs
+ *
+ * This enum is used to specify which wave output to do
+ * operations on.
+ */
+enum tcc_wave_output {
+# if defined(__DOXYGEN__)
+ /** Waveform output index table for TCC
+ *
+ * Each TCC module may contain several wave outputs; each output
+ * will have its own index in the table, with the index number substituted
+ * for "n" in the index name (e.g. \c TCC_WAVE_OUTPUT_0).
+ */
+ TCC_WAVE_OUTPUT_n = n,
+# else
+ /** Indexes of match capture channels, e.g., TCC_WAVEFORM_OUTPUT_0 */
+ _TCC_WO_ENUM_LIST(WAVE_OUTPUT)
+# endif
+# if !defined(__DOXYGEN__)
+ /** Number of supported channels */
+ TCC_WAVE_OUTPUT_N
+# endif
+};
+
+/**
+ * \brief TCC wave generation mode enum
+ *
+ * This enum is used to specify the waveform generation mode.
+ *
+ */
+enum tcc_wave_generation {
+ /** Normal Frequency: Top is the PER register, output toggled on each
+ * compare match */
+ TCC_WAVE_GENERATION_NORMAL_FREQ = 0,
+ /** Match Frequency: Top is CC0 register, output toggles on each update
+ * condition */
+ TCC_WAVE_GENERATION_MATCH_FREQ = 1,
+ /** Single-Slope PWM: Top is the PER register, CCx controls duty cycle
+ * (output active when count is greater than CCx) */
+ TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM = 2,
+
+ /** Double-slope (count up and down), non centre-aligned: Top is the PER
+ * register, CC[x] controls duty cycle while counting up and CC[x+N/2]
+ * controls it while counting down */
+ TCC_WAVE_GENERATION_DOUBLE_SLOPE_CRITICAL = 4,
+ /** Double-slope (count up and down), interrupt/event at Bottom (Top is the
+ * PER register, output active when count is greater than CCx) */
+ TCC_WAVE_GENERATION_DOUBLE_SLOPE_BOTTOM = 5,
+ /** Double-slope (count up and down), interrupt/event at Bottom and Top: (Top is the
+ * PER register, output active when count is lower than CCx) */
+ TCC_WAVE_GENERATION_DOUBLE_SLOPE_BOTH = 6,
+ /** Double-slope (count up and down), interrupt/event at Top (Top is the
+ * PER register, output active when count is greater than CCx) */
+ TCC_WAVE_GENERATION_DOUBLE_SLOPE_TOP = 7,
+};
+
+/**
+ * \brief Polarity of TCC wave generation on channels
+ *
+ * Specifies whether the wave output needs to be inverted or not.
+ */
+enum tcc_wave_polarity {
+ /** Wave output is not inverted */
+ TCC_WAVE_POLARITY_0,
+ /** Wave output is inverted */
+ TCC_WAVE_POLARITY_1
+};
+
+/**
+ * \brief TCC pattern generator for outputs
+ *
+ * Used when disabling output pattern or when selecting a specific pattern.
+ */
+enum tcc_output_pattern {
+ /** SWAP output pattern is not used */
+ TCC_OUTPUT_PATTERN_DISABLE,
+ /** Pattern 0 is applied to SWAP output */
+ TCC_OUTPUT_PATTERN_0,
+ /** Pattern 1 is applied to SWAP output */
+ TCC_OUTPUT_PATTERN_1
+};
+
+/**
+ * \brief Ramp Operations which are supported in single-slope PWM generation
+ *
+ * Ramp operations which are supported in single-slope PWM generation.
+ */
+enum tcc_ramp {
+ /** Default timer/counter PWM operation */
+ TCC_RAMP_RAMP1 = 0,
+
+ /** Uses a single channel (CC0) to control both CC0/CC1 compare outputs.
+ * In cycle A, the channel 0 output is disabled, and
+ * in cycle B, the channel 1 output is disabled. */
+ TCC_RAMP_RAMP2A,
+
+ /** Uses channels CC0 and CC1 to control compare outputs.
+ * In cycle A, the channel 0 output is disabled, and
+ * in cycle B, the channel 1 output is disabled.*/
+ TCC_RAMP_RAMP2
+};
+
+/**
+ * \brief Ramp Index for TCC wave generation
+ *
+ * In ramp operation, each two period cycles are marked as cycle A and B,
+ * the index 0 represents cycle A and 1 represents cycle B.
+ */
+enum tcc_ramp_index {
+ /** Default, cycle index toggles. */
+ TCC_RAMP_INDEX_DEFAULT,
+ /** Force next cycle to be cycle B (set to 1) */
+ TCC_RAMP_INDEX_FORCE_B,
+ /** Force next cycle to be cycle A (clear to 0) */
+ TCC_RAMP_INDEX_FORCE_A,
+ /** Force next cycle keeping the same as current */
+ TCC_RAMP_INDEX_FORCE_KEEP
+};
+
+/**
+ * \brief TCC output inversion
+ *
+ * Used when enabling or disabling output inversion.
+ */
+enum tcc_output_invertion {
+ /** Output inversion not to be enabled */
+ TCC_OUTPUT_INVERTION_DISABLE,
+ /** Invert the output from WO[x] */
+ TCC_OUTPUT_INVERTION_ENABLE
+};
+
+/**
+ * \brief TCC Counter reload action enum
+ *
+ * This enum specify how the counter is reloaded and whether the prescaler
+ * should be restarted.
+ */
+enum tcc_reload_action {
+ /** The counter is reloaded/reset on the next GCLK and starts
+ * counting on the prescaler clock
+ */
+ TCC_RELOAD_ACTION_GCLK,
+ /** The counter is reloaded/reset on the next prescaler clock
+ */
+ TCC_RELOAD_ACTION_PRESC,
+ /** The counter is reloaded/reset on the next GCLK, and the
+ * prescaler is restarted as well
+ */
+ TCC_RELOAD_ACTION_RESYNC
+};
+
+
+/**
+ * \brief TCC clock prescaler values
+ *
+ * This enum is used to choose the clock prescaler
+ * configuration. The prescaler divides the clock frequency of the TCC
+ * module to operate TCC at a slower clock rate.
+ */
+enum tcc_clock_prescaler {
+ /** Divide clock by 1 */
+ TCC_CLOCK_PRESCALER_DIV1,
+ /** Divide clock by 2 */
+ TCC_CLOCK_PRESCALER_DIV2,
+ /** Divide clock by 4 */
+ TCC_CLOCK_PRESCALER_DIV4,
+ /** Divide clock by 8 */
+ TCC_CLOCK_PRESCALER_DIV8,
+ /** Divide clock by 16 */
+ TCC_CLOCK_PRESCALER_DIV16,
+ /** Divide clock by 64 */
+ TCC_CLOCK_PRESCALER_DIV64,
+ /** Divide clock by 256 */
+ TCC_CLOCK_PRESCALER_DIV256,
+ /** Divide clock by 1024 */
+ TCC_CLOCK_PRESCALER_DIV1024
+};
+
+/**
+ * \brief TCC module count direction
+ *
+ * Used when selecting the Timer/Counter count direction.
+ */
+enum tcc_count_direction {
+ /** Timer should count upward */
+ TCC_COUNT_DIRECTION_UP,
+ /** Timer should count downward */
+ TCC_COUNT_DIRECTION_DOWN,
+};
+
+#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER
+/**
+ * \brief TCC module counter overflow DMA request mode
+ *
+ * Used when selecting the Timer/Counter overflow DMA request mode.
+ */
+enum tcc_count_overflow_dma_trigger_mode {
+ /** TCC generates a DMA request on each cycle when an update condition
+ * is detected
+ */
+ TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_CONTINUE,
+ /** When an update condition is detected, the TCC generates a DMA trigger
+ * on the cycle following the DMA One-Shot Command written to the Control
+ * B register
+ */
+ TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_ONE_SHOT,
+};
+#endif
+
+/**
+ * \brief Action to perform when the TCC module is triggered by events
+ *
+ * Event action to perform when the module is triggered by events.
+ */
+enum tcc_event_action {
+ /** No event action */
+ TCC_EVENT_ACTION_OFF,
+ /** Stop counting, the counter will maintain its current value, waveforms
+ * are set to a defined Non-Recoverable State output
+ * (\ref tcc_non_recoverable_state_output). */
+ TCC_EVENT_ACTION_STOP,
+ /** Re-trigger counter on event, may generate an event if the re-trigger
+ * event output is enabled.
+ * \note When re-trigger event action is enabled, enabling the counter
+ * will not start until the next incoming event appears. */
+ TCC_EVENT_ACTION_RETRIGGER,
+
+ /** Start counter when previously stopped.
+ * Start counting on the event rising edge. Further events will not
+ * restart the counter;
+ * the counter keeps on counting using prescaled GCLK_TCCx, until it
+ * reaches TOP or Zero
+ * depending on the direction. */
+ TCC_EVENT_ACTION_START,
+ /** Count events; i.e. Increment or decrement depending on count
+ * direction. */
+ TCC_EVENT_ACTION_COUNT_EVENT,
+ /** The event source must be an asynchronous event, input value will
+ * overrides the direction settings (input low: counting up, input high:
+ * counting down). */
+ TCC_EVENT_ACTION_DIR_CONTROL,
+ /** Increment the counter on event, irrespective of count direction */
+ TCC_EVENT_ACTION_INCREMENT,
+ /** Decrement the counter on event, irrespective of count direction */
+ TCC_EVENT_ACTION_DECREMENT,
+ /** Count during active state of asynchronous event. In this case,
+ * depending on the count direction, the count will be incremented
+ * or decremented on each prescaled GCLK_TCCx, as long as the input
+ * event remains active. */
+ TCC_EVENT_ACTION_COUNT_DURING_ACTIVE,
+
+ /** Store period in capture register 0, pulse width in capture
+ * register 1
+ */
+ TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE,
+ /** Store pulse width in capture register 0, period in capture
+ * register 1
+ */
+ TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURE,
+
+ /** Generate Non-Recoverable Fault on event */
+ TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT,
+};
+
+
+/**
+ * \brief Action to be performed when the TCC module is triggered by event0
+ *
+ * Event action to perform when the module is triggered by event0.
+ */
+enum tcc_event0_action {
+ /** No event action */
+ TCC_EVENT0_ACTION_OFF = TCC_EVENT_ACTION_OFF,
+ /** Re-trigger Counter on event */
+ TCC_EVENT0_ACTION_RETRIGGER = TCC_EVENT_ACTION_RETRIGGER,
+ /** Count events (increment or decrement, depending on count direction)
+ */
+ TCC_EVENT0_ACTION_COUNT_EVENT = TCC_EVENT_ACTION_COUNT_EVENT,
+ /** Start counter on event */
+ TCC_EVENT0_ACTION_START = TCC_EVENT_ACTION_START,
+ /** Increment counter on event */
+ TCC_EVENT0_ACTION_INCREMENT = TCC_EVENT_ACTION_INCREMENT,
+ /** Count during active state of asynchronous event */
+ TCC_EVENT0_ACTION_COUNT_DURING_ACTIVE = TCC_EVENT_ACTION_COUNT_DURING_ACTIVE,
+
+ /** Generate Non-Recoverable Fault on event */
+ TCC_EVENT0_ACTION_NON_RECOVERABLE_FAULT = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT
+};
+
+/**
+ * \brief Action to perform when the TCC module is triggered by event1
+ *
+ * Event action to perform when the module is triggered by event1.
+ */
+enum tcc_event1_action {
+ /** No event action */
+ TCC_EVENT1_ACTION_OFF = TCC_EVENT_ACTION_OFF,
+ /** Re-trigger Counter on event */
+ TCC_EVENT1_ACTION_RETRIGGER = TCC_EVENT_ACTION_RETRIGGER,
+ /** The event source must be an asynchronous event, and the input value
+ * will override the direction settings.
+ * If TCEINVx is 0 and input event is LOW: counter will count up.
+ * If TCEINVx is 0 and input event is HIGH: counter will count down.
+ */
+ TCC_EVENT1_ACTION_DIR_CONTROL = TCC_EVENT_ACTION_DIR_CONTROL,
+ /** Stop counter on event */
+ TCC_EVENT1_ACTION_STOP = TCC_EVENT_ACTION_STOP,
+ /** Decrement on event */
+ TCC_EVENT1_ACTION_DECREMENT = TCC_EVENT_ACTION_DECREMENT,
+
+ /** Store period in capture register 0, pulse width in capture
+ * register 1
+ */
+ TCC_EVENT1_ACTION_PERIOD_PULSE_WIDTH_CAPTURE = TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE,
+ /** Store pulse width in capture register 0, period in capture
+ * register 1
+ */
+ TCC_EVENT1_ACTION_PULSE_WIDTH_PERIOD_CAPTURE = TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURE,
+
+ /** Generate Non-Recoverable Fault on event */
+ TCC_EVENT1_ACTION_NON_RECOVERABLE_FAULT = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT
+};
+
+/**
+ * \brief On which part of the counter cycle the counter event output is generated
+ *
+ * This enum is used to define the point at which the counter event is generated.
+ */
+enum tcc_event_generation_selection {
+ /** Counter Event is generated when a new counter cycle starts */
+ TCC_EVENT_GENERATION_SELECTION_START,
+ /** Counter Event is generated when a counter cycle ends */
+ TCC_EVENT_GENERATION_SELECTION_END,
+ /** Counter Event is generated when a counter cycle ends, except for the
+ * first and last cycles */
+ TCC_EVENT_GENERATION_SELECTION_BETWEEN,
+ /** Counter Event is generated when a new counter cycle starts or ends */
+ TCC_EVENT_GENERATION_SELECTION_BOUNDARY
+};
+
+/**
+ * \brief TCC channel operation modes
+ *
+ * To set a timer channel either in compare or in capture mode.
+ */
+enum tcc_channel_function {
+ /** TCC channel performs compare operation */
+ TCC_CHANNEL_FUNCTION_COMPARE,
+ /** TCC channel performs capture operation */
+ TCC_CHANNEL_FUNCTION_CAPTURE
+};
+
+/**
+ * \brief TCC (recoverable) fault Halt action
+ */
+enum tcc_fault_halt_action {
+ /** Halt action disabled. */
+ TCC_FAULT_HALT_ACTION_DISABLE,
+ /** Hardware halt action, counter is halted until restart */
+ TCC_FAULT_HALT_ACTION_HW_HALT,
+ /** Software halt action, counter is halted until fault bit cleared */
+ TCC_FAULT_HALT_ACTION_SW_HALT,
+ /** Non-Recoverable fault, force output to pre-defined level */
+ TCC_FAULT_HALT_ACTION_NON_RECOVERABLE
+};
+
+/**
+ * \brief TCC (recoverable) fault Capture action
+ */
+enum tcc_fault_capture_action {
+ /** Capture disabled */
+ TCC_FAULT_CAPTURE_DISABLE,
+ /** Capture on Fault, each value is captured */
+ TCC_FAULT_CAPTURE_EACH,
+ /** Capture the minimum detection, but notify on smaller ones */
+ TCC_FAULT_CAPTURE_MINIMUM,
+ /** Capture the maximum detection, but notify on bigger ones */
+ TCC_FAULT_CAPTURE_MAXIMUM,
+ /** Capture if the value is smaller than last, notify event or interrupt
+ * if previous stamp is confirmed to be "local minimum" (not bigger than
+ * current stamp). */
+ TCC_FAULT_CAPTURE_SMALLER,
+ /** Capture if the value is bigger than last, notify event or interrupt
+ * if previous stamp is confirmed to be "local maximum" (not smaller than
+ * current stamp). */
+ TCC_FAULT_CAPTURE_BIGGER,
+ /** Capture if the time stamps changes its increment direction */
+ TCC_FAULT_CAPTURE_CHANGE
+};
+
+/**
+ * \brief Capture Channel triggered by TCC (recoverable) fault
+ */
+enum tcc_fault_capture_channel {
+ /** Recoverable fault triggers channel 0 capture operation */
+ TCC_FAULT_CAPTURE_CHANNEL_0,
+ /** Recoverable fault triggers channel 1 capture operation */
+ TCC_FAULT_CAPTURE_CHANNEL_1,
+ /** Recoverable fault triggers channel 2 capture operation */
+ TCC_FAULT_CAPTURE_CHANNEL_2,
+ /** Recoverable fault triggers channel 3 capture operation */
+ TCC_FAULT_CAPTURE_CHANNEL_3
+};
+
+/**
+ * \brief TCC (recoverable) fault Input Source
+ */
+enum tcc_fault_source {
+ /** Fault input is disabled */
+ TCC_FAULT_SOURCE_DISABLE,
+ /** Match Capture Event x (x=0,1) input */
+ TCC_FAULT_SOURCE_ENABLE,
+ /** Inverted MCEx (x=0,1) event input */
+ TCC_FAULT_SOURCE_INVERT,
+ /** Alternate fault (A or B) state at the end of the previous period */
+ TCC_FAULT_SOURCE_ALTFAULT
+};
+
+/**
+ * \brief TCC (recoverable) fault Input Blanking Start Point
+ */
+enum tcc_fault_blanking {
+ /** No blanking */
+ TCC_FAULT_BLANKING_DISABLE,
+ /** Blanking applied from rising edge of the output waveform */
+ TCC_FAULT_BLANKING_RISING_EDGE,
+ /** Blanking applied from falling edge of the output waveform */
+ TCC_FAULT_BLANKING_FALLING_EDGE,
+ /** Blanking applied from each toggle of the output waveform */
+ TCC_FAULT_BLANKING_BOTH_EDGE
+};
+
+/**
+ * \brief TCC (recoverable) fault Input Qualification Action
+ */
+enum tcc_fault_qualification {
+ /** The input is not disabled on compare condition */
+ TCC_FAULT_QUALIFICATION_DISABLE,
+ /** The input is disabled when match output signal is at inactive level */
+ TCC_FAULT_QUALIFICATION_BY_OUTPUT
+};
+
+/**
+ * \brief TCC (recoverable) fault Output Keep Action
+ */
+enum tcc_fault_keep {
+ /** Disable keeping, wave output released as soon as fault is released */
+ TCC_FAULT_KEEP_DISABLE,
+ /** Keep wave output until end of TCC cycle */
+ TCC_FAULT_KEEP_TILL_END
+};
+
+/**
+ * \brief TCC Non-recoverable State Outupt
+ */
+enum tcc_fault_state_output {
+ /** Non-recoverable fault output is tri-stated */
+ TCC_FAULT_STATE_OUTPUT_OFF,
+ /** Non-recoverable fault force output 0 */
+ TCC_FAULT_STATE_OUTPUT_0,
+ /** Non-recoverable fault force output 1 */
+ TCC_FAULT_STATE_OUTPUT_1
+};
+
+/**
+ * \brief TCC (recoverable) fault Restart Action
+ */
+enum tcc_fault_restart {
+ /** Restart Action disabled */
+ TCC_FAULT_RESTART_DISABLE,
+ /** Restart Action enabled */
+ TCC_FAULT_RESTART_ENABLE
+};
+
+/**
+ * \brief Configuration struct for TCC module recoverable fault
+ */
+struct tcc_recoverable_fault_config {
+ /** Fault filter value applied on MCEx event input line (0x0 ~ 0xF).
+ * Must be 0 when MCEx event is used as synchronous event.
+ * Apply to both recoverable and non-recoverable fault. */
+ uint8_t filter_value;
+ /** Fault blanking value (0 ~ 255), disable input source for several TCC
+ * clocks after the detection of the waveform edge */
+ uint8_t blanking_cycles;
+
+ /** Set to \c true to enable restart action */
+ bool restart;
+ /** Set to \c true to enable keep action (keep until end of TCC cycle) */
+ bool keep;
+
+ /** Set to \c true to enable input qualification
+ * (disable input when output is inactive) */
+ bool qualification;
+
+ /** Specifies if the event input generates recoverable Fault.
+ * The event system channel connected to MCEx event input must be
+ * configured as asynchronous.
+ */
+ enum tcc_fault_source source;
+ /** Fault Blanking Start Point for recoverable Fault */
+ enum tcc_fault_blanking blanking;
+
+ /** Halt action for recoverable Fault */
+ enum tcc_fault_halt_action halt_action;
+ /** Capture action for recoverable Fault */
+ enum tcc_fault_capture_action capture_action;
+ /** Channel triggered by recoverable Fault */
+ enum tcc_fault_capture_channel capture_channel;
+};
+
+/**
+ * \brief Configuration struct for TCC module non-recoverable fault
+ */
+struct tcc_non_recoverable_fault_config {
+ /** Fault filter value applied on TCEx event input line (0x0 ~ 0xF).
+ * Must be 0 when TCEx event is used as synchronous event. */
+ uint8_t filter_value;
+ /** Output */
+ enum tcc_fault_state_output output;
+};
+
+/**
+ * \brief TCC input event enable/disable/configure structure
+ *
+ * For configuring an input event.
+ */
+struct tcc_input_event_config {
+ /** Event action on incoming event */
+ enum tcc_event_action action;
+ /** Modify event action */
+ bool modify_action;
+ /** Invert incoming event input line */
+ bool invert;
+};
+
+/**
+ * \brief TCC output event enable/disable/configure structure
+ *
+ * Structure used for configuring an output event.
+ */
+struct tcc_output_event_config {
+ /** It decides which part of the counter cycle the counter event output
+ * is generated */
+ enum tcc_event_generation_selection generation_selection;
+ /** A switch to allow enable/disable of events, without modifying the
+ * event output configuration
+ */
+ bool modify_generation_selection;
+};
+
+/**
+ * \brief TCC event enable/disable structure
+ *
+ * Event flags for the \ref tcc_enable_events() and \ref tcc_disable_events().
+ */
+struct tcc_events {
+ /** Input events configuration */
+ struct tcc_input_event_config input_config[2];
+ /** Output event configuration */
+ struct tcc_output_event_config output_config;
+
+ /** Perform the configured event action when an incoming event is
+ * signalled */
+ bool on_input_event_perform_action[2];
+
+ /** Perform the configured event action when an incoming channel event is
+ * signalled */
+ bool on_event_perform_channel_action[TCC_NUM_CHANNELS];
+ /** Generate an output event on a channel capture/match.
+ * Specify which channels will generate events */
+ bool generate_event_on_channel[TCC_NUM_CHANNELS];
+
+ /** Generate an output event on counter overflow/underflow */
+ bool generate_event_on_counter_overflow;
+ /** Generate an output event on counter retrigger */
+ bool generate_event_on_counter_retrigger;
+ /** Generate an output event on counter boundary.
+ * See \ref tcc_event_output_action. */
+ bool generate_event_on_counter_event;
+};
+
+/**
+ * \brief Configuration struct for the TCC module base counter
+ *
+ * Structure for configuring a TCC as a counter.
+ */
+struct tcc_counter_config {
+ /** Value to initialize the count register */
+ uint32_t count;
+ /** Period/top and period/top buffer values for counter */
+ uint32_t period;
+
+ /** When \c true, the counter will be stopped on the next hardware or
+ * software re-trigger event or overflow/underflow
+ */
+ bool oneshot;
+
+#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER
+ /** Counter overflow trigger a DMA request mode */
+ enum tcc_count_overflow_dma_trigger_mode dma_trigger_mode;
+#endif
+
+ /** Specifies the direction for the TCC to count */
+ enum tcc_count_direction direction;
+
+ /** GCLK generator used to clock the peripheral */
+ enum gclk_generator clock_source;
+ /** Specifies the prescaler value for GCLK_TCC */
+ enum tcc_clock_prescaler clock_prescaler;
+ /** Specifies the reload or reset time of the counter and prescaler
+ * resynchronization on a re-trigger event for the TCC
+ */
+ enum tcc_reload_action reload_action;
+};
+
+/**
+ * \brief Configuration struct for the TCC module capture
+ *
+ * Structure used when configuring TCC channels in capture mode.
+ */
+struct tcc_capture_config {
+ /** Channel functions selection (capture/match) */
+ enum tcc_channel_function channel_function[TCC_NUM_CHANNELS];
+};
+
+/**
+ * \brief Configuration struct for the TCC module match/wave generation
+ *
+ * The structure, which helps to configure a TCC channel for compare
+ * operation and wave generation.
+ */
+struct tcc_match_wave_config {
+ /** Channel functions selection (capture/match) */
+ enum tcc_channel_function channel_function[TCC_NUM_CHANNELS];
+
+ /** Specifies polarity for match output waveform generation */
+ enum tcc_wave_polarity wave_polarity[TCC_NUM_CHANNELS];
+ /** Specifies which waveform generation mode to use */
+ enum tcc_wave_generation wave_generation;
+ /** Specifies Ramp mode for waveform generation */
+ enum tcc_ramp wave_ramp;
+
+ /** Value to be used for compare match on each channel */
+ uint32_t match[TCC_NUM_CHANNELS];
+};
+
+/**
+ * \brief Configuration struct for the TCC module waveform extension
+ *
+ * This structure is used to specify the waveform extension features for TCC.
+ */
+struct tcc_wave_extension_config {
+ /** Configuration for recoverable faults */
+ struct tcc_recoverable_fault_config
+ recoverable_fault[TCC_NUM_FAULTS];
+ /** Configuration for non-recoverable faults */
+ struct tcc_non_recoverable_fault_config
+ non_recoverable_fault[TCC_NUM_WAVE_OUTPUTS];
+
+ /** Invert waveform final outputs lines */
+ bool invert[TCC_NUM_WAVE_OUTPUTS];
+};
+
+/**
+ * \brief Configuration struct for the TCC module output pins
+ *
+ * Structure which is used when taking wave output from TCC.
+ */
+struct tcc_pins_config {
+ /** Specifies pin output for each channel */
+ uint32_t wave_out_pin[TCC_NUM_WAVE_OUTPUTS];
+ /** Specifies MUX setting for each output channel pin */
+ uint32_t wave_out_pin_mux[TCC_NUM_WAVE_OUTPUTS];
+ /** When \c true, PWM output pin for the given channel is enabled */
+ bool enable_wave_out_pin[TCC_NUM_WAVE_OUTPUTS];
+};
+
+/**
+ * \brief TCC configuration structure
+ *
+ * Configuration struct for a TCC instance. This structure should be
+ * initialized by the \ref tcc_get_config_defaults function before being
+ * modified by the user application.
+ */
+struct tcc_config {
+ /** Structure for configuring TCC base timer/counter */
+ struct tcc_counter_config counter;
+ /** TCC match/capture configurations */
+ union {
+ /** Helps to configure a TCC channel in capture mode */
+ struct tcc_capture_config capture;
+ /** For configuring a TCC channel in compare mode */
+ struct tcc_match_wave_config compare;
+ /** Serves the same purpose as compare. Used as an alias for
+ * compare,
+ * when a TCC channel is configured for wave generation */
+ struct tcc_match_wave_config wave;
+ };
+
+ /** Structure for configuring TCC waveform extension */
+ struct tcc_wave_extension_config wave_ext;
+
+ /** Structure for configuring TCC output pins */
+ struct tcc_pins_config pins;
+
+ /** Set to \c true to enable double buffering write. When enabled any write
+ * through \ref tcc_set_top_value(), \ref tcc_set_compare_value() and
+ * \ref tcc_set_pattern() will direct to the buffer register as buffered
+ * value, and the buffered value will be committed to effective register
+ * on UPDATE condition, if update is not locked.
+ *
+ * \note The init values in \ref tcc_config for \ref tcc_init are always
+ * filled to effective registers, no matter if double buffering is
+ * enabled or not.
+ */
+ bool double_buffering_enabled;
+
+ /** When \c true the module is enabled during standby */
+ bool run_in_standby;
+};
+
+#if TCC_ASYNC == true
+/* Forward Declaration for the device instance. */
+struct tcc_module;
+
+/** Type definition for the TCC callback function. */
+typedef void (*tcc_callback_t)(struct tcc_module *const module);
+#endif
+
+/**
+ * \brief TCC software device instance structure
+ *
+ * TCC software instance structure, used to retain software state information
+ * of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved only for module-internal use.
+ */
+struct tcc_module {
+ /** Hardware module pointer of the associated Timer/Counter peripheral. */
+ Tcc *hw;
+
+# if TCC_ASYNC == true
+ /** Array of callbacks */
+ tcc_callback_t callback[TCC_CALLBACK_N];
+ /** Bit mask for callbacks registered */
+ uint32_t register_callback_mask;
+ /** Bit mask for callbacks enabled */
+ uint32_t enable_callback_mask;
+# endif
+
+ /** Set to \c true to write to buffered registers */
+ bool double_buffering_enabled;
+};
+
+#if !defined(__DOXYGEN__)
+uint8_t _tcc_get_inst_index(
+ Tcc *const hw);
+#endif
+
+/**
+ * \name Driver Initialization and Configuration
+ * @{
+ */
+
+/**
+ * \brief Determines if the hardware module is currently synchronizing to the bus
+ *
+ * Checks to see if the underlying hardware peripheral module is currently
+ * synchronizing across multiple clock domains to the hardware bus. This
+ * function can be used to delay further operations on a module until such time
+ * that it is ready, to prevent blocking delays for synchronization in the
+ * user application.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ *
+ * \return Synchronization status of the underlying hardware module.
+ *
+ * \retval false If the module has completed synchronization
+ * \retval true If the module synchronization is ongoing
+ */
+static inline bool tcc_is_syncing(
+ const struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ return (module_inst->hw->SYNCBUSY.reg > 0);
+}
+
+
+void tcc_get_config_defaults(
+ struct tcc_config *const config,
+ Tcc *const hw);
+
+enum status_code tcc_init(
+ struct tcc_module *const module_inst,
+ Tcc *const hw,
+ const struct tcc_config *const config);
+
+/** @} */
+
+/**
+ * \name Event Management
+ * @{
+ */
+
+enum status_code tcc_enable_events(
+ struct tcc_module *const module_inst,
+ struct tcc_events *const events);
+
+void tcc_disable_events(
+ struct tcc_module *const module_inst,
+ struct tcc_events *const events);
+
+/** @} */
+
+/**
+ * \name Enable/Disable/Reset
+ * @{
+ */
+
+/**
+ * \brief Enable the TCC module
+ *
+ * Enables a TCC module that has been previously initialized. The counter will
+ * start when the counter is enabled.
+ *
+ * \note When the counter is configured to re-trigger on an event, the counter
+ * will not start until the next incoming event appears. Then it
+ * restarts on any following event.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tcc_enable(
+ 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;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_ENABLE) {
+ /* Wait for sync */
+ }
+
+ /* Enable the TCC module */
+ tcc_module->CTRLA.reg |= TCC_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Disables the TCC module
+ *
+ * Disables a TCC module and stops the counter.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tcc_disable(
+ 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;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_ENABLE) {
+ /* Wait for sync */
+ }
+
+ /* Disbale interrupt */
+ tcc_module->INTENCLR.reg = TCC_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ tcc_module->INTFLAG.reg = TCC_INTFLAG_MASK;
+
+ /* Disable the TCC module */
+ tcc_module->CTRLA.reg &= ~TC_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Resets the TCC module
+ *
+ * Resets the TCC module, restoring all hardware module registers to their
+ * default values and disabling the module. The TCC module will not be
+ * accessible while the reset is being performed.
+ *
+ * \note When resetting a 32-bit counter only the master TCC module's instance
+ * structure should be passed to the function.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ *
+ */
+static inline void tcc_reset(
+ const struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ /* Get a pointer to the module hardware instance */
+ Tcc *const tcc_module = module_inst->hw;
+
+ /* Disable this module if it is running */
+ if (tcc_module->CTRLA.reg & TCC_CTRLA_ENABLE) {
+ tcc_disable(module_inst);
+ while (tcc_is_syncing(module_inst)) {
+ /* wait while module is disabling */
+ }
+ }
+
+ /* Reset this TC module */
+ tcc_module->CTRLA.reg |= TCC_CTRLA_SWRST;
+}
+
+/** @} */
+
+
+/**
+ * \name Set/Toggle Count Direction
+ * @{
+ */
+
+/**
+ * \brief Sets the TCC module count direction
+ *
+ * Sets the count direction 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] dir New timer count direction to set
+ */
+static inline void tcc_set_count_direction(
+ const struct tcc_module *const module_inst,
+ enum tcc_count_direction dir)
+{
+ /* 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;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+
+ /* Set count direction */
+ if (TCC_COUNT_DIRECTION_DOWN == dir) {
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_DIR;
+ return;
+ }
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_DIR;
+}
+
+/**
+ * \brief Toggles the TCC module count direction
+ *
+ * Toggles the count direction 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
+ */
+static inline void tcc_toggle_count_direction(
+ 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;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ bool dir_value_1 = tcc_module->CTRLBSET.bit.DIR;
+ if (dir_value_1) {
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_DIR;
+ } else {
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_DIR;
+ }
+}
+
+/** @} */
+
+/**
+ * \name Get/Set Count Value
+ * @{
+ */
+
+uint32_t tcc_get_count_value(
+ const struct tcc_module *const module_inst);
+
+enum status_code tcc_set_count_value(
+ const struct tcc_module *const module_inst,
+ const uint32_t count);
+
+/** @} */
+
+/**
+ * \name Stop/Restart Counter
+ * @{
+ */
+
+/**
+ * \brief Stops the counter
+ *
+ * This function will stop the counter. When the counter is stopped
+ * the value in the count register is set to 0 if the counter was
+ * counting up, or maximum or the top value if the counter was counting
+ * down.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tcc_stop_counter(
+ 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 until last command is done */
+ do {
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk;
+ if (last_cmd == TCC_CTRLBSET_CMD_NONE) {
+ break;
+ } else if (last_cmd == TCC_CTRLBSET_CMD_STOP) {
+ /* Command have been issued */
+ return;
+ } else if (last_cmd == TCC_CTRLBSET_CMD_RETRIGGER) {
+ /* Cancel RETRIGGER command and issue STOP */
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_Msk;
+ }
+ } while (1);
+
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_STOP;
+}
+
+/**
+ * \brief Starts the counter from beginning
+ *
+ * Restarts an initialized TCC module's counter.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tcc_restart_counter(
+ 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 until last command is done */
+ do {
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk;
+ if (last_cmd == TCC_CTRLBSET_CMD_NONE) {
+ break;
+ } else if (last_cmd == TCC_CTRLBSET_CMD_RETRIGGER) {
+ /* Command have been issued */
+ return;
+ } else if (last_cmd == TCC_CTRLBSET_CMD_STOP) {
+ /* Cancel STOP command and issue RETRIGGER */
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_Msk;
+ }
+ } while (1);
+
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER;
+}
+
+/** @} */
+
+#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER
+/**
+ * \name Generate TCC DMA Triggers Command
+ * @{
+ */
+
+/**
+ * \brief TCC DMA Trigger.
+ *
+ * TCC DMA trigger command.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ */
+static inline void tcc_dma_trigger_command(
+ 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;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+
+ /* Make certain that there are no conflicting commands in the register */
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_NONE;
+
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+
+#if !(SAML21 || SAML22 || SAMR30 || SAMR34 || SAMR35 || WLR089)
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_DMATRG;
+#endif
+
+#if (SAML21XXXB) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089)
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_DMAOS;
+#endif
+}
+/** @} */
+#endif
+
+/**
+ * \name Get/Set Compare/Capture Register
+ * @{
+ */
+
+uint32_t tcc_get_capture_value(
+ const struct tcc_module *const module_inst,
+ const enum tcc_match_capture_channel channel_index);
+
+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);
+
+/** @} */
+
+/**
+ * \name Set Top Value
+ * @{
+ */
+
+enum status_code tcc_set_top_value(
+ const struct tcc_module *const module_inst,
+ const uint32_t top_value);
+
+/** @} */
+
+
+/**
+ * \name Set Output Pattern
+ * @{
+ */
+
+enum status_code tcc_set_pattern(
+ const struct tcc_module *const module_inst,
+ const uint32_t line_index,
+ const enum tcc_output_pattern pattern);
+
+/** @} */
+
+
+/**
+ * \name Set Ramp Index
+ * @{
+ */
+
+/**
+ * \brief Sets the TCC module ramp index on next cycle
+ *
+ * In RAMP2 and RAMP2A operation, we can force either cycle A or cycle B at
+ * the output, on the next clock cycle.
+ * When ramp index command is disabled, cycle A and cycle B will appear at
+ * the output, on alternate clock cycles.
+ * See \ref tcc_ramp.
+ *
+ * \param[in] module_inst Pointer to the software module instance struct
+ * \param[in] ramp_index Ramp index (\ref tcc_ramp_index) of the next cycle
+ */
+static inline void tcc_set_ramp_index(
+ const struct tcc_module *const module_inst,
+ const enum tcc_ramp_index ramp_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;
+ uint32_t last_cmd;
+
+ /* Wait until last command is done */
+ do {
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ if (TCC_RAMP_INDEX_DEFAULT == ramp_index) {
+ /* Cancel pending command */
+ tcc_module->CTRLBCLR.reg = TCC_CTRLBSET_IDXCMD_HOLD;
+ return;
+ }
+ last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_IDXCMD_Msk;
+ if (last_cmd == TCC_CTRLBSET_IDXCMD_DISABLE) {
+ break;
+ } else if (last_cmd == TCC_CTRLBSET_IDXCMD(ramp_index)) {
+ /* Command have been issued */
+ return;
+ }
+ } while (1);
+
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_IDXCMD(ramp_index);
+}
+
+/** @} */
+
+/**
+ * \name Status Management
+ * @{
+ */
+
+/**
+ * \brief Checks if the timer/counter is running
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ *
+ * \return Status which indicates whether the module is running.
+ *
+ * \retval true The timer/counter is running
+ * \retval false The timer/counter is stopped
+ */
+static inline bool tcc_is_running(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ return !module_inst->hw->STATUS.bit.STOP;
+}
+
+uint32_t tcc_get_status(
+ struct tcc_module *const module_inst);
+
+void tcc_clear_status(
+ struct tcc_module *const module_inst,
+ const uint32_t status_flags);
+
+/** @} */
+
+/**
+ * \name Double Buffering Management
+ * @{
+ */
+
+/**
+ * \brief Enable TCC double buffering write
+ *
+ * When double buffering write is enabled, the following function will write
+ * values to buffered registers instead of effective ones (buffered):
+ * - PERB: through \ref tcc_set_top_value()
+ * - CCBx(x is 0~3): through \ref tcc_set_compare_value()
+ * - PATTB: through \ref tcc_set_pattern()
+ *
+ * Then, on UPDATE condition the buffered registers are committed to regular ones
+ * to take effect.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ */
+static inline void tcc_enable_double_buffering(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+
+ module_inst->double_buffering_enabled = true;
+}
+
+/**
+ * \brief Disable TCC double buffering Write
+ *
+ * When double buffering write is disabled, following function will write values
+ * to effective registers (not buffered):
+ * - PER: through \ref tcc_set_top_value()
+ * - CCx(x is 0~3): through \ref tcc_set_compare_value()
+ * - PATT: through \ref tcc_set_pattern()
+ *
+ * \note This function does not lock double buffer update, which means on next
+ * UPDATE condition the last written buffered values will be committed to
+ * take effect. Invoke \ref tcc_lock_double_buffer_update() before this
+ * function to disable double buffering update, if this change is not
+ * expected.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ */
+static inline void tcc_disable_double_buffering(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ module_inst->double_buffering_enabled = false;
+}
+
+/**
+ * \brief Lock the TCC double buffered registers updates
+ *
+ * Locks the double buffered registers so they will not be updated through
+ * their buffered values on UPDATE conditions.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ *
+ */
+static inline void tcc_lock_double_buffer_update(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ while (module_inst->hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ module_inst->hw->CTRLBSET.reg = TCC_CTRLBSET_LUPD;
+}
+
+/**
+ * \brief Unlock the TCC double buffered registers updates
+ *
+ * Unlock the double buffered registers so they will be updated through
+ * their buffered values on UPDATE conditions.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ *
+ */
+static inline void tcc_unlock_double_buffer_update(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ while (module_inst->hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ module_inst->hw->CTRLBCLR.reg = TCC_CTRLBCLR_LUPD;
+}
+
+/**
+ * \brief Force the TCC double buffered registers to update once
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ *
+ */
+static inline void tcc_force_double_buffer_update(
+ 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 until last command is done */
+ do {
+ while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
+ /* Wait for sync */
+ }
+ last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk;
+ if (last_cmd == TCC_CTRLBSET_CMD_NONE) {
+ break;
+ } else if (last_cmd == TCC_CTRLBSET_CMD_UPDATE) {
+ /* Command have been issued */
+ return;
+ }
+ } while (1);
+
+ /* Write command to execute */
+ tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_UPDATE;
+}
+
+/**
+ * \brief Enable Circular option for double buffered Top/Period Values
+ *
+ * Enable circular option for the double buffered top/period values.
+ * On each UPDATE condition, the contents of PERB and PER are switched, meaning
+ * that the contents of PERB are transferred to PER and the contents of PER are
+ * transferred to PERB.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ */
+static inline void tcc_enable_circular_buffer_top(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ module_inst->hw->WAVE.reg |= TCC_WAVE_CIPEREN;
+}
+
+/**
+ * \brief Disable Circular option for double buffered Top/Period Values
+ *
+ * Stop circularing the double buffered top/period values.
+ *
+ * \param[in] module_inst Pointer to the TCC software instance struct
+ */
+static inline void tcc_disable_circular_buffer_top(
+ struct tcc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ module_inst->hw->WAVE.reg &= ~TCC_WAVE_CIPEREN;
+}
+
+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);
+
+
+enum status_code tcc_enable_circular_buffer_compare(
+ struct tcc_module *const module_inst,
+ enum tcc_match_capture_channel channel_index);
+enum status_code tcc_disable_circular_buffer_compare(
+ struct tcc_module *const module_inst,
+ enum tcc_match_capture_channel channel_index);
+enum status_code tcc_set_double_buffer_compare_values(
+ struct tcc_module *const module_inst,
+ enum tcc_match_capture_channel channel_index,
+ const uint32_t compare,
+ const uint32_t compare_buffer);
+
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * \page asfdoc_sam0_tcc_extra Extra Information for TCC Driver
+ *
+ * \section asfdoc_sam0_tcc_extra_acronyms Acronyms
+ * The table below presents the acronyms used in this module:
+ *
+ *
+ *
+ *
Acronym
+ *
Description
+ *
+ *
+ *
DMA
+ *
Direct Memory Access
+ *
+ *
+ *
TCC
+ *
Timer Counter for Control Applications
+ *
+ *
+ *
PWM
+ *
Pulse Width Modulation
+ *
+ *
+ *
PWP
+ *
Pulse Width Period
+ *
+ *
+ *
PPW
+ *
Period Pulse Width
+ *
+ *
+ *
+ *
+ * \section asfdoc_sam0_tcc_extra_dependencies Dependencies
+ * This driver has the following dependencies:
+ *
+ * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+ *
+ *
+ * \section asfdoc_sam0_tcc_extra_errata Errata
+ * There are no errata related to this driver.
+ *
+ *
+ * \section asfdoc_sam0_tcc_extra_history Module History
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in
+ * the table.
+ *
+ *
+ *
+ *
Changelog
+ *
+ *
+ *
Add double buffering functionality
+ *
+ *
+ *
Add fault handling functionality
+ *
+ *
+ *
Initial Release
+ *
+ *
+ */
+
+/**
+ * \page asfdoc_sam0_tcc_exqsg Examples for TCC Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_tcc_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that QSGs can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_sam0_tcc_basic_use_case
+ * - \subpage asfdoc_sam0_tcc_buffering_use_case
+ * \if TCC_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_tcc_timer_use_case
+ * - \subpage asfdoc_sam0_tcc_callback_use_case
+ * - \subpage asfdoc_sam0_tcc_faultx_use_case
+ * - \subpage asfdoc_sam0_tcc_faultn_use_case
+ * \endif
+ * - \subpage asfdoc_sam0_tcc_dma_use_case
+ *
+ * \page asfdoc_sam0_tcc_document_revision_history Document Revision History
+ *
+ *
+ *
+ *
Doc. Rev.
+ *
Date
+ *
Comments
+ *
+ *
+ *
42256C
+ *
12/2015
+ *
Added support for SAM L21/L22, SAM DA1, and SAM C20/C21
+ *
+ *
+ *
42256B
+ *
12/2014
+ *
Added fault handling functionality.
+ * Added double buffering functionality with use case.
+ * Added timer use case.
+ * Added SAM R21/D10/D11 support.
+ *
+ *
+ *
42256A
+ *
01/2014
+ *
Initial release
+ *
+ *
+ */
+
+#endif /* TCC_H_INCLUDED */
diff --git a/TE_Controller/src/asf.h b/TE_Controller/src/asf.h
index 7976a11..ab148d1 100644
--- a/TE_Controller/src/asf.h
+++ b/TE_Controller/src/asf.h
@@ -73,7 +73,7 @@
// From module: FreeRTOS - kernel 10.0.0
#include
-#include
+//#include
#include
#include
#include
@@ -135,6 +135,13 @@
#include
#include
+// From module: TC - Timer Counter (Callback APIs)
+#include
+#include
+
+// From module: TCC - Timer Counter for Control Applications (Polled APIs)
+#include
+
// From module: USB - Universal Serial Bus
#include
diff --git a/TE_Controller/src/include/adn8831.h b/TE_Controller/src/include/adn8831.h
new file mode 100644
index 0000000..9b4f239
--- /dev/null
+++ b/TE_Controller/src/include/adn8831.h
@@ -0,0 +1,16 @@
+/*
+ * adn8831.h
+ *
+ * Created: 04.01.2021 19:13:57
+ * Author: Lexus
+ */
+
+
+#ifndef ADN8831_H_
+#define ADN8831_H_
+#include
+#define MAX_STR_FLOAT 12
+void make_float2str(char * str, uint16_t len, float value);
+void ADN8831_control(void);
+
+#endif /* ADN8831_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/backlight.h b/TE_Controller/src/include/backlight.h
new file mode 100644
index 0000000..4d8039c
--- /dev/null
+++ b/TE_Controller/src/include/backlight.h
@@ -0,0 +1,27 @@
+/*
+ * backlight.h
+ *
+ * Created: 10.04.2020 0:41:41
+ * Author: User
+ */
+
+
+#ifndef BACKLIGHT_H_
+#define BACKLIGHT_H_
+
+
+void backlight_event_100ms(void);
+void backlight_event_1s(void);
+void backlight_mode_demo(void);
+void backlight_init(void);
+void backlight_ws2812_sendarray(void);
+void backlight_color_show(uint8_t R, uint8_t G, uint8_t B);
+
+enum backlight_mode
+{
+ mode_none=0,
+ mode_constant,
+ mode_demo
+};
+
+#endif /* BACKLIGHT_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/dht.h b/TE_Controller/src/include/dht.h
new file mode 100644
index 0000000..20ced1b
--- /dev/null
+++ b/TE_Controller/src/include/dht.h
@@ -0,0 +1,36 @@
+/*
+ * dht.h
+ *
+ * Created: 04.01.2021 21:06:23
+ * Author: Lexus
+ */
+
+
+#ifndef DHT_H_
+#define DHT_H_
+
+#include
+
+/* Структура возвращаемых датчиком данных */
+typedef struct {
+ float hum;
+ float temp;
+} DHT_data;
+/* Тип используемого датчика */
+typedef enum {
+ DHT11,
+ DHT22
+} DHT_type;
+
+/* Настройки */
+#define DHT_Pin PIN_PA15 //Пин линии данных
+#define DHT_timeout 1000000 //Количество итераций, после которых функция вернёт пустые значения
+
+/* Прототипы функций */
+uint8_t DHT_getData(DHT_type t, DHT_data* p_data); //Получить данные с датчика
+uint8_t _DHT_getData(DHT_type t, DHT_data* p_data);
+void measurement_DHT22(void);
+
+
+
+#endif /* DHT_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/light_ws2812_cortex.c b/TE_Controller/src/include/light_ws2812_cortex.c
new file mode 100644
index 0000000..f9a2c37
--- /dev/null
+++ b/TE_Controller/src/include/light_ws2812_cortex.c
@@ -0,0 +1,128 @@
+/*
+ * light weight WS2812 lib - ARM Cortex M0/M0+ version
+ *
+ * Created: 07.07.2013
+ * Author: Tim (cpldcpu@gmail.com)
+ */
+
+#include "light_ws2812_cortex.h"
+/*
+* The total length of each bit is 1.25Вµs (25 cycles @ 20Mhz)
+* At 0Вµs the dataline is pulled high.
+* To send a zero the dataline is pulled low after 0.375Вµs
+* To send a one the dataline is pulled low after 0.625Вµs
+*/
+
+#define ws2812_ctot (((F_CPU/1000)*1250)/1000000)
+#define ws2812_t1 (((F_CPU/1000)*375 )/1000000) // floor
+#define ws2812_t2 (((F_CPU/1000)*625+500000)/1000000) // ceil
+
+#define w1 (ws2812_t1-2)
+#define w2 (ws2812_t2-ws2812_t1-2)
+#define w3 (ws2812_ctot-ws2812_t2-5)
+
+#define ws2812_DEL1 " nop \n\t"
+#define ws2812_DEL2 ws2812_DEL1 ws2812_DEL1
+//#define ws2812_DEL2 " b .+2 \n\t"
+#define ws2812_DEL4 ws2812_DEL2 ws2812_DEL2
+#define ws2812_DEL8 ws2812_DEL4 ws2812_DEL4
+#define ws2812_DEL16 ws2812_DEL8 ws2812_DEL8
+
+#define ws2812_DEL ws2812_DEL8 ws2812_DEL2
+
+
+void ws2812_sendarray(uint8_t *data,int datlen)
+{
+ uint8_t gpio_pin = PIN_PA23;
+ PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
+ uint32_t pin_mask = (1UL << (gpio_pin % 32));
+
+ uint32_t maskhi = pin_mask;
+ uint32_t masklo = pin_mask;
+ volatile uint32_t *set = &port_base->OUTSET.reg;
+ volatile uint32_t *clr = &port_base->OUTCLR.reg;
+ uint32_t i=0;
+ uint32_t curbyte;
+
+ while (datlen--) {
+ curbyte=*data++;
+
+ asm volatile(
+ " lsl %[dat],#24 \n\t"
+ " movs %[ctr],#8 \n\t"
+ "ilop%=: \n\t"
+ " lsl %[dat], #1 \n\t"
+ " str %[maskhi], [%[set]] \n\t"
+ws2812_DEL
+// ws2812_DEL19
+/*
+#if (w1&1)
+ ws2812_DEL1
+#endif
+#if (w1&2)
+ ws2812_DEL2
+#endif
+#if (w1&4)
+ ws2812_DEL4
+#endif
+#if (w1&8)
+ ws2812_DEL8
+#endif
+#if (w1&16)
+ ws2812_DEL16
+#endif
+*/
+ " bcs one%= \n\t"
+ " str %[masklo], [%[clr]] \n\t"
+ "one%=: \n\t"
+
+ws2812_DEL
+
+/*
+#if (w2&1)
+ ws2812_DEL1
+#endif
+#if (w2&2)
+ ws2812_DEL2
+#endif
+#if (w2&4)
+ ws2812_DEL4
+#endif
+#if (w2&8)
+ ws2812_DEL8
+#endif
+#if (w2&16)
+ ws2812_DEL16
+#endif
+*/
+ " sub %[ctr], #1 \n\t"
+ " str %[masklo], [%[clr]] \n\t"
+ " beq end%= \n\t"
+
+ws2812_DEL
+
+/*
+#if (w3&1)
+ ws2812_DEL1
+#endif
+#if (w3&2)
+ ws2812_DEL2
+#endif
+#if (w3&4)
+ ws2812_DEL4
+#endif
+#if (w3&8)
+ ws2812_DEL8
+#endif
+#if (w3&16)
+ ws2812_DEL16
+#endif
+*/
+
+ " b ilop%= \n\t"
+ "end%=: \n\t"
+ : [ctr] "+r" (i)
+ : [dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi)
+ );
+ }
+}
diff --git a/TE_Controller/src/include/light_ws2812_cortex.h b/TE_Controller/src/include/light_ws2812_cortex.h
new file mode 100644
index 0000000..b7a412d
--- /dev/null
+++ b/TE_Controller/src/include/light_ws2812_cortex.h
@@ -0,0 +1,110 @@
+/*
+ * light weight WS2812 lib - ARM Cortex M0/M0+ version
+ *
+ * Created: 07.07.2013
+ * Author: Tim (cpldcpu@gmail.com)
+ */
+
+#ifndef LIGHT_WS2812_H_
+#define LIGHT_WS2812_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define F_CPU 48000000LU
+#define LIGHT_WS2812_SAM
+
+///////////////////////////////////////////////////////////////////////
+// User defined area: CPU specific CMSIS include
+///////////////////////////////////////////////////////////////////////
+
+#if defined(LIGHT_WS2812_UC_LPC8XX)
+ #include "LPC8XX.h"
+ #define LIGHT_WS2812_LPC
+#elif defined(LIGHT_WS2812_UC_STM32L0XX)
+ #include "stm32l0xx_hal.h"
+ #define LIGHT_WS2812_STM32
+#elif defined(LIGHT_WS2812_UC_FSL)
+#include "fsl_port.h"
+#include "fsl_gpio.h"
+#define LIGHT_WS2812_FSL
+#elif defined(LIGHT_WS2812_SAM)
+#include
+#else
+#error "Error: Please define WS2812_UC_XXXXX"
+#endif
+
+///////////////////////////////////////////////////////////////////////
+// User defined area: Define I/O pin
+///////////////////////////////////////////////////////////////////////
+
+// Data port and pin definition for your CPU. Depending on the way
+// port access is implemented in your Cortex CPU, the set and clr
+// mask and addresses may be the same.
+#ifdef LIGHT_WS2812_LPC
+ // This example is for the NXP LPC81X
+ #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->SET0) // Address of the data port register to set the pin
+ #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->CLR0) // Address of the data port register to clear the pin
+
+ #define ws2812_mask_set (1<<2) // Bitmask to set the data out pin
+ #define ws2812_mask_clr (1<<2) // Bitmask to clear the data out pin
+#endif
+#ifdef LIGHT_WS2812_STM32
+ // This example is for STM32 family
+ #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->BSRR) // Address of the data port register to set the pin
+ #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->BRR) // Address of the data port register to clear the pin
+
+ #define ws2812_mask_set LIGHT_WS2812_GPIO_PIN // Bitmask to set the data out pin
+ #define ws2812_mask_clr LIGHT_WS2812_GPIO_PIN // Bitmask to clear the data out pin
+#endif
+#ifdef LIGHT_WS2812_FSL
+ // This example is for Freescale family
+ #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->PSOR) // Address of the data port register to set the pin
+ #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->PCOR) // Address of the data port register to clear the pin
+
+ #define ws2812_mask_set 1u << 2u // Bitmask to set the data out pin
+ #define ws2812_mask_clr 1u << 2u // Bitmask to clear the data out pin
+#endif
+///////////////////////////////////////////////////////////////////////
+// CPU clock speed
+//
+// The current implementation of the sendarray routine uses cycle accurate
+// active waiting. The routine is automatically adjusted according to
+// the clockspeed defined below. Only values between 8 Mhz and 60 Mhz
+// are allowable.
+//
+// Important: The timing calculation assumes that there are no waitstates
+// for code memory access. If there are waitstates you may have to reduce
+// the value below until you get acceptable timing. It is highly recommended
+// to use this library only on devices without flash waitstates and
+// predictable code execution timing.
+///////////////////////////////////////////////////////////////////////
+
+#ifndef F_CPU
+ #error "Error: F_CPU (CPU clock speed) is not defined"
+#endif
+
+#if (F_CPU<8000000)
+ #error "Minimum clockspeed for ARM ws2812 library is 8 Mhz!"
+#endif
+
+#if (F_CPU>60000000)
+ #error "Maximum clockspeed for ARM ws2812 library is 60 Mhz!"
+#endif
+
+
+///////////////////////////////////////////////////////////////////////
+// Main function call
+//
+// Call with address to led color array (order is Green-Red-Blue)
+// Numer of bytes to be transmitted is leds*3
+///////////////////////////////////////////////////////////////////////
+
+void ws2812_sendarray(uint8_t *ledarray,int length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIGHT_WS2812_H_ */
diff --git a/TE_Controller/src/include/ntc.h b/TE_Controller/src/include/ntc.h
new file mode 100644
index 0000000..d36eb3a
--- /dev/null
+++ b/TE_Controller/src/include/ntc.h
@@ -0,0 +1,27 @@
+/*
+ * ntc.h
+ *
+ * Created: 04.01.2021 18:57:42
+ * Author: Lexus
+ */
+
+
+#ifndef NTC_H_
+#define NTC_H_
+#include
+
+ // ADC value to R
+ float NTC_MCU_value2R(uint16_t value);
+
+ float NTC_TEC_value2R(uint16_t value);
+
+ // Resistance to Temp
+ float NTC_R2T(float R);
+
+ // Read ADC and calculate temperature in Cenlsius.
+ float NTC_MCU_get_temp(void);
+
+ float NTC_TEC_get_temp(uint16_t *p_value, float *p_R);
+
+
+#endif /* NTC_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/realsence.h b/TE_Controller/src/include/realsence.h
index 7c59e4f..b9e90fd 100644
--- a/TE_Controller/src/include/realsence.h
+++ b/TE_Controller/src/include/realsence.h
@@ -8,8 +8,8 @@
#ifndef REALSENCE_H_
#define REALSENCE_H_
-
+#include
void rs_configure_port_pins(void);
-void rs_set(_Bool value);
+void rs_set(bool value);
#endif /* REALSENCE_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/tec.h b/TE_Controller/src/include/tec.h
new file mode 100644
index 0000000..3539076
--- /dev/null
+++ b/TE_Controller/src/include/tec.h
@@ -0,0 +1,19 @@
+/*
+ * tec.h
+ *
+ * Created: 04.01.2021 17:08:46
+ * Author: Lexus
+ */
+
+
+#ifndef TEC_H_
+#define TEC_H_
+#include
+
+bool VTEC_read(float *p_Vin, float *p_VTEC);
+bool ITEC_read(float *p_Vin, float *p_ITEC);
+void TEC_L_set(bool value);
+void TEC_set_level(float value);
+void TEC_set_TEMPSET_volt(float value);
+void pin_set_output(uint8_t pin, bool output_flag, uint8_t value);
+#endif /* TEC_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/include/tm_ds18b20.h b/TE_Controller/src/include/tm_ds18b20.h
new file mode 100644
index 0000000..e86a86a
--- /dev/null
+++ b/TE_Controller/src/include/tm_ds18b20.h
@@ -0,0 +1,273 @@
+/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.net
+ * @link http://stm32f4-discovery.net/2015/07/hal-library-06-ds18b20-for-stm32fxxx/
+ * @version v1.0
+ * @ide Keil uVision
+ * @license MIT
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors.
+ *
+\verbatim
+ ----------------------------------------------------------------------
+ Copyright (c) 2016 Tilen Majerle
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------
+\endverbatim
+ */
+#ifndef TM_DS18B20_H
+#define TM_DS18B20_H 100
+
+/**
+ * @addtogroup TM_STM32Fxxx_HAL_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_DS12820
+ * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors - http://stm32f4-discovery.net/2015/07/hal-library-06-ds18b20-for-stm32fxxx/
+ * @{
+ *
+ * With this you can read temperature, set and get temperature resolution from 9 to 12 bits and check if device is DS18B20.
+ *
+ * Pin for STM32Fxxx is the same as set with @ref TM_ONEWIRE library.
+ *
+ * \par Changelog
+ *
+\verbatim
+ Version 1.0
+ - First release
+\endverbatim
+ *
+ * \par Dependencies
+ *
+\verbatim
+ - STM32Fxxx HAL
+ - TM ONEWIRE
+ - TM GPIO
+ - defines.h
+\endverbatim
+ */
+
+#include "tm_onewire.h"
+
+/* OneWire version check */
+#if TM_ONEWIRE_H < 100
+#error "Please update TM ONEWIRE LIB, minimum required version is 2.0.0. Download available on stm32f4-discovery.net website"
+#endif
+
+/**
+ * @defgroup TM_DS18B20_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* Every onewire chip has different ROM code, but all the same chips has same family code */
+/* in case of DS18B20 this is 0x28 and this is first byte of ROM address */
+#define DS18B20_FAMILY_CODE 0x28
+#define DS18B20_CMD_ALARMSEARCH 0xEC
+
+/* DS18B20 read temperature command */
+#define DS18B20_CMD_CONVERTTEMP 0x44 /* Convert temperature */
+#define DS18B20_DECIMAL_STEPS_12BIT 0.0625
+#define DS18B20_DECIMAL_STEPS_11BIT 0.125
+#define DS18B20_DECIMAL_STEPS_10BIT 0.25
+#define DS18B20_DECIMAL_STEPS_9BIT 0.5
+
+/* Bits locations for resolution */
+#define DS18B20_RESOLUTION_R1 6
+#define DS18B20_RESOLUTION_R0 5
+
+/* CRC enabled */
+#ifdef DS18B20_USE_CRC
+#define DS18B20_DATA_LEN 9
+#else
+#define DS18B20_DATA_LEN 2
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief DS18B0 Resolutions available
+ */
+typedef enum {
+ TM_DS18B20_Resolution_9bits = 9, /*!< DS18B20 9 bits resolution */
+ TM_DS18B20_Resolution_10bits = 10, /*!< DS18B20 10 bits resolution */
+ TM_DS18B20_Resolution_11bits = 11, /*!< DS18B20 11 bits resolution */
+ TM_DS18B20_Resolution_12bits = 12 /*!< DS18B20 12 bits resolution */
+} TM_DS18B20_Resolution_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_DS18B20_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Starts temperature conversion for specific DS18B20 on specific onewire channel
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval 1 if device is DS18B20 or 0 if not
+ */
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Starts temperature conversion for all DS18B20 devices on specific onewire channel
+ * @note This mode will skip ROM addressing
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval None
+ */
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads temperature from DS18B20
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param *destination: Pointer to float variable to store temperature
+ * @retval Temperature status:
+ * - 0: Device is not DS18B20 or conversion is not done yet or CRC failed
+ * - > 0: Temperature is read OK
+ */
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWireStruct, uint8_t* ROM, float* destination);
+
+/**
+ * @brief Gets resolution for temperature conversion from DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Resolution:
+ * - 0: Device is not DS18B20
+ * - 9 - 12: Resolution of DS18B20
+ */
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Sets resolution for specific DS18B20 device
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param resolution: Resolution for DS18B20 device. This parameter can be a value of @ref TM_DS18B20_Resolution_t enumeration.
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Resolution set OK
+ */
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM, TM_DS18B20_Resolution_t resolution);
+
+/**
+ * @brief Checks if device with specific ROM number is DS18B20
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Device status
+ * - 0: Device is not DS18B20
+ * - > 0: Device is DS18B20
+ */
+uint8_t TM_DS18B20_Is(uint8_t* ROM);
+
+/**
+ * @brief Sets high alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: High alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Sets low alarm temperature to specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @param temp: integer value for temperature between -55 to 125 degrees
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Low alarm set OK
+ */
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp);
+
+/**
+ * @brief Disables alarm temperature for specific DS18B20 sensor
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device.
+ * Entire ROM address is 8-bytes long
+ * @retval Success status:
+ * - 0: Device is not DS18B20
+ * - > 0: Alarm disabled OK
+ */
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Searches for devices with alarm flag set
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Alarm search status
+ * - 0: No device found with alarm flag set
+ * - > 0: Device is found with alarm flag
+ * @note To get all devices on one onewire channel with alarm flag set, you can do this:
+\verbatim
+while (TM_DS18B20_AlarmSearch(&OneWireStruct)) {
+ //Read device ID here
+ //Print to user device by device
+}
+\endverbatim
+ * @retval 1 if any device has flag, otherwise 0
+ */
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Checks if all DS18B20 sensors are done with temperature conversion
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel)
+ * @retval Conversion status
+ * - 0: Not all devices are done
+ * - > 0: All devices are done with conversion
+ */
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @}
+ */
+void measurement_DS1820(void);
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
+
diff --git a/TE_Controller/src/include/tm_onewire.h b/TE_Controller/src/include/tm_onewire.h
new file mode 100644
index 0000000..b7a5e68
--- /dev/null
+++ b/TE_Controller/src/include/tm_onewire.h
@@ -0,0 +1,293 @@
+/**
+ * @author Tilen Majerle
+ * @email tilen@majerle.eu
+ * @website http://stm32f4-discovery.net
+ * @link http://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/
+ * @version v1.0
+ * @ide Keil uVision
+ * @license MIT
+ * @brief Onewire library for STM32Fxxx devices
+ *
+\verbatim
+ ----------------------------------------------------------------------
+ Copyright (c) 2016 Tilen Majerle
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------
+\endverbatim
+ */
+#ifndef TM_ONEWIRE_H
+#define TM_ONEWIRE_H 100
+
+/* C++ detection */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup TM_STM32Fxxx_HAL_Libraries
+ * @{
+ */
+
+/**
+ * @defgroup TM_ONEWIRE
+ * @brief Onewire library for STM32Fxxx devices - http://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/
+ * @{
+ *
+ * \par Changelog
+ *
+\verbatim
+ Version 1.0
+ - First release
+\endverbatim
+ *
+ * \par Dependencies
+ *
+\verbatim
+ - STM32Fxxx HAL
+ - defines.h
+ - TM DELAY
+ - TM GPIO
+\endverbatim
+ */
+
+#include
+
+/**
+ * @defgroup TM_ONEWIRE_Macros
+ * @brief Library defines
+ * @{
+ */
+
+/* OneWire delay */
+#define ONEWIRE_DELAY(x) delay_us(x)
+
+/* Pin settings */
+#define ONEWIRE_LOW(structure) port_pin_set_output_level((structure)->GPIO_Pin, 0)
+#define ONEWIRE_HIGH(structure) port_pin_set_output_level((structure)->GPIO_Pin, 1)
+#define ONEWIRE_GET_VALUE(structure) port_pin_get_input_level((structure)->GPIO_Pin)
+//#define ONEWIRE_INPUT(structure) TM_GPIO_SetPinAsInput(structure->GPIOx, (structure)->GPIO_Pin)
+//#define ONEWIRE_OUTPUT(structure) TM_GPIO_SetPinAsOutput(structure->GPIOx, (structure)->GPIO_Pin)
+
+/* OneWire commands */
+#define ONEWIRE_CMD_RSCRATCHPAD 0xBE
+#define ONEWIRE_CMD_WSCRATCHPAD 0x4E
+#define ONEWIRE_CMD_CPYSCRATCHPAD 0x48
+#define ONEWIRE_CMD_RECEEPROM 0xB8
+#define ONEWIRE_CMD_RPWRSUPPLY 0xB4
+#define ONEWIRE_CMD_SEARCHROM 0xF0
+#define ONEWIRE_CMD_READROM 0x33
+#define ONEWIRE_CMD_MATCHROM 0x55
+#define ONEWIRE_CMD_SKIPROM 0xCC
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Typedefs
+ * @brief Library Typedefs
+ * @{
+ */
+
+/**
+ * @brief OneWire working struct
+ * @note Except ROM_NO member, everything is fully private and should not be touched by user
+ */
+typedef struct {
+ uint8_t GPIO_Pin; /*!< GPIO Pin to be used for I/O functions */
+ uint8_t LastDiscrepancy; /*!< Search private */
+ uint8_t LastFamilyDiscrepancy; /*!< Search private */
+ uint8_t LastDeviceFlag; /*!< Search private */
+ uint8_t ROM_NO[8]; /*!< 8-bytes address of last search device */
+} TM_OneWire_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup TM_ONEWIRE_Functions
+ * @brief Library Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes OneWire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t empty working onewire structure
+ * @param *Pointer to GPIO port used for onewire channel
+ * @param GPIO_Pin: GPIO Pin on specific GPIOx to be used for onewire channel
+ * @retval None
+ */
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, uint8_t GPIO_Pin);
+
+/**
+ * @brief Resets OneWire bus
+ *
+ * @note Sends reset command for OneWire
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval None
+ */
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads byte from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Byte from read operation
+ */
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Writes byte to bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param byte: 8-bit value to write over OneWire protocol
+ * @retval None
+ */
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte);
+
+/**
+ * @brief Writes single bit to onewire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @param bit: Bit value to send, 1 or 0
+ * @retval None
+ */
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit);
+
+/**
+ * @brief Reads single bit from one wire bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure
+ * @retval Bit value:
+ * - 0: Bit is low (zero)
+ * - > 0: Bit is high (one)
+ */
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Searches for OneWire devices on specific Onewire port
+ * @note Not meant for public use. Use @ref TM_OneWire_First and @ref TM_OneWire_Next for this.
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure where to search
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command);
+
+/**
+ * @brief Resets search states
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @retval None
+ */
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Starts search, reset states first
+ * @note When you want to search for ALL devices on one onewire port, you should first use this function.
+\code
+//...Initialization before
+status = TM_OneWire_First(&OneWireStruct);
+while (status) {
+ //Save ROM number from device
+ TM_OneWire_GetFullROM(ROM_Array_Pointer);
+ //Check for new device
+ status = TM_OneWire_Next(&OneWireStruct);
+}
+\endcode
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values
+ * @param Device status:
+ * - 0: No devices detected
+ * - > 0: Device detected
+ */
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Reads next device
+ * @note Use @ref TM_OneWire_First to start searching
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param Device status:
+ * - 0: No devices detected any more
+ * - > 0: New device detected
+ */
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @brief Gets ROM number from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param index: Because each device has 8-bytes long ROm address, you have to call this 8 times, to get ROM bytes from 0 to 7
+ * @reetval ROM byte for index (0 to 7) at current found device
+ */
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index);
+
+/**
+ * @brief Gets all 8 bytes ROM value from device from search
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *firstIndex: Pointer to first location for first byte, other bytes are automatically incremented
+ * @retval None
+ */
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex);
+
+/**
+ * @brief Selects specific slave on bus
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *addr: Pointer to first location of 8-bytes long ROM address
+ * @retval None
+ */
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr);
+
+/**
+ * @brief Selects specific slave on bus with pointer address
+ * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire
+ * @param *ROM: Pointer to first byte of ROM address
+ * @retval None
+ */
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t* ROM);
+
+/**
+ * @brief Calculates 8-bit CRC for 1-wire devices
+ * @param *addr: Pointer to 8-bit array of data to calculate CRC
+ * @param len: Number of bytes to check
+ *
+ * @retval Calculated CRC from input data
+ */
+uint8_t TM_OneWire_CRC8(uint8_t* addr, uint8_t len);
+
+
+void ONEWIRE_OUTPUT(TM_OneWire_t* OneWireStruct);
+void ONEWIRE_INPUT(TM_OneWire_t* OneWireStruct);
+
+/**
+ * @}
+ */
+ int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct);
+/**
+ * @}
+ */
+ void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code);
+/**
+ * @}
+ */
+ void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct);
+/* C++ detection */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/TE_Controller/src/include/tmpgood.h b/TE_Controller/src/include/tmpgood.h
index 6853152..2324905 100644
--- a/TE_Controller/src/include/tmpgood.h
+++ b/TE_Controller/src/include/tmpgood.h
@@ -8,8 +8,8 @@
#ifndef TMPGOOD_H_
#define TMPGOOD_H_
-
+#include
void tmpgood_configure_port_pins(void);
-_Bool tmpgood_get_state(void);
+bool tmpgood_get_state(void);
#endif /* TMPGOOD_H_ */
\ No newline at end of file
diff --git a/TE_Controller/src/main.c b/TE_Controller/src/main.c
index aeb88ac..13b0829 100644
--- a/TE_Controller/src/main.c
+++ b/TE_Controller/src/main.c
@@ -50,15 +50,9 @@ char str[128] = {0};
UBaseType_t uxHighWaterMark_cdc_rx_check;
UBaseType_t uxHighWaterMark_led_blink;
static volatile bool main_b_cdc_enable = false;
+struct measured_params m_params;
+
-void prvGetRegistersFromStack (uint32_t *pulFaultStackAddress);
-void led_configure_port_pins(void);
-void vApplicationMallocFailedHook (void);
-void vApplicationStackOverflowHook (void);
-void Task_cdc_rx_check(void *parameters);
-void Task_led_blink(void *parameters);
-void InitTask_cdc_rx_check(void);
-void InitTask_led_blink(void);
/*! \brief Main function. Execution starts here.
*/
int main(void)
diff --git a/TE_Controller/src/main.h b/TE_Controller/src/main.h
index 2944919..1b1df87 100644
--- a/TE_Controller/src/main.h
+++ b/TE_Controller/src/main.h
@@ -39,6 +39,25 @@
#include "usb_protocol_cdc.h"
+struct measured_params{
+ float TEC_Temp;
+ float MCU_Temp;
+ float Vin_LFB;
+ float Vin_SFB;
+ float Vin_CS;
+ float DHT22_Temp;
+ float DHT22_Hum;
+ float DS1820_Temp;
+ float TEC_Power;
+};
+void prvGetRegistersFromStack (uint32_t *pulFaultStackAddress);
+void led_configure_port_pins(void);
+void vApplicationMallocFailedHook (void);
+void vApplicationStackOverflowHook (void);
+void Task_cdc_rx_check(void *parameters);
+void Task_led_blink(void *parameters);
+void InitTask_cdc_rx_check(void);
+void InitTask_led_blink(void);
/*! \brief Opens the communication port
* This is called by CDC interface when USB Host enable it.
*
diff --git a/TE_Controller/src/source/adc_user.c b/TE_Controller/src/source/adc_user.c
index 0081d44..3879ef8 100644
--- a/TE_Controller/src/source/adc_user.c
+++ b/TE_Controller/src/source/adc_user.c
@@ -5,7 +5,7 @@
* Author: Lexus
*/
#include "adc_user.h"
-#include "adc.h"
+#include
struct adc_module adc_instance;
// init ADC
void configure_adc(void)
diff --git a/TE_Controller/src/source/adc_user.h b/TE_Controller/src/source/adc_user.h
index 460b888..8ad6123 100644
--- a/TE_Controller/src/source/adc_user.h
+++ b/TE_Controller/src/source/adc_user.h
@@ -8,7 +8,7 @@
#ifndef ADC_H_
#define ADC_H_
-#include
+#include
#define chan_NTC_MCU ADC_POSITIVE_INPUT_PIN1
#define chan_NTC_TEC ADC_POSITIVE_INPUT_PIN5
#define chan_LFB ADC_POSITIVE_INPUT_PIN19
diff --git a/TE_Controller/src/source/adn8831.c b/TE_Controller/src/source/adn8831.c
new file mode 100644
index 0000000..282a4db
--- /dev/null
+++ b/TE_Controller/src/source/adn8831.c
@@ -0,0 +1,60 @@
+/*
+ * adn8831.c
+ *
+ * Created: 04.01.2021 19:13:33
+ * Author: Lexus
+ */
+#include "adn8831.h"
+#include "ntc.h"
+#include "tec.h"
+#include "tmpgood.h"
+
+void make_float2str(char * str, uint16_t len, float value){
+ bool neg_flag;
+ if(value >= 0)
+ neg_flag = false;
+ else{
+ neg_flag = true;
+ value = value * -1;
+ }
+
+ int a1 = value;
+ int a2 = (value - a1)*100.0;
+ snprintf(str, len, "%c%d.%2.2d",neg_flag?'-':'+', a1, a2);
+}
+
+void ADN8831_control(void){
+ char t_TEC_str[MAX_STR_FLOAT];
+ char t_MCU_str[MAX_STR_FLOAT];
+ char v_VTEC_str[MAX_STR_FLOAT];
+ char v_ITEC_str[MAX_STR_FLOAT];
+ char VTEC_str[MAX_STR_FLOAT];
+ char ITEC_str[MAX_STR_FLOAT];
+
+ TEC_set_TEMPSET_volt(0.9);
+
+ // MCU temp
+ float t = NTC_MCU_get_temp();
+ make_float2str(t_MCU_str, MAX_STR_FLOAT, (float)t);
+
+
+ // TEC temp
+ uint16_t value_TEC;
+ float R_TEC;
+ float t_TEC = NTC_TEC_get_temp(&value_TEC, &R_TEC);
+ make_float2str(t_TEC_str, MAX_STR_FLOAT, (float)t_TEC);
+
+ bool TMPGD = tmpgood_get_state();
+
+ // VTEC & ITEC
+ float v_VTEC=0, v_ITEC=0, VTEC=0, ITEC=0;
+ VTEC_read(&v_VTEC, &VTEC);
+ ITEC_read(&v_ITEC, &ITEC);
+
+ make_float2str(v_VTEC_str, MAX_STR_FLOAT, v_VTEC);
+ make_float2str(v_ITEC_str, MAX_STR_FLOAT, v_ITEC);
+ make_float2str(VTEC_str, MAX_STR_FLOAT, VTEC);
+ make_float2str(ITEC_str, MAX_STR_FLOAT, ITEC);
+
+ printf("Info: t_MCU: %10s, t_TEC:%10s, TMPGD: %d, VTEC: %10s, v_VTEC: %10s, ITEC: %10s, v_ITEC: %10s\r\n",t_MCU_str, t_TEC_str, (int)TMPGD, VTEC_str, v_VTEC_str, ITEC_str, v_ITEC_str);
+}
\ No newline at end of file
diff --git a/TE_Controller/src/source/backlight.c b/TE_Controller/src/source/backlight.c
new file mode 100644
index 0000000..44bee0f
--- /dev/null
+++ b/TE_Controller/src/source/backlight.c
@@ -0,0 +1,127 @@
+/*
+ * backlight.c
+ *
+ * Created: 10.04.2020 0:41:24
+ * Author: User
+ */
+
+#include
+#include
+
+#include "light_ws2812_cortex.h"
+#include "backlight.h"
+
+enum backlight_mode mode=mode_none;
+
+bool mode_run_light=false;
+uint8_t mode_run_light_cnt=0;
+
+uint8_t led_data[LEN_WS2812*3];
+
+
+void backlight_event_100ms(void){
+ if(mode == mode_demo){
+ if(mode_run_light){
+ for(uint16_t i=0; i < LEN_WS2812/2;i++){
+ if(mode_run_light_cnt == i){
+ led_data[0 + i*3] = 0xff;
+ led_data[1 + i*3] = 0x00;
+ led_data[2 + i*3] = 0x00;
+
+ led_data[0 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00;
+ led_data[1 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0xff;
+ led_data[2 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00;
+ }else{
+ led_data[0 + i*3] = 0x00;
+ led_data[1 + i*3] = 0x00;
+ led_data[2 + i*3] = 0x00;
+
+ led_data[0 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00;
+ led_data[1 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00;
+ led_data[2 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00;
+ }
+ }
+ backlight_ws2812_sendarray();
+ mode_run_light_cnt++;
+ if(mode_run_light_cnt >= LEN_WS2812/2){
+ mode_run_light=false;
+ }
+ }
+ }
+}
+
+uint32_t s1_cnt=0;
+void backlight_event_1s(void){
+ // LED WS2812
+
+ if(mode == mode_demo){
+ uint8_t modes = 6;
+ if(!mode_run_light){
+ if((s1_cnt % modes) == 0){
+ for(uint16_t i=0; i < LEN_WS2812;i++){
+ led_data[0 + i*3] = 0xff;
+ led_data[1 + i*3] = 0xff;
+ led_data[2 + i*3] = 0xff;
+ }
+ }else if((s1_cnt % modes) == 1){
+ for(uint16_t i=0; i < LEN_WS2812;i++){
+ led_data[0 + i*3] = 0xff;
+ led_data[1 + i*3] = 0x00;
+ led_data[2 + i*3] = 0x00;
+ }
+ }else if((s1_cnt % modes) == 2){
+ for(uint16_t i=0; i < LEN_WS2812;i++){
+ led_data[0 + i*3] = 0x00;
+ led_data[1 + i*3] = 0xff;
+ led_data[2 + i*3] = 0x00;
+ }
+ }else if((s1_cnt % modes) == 3){
+ for(uint16_t i=0; i < LEN_WS2812;i++){
+ led_data[0 + i*3] = 0x00;
+ led_data[1 + i*3] = 0x00;
+ led_data[2 + i*3] = 0xff;
+ }
+ }else if((s1_cnt % modes) == 4){
+ for(uint16_t i=0; i < LEN_WS2812;i++){
+ led_data[0 + i*3] = 0x00;
+ led_data[1 + i*3] = 0x00;
+ led_data[2 + i*3] = 0x00;
+ }
+ }else if((s1_cnt % modes) == 5){
+ mode_run_light=true;
+ mode_run_light_cnt=0;
+ }
+ backlight_ws2812_sendarray();
+ s1_cnt++;
+ }
+ }
+}
+
+void backlight_mode_demo(void){
+ mode = mode_demo;
+}
+
+void backlight_init(void){
+ mode = mode_none;
+// memset(led_data, 0, sizeof(led_data));
+ backlight_color_show(0,0,0);
+// for(uint16_t i=0; i < LEN_WS2812*3; i++){
+// printf("%d: %d\r\n", i, (int)led_data[i]);
+// }
+}
+
+void backlight_ws2812_sendarray(void){
+ cpu_irq_disable();
+ ws2812_sendarray(led_data,sizeof(led_data));
+ cpu_irq_enable();
+}
+
+void backlight_color_show(uint8_t R, uint8_t G, uint8_t B){
+ for(uint16_t i=0; i < LEN_WS2812; i++){
+ led_data[0 + i*3] = G;
+ led_data[1 + i*3] = R;
+ led_data[2 + i*3] = B;
+// printf("%d: R: %d, G: %d, B: %d\r\n",(int)i, (int)led_data[1 + i*3], (int)led_data[0 + i*3], (int)led_data[2 + i*3]);
+ }
+ backlight_ws2812_sendarray();
+}
\ No newline at end of file
diff --git a/TE_Controller/src/source/dac_user.c b/TE_Controller/src/source/dac_user.c
index abd2d51..8ed5eb0 100644
--- a/TE_Controller/src/source/dac_user.c
+++ b/TE_Controller/src/source/dac_user.c
@@ -4,9 +4,11 @@
* Created: 04.01.2021 0:51:07
* Author: Lexus
*/
-#include
#include "dac_user.h"
+#include
+
struct dac_module dac_instance;
+
void configure_dac_channel(void)
{
struct dac_chan_config config_dac_chan;
diff --git a/TE_Controller/src/source/dht.c b/TE_Controller/src/source/dht.c
new file mode 100644
index 0000000..c7799c6
--- /dev/null
+++ b/TE_Controller/src/source/dht.c
@@ -0,0 +1,128 @@
+/*
+ * dht.c
+ *
+ * Created: 04.01.2021 21:06:09
+ * Author: Lexus
+ */
+
+#include "dht.h"
+
+#define lineDown() port_pin_set_output_level(DHT_Pin, 0)
+#define lineUp() port_pin_set_output_level(DHT_Pin, 1)
+#define getLine() port_pin_get_input_level(DHT_Pin)
+#define Delay(d) delay_ms(d)
+
+#define CPU_IRQ_enable() cpu_irq_enable()
+#define CPU_IRQ_disable() cpu_irq_disable()
+extern struct measured_params m_params;
+static void goToOutput(void) {
+
+ // по умолчанию на линии высокий уровень
+ port_pin_set_output_level(DHT_Pin, 1);
+
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ config_port_pin.direction = PORT_PIN_DIR_OUTPUT;
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(DHT_Pin, &config_port_pin);
+}
+
+static void goToInput(void) {
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ config_port_pin.direction = PORT_PIN_DIR_INPUT;
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(DHT_Pin, &config_port_pin);
+}
+
+uint8_t DHT_getData(DHT_type t, DHT_data* p_data){
+ uint8_t ret;
+ CPU_IRQ_disable();
+ ret = _DHT_getData(t, p_data);
+ CPU_IRQ_enable();
+ return ret;
+}
+
+uint8_t _DHT_getData(DHT_type t, DHT_data* p_data) {
+ p_data->hum=0.0f;
+ p_data->temp=0.0f;
+
+
+ /* Запрос данных у датчика */
+ //Перевод пина "на выход"
+ goToOutput();
+ //Опускание линии данных на 15 мс
+ lineDown();
+ Delay(15);
+ //Подъём линии, перевод порта "на вход"
+ lineUp();
+ goToInput();
+
+ /* Ожидание ответа от датчика */
+ uint32_t timeout = 0;
+ //Ожидание спада
+ while(getLine()) {
+ timeout++;
+ if (timeout > DHT_timeout) return 0x01;
+ }
+ timeout = 0;
+ //Ожидание подъёма
+ while(!getLine()) {
+ timeout++;
+ if (timeout > DHT_timeout) return 0x02;
+ }
+ timeout = 0;
+ //Ожидание спада
+ while(getLine()) {
+ timeout++;
+ if (timeout > DHT_timeout) return 0x03;
+ }
+
+ /* Чтение ответа от датчика */
+ uint8_t rawData[5] = {0,0,0,0,0};
+ for(uint8_t a = 0; a < 5; a++) {
+ for(uint8_t b = 7; b != 255; b--) {
+ uint32_t hT = 0, lT = 0;
+ //Пока линия в низком уровне, инкремент переменной lT
+ while(!getLine()) lT++;
+ //Пока линия в высоком уровне, инкремент переменной hT
+ while(getLine()) hT++;
+ //Если hT больше lT, то пришла единица
+ if(hT > lT) rawData[a] |= (1<hum = (float)(((uint16_t)rawData[0]<<8) | rawData[1])*0.1f;
+ //Проверка на отрицательность температуры
+ if(!(rawData[2] & (1<<7))) {
+ p_data->temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*0.1f;
+ } else {
+ rawData[2] &= ~(1<<7);
+ p_data->temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*-0.1f;
+ }
+ }
+ if (t == DHT11) {
+ p_data->hum = (float)rawData[0];
+ p_data->temp = (float)rawData[2];
+ }
+ }else{
+ return 0x04;
+ }
+
+ return 0;
+}
+
+void measurement_DHT22(){
+ DHT_data d;
+ uint8_t ret = DHT_getData(DHT22, &d);
+ if(ret){
+ printf("DHT22 error: %d\r\n",(int)ret);
+ }else{
+ m_params.DHT22_Temp = d.temp;
+ m_params.DHT22_Hum = d.hum;
+ }
+}
diff --git a/TE_Controller/src/source/light_ws2812_cortex.c b/TE_Controller/src/source/light_ws2812_cortex.c
new file mode 100644
index 0000000..f9a2c37
--- /dev/null
+++ b/TE_Controller/src/source/light_ws2812_cortex.c
@@ -0,0 +1,128 @@
+/*
+ * light weight WS2812 lib - ARM Cortex M0/M0+ version
+ *
+ * Created: 07.07.2013
+ * Author: Tim (cpldcpu@gmail.com)
+ */
+
+#include "light_ws2812_cortex.h"
+/*
+* The total length of each bit is 1.25Вµs (25 cycles @ 20Mhz)
+* At 0Вµs the dataline is pulled high.
+* To send a zero the dataline is pulled low after 0.375Вµs
+* To send a one the dataline is pulled low after 0.625Вµs
+*/
+
+#define ws2812_ctot (((F_CPU/1000)*1250)/1000000)
+#define ws2812_t1 (((F_CPU/1000)*375 )/1000000) // floor
+#define ws2812_t2 (((F_CPU/1000)*625+500000)/1000000) // ceil
+
+#define w1 (ws2812_t1-2)
+#define w2 (ws2812_t2-ws2812_t1-2)
+#define w3 (ws2812_ctot-ws2812_t2-5)
+
+#define ws2812_DEL1 " nop \n\t"
+#define ws2812_DEL2 ws2812_DEL1 ws2812_DEL1
+//#define ws2812_DEL2 " b .+2 \n\t"
+#define ws2812_DEL4 ws2812_DEL2 ws2812_DEL2
+#define ws2812_DEL8 ws2812_DEL4 ws2812_DEL4
+#define ws2812_DEL16 ws2812_DEL8 ws2812_DEL8
+
+#define ws2812_DEL ws2812_DEL8 ws2812_DEL2
+
+
+void ws2812_sendarray(uint8_t *data,int datlen)
+{
+ uint8_t gpio_pin = PIN_PA23;
+ PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
+ uint32_t pin_mask = (1UL << (gpio_pin % 32));
+
+ uint32_t maskhi = pin_mask;
+ uint32_t masklo = pin_mask;
+ volatile uint32_t *set = &port_base->OUTSET.reg;
+ volatile uint32_t *clr = &port_base->OUTCLR.reg;
+ uint32_t i=0;
+ uint32_t curbyte;
+
+ while (datlen--) {
+ curbyte=*data++;
+
+ asm volatile(
+ " lsl %[dat],#24 \n\t"
+ " movs %[ctr],#8 \n\t"
+ "ilop%=: \n\t"
+ " lsl %[dat], #1 \n\t"
+ " str %[maskhi], [%[set]] \n\t"
+ws2812_DEL
+// ws2812_DEL19
+/*
+#if (w1&1)
+ ws2812_DEL1
+#endif
+#if (w1&2)
+ ws2812_DEL2
+#endif
+#if (w1&4)
+ ws2812_DEL4
+#endif
+#if (w1&8)
+ ws2812_DEL8
+#endif
+#if (w1&16)
+ ws2812_DEL16
+#endif
+*/
+ " bcs one%= \n\t"
+ " str %[masklo], [%[clr]] \n\t"
+ "one%=: \n\t"
+
+ws2812_DEL
+
+/*
+#if (w2&1)
+ ws2812_DEL1
+#endif
+#if (w2&2)
+ ws2812_DEL2
+#endif
+#if (w2&4)
+ ws2812_DEL4
+#endif
+#if (w2&8)
+ ws2812_DEL8
+#endif
+#if (w2&16)
+ ws2812_DEL16
+#endif
+*/
+ " sub %[ctr], #1 \n\t"
+ " str %[masklo], [%[clr]] \n\t"
+ " beq end%= \n\t"
+
+ws2812_DEL
+
+/*
+#if (w3&1)
+ ws2812_DEL1
+#endif
+#if (w3&2)
+ ws2812_DEL2
+#endif
+#if (w3&4)
+ ws2812_DEL4
+#endif
+#if (w3&8)
+ ws2812_DEL8
+#endif
+#if (w3&16)
+ ws2812_DEL16
+#endif
+*/
+
+ " b ilop%= \n\t"
+ "end%=: \n\t"
+ : [ctr] "+r" (i)
+ : [dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi)
+ );
+ }
+}
diff --git a/TE_Controller/src/source/ntc.c b/TE_Controller/src/source/ntc.c
new file mode 100644
index 0000000..dc6fbf1
--- /dev/null
+++ b/TE_Controller/src/source/ntc.c
@@ -0,0 +1,77 @@
+/*
+ * ntc.c
+ *
+ * Created: 04.01.2021 18:57:53
+ * Author: Lexus
+ */
+#include "ntc.h"
+#include
+#include "adc_user.h"
+
+#define MCU_CONTROL
+// ADC value to R
+float NTC_MCU_value2R(uint16_t value)
+{
+ float R10 = 17800.0;
+ float R11 = 7680.0;
+
+ float Q = adc_get_Q(value);
+
+ return ((R10*Q)/(1 - Q) - R11);
+}
+
+float NTC_TEC_value2R(uint16_t value)
+{
+ #ifdef MCU_CONTROL
+ float R32 = 17800.0;
+ float R36 = 7680.0;
+ float Q = adc_get_Q(value);
+
+ return ((R32*Q)/(1 - Q) - R36);
+ #else
+ float R36 = 7680.0;
+ float Uref = 2.5/2.;
+ float Uvcc = 3.3;
+ float Q = adc_get_Q(value);
+
+ return R36/(Uref/(Q*Uvcc) - 1);
+ #endif
+}
+
+// Resistance to Temp
+float NTC_R2T(float R)
+{
+ float K0 = 273.15;
+ float T0 = 25.0 + K0;
+ float R0 = 10000.0;
+
+ float B = 3863.737706;
+ return (1.0/((log(R/R0)/B) + (1/T0)) - K0);
+}
+
+// Read ADC and calculate temperature in Cenlsius.
+float NTC_MCU_get_temp(void)
+{
+ uint16_t adc_val = adc_read_value_spec(chan_NTC_MCU);
+
+ float R = NTC_MCU_value2R(adc_val);
+ float t = NTC_R2T(R);
+ return t;
+}
+
+float NTC_TEC_get_temp(uint16_t *p_value, float *p_R)
+{
+ uint16_t adc_val = adc_read_value_spec(chan_NTC_TEC);
+
+ if(p_value){
+ *p_value = adc_val;
+ }
+
+ float R = NTC_TEC_value2R(adc_val);
+
+ if(p_R){
+ *p_R = R;
+ }
+ float t = NTC_R2T(R);
+ return t;
+}
\ No newline at end of file
diff --git a/TE_Controller/src/source/realsence.c b/TE_Controller/src/source/realsence.c
index f37c740..e046f5a 100644
--- a/TE_Controller/src/source/realsence.c
+++ b/TE_Controller/src/source/realsence.c
@@ -5,8 +5,8 @@
* Author: Lexus
*/
#include "realsence.h"
-#include "port.h"
#include "conf_board.h"
+
bool rs_power;
void rs_configure_port_pins(void)
@@ -18,7 +18,7 @@ void rs_configure_port_pins(void)
port_pin_set_config(PIN_RS_POWER, &config_port_pin);
}
-void rs_set(_Bool value){
+void rs_set(bool value){
port_pin_set_output_level(PIN_RS_POWER, value?0:1);
rs_power = value;
}
diff --git a/TE_Controller/src/source/tec.c b/TE_Controller/src/source/tec.c
new file mode 100644
index 0000000..2c2b5e2
--- /dev/null
+++ b/TE_Controller/src/source/tec.c
@@ -0,0 +1,124 @@
+/*
+ * tec.c
+ *
+ * Created: 04.01.2021 17:08:34
+ * Author: Lexus
+ */
+
+#include "tec.h"
+#include
+#include "adc_user.h"
+#include "dac_user.h"
+struct tcc_module tcc_instance;
+extern struct dac_module dac_instance;
+bool VTEC_read(float *p_Vin, float *p_VTEC){
+ float Vin= adc_get_V_spec(chan_VTEC);
+ if(p_Vin){
+ *p_Vin = Vin;
+ }
+ if(p_VTEC){
+ //float K __attribute__((used)) =3.67 ;
+ // *p_VTEC = ((Vin - 1.25)*K)/0.25;
+ *p_VTEC = ((Vin - 1.25))/0.25;
+ }
+ return true;
+}
+
+bool ITEC_read(float *p_Vin, float *p_ITEC){
+ float Vin= adc_get_V_spec(chan_ITEC);
+ if(p_Vin){
+ *p_Vin = Vin;
+ }
+ if(p_ITEC){
+ float Rsense = 0.005;
+ *p_ITEC = (Vin-1.25)/(25*Rsense);
+ }
+ return true;
+}
+
+void TEC_L_set(bool value){
+
+ // switch off
+ pin_set_output(PIN_LPGATE, true, 1);
+ pin_set_output(PIN_LNGATE, true, 0);
+
+ if(value){
+ // L to +12
+ pin_set_output(PIN_LPGATE, true, 0);
+ }else{
+ // L to GND
+ pin_set_output(PIN_LNGATE, true, 1);
+ }
+}
+
+void pin_set_output(uint8_t pin, bool output_flag, uint8_t value){
+
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ if(output_flag){
+ port_pin_set_output_level(pin, value);
+ config_port_pin.direction = PORT_PIN_DIR_OUTPUT;
+ }else{
+ config_port_pin.direction = PORT_PIN_DIR_INPUT;
+ }
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(pin, &config_port_pin);
+}
+
+// Range from -1 to 0
+void TEC_set_level(float value){
+ tcc_reset(&tcc_instance);
+ if(fpclassify(value) == FP_ZERO){//if(value == (float)0.0){//
+ // TEC OFF
+ pin_set_output(PIN_SPGATE, true, 1);
+ pin_set_output(PIN_SNGATE, true, 0);
+ pin_set_output(PIN_LPGATE, true, 1);
+ pin_set_output(PIN_LNGATE, true, 0);
+ }else{
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ config_port_pin.direction = PORT_PIN_DIR_INPUT;
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(PIN_SNGATE, &config_port_pin);
+
+ struct tcc_config config_tcc;
+ tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE);
+ config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1;
+ config_tcc.counter.period = PWM_GCLK_PERIOD;
+
+ config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
+
+ uint8_t pin_output, chan;
+ if(value > 0.0){
+ TEC_L_set(true); // to +12
+ pin_set_output(PIN_SPGATE, true, 1);
+ pin_set_output(PIN_SNGATE, false, 0);
+ pin_output=7;
+ chan=3;
+ config_tcc.pins.wave_out_pin[pin_output] = PIN_PA17F_TCC0_WO7;
+ config_tcc.pins.wave_out_pin_mux[pin_output] = MUX_PA17F_TCC0_WO7;
+
+ config_tcc.compare.match[chan] = PWM_GCLK_PERIOD*value;
+ }else{
+ TEC_L_set(false); // to GND
+ pin_set_output(PIN_SPGATE, false, 0);
+ pin_set_output(PIN_SNGATE, true, 0);
+ pin_output=6;
+ chan=2;
+ config_tcc.pins.wave_out_pin[pin_output] = PIN_PA16F_TCC0_WO6;
+ config_tcc.pins.wave_out_pin_mux[pin_output] = MUX_PA16F_TCC0_WO6;
+ config_tcc.compare.match[chan] = PWM_GCLK_PERIOD*value*(-1.0);
+ config_tcc.wave_ext.invert[pin_output]=true;
+ }
+ config_tcc.pins.enable_wave_out_pin[pin_output] = true;
+ tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc);
+ tcc_enable(&tcc_instance);
+ }
+}
+
+void TEC_set_TEMPSET_volt(float value)
+{
+ float Uref=3.3;
+ uint16_t dig_value = (value*1024)/Uref;
+ dac_chan_write(&dac_instance, DAC_CHANNEL_0, dig_value);
+}
\ No newline at end of file
diff --git a/TE_Controller/src/source/tm_ds18b20.c b/TE_Controller/src/source/tm_ds18b20.c
new file mode 100644
index 0000000..369b2f0
--- /dev/null
+++ b/TE_Controller/src/source/tm_ds18b20.c
@@ -0,0 +1,420 @@
+/**
+ * |----------------------------------------------------------------------
+ * | Copyright (c) 2016 Tilen Majerle
+ * |
+ * | Permission is hereby granted, free of charge, to any person
+ * | obtaining a copy of this software and associated documentation
+ * | files (the "Software"), to deal in the Software without restriction,
+ * | including without limitation the rights to use, copy, modify, merge,
+ * | publish, distribute, sublicense, and/or sell copies of the Software,
+ * | and to permit persons to whom the Software is furnished to do so,
+ * | subject to the following conditions:
+ * |
+ * | The above copyright notice and this permission notice shall be
+ * | included in all copies or substantial portions of the Software.
+ * |
+ * | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * | AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * | OTHER DEALINGS IN THE SOFTWARE.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_ds18b20.h"
+TM_OneWire_t ow_instance;
+extern struct measured_params m_params;
+uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Start temperature conversion */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+
+ return 1;
+}
+
+void TM_DS18B20_StartAll(TM_OneWire_t* OneWire) {
+ /* Reset pulse */
+ TM_OneWire_Reset(OneWire);
+ /* Skip rom */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_SKIPROM);
+ /* Start conversion on all connected devices */
+ TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP);
+}
+
+uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWire, uint8_t *ROM, float *destination) {
+ uint16_t temperature;
+ uint8_t resolution;
+ int8_t digit, minus = 0;
+ float decimal;
+ uint8_t i = 0;
+ uint8_t data[9];
+ uint8_t crc;
+
+ /* Check if device is DS18B20 */
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Check if line is released, if it is, then conversion is complete */
+ if (!TM_OneWire_ReadBit(OneWire)) {
+ /* Conversion is not finished yet */
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Get data */
+ for (i = 0; i < 9; i++) {
+ /* Read byte by byte */
+ data[i] = TM_OneWire_ReadByte(OneWire);
+ }
+
+ /* Calculate CRC */
+ crc = TM_OneWire_CRC8(data, 8);
+
+ /* Check if CRC is ok */
+ if (crc != data[8]) {
+ /* CRC invalid */
+ return 0;
+ }
+
+ /* First two bytes of scratchpad are temperature values */
+ temperature = data[0] | (data[1] << 8);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+
+ /* Check if temperature is negative */
+ if (temperature & 0x8000) {
+ /* Two's complement, temperature is negative */
+ temperature = ~temperature + 1;
+ minus = 1;
+ }
+
+
+ /* Get sensor resolution */
+ resolution = ((data[4] & 0x60) >> 5) + 9;
+
+
+ /* Store temperature integer digits and decimal digits */
+ digit = temperature >> 4;
+ digit |= ((temperature >> 8) & 0x7) << 4;
+
+ /* Store decimal digits */
+ switch (resolution) {
+ case 9: {
+ decimal = (temperature >> 3) & 0x01;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_9BIT;
+ } break;
+ case 10: {
+ decimal = (temperature >> 2) & 0x03;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_10BIT;
+ } break;
+ case 11: {
+ decimal = (temperature >> 1) & 0x07;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_11BIT;
+ } break;
+ case 12: {
+ decimal = temperature & 0x0F;
+ decimal *= (float)DS18B20_DECIMAL_STEPS_12BIT;
+ } break;
+ default: {
+ decimal = 0xFF;
+ digit = 0;
+ }
+ }
+
+ /* Check for negative part */
+ decimal = digit + decimal;
+ if (minus) {
+ decimal = 0 - decimal;
+ }
+
+ /* Set to pointer */
+ *destination = decimal;
+
+ /* Return 1, temperature valid */
+ return 1;
+}
+
+uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t conf;
+
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 4 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ /* 5th byte of scratchpad is configuration register */
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ /* Return 9 - 12 value according to number of bits */
+ return ((conf & 0x60) >> 5) + 9;
+}
+
+uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWire, uint8_t *ROM, TM_DS18B20_Resolution_t resolution) {
+ uint8_t th, tl, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ if (resolution == TM_DS18B20_Resolution_9bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_10bits) {
+ conf &= ~(1 << DS18B20_RESOLUTION_R1);
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ } else if (resolution == TM_DS18B20_Resolution_11bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf &= ~(1 << DS18B20_RESOLUTION_R0);
+ } else if (resolution == TM_DS18B20_Resolution_12bits) {
+ conf |= 1 << DS18B20_RESOLUTION_R1;
+ conf |= 1 << DS18B20_RESOLUTION_R0;
+ }
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_Is(uint8_t *ROM) {
+ /* Checks if first byte is equal to DS18B20's family code */
+ if (*ROM == DS18B20_FAMILY_CODE) {
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ tl = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ if (temp > 125) {
+ temp = 125;
+ }
+ if (temp < -55) {
+ temp = -55;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = (uint8_t)temp;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWire, uint8_t *ROM) {
+ uint8_t tl, th, conf;
+ if (!TM_DS18B20_Is(ROM)) {
+ return 0;
+ }
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Read scratchpad command by onewire protocol */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD);
+
+ /* Ignore first 2 bytes */
+ TM_OneWire_ReadByte(OneWire);
+ TM_OneWire_ReadByte(OneWire);
+
+ th = TM_OneWire_ReadByte(OneWire);
+ tl = TM_OneWire_ReadByte(OneWire);
+ conf = TM_OneWire_ReadByte(OneWire);
+
+ th = 125;
+ tl = (uint8_t)-55;
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD);
+
+ /* Write bytes */
+ TM_OneWire_WriteByte(OneWire, th);
+ TM_OneWire_WriteByte(OneWire, tl);
+ TM_OneWire_WriteByte(OneWire, conf);
+
+ /* Reset line */
+ TM_OneWire_Reset(OneWire);
+ /* Select ROM number */
+ TM_OneWire_SelectWithPointer(OneWire, ROM);
+ /* Copy scratchpad to EEPROM of DS18B20 */
+ TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD);
+
+ return 1;
+}
+
+uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWire) {
+ /* Start alarm search */
+ return TM_OneWire_Search(OneWire, DS18B20_CMD_ALARMSEARCH);
+}
+
+uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWire) {
+ /* If read bit is low, then device is not finished yet with calculation temperature */
+ return TM_OneWire_ReadBit(OneWire);
+}
+
+void measurement_DS1820(void){
+ uint8_t ret;
+ cpu_irq_disable();
+ if (TM_OneWire_First(&ow_instance)) {
+ if(TM_DS18B20_Is(ow_instance.ROM_NO)){
+ if(TM_DS18B20_AllDone(&ow_instance)){
+ ret = TM_DS18B20_Read(&ow_instance, ow_instance.ROM_NO, &m_params.DS1820_Temp);
+ if(!ret){
+ printf("TM_DS18B20_Read() - error\r\n");
+ }
+ ret = TM_DS18B20_Start(&ow_instance, ow_instance.ROM_NO);
+ if(!ret){
+ printf("TM_DS18B20_Start() - ROM isn't correct\r\n");
+ }
+ }
+ }
+ }
+ cpu_irq_enable();
+}
diff --git a/TE_Controller/src/source/tm_onewire.c b/TE_Controller/src/source/tm_onewire.c
new file mode 100644
index 0000000..629e49f
--- /dev/null
+++ b/TE_Controller/src/source/tm_onewire.c
@@ -0,0 +1,389 @@
+/**
+ * https://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/
+ * https://github.com/MaJerle/stm32fxxx-hal-libraries/blob/master/06-STM32Fxxx_DS18B20/User/main.c
+ * |----------------------------------------------------------------------
+ * | Copyright (c) 2016 Tilen Majerle
+ * |
+ * | Permission is hereby granted, free of charge, to any person
+ * | obtaining a copy of this software and associated documentation
+ * | files (the "Software"), to deal in the Software without restriction,
+ * | including without limitation the rights to use, copy, modify, merge,
+ * | publish, distribute, sublicense, and/or sell copies of the Software,
+ * | and to permit persons to whom the Software is furnished to do so,
+ * | subject to the following conditions:
+ * |
+ * | The above copyright notice and this permission notice shall be
+ * | included in all copies or substantial portions of the Software.
+ * |
+ * | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * | AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * | OTHER DEALINGS IN THE SOFTWARE.
+ * |----------------------------------------------------------------------
+ */
+#include "tm_onewire.h"
+
+void ONEWIRE_OUTPUT(TM_OneWire_t* OneWireStruct){
+ // по умолчанию на линии высокий уровень
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ config_port_pin.direction = PORT_PIN_DIR_OUTPUT;
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(OneWireStruct->GPIO_Pin, &config_port_pin);
+}
+
+void ONEWIRE_INPUT(TM_OneWire_t* OneWireStruct){
+ struct port_config config_port_pin;
+ port_get_config_defaults(&config_port_pin);
+ config_port_pin.direction = PORT_PIN_DIR_INPUT;
+ config_port_pin.input_pull = PORT_PIN_PULL_NONE;
+ port_pin_set_config(OneWireStruct->GPIO_Pin, &config_port_pin);
+}
+
+void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, uint8_t GPIO_Pin) {
+
+ /* Save settings */
+ OneWireStruct->GPIO_Pin = GPIO_Pin;
+ ONEWIRE_INPUT(OneWireStruct);
+}
+
+uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct) {
+ uint8_t i;
+
+ /* Line low, and wait 480us */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(480);
+
+ /* Release line and wait for 70us */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(70);
+
+ /* Check bit value */
+ i = ONEWIRE_GET_VALUE(OneWireStruct);
+
+ /* Delay for 410 us */
+ ONEWIRE_DELAY(410);
+
+ /* Return value of presence pulse, 0 = OK, 1 = ERROR */
+ return i;
+}
+
+void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit) {
+ if (bit) {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 55 us and release the line */
+ ONEWIRE_DELAY(55);
+ ONEWIRE_INPUT(OneWireStruct);
+ } else {
+ /* Set line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(65);
+
+ /* Bit high */
+ ONEWIRE_INPUT(OneWireStruct);
+
+ /* Wait for 5 us and release the line */
+ ONEWIRE_DELAY(5);
+ ONEWIRE_INPUT(OneWireStruct);
+ }
+}
+
+uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct) {
+ uint8_t bit = 0;
+
+ /* Line low */
+ ONEWIRE_LOW(OneWireStruct);
+ ONEWIRE_OUTPUT(OneWireStruct);
+ ONEWIRE_DELAY(3);
+
+ /* Release line */
+ ONEWIRE_INPUT(OneWireStruct);
+ ONEWIRE_DELAY(10);
+
+ /* Read line value */
+ if (ONEWIRE_GET_VALUE(OneWireStruct)) {
+ /* Bit is HIGH */
+ bit = 1;
+ }
+
+ /* Wait 50us to complete 60us period */
+ ONEWIRE_DELAY(50);
+
+ /* Return bit value */
+ return bit;
+}
+
+void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte) {
+ uint8_t i = 8;
+ /* Write 8 bits */
+ while (i--) {
+ /* LSB bit is first */
+ TM_OneWire_WriteBit(OneWireStruct, byte & 0x01);
+ byte >>= 1;
+ }
+}
+
+uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct) {
+ uint8_t i = 8, byte = 0;
+ while (i--) {
+ byte >>= 1;
+ byte |= (TM_OneWire_ReadBit(OneWireStruct) << 7);
+ }
+
+ return byte;
+}
+
+uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct) {
+ /* Reset search values */
+ TM_OneWire_ResetSearch(OneWireStruct);
+
+ /* Start with searching */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct) {
+ /* Leave the search state alone */
+ return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM);
+}
+
+void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct) {
+ /* Reset the search state */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+}
+
+uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command) {
+ uint8_t id_bit_number;
+ uint8_t last_zero, rom_byte_number, search_result;
+ uint8_t id_bit, cmp_id_bit;
+ uint8_t rom_byte_mask, search_direction;
+
+ /* Initialize for search */
+ id_bit_number = 1;
+ last_zero = 0;
+ rom_byte_number = 0;
+ rom_byte_mask = 1;
+ search_result = 0;
+
+ /* Check if any devices */
+ if (!OneWireStruct->LastDeviceFlag) {
+ /* 1-Wire reset */
+ if (TM_OneWire_Reset(OneWireStruct)) {
+ /* Reset the search */
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ return 0;
+ }
+
+ /* Issue the search command */
+ TM_OneWire_WriteByte(OneWireStruct, command);
+
+ /* Loop to do the search */
+ do {
+ /* Read a bit and its complement */
+ id_bit = TM_OneWire_ReadBit(OneWireStruct);
+ cmp_id_bit = TM_OneWire_ReadBit(OneWireStruct);
+
+ /* Check for no devices on 1-wire */
+ if ((id_bit == 1) && (cmp_id_bit == 1)) {
+ break;
+ } else {
+ /* All devices coupled have 0 or 1 */
+ if (id_bit != cmp_id_bit) {
+ /* Bit write value for search */
+ search_direction = id_bit;
+ } else {
+ /* If this discrepancy is before the Last Discrepancy on a previous next then pick the same as last time */
+ if (id_bit_number < OneWireStruct->LastDiscrepancy) {
+ search_direction = ((OneWireStruct->ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
+ } else {
+ /* If equal to last pick 1, if not then pick 0 */
+ search_direction = (id_bit_number == OneWireStruct->LastDiscrepancy);
+ }
+
+ /* If 0 was picked then record its position in LastZero */
+ if (search_direction == 0) {
+ last_zero = id_bit_number;
+
+ /* Check for Last discrepancy in family */
+ if (last_zero < 9) {
+ OneWireStruct->LastFamilyDiscrepancy = last_zero;
+ }
+ }
+ }
+
+ /* Set or clear the bit in the ROM byte rom_byte_number with mask rom_byte_mask */
+ if (search_direction == 1) {
+ OneWireStruct->ROM_NO[rom_byte_number] |= rom_byte_mask;
+ } else {
+ OneWireStruct->ROM_NO[rom_byte_number] &= ~rom_byte_mask;
+ }
+
+ /* Serial number search direction write bit */
+ TM_OneWire_WriteBit(OneWireStruct, search_direction);
+
+ /* Increment the byte counter id_bit_number and shift the mask rom_byte_mask */
+ id_bit_number++;
+ rom_byte_mask <<= 1;
+
+ /* If the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask */
+ if (rom_byte_mask == 0) {
+ rom_byte_number++;
+ rom_byte_mask = 1;
+ }
+ }
+ /* Loop until through all ROM bytes 0-7 */
+ } while (rom_byte_number < 8);
+
+ /* If the search was successful then */
+ if (!(id_bit_number < 65)) {
+ /* Search successful so set LastDiscrepancy, LastDeviceFlag, search_result */
+ OneWireStruct->LastDiscrepancy = last_zero;
+
+ /* Check for last device */
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+
+ search_result = 1;
+ }
+ }
+
+ /* If no device found then reset counters so next 'search' will be like a first */
+ if (!search_result || !OneWireStruct->ROM_NO[0]) {
+ OneWireStruct->LastDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ search_result = 0;
+ }
+
+ return search_result;
+}
+
+int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct) {
+ unsigned char rom_backup[8];
+ int i,rslt,ld_backup,ldf_backup,lfd_backup;
+
+ /* Keep a backup copy of the current state */
+ for (i = 0; i < 8; i++)
+ rom_backup[i] = OneWireStruct->ROM_NO[i];
+ ld_backup = OneWireStruct->LastDiscrepancy;
+ ldf_backup = OneWireStruct->LastDeviceFlag;
+ lfd_backup = OneWireStruct->LastFamilyDiscrepancy;
+
+ /* Set search to find the same device */
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastDeviceFlag = 0;
+
+ if (TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM)) {
+ /* Check if same device found */
+ rslt = 1;
+ for (i = 0; i < 8; i++) {
+ if (rom_backup[i] != OneWireStruct->ROM_NO[i]) {
+ rslt = 1;
+ break;
+ }
+ }
+ } else {
+ rslt = 0;
+ }
+
+ /* Restore the search state */
+ for (i = 0; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = rom_backup[i];
+ }
+ OneWireStruct->LastDiscrepancy = ld_backup;
+ OneWireStruct->LastDeviceFlag = ldf_backup;
+ OneWireStruct->LastFamilyDiscrepancy = lfd_backup;
+
+ /* Return the result of the verify */
+ return rslt;
+}
+
+void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code) {
+ uint8_t i;
+
+ /* Set the search state to find SearchFamily type devices */
+ OneWireStruct->ROM_NO[0] = family_code;
+ for (i = 1; i < 8; i++) {
+ OneWireStruct->ROM_NO[i] = 0;
+ }
+
+ OneWireStruct->LastDiscrepancy = 64;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+ OneWireStruct->LastDeviceFlag = 0;
+}
+
+void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct) {
+ /* Set the Last discrepancy to last family discrepancy */
+ OneWireStruct->LastDiscrepancy = OneWireStruct->LastFamilyDiscrepancy;
+ OneWireStruct->LastFamilyDiscrepancy = 0;
+
+ /* Check for end of list */
+ if (OneWireStruct->LastDiscrepancy == 0) {
+ OneWireStruct->LastDeviceFlag = 1;
+ }
+}
+
+uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index) {
+ return OneWireStruct->ROM_NO[index];
+}
+
+void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(addr + i));
+ }
+}
+
+void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t *ROM) {
+ uint8_t i;
+ TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM);
+
+ for (i = 0; i < 8; i++) {
+ TM_OneWire_WriteByte(OneWireStruct, *(ROM + i));
+ }
+}
+
+void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex) {
+ uint8_t i;
+ for (i = 0; i < 8; i++) {
+ *(firstIndex + i) = OneWireStruct->ROM_NO[i];
+ }
+}
+
+uint8_t TM_OneWire_CRC8(uint8_t *addr, uint8_t len) {
+ uint8_t crc = 0, inbyte, i, mix;
+
+ while (len--) {
+ inbyte = *addr++;
+ for (i = 8; i; i--) {
+ mix = (crc ^ inbyte) & 0x01;
+ crc >>= 1;
+ if (mix) {
+ crc ^= 0x8C;
+ }
+ inbyte >>= 1;
+ }
+ }
+
+ /* Return calculated CRC */
+ return crc;
+}
diff --git a/TE_Controller/src/source/tmpgood.c b/TE_Controller/src/source/tmpgood.c
index 3155c14..0cf954a 100644
--- a/TE_Controller/src/source/tmpgood.c
+++ b/TE_Controller/src/source/tmpgood.c
@@ -4,8 +4,9 @@
* Created: 03.01.2021 23:22:04
* Author: Lexus
*/
+#include "tmpgood.h"
#include "conf_board.h"
-#include "port.h"
+
void tmpgood_configure_port_pins(void)
{
struct port_config config_port_pin;
@@ -15,7 +16,7 @@ void tmpgood_configure_port_pins(void)
port_pin_set_config(TC_TMPGD, &config_port_pin);
}
-_Bool tmpgood_get_state(void)
+bool tmpgood_get_state(void)
{
return port_pin_get_input_level(TC_TMPGD);
}
\ No newline at end of file
diff --git a/TE_Controller/src/source/ws2812.c b/TE_Controller/src/source/ws2812.c
index c65fdce..a31e175 100644
--- a/TE_Controller/src/source/ws2812.c
+++ b/TE_Controller/src/source/ws2812.c
@@ -6,7 +6,7 @@
*/
#include "ws2812.h"
#include "conf_board.h"
-#include "port.h"
+#include
void ws2812_configure_port_pins(void)
{