diff --git a/src/ASF/sam0/drivers/adc/adc.h b/src/ASF/sam0/drivers/adc/adc.h new file mode 100644 index 0000000000000000000000000000000000000000..1236203e7b2f37911111231b3510ef6f084f7283 --- /dev/null +++ b/src/ASF/sam0/drivers/adc/adc.h @@ -0,0 +1,1147 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2012-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 <a href="https://www.microchip.com/support/">Microchip Support</a> + */ + +#ifndef ADC_H_INCLUDED +#define ADC_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_adc_group SAM Analog-to-Digital Converter (ADC) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the device's Analog-to-Digital Converter functionality, for + * the conversion of analog voltages into a corresponding digital form. + * The following driver Application Programming Interface (API) modes are covered by this manual: + * - Polled APIs + * \if ADC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - ADC (Analog-to-Digital Converter) + * + * The following devices can use this module: + * \if DEVICE_SAML21_SUPPORT + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM R34/R35 + * \else + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM HA1 + * \endif + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_adc_prerequisites + * - \ref asfdoc_sam0_adc_module_overview + * - \ref asfdoc_sam0_adc_special_considerations + * - \ref asfdoc_sam0_adc_extra_info + * - \ref asfdoc_sam0_adc_examples + * - \ref asfdoc_sam0_adc_api_overview + * + * + * \section asfdoc_sam0_adc_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_adc_module_overview Module Overview + * + * This driver provides an interface for the Analog-to-Digital conversion + * functions on the device, to convert analog voltages to a corresponding + * digital value. The ADC has up to 12-bit resolution, and is capable of + * \if DEVICE_SAML21_SUPPORT + * converting up to 1,000,000 samples per second (MSPS). + * \else + * converting up to 500K samples per second (KSPS). + * \endif + * + * The ADC has a compare function for accurate monitoring of user defined + * thresholds with minimum software intervention required. + * The ADC may be configured for 8-, 10-, or 12-bit result, reducing the + * conversion time. ADC conversion results are provided left or right adjusted + * which eases calculation when the result is represented as a signed integer. + * + * The input selection is flexible, and both single-ended and differential + * measurements can be made. For differential measurements, an optional gain + * stage is available to increase the dynamic range. In addition, several + * internal signal inputs are available. The ADC can provide both signed and + * unsigned results. + * + * The ADC measurements can either be started by application software or an + * incoming event from another peripheral in the device, and both internal and + * external reference voltages can be selected. + * + * \note Internal references will be enabled by the driver, but not disabled. + * Any reference not used by the application should be disabled by the application. + * + * A simplified block diagram of the ADC can be seen in + * \ref asfdoc_sam0_adc_module_block_diagram "the figure below". + * + * \anchor asfdoc_sam0_adc_module_block_diagram + * \dot + * digraph overview { + * splines = false; + * rankdir=LR; + * + * mux1 [label="Positive input", shape=box]; + * mux2 [label="Negative input", shape=box]; + * + * + * mux3 [label="Reference", shape=box]; + * + * adc [label="ADC", shape=polygon, sides=5, orientation=90, distortion=-0.6, style=filled, fillcolor=darkolivegreen1, height=1, width=1]; + * prescaler [label="PRESCALER", shape=box, style=filled, fillcolor=lightblue]; + * + * mux1 -> adc; + * mux2 -> adc; + * mux3 -> adc:sw; + * prescaler -> adc; + * + * postproc [label="Post processing", shape=box]; + * result [label="RESULT", shape=box, style=filled, fillcolor=lightblue]; + * + * adc:e -> postproc:w; + * postproc:e -> result:w; + * + * {rank=same; mux1 mux2} + * {rank=same; prescaler adc} + * + * } + * \enddot + * + * + * \subsection asfdoc_sam0_adc_module_overview_prescaler Sample Clock Prescaler + * The ADC features a prescaler, which enables conversion at lower clock rates + * than the input Generic Clock to the ADC module. This feature can be used to + * lower the synchronization time of the digital interface to the ADC module + * via a high speed Generic Clock frequency, while still allowing the ADC + * sampling rate to be reduced. + * + * \subsection asfdoc_sam0_adc_module_overview_resolution ADC Resolution + * The ADC supports full 8-, 10-, or 12-bit resolution. Hardware + * oversampling and decimation can be used to increase the + * effective resolution at the expense of throughput. Using oversampling and + * decimation mode the ADC resolution is increased from 12-bit to an effective + * 13-, 14-, 15-, or 16-bit. In these modes the conversion rate is reduced, as + * a greater number of samples is used to achieve the increased resolution. The + * available resolutions and effective conversion rate is listed in + * \ref asfdoc_sam0_adc_module_conversion_rate "the table below". + * + * \anchor asfdoc_sam0_adc_module_conversion_rate + * <table> + * <caption>Effective ADC Conversion Speed Using Oversampling</caption> + * <tr> + * <th>Resolution</th> + * <th>Effective conversion rate</th> + * </tr> + * <tr> + * <td>13-bit</td> + * <td>Conversion rate divided by 4</td> + * </tr> + * <tr> + * <td>14-bit</td> + * <td>Conversion rate divided by 16</td> + * </tr> + * <tr> + * <td>15-bit</td> + * <td>Conversion rate divided by 64</td> + * </tr> + * <tr> + * <td>16-bit</td> + * <td>Conversion rate divided by 256</td> + * </tr> + * </table> + * + * \subsection asfdoc_sam0_adc_module_overview_conversion Conversion Modes + * ADC conversions can be software triggered on demand by the user application, + * if continuous sampling is not required. It is also possible to configure the + * ADC in free running mode, where new conversions are started as soon as the + * previous conversion is completed, or configure the ADC to scan across a + * number of input pins (see \ref asfdoc_sam0_adc_module_overview_pin_scan). + * + * \subsection asfdoc_sam0_adc_module_overview_diff_mode Differential and Single-ended Conversion + * The ADC has two conversion modes; differential and single-ended. When + * measuring signals where the positive input pin is always at a higher voltage + * than the negative input pin, the single-ended conversion mode should be used + * in order to achieve a full 12-bit output resolution. + * + * If however the positive input pin voltage may drop below the negative input + * pin the signed differential mode should be used. + * + * \subsection asfdoc_sam0_adc_module_overview_sample_time Sample Time + * The sample time for each ADC conversion is configurable as a number of half + * prescaled ADC clock cycles (depending on the prescaler value), allowing the + * user application to achieve faster or slower sampling depending on the + * source impedance of the ADC input channels. For applications with high + * impedance inputs the sample time can be increased to give the ADC an adequate + * time to sample and convert the input channel. + * + * The resulting sampling time is given by the following equation: + * \f[ + * t_{SAMPLE} = (sample\_length+1) \times \frac{ADC_{CLK}} {2} + * \f] + * + * \subsection asfdoc_sam0_adc_module_overview_averaging Averaging + * The ADC can be configured to trade conversion speed for accuracy by averaging + * multiple samples in hardware. This feature is suitable when operating in + * noisy conditions. + * + * You can specify any number of samples to accumulate (up to 1024) and the + * divide ratio to use (up to divide by 128). To modify these settings the + * ADC_RESOLUTION_CUSTOM needs to be set as the resolution. When this is set + * the number of samples to accumulate and the division ratio can be set by + * the configuration struct members \ref adc_config.accumulate_samples and + * \ref adc_config.divide_result. When using this mode the ADC result register + * will be set to be 16-bit wide to accommodate the larger result sizes + * produced by the accumulator. + * + * The effective ADC conversion rate will be reduced by a factor of the number + * of accumulated samples; + * however, the effective resolution will be increased according to + * \ref asfdoc_sam0_adc_module_hw_av_resolution "the table below". + * + * \anchor asfdoc_sam0_adc_module_hw_av_resolution + * <table> + * <caption>Effective ADC Resolution From Various Hardware Averaging Modes</caption> + * <tr> + * <th>Number of samples</tr> + * <th>Final result</tr> + * </tr> + * <tr> + * <td>1</td> + * <td>12-bit</td> + * </tr> + * <tr> + * <td>2</td> + * <td>13-bit</td> + * </tr> + * <tr> + * <td>4</td> + * <td>14-bit</td> + * </tr> + * <tr> + * <td>8</td> + * <td>15-bit</td> + * </tr> + * <tr> + * <td>16</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>32</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>64</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>128</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>256</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>512</td> + * <td>16-bit</td> + * </tr> + * <tr> + * <td>1024</td> + * <td>16-bit</td> + * </tr> + * </table> + * + * + * \subsection asfdoc_sam0_adc_module_overview_offset_corr Offset and Gain Correction + * Inherent gain and offset errors affect the absolute accuracy of the ADC. + * + * The offset error is defined as the deviation of the ADC's actual transfer + * function from ideal straight line at zero input voltage. + * + * The gain error is defined as the deviation of the last output step's + * midpoint from the ideal straight line, after compensating for offset error. + * + * The offset correction value is subtracted from the converted data before the + * result is ready. The gain correction value is multiplied with the offset + * corrected value. + * + * The equation for both offset and gain error compensation is shown below: + * \f[ + * ADC_{RESULT} = (VALUE_{CONV} + CORR_{OFFSET}) \times CORR_{GAIN} + * \f] + * + * When enabled, a given set of offset and gain correction values can be applied + * to the sampled data in hardware, giving a corrected stream of sample data to + * the user application at the cost of an increased sample latency. + * + * In single conversion, a latency of 13 ADC Generic Clock cycles is added for + * the final sample result availability. As the correction time is always less + * than the propagation delay, in free running mode this latency appears only + * during the first conversion. After the first conversion is complete, future + * conversion results are available at the defined sampling rate. + * + * \subsection asfdoc_sam0_adc_module_overview_pin_scan Pin Scan + * In pin scan mode, the first ADC conversion will begin from the configured + * positive channel, plus the requested starting offset. When the first + * conversion is completed, the next conversion will start at the next positive + * input channel and so on, until all requested pins to scan have been sampled + * and converted. + * SAM L21/L22 has automatic sequences feature instead of pin scan mode. In automatic + * sequence mode, all of 32 positives inputs can be included in a sequence. The + * sequence starts from the lowest input, and go to the next enabled input + * automatically. + * + * Pin scanning gives a simple mechanism to sample a large number of physical + * input channel samples, using a single physical ADC channel. + * + * \subsection asfdoc_sam0_adc_module_overview_window_monitor Window Monitor + * The ADC module window monitor function can be used to automatically compare + * the conversion result against a preconfigured pair of upper and lower + * threshold values. + * + * The threshold values are evaluated differently, depending on whether + * differential or single-ended mode is selected. In differential mode, the + * upper and lower thresholds are evaluated as signed values for the comparison, + * while in single-ended mode the comparisons are made as a set of unsigned + * values. + * + * The significant bits of the lower window monitor threshold and upper window + * monitor threshold values are user-configurable, and follow the overall ADC + * sampling bit precision set when the ADC is configured by the user application. + * For example, only the eight lower bits of the window threshold values will be + * compared to the sampled data whilst the ADC is configured in 8-bit mode. + * In addition, if using differential mode, the 8<SUP>th</SUP> bit will be considered as + * the sign bit even if bit 9 is zero. + * + * \subsection asfdoc_sam0_adc_module_overview_events Events + * Event generation and event actions are configurable in the ADC. + * + * The ADC has two actions that can be triggered upon event reception: + * \li Start conversion + * \li Flush pipeline and start conversion + * + * The ADC can generate two events: + * \li Window monitor + * \li Result ready + * + * If the event actions are enabled in the configuration, any incoming event + * will trigger the action. + * + * If the window monitor event is enabled, an event will be generated + * when the configured window condition is detected. + * + * If the result ready event is enabled, an event will be generated when a + * conversion is completed. + * + * \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. + * + * + * \section asfdoc_sam0_adc_special_considerations Special Considerations + * + * An integrated analog temperature sensor is available for use with the ADC. + * The bandgap voltage, as well as the scaled I/O and core voltages can also be + * measured by the ADC. For internal ADC inputs, the internal source(s) may need + * to be manually enabled by the user application before they can be measured. + * + * + * \section asfdoc_sam0_adc_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_adc_extra. This includes: + * - \ref asfdoc_sam0_adc_extra_acronyms + * - \ref asfdoc_sam0_adc_extra_dependencies + * - \ref asfdoc_sam0_adc_extra_errata + * - \ref asfdoc_sam0_adc_extra_history + * + * + * \section asfdoc_sam0_adc_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_adc_exqsg. + * + * + * \section asfdoc_sam0_adc_api_overview API Overview + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <compiler.h> +#include <system.h> +#include <adc_feature.h> + +/** + * \name Module Status Flags + * + * ADC status flags, returned by \ref adc_get_status() and cleared by + * \ref adc_clear_status(). + * + * @{ + */ + +/** ADC result ready. */ +#define ADC_STATUS_RESULT_READY (1UL << 0) +/** Window monitor match. */ +#define ADC_STATUS_WINDOW (1UL << 1) +/** ADC result overwritten before read. */ +#define ADC_STATUS_OVERRUN (1UL << 2) + +/** @} */ + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) +# define _ADC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_ADC##n, +/** + * \internal Get the interrupt vector for the given device instance + * + * \param[in] The ADC module instance number + * + * \return Interrupt vector for of the given ADC module instance. + */ +static enum system_interrupt_vector _adc_interrupt_get_interrupt_vector( + uint32_t inst_num) +{ + static uint8_t adc_interrupt_vectors[ADC_INST_NUM] = { + MREPEAT(ADC_INST_NUM, _ADC_INTERRUPT_VECT_NUM, 0) + }; + + return (enum system_interrupt_vector)adc_interrupt_vectors[inst_num]; +} +# endif +#endif + +#if !defined(__DOXYGEN__) +uint8_t _adc_get_inst_index( + Adc *const hw); +#endif + +/** + * \name Driver Initialization and Configuration + * @{ + */ +enum status_code adc_init( + struct adc_module *const module_inst, + Adc *hw, + struct adc_config *config); + +void adc_get_config_defaults( + struct adc_config *const config); + +#if (SAMD) || (SAMHA1) || (SAMHA0) || (SAMR21) +void adc_regular_ain_channel( + uint32_t *pin_array, uint8_t size); +#endif + +/** @} */ + +/** + * \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 ADC software instance struct + * + * \return Bitmask of \c ADC_STATUS_* flags. + * + * \retval ADC_STATUS_RESULT_READY ADC result is ready to be read + * \retval ADC_STATUS_WINDOW ADC has detected a value inside the set + * window range + * \retval ADC_STATUS_OVERRUN ADC result has overrun + */ +static inline uint32_t adc_get_status( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + uint32_t int_flags = adc_module->INTFLAG.reg; + + uint32_t status_flags = 0; + + /* Check for ADC Result Ready */ + if (int_flags & ADC_INTFLAG_RESRDY) { + status_flags |= ADC_STATUS_RESULT_READY; + } + + /* Check for ADC Window Match */ + if (int_flags & ADC_INTFLAG_WINMON) { + status_flags |= ADC_STATUS_WINDOW; + } + + /* Check for ADC Overrun */ + if (int_flags & ADC_INTFLAG_OVERRUN) { + status_flags |= ADC_STATUS_OVERRUN; + } + + return status_flags; +} + +/** + * \brief Clears a module status flag. + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] status_flags Bitmask of \c ADC_STATUS_* flags to clear + */ +static inline void adc_clear_status( + struct adc_module *const module_inst, + const uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + uint32_t int_flags = 0; + + /* Check for ADC Result Ready */ + if (status_flags & ADC_STATUS_RESULT_READY) { + int_flags |= ADC_INTFLAG_RESRDY; + } + + /* Check for ADC Window Match */ + if (status_flags & ADC_STATUS_WINDOW) { + int_flags |= ADC_INTFLAG_WINMON; + } + + /* Check for ADC Overrun */ + if (status_flags & ADC_STATUS_OVERRUN) { + int_flags |= ADC_INTFLAG_OVERRUN; + } + + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = int_flags; +} +/** @} */ + +/** + * \name Enable, Disable, and Reset ADC Module, Start Conversion and Read Result + * @{ + */ + +/** + * \brief Enables the ADC module. + * + * Enables an ADC module that has previously been configured. If any internal reference + * is selected it will be enabled. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_enable( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) + system_interrupt_enable(_adc_interrupt_get_interrupt_vector( + _adc_get_inst_index(adc_module))); +# elif (SAMC20) + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC0); +# else + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC); +# endif +#endif + + /* Disbale interrupt */ + adc_module->INTENCLR.reg = ADC_INTENCLR_MASK; + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = ADC_INTFLAG_MASK; + + adc_module->CTRLA.reg |= ADC_CTRLA_ENABLE; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + +/** + * \brief Disables the ADC module. + * + * Disables an ADC module that was previously enabled. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_disable( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) + system_interrupt_disable(_adc_interrupt_get_interrupt_vector( + _adc_get_inst_index(adc_module))); +# elif (SAMC20) + system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC0); +# else + system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC); +# endif +#endif + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Disbale interrupt */ + adc_module->INTENCLR.reg = ADC_INTENCLR_MASK; + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = ADC_INTFLAG_MASK; + + adc_module->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + +/** + * \brief Resets the ADC module. + * + * Resets an ADC module, clearing all module state, and registers to their + * default values. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_reset( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + /* Disable to make sure the pipeline is flushed before reset */ + adc_disable(module_inst); + + /* Software reset the module */ + adc_module->CTRLA.reg |= ADC_CTRLA_SWRST; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + + +/** + * \brief Enables an ADC event input or output. + * + * Enables one or more input or output events to or from the ADC module. See + * \ref adc_events "Struct adc_events" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the ADC peripheral + * \param[in] events Struct containing flags of events to enable + */ +static inline void adc_enable_events( + struct adc_module *const module_inst, + struct adc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Adc *const adc_module = module_inst->hw; + + uint32_t event_mask = 0; + + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } + + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg |= event_mask; +} + +/** + * \brief Disables an ADC event input or output. + * + * Disables one or more input or output events to or from the ADC module. See + * \ref adc_events "Struct adc_events" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the ADC peripheral + * \param[in] events Struct containing flags of events to disable + */ +static inline void adc_disable_events( + struct adc_module *const module_inst, + struct adc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Adc *const adc_module = module_inst->hw; + + uint32_t event_mask = 0; + + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } + + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg &= ~event_mask; +} + +/** + * \brief Starts an ADC conversion. + * + * Starts a new ADC conversion. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_start_conversion( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_START; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + +/** + * \brief Reads the ADC result. + * + * Reads the result from an ADC conversion that was previously started. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[out] result Pointer to store the result value in + * + * \return Status of the ADC read request. + * \retval STATUS_OK The result was retrieved successfully + * \retval STATUS_BUSY A conversion result was not ready + * \retval STATUS_ERR_OVERFLOW The result register has been overwritten by the + * ADC module before the result was read by the software + */ +static inline enum status_code adc_read( + struct adc_module *const module_inst, + uint16_t *result) +{ + Assert(module_inst); + Assert(module_inst->hw); + Assert(result); + + if (!(adc_get_status(module_inst) & ADC_STATUS_RESULT_READY)) { + /* Result not ready */ + return STATUS_BUSY; + } + + Adc *const adc_module = module_inst->hw; + +#if (SAMD) || (SAMHA1) || (SAMHA0) || (SAMR21) + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +#endif + + /* Get ADC result */ + *result = adc_module->RESULT.reg; + + /* Reset ready flag */ + adc_clear_status(module_inst, ADC_STATUS_RESULT_READY); + + if (adc_get_status(module_inst) & ADC_STATUS_OVERRUN) { + adc_clear_status(module_inst, ADC_STATUS_OVERRUN); + return STATUS_ERR_OVERFLOW; + } + + return STATUS_OK; +} + +/** @} */ + +/** + * \name Runtime Changes of ADC Module + * @{ + */ + +/** + * \brief Flushes the ADC pipeline. + * + * Flushes the pipeline and restarts the ADC clock on the next peripheral clock + * edge. All conversions in progress will be lost. When flush is complete, the + * module will resume where it left off. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_flush( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_FLUSH; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} +void adc_set_window_mode( + struct adc_module *const module_inst, + const enum adc_window_mode window_mode, + const int16_t window_lower_value, + const int16_t window_upper_value); + +/** + * \brief Sets positive ADC input pin. + * + * Sets the positive ADC input pin selection. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] positive_input Positive input pin + */ +static inline void adc_set_positive_input( + struct adc_module *const module_inst, + const enum adc_positive_input positive_input) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set positive input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXPOS_Msk) | + (positive_input); + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + + +/** + * \brief Sets negative ADC input pin for differential mode. + * + * Sets the negative ADC input pin, when the ADC is configured in differential + * mode. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] negative_input Negative input pin + */ +static inline void adc_set_negative_input( + struct adc_module *const module_inst, + const enum adc_negative_input negative_input) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set negative input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXNEG_Msk) | + (negative_input); + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + +/** @} */ + +#if ADC_CALLBACK_MODE == true +/** + * \name Enable and Disable Interrupts + * @{ + */ + +/** + * \brief Enable interrupt. + * + * Enable the given interrupt request from the ADC module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] interrupt Interrupt to enable + */ +static inline void adc_enable_interrupt(struct adc_module *const module_inst, + enum adc_interrupt_flag interrupt) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + /* Enable interrupt */ + adc_module->INTENSET.reg = interrupt; +} + +/** + * \brief Disable interrupt. + * + * Disable the given interrupt request from the ADC module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] interrupt Interrupt to disable + */ +static inline void adc_disable_interrupt(struct adc_module *const module_inst, + enum adc_interrupt_flag interrupt) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + /* Enable interrupt */ + adc_module->INTENCLR.reg = interrupt; +} + +/** @} */ +#endif /* ADC_CALLBACK_MODE == true */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + + +/** + * \page asfdoc_sam0_adc_extra Extra Information for ADC Driver + * + * \section asfdoc_sam0_adc_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * <table> + * <tr> + * <th>Acronym</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>ADC</td> + * <td>Analog-to-Digital Converter</td> + * </tr> + * <tr> + * <td>DAC</td> + * <td>Digital-to-Analog Converter</td> + * </tr> + * <tr> + * <td>LSB</td> + * <td>Least Significant Bit</td> + * </tr> + * <tr> + * <td>MSB</td> + * <td>Most Significant Bit</td> + * </tr> + * <tr> + * <td>DMA</td> + * <td>Direct Memory Access</td> + * </tr> + * </table> + * + * + * \section asfdoc_sam0_adc_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_adc_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_adc_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. + * + * <table> + * <tr> + * <th>Changelog</th> + * </tr> + * \if DEVICE_SAML21_SUPPORT + * <tr> + * <td>Initial Release</td> + * </tr> + * \else + * <tr> + * <td>Added support for SAM R21</td> + * </tr> + * <tr> + * <td>Added support for SAM D21 and new DMA quick start guide</td> + * </tr> + * <tr> + * <td>Added ADC calibration constant loading from the device signature + * row when the module is initialized</td> + * </tr> + * <tr> + * <td>Initial Release</td> + * </tr> + * \endif + * </table> + */ + +/** + * \page asfdoc_sam0_adc_exqsg Examples for ADC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_adc_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_adc_basic_use_case + * \if ADC_CALLBACK_MODE + * - \subpage asfdoc_sam0_adc_basic_use_case_callback + * \endif + * - \subpage asfdoc_sam0_adc_dma_use_case + * + * \page asfdoc_sam0_adc_document_revision_history Document Revision History + * + * <table> + * <tr> + * <th>Doc. Rev.</th> + * <th>Date</th> + * <th>Comments</th> + * </tr> + * \if DEVICE_SAML21_SUPPORT + * <tr> + * <td>42451B</td> + * <td>12/2015</td> + * <td>Added support for SAM L22</td> + * </tr> + * <tr> + * <td>42451A</td> + * <td>07/2015</td> + * <td>Initial document release</td> + * </tr> + * \else + * <tr> + * <td>42109E</td> + * <td>12/2015</td> + * <td>Added support for SAM DA1 and SAM D09</td> + * </tr> + * <tr> + * <td>42109D</td> + * <td>12/2014</td> + * <td>Added support for SAM R21 and SAM D10/D11</td> + * </tr> + * <tr> + * <td>42109C</td> + * <td>01/2014</td> + * <td>Added support for SAM D21</td> + * </tr> + * <tr> + * <td>42109B</td> + * <td>06/2013</td> + * <td>Added additional documentation on the event system. Corrected + * documentation typos.</td> + * </tr> + * <tr> + * <td>42109A</td> + * <td>06/2013</td> + * <td>Initial release</td> + * </tr> + * \endif + * </table> + */ + +#endif /* ADC_H_INCLUDED */ diff --git a/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc.c b/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc.c new file mode 100644 index 0000000000000000000000000000000000000000..32ce661ded157b46fc1d72f88e63539e28b126b4 --- /dev/null +++ b/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc.c @@ -0,0 +1,726 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2012-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 <a href="https://www.microchip.com/support/">Microchip Support</a> + */ + +#include "adc.h" + +#if SAMD20 +/* The Die revision D number */ +#define REVISON_D_NUM 3 +#endif + +/** + * \brief Initializes an ADC configuration structure to defaults + * + * Initializes a given ADC configuration struct to a set of known default + * values. This function should be called on any new instance of the + * configuration struct before being modified by the user application. + * + * The default configuration is as follows: + * \li GCLK generator 0 (GCLK main) clock source + * \li 1V from internal bandgap reference + * \li Div 4 clock prescaler + * \li 12-bit resolution + * \li Window monitor disabled + * \li No gain + * \li Positive input on ADC PIN 0 + * \li Negative input on ADC PIN 1 + * \li Averaging disabled + * \li Oversampling disabled + * \li Right adjust data + * \li Single-ended mode + * \li Free running disabled + * \li All events (input and generation) disabled + * \li Sleep operation disabled + * \li No reference compensation + * \li No gain/offset correction + * \li No added sampling time + * \li Pin scan mode disabled + * + * \param[out] config Pointer to configuration struct to initialize to + * default values + */ +void adc_get_config_defaults(struct adc_config *const config) +{ + Assert(config); + config->clock_source = GCLK_GENERATOR_0; + config->reference = ADC_REFERENCE_INT1V; + config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV4; + config->resolution = ADC_RESOLUTION_12BIT; + config->window.window_mode = ADC_WINDOW_MODE_DISABLE; + config->window.window_upper_value = 0; + config->window.window_lower_value = 0; + config->gain_factor = ADC_GAIN_FACTOR_1X; +#if SAMR21 + config->positive_input = ADC_POSITIVE_INPUT_PIN6 ; +#else + config->positive_input = ADC_POSITIVE_INPUT_PIN0 ; +#endif + config->negative_input = ADC_NEGATIVE_INPUT_GND ; + config->accumulate_samples = ADC_ACCUMULATE_DISABLE; + config->divide_result = ADC_DIVIDE_RESULT_DISABLE; + config->left_adjust = false; + config->differential_mode = false; + config->freerunning = false; + config->event_action = ADC_EVENT_ACTION_DISABLED; + config->run_in_standby = false; + config->reference_compensation_enable = false; + config->correction.correction_enable = false; + config->correction.gain_correction = ADC_GAINCORR_RESETVALUE; + config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE; + config->sample_length = 0; + config->pin_scan.offset_start_scan = 0; + config->pin_scan.inputs_to_scan = 0; +} + +/** + * \brief Sets the ADC window mode + * + * Sets the ADC window mode to a given mode and value range. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] window_mode Window monitor mode to set + * \param[in] window_lower_value Lower window monitor threshold value + * \param[in] window_upper_value Upper window monitor threshold value + */ +void adc_set_window_mode( + struct adc_module *const module_inst, + const enum adc_window_mode window_mode, + const int16_t window_lower_value, + const int16_t window_upper_value) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set window mode */ + adc_module->WINCTRL.reg = window_mode << ADC_WINCTRL_WINMODE_Pos; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set lower window monitor threshold value */ + adc_module->WINLT.reg = window_lower_value << ADC_WINLT_WINLT_Pos; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set upper window monitor threshold value */ + adc_module->WINUT.reg = window_upper_value << ADC_WINUT_WINUT_Pos; +} + +/** +* \internal Configure MUX settings for the analog pins +* +* This function will set the given ADC input pins +* to the analog function in the pinmux, giving +* the ADC access to the analog signal +* +* \param [in] pin AINxx pin to configure +*/ +static inline void _adc_configure_ain_pin(uint32_t pin) +{ +#define PIN_INVALID_ADC_AIN 0xFFFFUL + + /* Pinmapping table for AINxx -> GPIO pin number */ + const uint32_t pinmapping[] = { +#if (SAMD20E) || (SAMD21E)|| (SAMDA1E) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, +#elif (SAMD20G) || (SAMD21G)|| (SAMDA1G) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, +#elif (SAMD20J) || (SAMD21J)|| (SAMDA1J) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, + PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, +#elif SAMR21E + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif SAMR21G + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMD09C) || (SAMD10C) || (SAMD11C) + PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMD09D) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, + PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5, + PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMD10DS) || (SAMD10DU) || (SAMD11DS) || (SAMD11DU) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, + PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5, + PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMD10DM) || (SAMD11DM) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, + PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5, + PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, + PIN_PA10B_ADC_AIN8, PIN_PA11B_ADC_AIN9, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMHA1G) || (SAMHA0G) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_PB03B_ADC_AIN11, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, +#elif (SAMHA1E) || (SAMHA0E) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, +#else +# error ADC pin mappings are not defined for this device. +#endif + }; + + uint32_t pin_map_result = PIN_INVALID_ADC_AIN; + + if (pin <= ADC_EXTCHANNEL_MSB) { + pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; + + Assert(pin_map_result != PIN_INVALID_ADC_AIN); + + struct system_pinmux_config config; + system_pinmux_get_config_defaults(&config); + + /* Analog functions are all on MUX setting B */ + config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + config.mux_position = 1; + + system_pinmux_pin_set_config(pin_map_result, &config); + } +} + +/** + * \internal Writes an ADC configuration to the hardware module + * + * Writes out a given ADC module configuration to the hardware module. + * + * \param[out] module_inst Pointer to the ADC software instance struct + * \param[in] config Pointer to configuration struct + * + * \return Status of the configuration procedure + * \retval STATUS_OK The configuration was successful + * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided + */ +static enum status_code _adc_set_config( + struct adc_module *const module_inst, + struct adc_config *const config) +{ + uint8_t adjres = 0; + uint32_t resolution = ADC_RESOLUTION_16BIT; + enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE; +#if SAMD20 + uint8_t revision_num = ((REG_DSU_DID & DSU_DID_REVISION_Msk) >> DSU_DID_REVISION_Pos); +#endif + + /* Get the hardware module pointer */ + Adc *const adc_module = module_inst->hw; + + /* Configure GCLK channel and enable clock */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->clock_source; + system_gclk_chan_set_config(ADC_GCLK_ID, &gclk_chan_conf); + system_gclk_chan_enable(ADC_GCLK_ID); + + /* Setup pinmuxing for analog inputs */ + if (config->pin_scan.inputs_to_scan != 0) { + uint8_t offset = config->pin_scan.offset_start_scan; + uint8_t start_pin = + offset +(uint8_t)config->positive_input; + uint8_t end_pin = + start_pin + config->pin_scan.inputs_to_scan; + + while (start_pin < end_pin) { + _adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input); + start_pin++; + offset++; + } + _adc_configure_ain_pin(config->negative_input); + } else { + _adc_configure_ain_pin(config->positive_input); + _adc_configure_ain_pin(config->negative_input); + } + + /* Configure run in standby */ + adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos); + + /* Configure reference */ + adc_module->REFCTRL.reg = + (config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) | + (config->reference); + + /* Set adjusting result and number of samples */ + switch (config->resolution) { + + case ADC_RESOLUTION_CUSTOM: + adjres = config->divide_result; + accumulate = config->accumulate_samples; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_13BIT: + /* Increase resolution by 1 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_4; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_14BIT: + /* Increase resolution by 2 bit */ + adjres = ADC_DIVIDE_RESULT_4; + accumulate = ADC_ACCUMULATE_SAMPLES_16; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; +#if SAMD20 + /* See $35.1.8 for ADC errata of SAM D20. + The revisions before D have this issue.*/ + case ADC_RESOLUTION_15BIT: + /* Increase resolution by 3 bit */ + if(revision_num < REVISON_D_NUM) { + adjres = ADC_DIVIDE_RESULT_8; + } else { + adjres = ADC_DIVIDE_RESULT_2; + } + accumulate = ADC_ACCUMULATE_SAMPLES_64; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_16BIT: + if(revision_num < REVISON_D_NUM) { + /* Increase resolution by 4 bit */ + adjres = ADC_DIVIDE_RESULT_16; + } else { + adjres = ADC_DIVIDE_RESULT_DISABLE; + } + accumulate = ADC_ACCUMULATE_SAMPLES_256; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; +#else + case ADC_RESOLUTION_15BIT: + /* Increase resolution by 3 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_64; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_16BIT: + /* Increase resolution by 4 bit */ + adjres = ADC_DIVIDE_RESULT_DISABLE; + accumulate = ADC_ACCUMULATE_SAMPLES_256; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; +#endif + case ADC_RESOLUTION_8BIT: + /* 8-bit result register */ + resolution = ADC_RESOLUTION_8BIT; + break; + case ADC_RESOLUTION_10BIT: + /* 10-bit result register */ + resolution = ADC_RESOLUTION_10BIT; + break; + case ADC_RESOLUTION_12BIT: + /* 12-bit result register */ + resolution = ADC_RESOLUTION_12BIT; + break; + + default: + /* Unknown. Abort. */ + return STATUS_ERR_INVALID_ARG; + } + + adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate; + + /* Check validity of sample length value */ + if (config->sample_length > 63) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Configure sample length */ + adc_module->SAMPCTRL.reg = + (config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos); + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure CTRLB */ + adc_module->CTRLB.reg = + config->clock_prescaler | + resolution | + (config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) | + (config->freerunning << ADC_CTRLB_FREERUN_Pos) | + (config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) | + (config->differential_mode << ADC_CTRLB_DIFFMODE_Pos); + + /* Check validity of window thresholds */ + if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) { + switch (resolution) { + case ADC_RESOLUTION_8BIT: + if (config->differential_mode && + (config->window.window_lower_value > 127 || + config->window.window_lower_value < -128 || + config->window.window_upper_value > 127 || + config->window.window_upper_value < -128)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 255 || + config->window.window_upper_value > 255){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_10BIT: + if (config->differential_mode && + (config->window.window_lower_value > 511 || + config->window.window_lower_value < -512 || + config->window.window_upper_value > 511 || + config->window.window_upper_value < -512)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 1023 || + config->window.window_upper_value > 1023){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_12BIT: + if (config->differential_mode && + (config->window.window_lower_value > 2047 || + config->window.window_lower_value < -2048 || + config->window.window_upper_value > 2047 || + config->window.window_upper_value < -2048)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 4095 || + config->window.window_upper_value > 4095){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_16BIT: + if (config->differential_mode && + (config->window.window_lower_value > 32767 || + config->window.window_lower_value < -32768 || + config->window.window_upper_value > 32767 || + config->window.window_upper_value < -32768)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 65535 || + config->window.window_upper_value > 65535){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + } + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure window mode */ + adc_module->WINCTRL.reg = config->window.window_mode; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure lower threshold */ + adc_module->WINLT.reg = + config->window.window_lower_value << ADC_WINLT_WINLT_Pos; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure lower threshold */ + adc_module->WINUT.reg = config->window.window_upper_value << + ADC_WINUT_WINUT_Pos; + + uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan; + if (inputs_to_scan > 0) { + /* + * Number of input sources included is the value written to INPUTSCAN + * plus 1. + */ + inputs_to_scan--; + } + + if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || + config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { + /* Invalid number of input pins or input offset */ + return STATUS_ERR_INVALID_ARG; + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure pin scan mode and positive and negative input pins */ + adc_module->INPUTCTRL.reg = + config->gain_factor | + (config->pin_scan.offset_start_scan << + ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) | + config->negative_input | + config->positive_input; + + /* Configure events */ + adc_module->EVCTRL.reg = config->event_action; + + /* Disable all interrupts */ + adc_module->INTENCLR.reg = + (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) | + (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos); + + if (config->correction.correction_enable){ + /* Make sure gain_correction value is valid */ + if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Set gain correction value */ + adc_module->GAINCORR.reg = config->correction.gain_correction << + ADC_GAINCORR_GAINCORR_Pos; + } + + /* Make sure offset correction value is valid */ + if (config->correction.offset_correction > 2047 || + config->correction.offset_correction < -2048) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Set offset correction value */ + adc_module->OFFSETCORR.reg = config->correction.offset_correction << + ADC_OFFSETCORR_OFFSETCORR_Pos; + } + } + + /* Load in the fixed device ADC calibration constants */ + adc_module->CALIB.reg = + ADC_CALIB_BIAS_CAL( + (*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos) + ) | + ADC_CALIB_LINEARITY_CAL( + (*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos) + ); + + return STATUS_OK; +} + +/** + * \brief Initializes the ADC channel sequence + * + * Like SAMD and SAMR21 the INPUTOFFSET register will be incremented one + * automatically after a conversion done, causing the next conversion + * to be done with the positive input equal to MUXPOS + INPUTOFFSET, + * it is scanning continuously one by one even ADC channels are not continuous. + * + * Initializes the ADC channel sequence by the sequence of pin_array. + * + * \param[in] pin_array The array of the Mux selection for the positive ADC input + * \param[in] size The size of pin_array + */ +void adc_regular_ain_channel(uint32_t *pin_array, uint8_t size) +{ + for (int i = 0; i < size; i++) { + _adc_configure_ain_pin(pin_array[i]); + } +} + +/** + * \brief Initializes the ADC + * + * Initializes the ADC device struct and the hardware module based on the + * given configuration struct values. + * + * \param[out] module_inst Pointer to the ADC software instance struct + * \param[in] hw Pointer to the ADC module instance + * \param[in] config Pointer to the configuration struct + * + * \return Status of the initialization procedure. + * \retval STATUS_OK The initialization was successful + * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided + * \retval STATUS_BUSY The module is busy with a reset operation + * \retval STATUS_ERR_DENIED The module is enabled + */ +enum status_code adc_init( + struct adc_module *const module_inst, + Adc *hw, + struct adc_config *config) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(hw); + Assert(config); + + /* Associate the software module instance with the hardware module */ + module_inst->hw = hw; + + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC); + + if (hw->CTRLA.reg & ADC_CTRLA_SWRST) { + /* We are in the middle of a reset. Abort. */ + return STATUS_BUSY; + } + + if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) { + /* Module must be disabled before initialization. Abort. */ + return STATUS_ERR_DENIED; + } + + /* Store the selected reference for later use */ + module_inst->reference = config->reference; + + /* Make sure bandgap is enabled if requested by the config */ + if (module_inst->reference == ADC_REFERENCE_INT1V) { + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP); + } + +#if ADC_CALLBACK_MODE == true + for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) { + module_inst->callback[i] = NULL; + }; + + module_inst->registered_callback_mask = 0; + module_inst->enabled_callback_mask = 0; + module_inst->remaining_conversions = 0; + module_inst->job_status = STATUS_OK; + + _adc_instances[0] = module_inst; + + if (config->event_action == ADC_EVENT_ACTION_DISABLED && + !config->freerunning) { + module_inst->software_trigger = true; + } else { + module_inst->software_trigger = false; + } +#endif + + /* Write configuration to module */ + return _adc_set_config(module_inst, config); +} diff --git a/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc_feature.h b/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc_feature.h new file mode 100644 index 0000000000000000000000000000000000000000..d715b9d11642168e2ff9bf767234f290715ab15f --- /dev/null +++ b/src/ASF/sam0/drivers/adc/adc_sam_d_r_h/adc_feature.h @@ -0,0 +1,718 @@ +/** + * \file + * + * \brief SAM ADC functionality + * + * 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 <a href="https://www.microchip.com/support/">Microchip Support</a> + */ +#ifndef ADC_FEATURE_H_INCLUDED +#define ADC_FEATURE_H_INCLUDED + +/** + * \addtogroup asfdoc_sam0_adc_group + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if ADC_CALLBACK_MODE == true +# include <system_interrupt.h> + +#if !defined(__DOXYGEN__) +extern struct adc_module *_adc_instances[ADC_INST_NUM]; +#endif + +/** Forward definition of the device instance. */ +struct adc_module; + +/** Type of the callback functions. */ +typedef void (*adc_callback_t)(struct adc_module *const module); + +/** + * \brief ADC Callback enum + * + * Callback types for ADC callback driver. + * + */ +enum adc_callback { + /** Callback for buffer received */ + ADC_CALLBACK_READ_BUFFER, + /** Callback when window is hit */ + ADC_CALLBACK_WINDOW, + /** Callback for error */ + ADC_CALLBACK_ERROR, +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + ADC_CALLBACK_N, +# endif +}; + +#endif + +/** + * \brief ADC reference voltage enum + * + * Enum for the possible reference voltages for the ADC. + * + */ +enum adc_reference { + /** 1.0V voltage reference */ + ADC_REFERENCE_INT1V = ADC_REFCTRL_REFSEL_INT1V, + /** 1/1.48V<SUB>CC</SUB> reference */ + ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0, + /** 1/2V<SUB>CC</SUB> (only for internal V<SUB>CC</SUB> > 2.1V) */ + ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1, + /** External reference A */ + ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA, + /** External reference B */ + ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB, +}; + +/** + * \brief ADC clock prescaler enum + * + * Enum for the possible clock prescaler values for the ADC. + * + */ +enum adc_clock_prescaler { + /** ADC clock division factor 4 */ + ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4, + /** ADC clock division factor 8 */ + ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8, + /** ADC clock division factor 16 */ + ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16, + /** ADC clock division factor 32 */ + ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32, + /** ADC clock division factor 64 */ + ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64, + /** ADC clock division factor 128 */ + ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128, + /** ADC clock division factor 256 */ + ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256, + /** ADC clock division factor 512 */ + ADC_CLOCK_PRESCALER_DIV512 = ADC_CTRLB_PRESCALER_DIV512, +}; + +/** + * \brief ADC resolution enum + * + * Enum for the possible resolution values for the ADC. + * + */ +enum adc_resolution { + /** ADC 12-bit resolution */ + ADC_RESOLUTION_12BIT = ADC_CTRLB_RESSEL_12BIT, + /** ADC 16-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_16BIT = ADC_CTRLB_RESSEL_16BIT, + /** ADC 10-bit resolution */ + ADC_RESOLUTION_10BIT = ADC_CTRLB_RESSEL_10BIT, + /** ADC 8-bit resolution */ + ADC_RESOLUTION_8BIT = ADC_CTRLB_RESSEL_8BIT, + /** ADC 13-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_13BIT, + /** ADC 14-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_14BIT, + /** ADC 15-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_15BIT, + /** ADC 16-bit result register for use with averaging. When using this mode + * the ADC result register will be set to 16-bit wide, and the number of + * samples to accumulate and the division factor is configured by the + * \ref adc_config.accumulate_samples and \ref adc_config.divide_result + * members in the configuration struct. + */ + ADC_RESOLUTION_CUSTOM, +}; + +/** + * \brief ADC window monitor mode enum + * + * Enum for the possible window monitor modes for the ADC. + * + */ +enum adc_window_mode { + /** No window mode */ + ADC_WINDOW_MODE_DISABLE = ADC_WINCTRL_WINMODE_DISABLE, + /** RESULT > WINLT */ + ADC_WINDOW_MODE_ABOVE_LOWER = ADC_WINCTRL_WINMODE_MODE1, + /** RESULT < WINUT */ + ADC_WINDOW_MODE_BELOW_UPPER = ADC_WINCTRL_WINMODE_MODE2, + /** WINLT < RESULT < WINUT */ + ADC_WINDOW_MODE_BETWEEN = ADC_WINCTRL_WINMODE_MODE3, + /** !(WINLT < RESULT < WINUT) */ + ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_WINCTRL_WINMODE_MODE4, +}; + +/** + * \brief ADC gain factor selection enum + * + * Enum for the possible gain factor values for the ADC. + * + */ +enum adc_gain_factor { + /** 1x gain */ + ADC_GAIN_FACTOR_1X = ADC_INPUTCTRL_GAIN_1X, + /** 2x gain */ + ADC_GAIN_FACTOR_2X = ADC_INPUTCTRL_GAIN_2X, + /** 4x gain */ + ADC_GAIN_FACTOR_4X = ADC_INPUTCTRL_GAIN_4X, + /** 8x gain */ + ADC_GAIN_FACTOR_8X = ADC_INPUTCTRL_GAIN_8X, + /** 16x gain */ + ADC_GAIN_FACTOR_16X = ADC_INPUTCTRL_GAIN_16X, + /** 1/2x gain */ + ADC_GAIN_FACTOR_DIV2 = ADC_INPUTCTRL_GAIN_DIV2, +}; + +/** + * \brief ADC event action enum + * + * Enum for the possible actions to take on an incoming event. + * + */ +enum adc_event_action { + /** Event action disabled */ + ADC_EVENT_ACTION_DISABLED = 0, + /** Flush ADC and start conversion */ + ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_SYNCEI, + /** Start conversion */ + ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI, +}; + +/** + * \brief ADC positive MUX input selection enum + * + * Enum for the possible positive MUX input selections for the ADC. + * + */ +enum adc_positive_input { + /** ADC0 pin */ + ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_PIN0, + /** ADC1 pin */ + ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_PIN1, + /** ADC2 pin */ + ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_PIN2, + /** ADC3 pin */ + ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_PIN3, + /** ADC4 pin */ + ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_PIN4, + /** ADC5 pin */ + ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_PIN5, + /** ADC6 pin */ + ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_PIN6, + /** ADC7 pin */ + ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_PIN7, + /** ADC8 pin */ + ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_PIN8, + /** ADC9 pin */ + ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_PIN9, + /** ADC10 pin */ + ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_PIN10, + /** ADC11 pin */ + ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_PIN11, + /** ADC12 pin */ + ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_PIN12, + /** ADC13 pin */ + ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_PIN13, + /** ADC14 pin */ + ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_PIN14, + /** ADC15 pin */ + ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_PIN15, + /** ADC16 pin */ + ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_PIN16, + /** ADC17 pin */ + ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_PIN17, + /** ADC18 pin */ + ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_PIN18, + /** ADC19 pin */ + ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_PIN19, + /** Temperature reference */ + ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP, + /** Bandgap voltage */ + ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP, + /** 1/4 scaled core supply */ + ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC, + /** 1/4 scaled I/O supply */ + ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC, + /** DAC input */ + ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC, +}; + +/** + * \brief ADC negative Multiplexer(MUX) input selection enum + * + * Enum for the possible negative Multiplexer(MUX) input selections for the ADC. + * + */ +enum adc_negative_input { + /** ADC0 pin */ + ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_PIN0, + /** ADC1 pin */ + ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_PIN1, + /** ADC2 pin */ + ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_PIN2, + /** ADC3 pin */ + ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_PIN3, + /** ADC4 pin */ + ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_PIN4, + /** ADC5 pin */ + ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_PIN5, + /** ADC6 pin */ + ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_PIN6, + /** ADC7 pin */ + ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_PIN7, + /** Internal ground */ + ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG_GND, + /** I/O ground */ + ADC_NEGATIVE_INPUT_IOGND = ADC_INPUTCTRL_MUXNEG_IOGND, +}; + +/** + * \brief ADC number of accumulated samples enum + * + * Enum for the possible numbers of ADC samples to accumulate. + * This setting is only used when the \ref ADC_RESOLUTION_CUSTOM + * resolution setting is used. + * + */ +enum adc_accumulate_samples { + /** No averaging */ + ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1, + /** Average 2 samples */ + ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2, + /** Average 4 samples */ + ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4, + /** Average 8 samples */ + ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8, + /** Average 16 samples */ + ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16, + /** Average 32 samples */ + ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32, + /** Average 64 samples */ + ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64, + /** Average 128 samples */ + ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128, + /** Average 256 samples */ + ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256, + /** Average 512 samples */ + ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512, + /** Average 1024 samples */ + ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024, +}; + +/** + * \brief ADC possible dividers for the result register + * + * Enum for the possible division factors to use when accumulating + * multiple samples. To keep the same resolution for the averaged + * result and the actual input value, the division factor must + * be equal to the number of samples accumulated. This setting is only + * used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used. + */ +enum adc_divide_result { + /** Don't divide result register after accumulation */ + ADC_DIVIDE_RESULT_DISABLE = 0, + /** Divide result register by 2 after accumulation */ + ADC_DIVIDE_RESULT_2 = 1, + /** Divide result register by 4 after accumulation */ + ADC_DIVIDE_RESULT_4 = 2, + /** Divide result register by 8 after accumulation */ + ADC_DIVIDE_RESULT_8 = 3, + /** Divide result register by 16 after accumulation */ + ADC_DIVIDE_RESULT_16 = 4, + /** Divide result register by 32 after accumulation */ + ADC_DIVIDE_RESULT_32 = 5, + /** Divide result register by 64 after accumulation */ + ADC_DIVIDE_RESULT_64 = 6, + /** Divide result register by 128 after accumulation */ + ADC_DIVIDE_RESULT_128 = 7, +}; + +#if ADC_CALLBACK_MODE == true +/** + * Enum for the possible ADC interrupt flags. + */ +enum adc_interrupt_flag { + /** ADC result ready */ + ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY, + /** Window monitor match */ + ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON, + /** ADC result overwritten before read */ + ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN, +}; +#endif + +/** + * \brief ADC oversampling and decimation enum + * + * Enum for the possible numbers of bits resolution can be increased by when + * using oversampling and decimation. + * + */ +enum adc_oversampling_and_decimation { + /** Don't use oversampling and decimation mode */ + ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0, + /** 1-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_1BIT, + /** 2-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_2BIT, + /** 3-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_3BIT, + /** 4-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_4BIT +}; + +/** + * \brief Window monitor configuration structure + * + * Window monitor configuration structure. + */ +struct adc_window_config { + /** Selected window mode */ + enum adc_window_mode window_mode; + /** Lower window value */ + int32_t window_lower_value; + /** Upper window value */ + int32_t window_upper_value; +}; + +/** + * \brief ADC event enable/disable structure. + * + * Event flags for the ADC module. This is used to enable and + * disable events via \ref adc_enable_events() and \ref adc_disable_events(). + */ +struct adc_events { + /** Enable event generation on conversion done */ + bool generate_event_on_conversion_done; + /** Enable event generation on window monitor */ + bool generate_event_on_window_monitor; +}; + +/** + * \brief Gain and offset correction configuration structure + * + * Gain and offset correction configuration structure. + * Part of the \ref adc_config struct and will be initialized by + * \ref adc_get_config_defaults. + */ +struct adc_correction_config { + /** + * Enables correction for gain and offset based on values of gain_correction and + * offset_correction if set to true + */ + bool correction_enable; + /** + * This value defines how the ADC conversion result is compensated for gain + * error before written to the result register. This is a fractional value, + * 1-bit integer plus an 11-bit fraction, therefore + * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from + * \c 0b010000000000 to \c 0b111111111111. + */ + uint16_t gain_correction; + /** + * This value defines how the ADC conversion result is compensated for + * offset error before written to the result register. This is a 12-bit + * value in two's complement format. + */ + int16_t offset_correction; +}; + +/** + * \brief Pin scan configuration structure + * + * Pin scan configuration structure. Part of the \ref adc_config struct and will + * be initialized by \ref adc_get_config_defaults. + */ +struct adc_pin_scan_config { + /** + * Offset (relative to selected positive input) of the first input pin to be + * used in pin scan mode + */ + uint8_t offset_start_scan; + /** + * Number of input pins to scan in pin scan mode. A value below two will + * disable pin scan mode. + */ + uint8_t inputs_to_scan; +}; + +/** + * \brief ADC configuration structure + * + * Configuration structure for an ADC instance. This structure should be + * initialized by the \ref adc_get_config_defaults() + * function before being modified by the user application. + */ +struct adc_config { + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + /** Voltage reference */ + enum adc_reference reference; + /** Clock prescaler */ + enum adc_clock_prescaler clock_prescaler; + /** Result resolution */ + enum adc_resolution resolution; + /** Gain factor */ + enum adc_gain_factor gain_factor; + /** Positive Multiplexer (MUX) input */ + enum adc_positive_input positive_input; + /** Negative MUX input. For singled-ended conversion mode, the negative + * input must be connected to ground. This ground could be the internal + * GND, IOGND or an external ground connected to a pin. */ + enum adc_negative_input negative_input; + /** Number of ADC samples to accumulate when using the + * \c ADC_RESOLUTION_CUSTOM mode. Note: if the result width increases, + * result resolution will be changed accordingly. + */ + enum adc_accumulate_samples accumulate_samples; + /** Division ration when using the ADC_RESOLUTION_CUSTOM mode */ + enum adc_divide_result divide_result; + /** Left adjusted result */ + bool left_adjust; + /** Enables differential mode if true. + * if false, ADC will run in singled-ended mode. */ + bool differential_mode; + /** Enables free running mode if true */ + bool freerunning; + /** Enables ADC in standby sleep mode if true */ + bool run_in_standby; + /** + * Enables reference buffer offset compensation if true. + * This will increase the accuracy of the gain stage, but decreases the input + * impedance; therefore the startup time of the reference must be increased. + */ + bool reference_compensation_enable; + /** + * This value (0-63) control the ADC sampling time in number of half ADC + * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus + * controlling the ADC input impedance. Sampling time is set according to + * the formula: + * Sample time = (sample_length+1) * (ADCclk / 2). + */ + uint8_t sample_length; + /** Window monitor configuration structure */ + struct adc_window_config window; + /** Gain and offset correction configuration structure */ + struct adc_correction_config correction; + /** Event action to take on incoming event */ + enum adc_event_action event_action; + /** Pin scan configuration structure */ + struct adc_pin_scan_config pin_scan; +}; + +/** + * \brief ADC software device instance structure. + * + * ADC 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 adc_module { +#if !defined(__DOXYGEN__) + /** Pointer to ADC hardware module */ + Adc *hw; + /** Keep reference configuration so we know when enable is called */ + enum adc_reference reference; +# if ADC_CALLBACK_MODE == true + /** Array to store callback functions */ + adc_callback_t callback[ADC_CALLBACK_N]; + /** Pointer to buffer used for ADC results */ + volatile uint16_t *job_buffer; + /** Remaining number of conversions in current job */ + volatile uint16_t remaining_conversions; + /** Bit mask for callbacks registered */ + uint8_t registered_callback_mask; + /** Bit mask for callbacks enabled */ + uint8_t enabled_callback_mask; + /** Holds the status of the ongoing or last conversion job */ + volatile enum status_code job_status; + /** If software triggering is needed */ + bool software_trigger; +# endif +#endif +}; + +#if !defined(__DOXYGEN__) + +/** + * \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 ADC software instance struct + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval true if the module synchronization is ongoing + * \retval false if the module has completed synchronization + */ +static inline bool adc_is_syncing( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + + Adc *const adc_module = module_inst->hw; + + if (adc_module->STATUS.reg & ADC_STATUS_SYNCBUSY) { + return true; + } + + return false; +} +#endif + +/** + * \name ADC Gain and Pin Scan Mode + * @{ + */ + +/** + * \brief Sets ADC gain factor + * + * Sets the ADC gain factor to a specified gain setting. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] gain_factor Gain factor value to set + */ +static inline void adc_set_gain( + struct adc_module *const module_inst, + const enum adc_gain_factor gain_factor) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set new gain factor */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_GAIN_Msk) | + (gain_factor); +} + +/** + * \brief Sets the ADC pin scan mode + * + * Configures the pin scan mode of the ADC module. In pin scan mode, the first + * conversion will start at the configured positive input + start_offset. When + * a conversion is done, a conversion will start on the next input, until + * \c inputs_to_scan number of conversions are made. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] inputs_to_scan Number of input pins to perform a conversion on + * (must be two or more) + * \param[in] start_offset Offset of first pin to scan (relative to + * configured positive input) + * + * \return Status of the pin scan configuration set request. + * + * \retval STATUS_OK Pin scan mode has been set successfully + * \retval STATUS_ERR_INVALID_ARG Number of input pins to scan or offset has + * an invalid value + */ +static inline enum status_code adc_set_pin_scan_mode( + struct adc_module *const module_inst, + uint8_t inputs_to_scan, + const uint8_t start_offset) + +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + if (inputs_to_scan > 0) { + /* + * Number of input sources included is the value written to INPUTSCAN + * plus 1. + */ + inputs_to_scan--; + } + + if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || + start_offset > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { + /* Invalid number of input pins */ + return STATUS_ERR_INVALID_ARG; + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set pin scan mode */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & + ~(ADC_INPUTCTRL_INPUTSCAN_Msk | ADC_INPUTCTRL_INPUTOFFSET_Msk)) | + (start_offset << ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos); + + return STATUS_OK; +} + +/** + * \brief Disables pin scan mode + * + * Disables pin scan mode. The next conversion will be made on only one pin + * (the configured positive input pin). + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_disable_pin_scan_mode( + struct adc_module *const module_inst) +{ + /* Disable pin scan mode */ + adc_set_pin_scan_mode(module_inst, 0, 0); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ADC_FEATURE_H_INCLUDED */ + diff --git a/src/ASF/sam0/drivers/wdt/quick_start/qs_wdt_basic.h b/src/ASF/sam0/drivers/wdt/quick_start/qs_wdt_basic.h new file mode 100644 index 0000000000000000000000000000000000000000..c363d37cae7614d9df62b29ffd5347b8d68bf249 --- /dev/null +++ b/src/ASF/sam0/drivers/wdt/quick_start/qs_wdt_basic.h @@ -0,0 +1,98 @@ +/** + * \file + * + * \brief SAM Watchdog Driver Quick Start + * + * Copyright (c) 2012-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 + * + */ + +/** + * \page asfdoc_sam0_wdt_basic_use_case Quick Start Guide for WDT - Basic + * + * In this use case, the Watchdog module is configured for: + * \li System reset after 2048 clocks of the Watchdog generic clock + * \li Always on mode disabled + * \li Basic mode, with no window or early warning periods + * + * This use case sets up the Watchdog to force a system reset after every 2048 + * clocks of the Watchdog's Generic Clock channel, unless the user periodically + * resets the Watchdog counter via a button before the timer expires. If the + * Watchdog resets the device, a LED on the board is turned off. + * + * \section asfdoc_sam0_wdt_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_wdt_basic_use_case_setup_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_wdt_basic_use_case_setup_code Code + * Copy-paste the following setup code to your user application: + * \snippet qs_wdt_basic.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_wdt_basic.c setup_init + * + * \subsection asfdoc_sam0_wdt_basic_use_case_setup_flow Workflow + * -# Create a Watchdog module configuration struct, which can be filled out to + * adjust the configuration of the Watchdog. + * \snippet qs_wdt_basic.c setup_1 + * -# Initialize the Watchdog configuration struct with the module's default + * values. + * \snippet qs_wdt_basic.c 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 configuration struct to set the timeout period and lock mode + * of the Watchdog. + * \snippet qs_wdt_basic.c setup_3 + * -# Setups the WDT hardware module with the requested settings. + * \snippet qs_wdt_basic.c setup_4 + * + * \section asfdoc_sam0_wdt_basic_use_case Use Case + * + * \subsection asfdoc_sam0_wdt_basic_use_case_code Code + * Copy-paste the following code to your user application: + * \snippet qs_wdt_basic.c main + * + * \subsection asfdoc_sam0_wdt_basic_use_case_main Workflow + * -# Retrieve the cause of the system reset to determine if the Watchdog module + * was the cause of the last reset. + * \snippet qs_wdt_basic.c main_1 + * -# Turn on or off the board LED based on whether the Watchdog reset the device. + * \snippet qs_wdt_basic.c main_2 + * -# Enter an infinite loop to hold the main program logic. + * \snippet qs_wdt_basic.c main_3 + * -# Test to see if the board button is currently being pressed. + * \snippet qs_wdt_basic.c main_4 + * -# If the button is pressed, turn on the board LED and reset the Watchdog + * timer. + * \snippet qs_wdt_basic.c main_5 + */ +/* + * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a> + */ diff --git a/src/ASF/sam0/drivers/wdt/wdt.c b/src/ASF/sam0/drivers/wdt/wdt.c new file mode 100644 index 0000000000000000000000000000000000000000..3fae4d3c90ca0af2cebda1d4af516637e4feef35 --- /dev/null +++ b/src/ASF/sam0/drivers/wdt/wdt.c @@ -0,0 +1,254 @@ +/** + * \file + * + * \brief SAM Watchdog Driver + * + * Copyright (c) 2012-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 <a href="https://www.microchip.com/support/">Microchip Support</a> + */ +#include "wdt.h" +#include <system.h> + +/** + * \brief Sets up the WDT hardware module based on the configuration. + * + * Writes a given configuration of a WDT configuration to the + * hardware module, and initializes the internal device struct. + * + * \param[in] config Pointer to the configuration struct + * + * \return Status of the configuration procedure. + * + * \retval STATUS_OK If the module was configured correctly + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were supplied + * \retval STATUS_ERR_IO If the Watchdog module is locked to be always on + */ +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) +enum status_code wdt_set_config( + const struct wdt_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + Wdt *const WDT_module = WDT; + + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_WDT); + + /* Check of the Watchdog has been locked to be always on, if so, abort */ + if (wdt_is_locked()) { + return STATUS_ERR_IO; + } + + /* Check for an invalid timeout period, abort if found */ + if (config->timeout_period == WDT_PERIOD_NONE) { + return STATUS_ERR_INVALID_ARG; + } + + /* Make sure the Window and Early Warning periods are not more than the + * reset period, abort if either is invalid */ + if ((config->timeout_period < config->window_period) || + (config->timeout_period < config->early_warning_period)) { + return STATUS_ERR_INVALID_ARG; + } + + /* Disable the Watchdog module */ + WDT_module->CTRLA.reg &= ~WDT_CTRLA_ENABLE; + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + if(config->enable == false) { + return STATUS_OK; + } + + uint32_t new_config = 0; + + /* Update the timeout period value with the requested period */ + new_config |= (config->timeout_period - 1) << WDT_CONFIG_PER_Pos; + + /* Check if the user has requested a reset window period */ + if (config->window_period != WDT_PERIOD_NONE) { + WDT_module->CTRLA.reg |= WDT_CTRLA_WEN; + + /* Update and enable the timeout period value */ + new_config |= (config->window_period - 1) << WDT_CONFIG_WINDOW_Pos; + } else { + /* Ensure the window enable control flag is cleared */ + WDT_module->CTRLA.reg &= ~WDT_CTRLA_WEN; + } + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + /* Write the new Watchdog configuration */ + WDT_module->CONFIG.reg = new_config; + + /* Check if the user has requested an early warning period */ + if (config->early_warning_period != WDT_PERIOD_NONE) { + /* Set the Early Warning period */ + WDT_module->EWCTRL.reg + = (config->early_warning_period - 1) << WDT_EWCTRL_EWOFFSET_Pos; + } + + /* Either enable or lock-enable the Watchdog timer depending on the user + * settings */ + if (config->always_on) { + WDT_module->CTRLA.reg |= WDT_CTRLA_ALWAYSON; + } else { + WDT_module->CTRLA.reg |= WDT_CTRLA_ENABLE; + } + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + return STATUS_OK; +} +#else +enum status_code wdt_set_config( + const struct wdt_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + Wdt *const WDT_module = WDT; + + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, PM_APBAMASK_WDT); + + /* Check of the Watchdog has been locked to be always on, if so, abort */ + if (wdt_is_locked()) { + return STATUS_ERR_IO; + } + + /* Check for an invalid timeout period, abort if found */ + if (config->timeout_period == WDT_PERIOD_NONE) { + return STATUS_ERR_INVALID_ARG; + } + + /* Make sure the Window and Early Warning periods are not more than the + * reset period, abort if either is invalid */ + if ((config->timeout_period < config->window_period) || + (config->timeout_period < config->early_warning_period)) { + return STATUS_ERR_INVALID_ARG; + } + + /* Disable the Watchdog module */ + WDT_module->CTRL.reg &= ~WDT_CTRL_ENABLE; + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + if(config->enable == false) { + return STATUS_OK; + } + + /* Configure GCLK channel and enable clock */ + struct system_gclk_chan_config gclk_chan_conf; + gclk_chan_conf.source_generator = config->clock_source; + system_gclk_chan_set_config(WDT_GCLK_ID, &gclk_chan_conf); + system_gclk_chan_enable(WDT_GCLK_ID); + if (config->always_on) { + system_gclk_chan_lock(WDT_GCLK_ID); + } + + uint32_t new_config = 0; + + /* Update the timeout period value with the requested period */ + new_config |= (config->timeout_period - 1) << WDT_CONFIG_PER_Pos; + + /* Check if the user has requested a reset window period */ + if (config->window_period != WDT_PERIOD_NONE) { + WDT_module->CTRL.reg |= WDT_CTRL_WEN; + + /* Update and enable the timeout period value */ + new_config |= (config->window_period - 1) << WDT_CONFIG_WINDOW_Pos; + } else { + /* Ensure the window enable control flag is cleared */ + WDT_module->CTRL.reg &= ~WDT_CTRL_WEN; + } + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + /* Write the new Watchdog configuration */ + WDT_module->CONFIG.reg = new_config; + + /* Check if the user has requested an early warning period */ + if (config->early_warning_period != WDT_PERIOD_NONE) { + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + /* Set the Early Warning period */ + WDT_module->EWCTRL.reg + = (config->early_warning_period - 1) << WDT_EWCTRL_EWOFFSET_Pos; + } + + /* Either enable or lock-enable the Watchdog timer depending on the user + * settings */ + if (config->always_on) { + WDT_module->CTRL.reg |= WDT_CTRL_ALWAYSON; + } else { + WDT_module->CTRL.reg |= WDT_CTRL_ENABLE; + } + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + + return STATUS_OK; +} +#endif + +/** + * \brief Resets the count of the running Watchdog Timer that was previously enabled. + * + * Resets the current count of the Watchdog Timer, restarting the timeout + * period count elapsed. This function should be called after the window + * period (if one was set in the module configuration) but before the timeout + * period to prevent a reset of the system. + */ +void wdt_reset_count(void) +{ + Wdt *const WDT_module = WDT; + + /* Disable the Watchdog module */ + WDT_module->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; + + while (wdt_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } +} diff --git a/src/ASF/sam0/drivers/wdt/wdt.h b/src/ASF/sam0/drivers/wdt/wdt.h new file mode 100644 index 0000000000000000000000000000000000000000..088f5891d25e85e74ceab66be5d68a4ad5a6308f --- /dev/null +++ b/src/ASF/sam0/drivers/wdt/wdt.h @@ -0,0 +1,495 @@ +/** + * \file + * + * \brief SAM Watchdog Driver + * + * Copyright (c) 2012-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 <a href="https://www.microchip.com/support/">Microchip Support</a> + */ +#ifndef WDT_H_INCLUDED +#define WDT_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_wdt_group SAM Watchdog (WDT) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the device's Watchdog + * Timer module, including the enabling, disabling, and kicking within the device. + * The following driver API modes are covered by this manual: + * + * - Polled APIs + * \if WDT_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripherals are used by this module: + * - WDT (Watchdog Timer) + * + * 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_wdt_prerequisites + * - \ref asfdoc_sam0_wdt_module_overview + * - \ref asfdoc_sam0_wdt_special_considerations + * - \ref asfdoc_sam0_wdt_extra_info + * - \ref asfdoc_sam0_wdt_examples + * - \ref asfdoc_sam0_wdt_api_overview + * + * + * \section asfdoc_sam0_wdt_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_wdt_module_overview Module Overview + * + * The Watchdog module (WDT) is designed to give an added level of safety in + * critical systems, to ensure a system reset is triggered in the case of a + * deadlock or other software malfunction that prevents normal device operation. + * + * At a basic level, the Watchdog is a system timer with a fixed period; once + * enabled, it will continue to count ticks of its asynchronous clock until + * it is periodically reset, or the timeout period is reached. In the event of a + * Watchdog timeout, the module will trigger a system reset identical to a pulse + * of the device's reset pin, resetting all peripherals to their power-on + * default states and restarting the application software from the reset vector. + * + * In many systems, there is an obvious upper bound to the amount of time each + * iteration of the main application loop can be expected to run, before a + * malfunction can be assumed (either due to a deadlock waiting on hardware or + * software, or due to other means). When the Watchdog is configured with a + * timeout period equal to this upper bound, a malfunction in the system will + * force a full system reset to allow for a graceful recovery. + * + * \subsection asfdoc_sam0_wdt_module_locked_mode Locked Mode + * The Watchdog configuration can be set in the device fuses and locked in + * hardware, so that no software changes can be made to the Watchdog + * configuration. Additionally, the Watchdog can be locked on in software if it + * is not already locked, so that the module configuration cannot be modified + * until a power on reset of the device. + * + * The locked configuration can be used to ensure that faulty software does not + * cause the Watchdog configuration to be changed, preserving the level of + * safety given by the module. + * + * \subsection asfdoc_sam0_wdt_module_window_mode Window Mode + * Just as there is a reasonable upper bound to the time the main program loop + * should take for each iteration, there is also in many applications a lower + * bound, i.e. a \a minimum time for which each loop iteration should run for + * under normal circumstances. To guard against a system failure resetting the + * Watchdog in a tight loop (or a failure in the system application causing the + * main loop to run faster than expected) a "Window" mode can be enabled to + * disallow resetting of the Watchdog counter before a certain period of time. + * If the Watchdog is not reset \a after the window opens but not \a before the + * Watchdog expires, the system will reset. + * + * \subsection asfdoc_sam0_wdt_module_early_warning Early Warning + * In some cases it is desirable to receive an early warning that the Watchdog is + * about to expire, so that some system action (such as saving any system + * configuration data for failure analysis purposes) can be performed before the + * system reset occurs. The Early Warning feature of the Watchdog module allows + * such a notification to be requested; after the configured early warning time + * (but before the expiry of the Watchdog counter) the Early Warning flag will + * become set, so that the user application can take an appropriate action. + * + * \note It is important to note that the purpose of the Early Warning feature + * is \a not to allow the user application to reset the Watchdog; doing + * so will defeat the safety the module gives to the user application. + * Instead, this feature should be used purely to perform any tasks that + * need to be undertaken before the system reset occurs. + * + * \subsection asfdoc_sam0_wdt_module_overview_physical Physical Connection + * + * \ref asfdoc_sam0_wdt_module_int_connections "The figure below" shows how + * this module is interconnected within the device. + * + * \anchor asfdoc_sam0_wdt_module_int_connections + * \dot + * digraph overview { + * rankdir=LR; + * node [label="GCLK*\nGeneric Clock" shape=square] wdt_clock; + * + * subgraph driver { + * node [label="<f0> WDT | <f1> Watchdog Counter" shape=record] wdt_module; + * node [label="System Reset Logic" shape=ellipse style=filled fillcolor=lightgray] sys_reset; + * } + * + * wdt_clock -> wdt_module:f1; + * wdt_module:f1 -> sys_reset; + * } + * \enddot + * + * \note Watchdog Counter of SAM L21/L22/R30/R34/R35 is \a not provided by GCLK, but it uses an + * internal 1KHz OSCULP32K output clock. + * + * \section asfdoc_sam0_wdt_special_considerations Special Considerations + * + * On some devices the Watchdog configuration can be fused to be always on in + * a particular configuration; if this mode is enabled the Watchdog is not + * software configurable and can have its count reset and early warning state + * checked/cleared only. + * + * \section asfdoc_sam0_wdt_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_wdt_extra. This includes: + * - \ref asfdoc_sam0_wdt_extra_acronyms + * - \ref asfdoc_sam0_wdt_extra_dependencies + * - \ref asfdoc_sam0_wdt_extra_errata + * - \ref asfdoc_sam0_wdt_extra_history + * + * + * \section asfdoc_sam0_wdt_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_wdt_exqsg. + * + * \section asfdoc_sam0_wdt_api_overview API Overview + * @{ + */ + +#include <compiler.h> +#include <clock.h> +#include <gclk.h> + +#if WDT_CALLBACK_MODE == true +# include "wdt_callback.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Watchdog Timer period configuration enum. + * + * Enum for the possible period settings of the Watchdog timer module, for + * values requiring a period as a number of Watchdog timer clock ticks. + */ +enum wdt_period { + /** No Watchdog period. This value can only be used when setting the + * Window and Early Warning periods; its use as the Watchdog Reset + * Period is invalid. */ + WDT_PERIOD_NONE = 0, + /** Watchdog period of 8 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_8CLK = 1, + /** Watchdog period of 16 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_16CLK = 2, + /** Watchdog period of 32 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_32CLK = 3, + /** Watchdog period of 64 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_64CLK = 4, + /** Watchdog period of 128 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_128CLK = 5, + /** Watchdog period of 256 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_256CLK = 6, + /** Watchdog period of 512 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_512CLK = 7, + /** Watchdog period of 1024 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_1024CLK = 8, + /** Watchdog period of 2048 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_2048CLK = 9, + /** Watchdog period of 4096 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_4096CLK = 10, + /** Watchdog period of 8192 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_8192CLK = 11, + /** Watchdog period of 16384 clocks of the Watchdog Timer Generic Clock */ + WDT_PERIOD_16384CLK = 12, +}; + +/** + * \brief Watchdog Timer configuration structure. + * + * Configuration structure for a Watchdog Timer instance. This + * structure should be initialized by the \ref wdt_get_config_defaults() + * function before being modified by the user application. + */ +struct wdt_conf { + /** If \c true, the Watchdog will be locked to the current configuration + * settings when the Watchdog is enabled */ + bool always_on; + /** Enable/Disable the Watchdog Timer */ + bool enable; +#if !(SAML21) && !(SAML22) && !(SAMC20) && !(SAMC21) && !(SAMR30) && !(SAMR34) && !(SAMR35) && !(WLR089) + /** GCLK generator used to clock the peripheral except SAM L21/L22/C21/C20/R30*/ + enum gclk_generator clock_source; +#endif + /** Number of Watchdog timer clock ticks until the Watchdog expires */ + enum wdt_period timeout_period; + /** Number of Watchdog timer clock ticks until the reset window opens */ + enum wdt_period window_period; + /** Number of Watchdog timer clock ticks until the early warning flag is + * set */ + enum wdt_period early_warning_period; +}; + +/** \name Configuration and Initialization + * @{ + */ + +/** + * \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. + * + * \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 wdt_is_syncing(void) +{ + Wdt *const WDT_module = WDT; + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (WDT_module->SYNCBUSY.reg) { +#else + if (WDT_module->STATUS.reg & WDT_STATUS_SYNCBUSY) { +#endif + return true; + } + + return false; +} + +/** + * \brief Initializes a Watchdog Timer configuration structure to defaults. + * + * Initializes a given Watchdog Timer configuration structure to a set of + * known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Not locked, to allow for further (re-)configuration + * \li Enable WDT + * \li Watchdog timer sourced from Generic Clock Channel 4 + * \li A timeout period of 16384 clocks of the Watchdog module clock + * \li No window period, so that the Watchdog count can be reset at any time + * \li No early warning period to indicate the Watchdog will soon expire + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void wdt_get_config_defaults( + struct wdt_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->always_on = false; + config->enable = true; +#if !(SAML21) && !(SAML22) && !(SAMC20) && !(SAMC21) && !(SAMR30) && !(SAMR34) && !(SAMR35) && !(WLR089) + config->clock_source = GCLK_GENERATOR_4; +#endif + config->timeout_period = WDT_PERIOD_16384CLK; + config->window_period = WDT_PERIOD_NONE; + config->early_warning_period = WDT_PERIOD_NONE; +} + +enum status_code wdt_set_config( + const struct wdt_conf *const config); + +/** \brief Determines if the Watchdog timer is currently locked in an enabled state. + * + * Determines if the Watchdog timer is currently enabled and locked, so that + * it cannot be disabled or otherwise reconfigured. + * + * \return Current Watchdog lock state. + */ +static inline bool wdt_is_locked(void) +{ + Wdt *const WDT_module = WDT; + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + return (WDT_module->CTRLA.reg & WDT_CTRLA_ALWAYSON); +#else + return (WDT_module->CTRL.reg & WDT_CTRL_ALWAYSON); +#endif +} + +/** @} */ + +/** \name Timeout and Early Warning Management + * @{ + */ + +/** \brief Clears the Watchdog timer early warning period elapsed flag. + * + * Clears the Watchdog timer early warning period elapsed flag, so that a new + * early warning period can be detected. + */ +static inline void wdt_clear_early_warning(void) +{ + Wdt *const WDT_module = WDT; + + WDT_module->INTFLAG.reg = WDT_INTFLAG_EW; +} + +/** \brief Determines if the Watchdog timer early warning period has elapsed. + * + * Determines if the Watchdog timer early warning period has elapsed. + * + * \note If no early warning period was configured, the value returned by this + * function is invalid. + * + * \return Current Watchdog Early Warning state. + */ +static inline bool wdt_is_early_warning(void) +{ + Wdt *const WDT_module = WDT; + + return (WDT_module->INTFLAG.reg & WDT_INTFLAG_EW); +} + +void wdt_reset_count(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** + * \page asfdoc_sam0_wdt_extra Extra Information for WDT Driver + * + * \section asfdoc_sam0_wdt_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * <table> + * <tr> + * <th>Acronym</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>WDT</td> + * <td>Watchdog Timer</td> + * </tr> + * </table> + * + * + * \section asfdoc_sam0_wdt_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_clock_group "System Clock Driver" + * + * + * \section asfdoc_sam0_wdt_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_wdt_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. + * + * <table> + * <tr> + * <th>Changelog</th> + * </tr> + * <tr> + * <td>Driver updated to follow driver type convention: + * \li wdt_init, wdt_enable, wdt_disable functions removed + * \li wdt_set_config function added + * \li WDT module enable state moved inside the configuration struct </td> + * </tr> + * <tr> + * <td>Initial Release</td> + * </tr> + * </table> + */ + +/** + * \page asfdoc_sam0_wdt_exqsg Examples for WDT Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_wdt_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_wdt_basic_use_case + * \if WDT_CALLBACK_MODE + * - \subpage asfdoc_sam0_wdt_callback_use_case + * \endif + * + * \page asfdoc_sam0_wdt_document_revision_history Document Revision History + * + * <table> + * <tr> + * <th>Doc. Rev.</th> + * <th>Date</th> + * <th>Comments</th> + * </tr> + * <tr> + * <td>42124E</td> + * <td>12/2015</td> + * <td>Added support for SAM L21/L22, SAM DA1, SAM D09, SAM R30, and SAM C20/C21</td> + * </tr> + * <tr> + * <td>42124D</td> + * <td>12/2014</td> + * <td>Added SAM R21 and SAM D10/D11 support</td> + * </tr> + * <tr> + * <td>42124C</td> + * <td>01/2014</td> + * <td>Add SAM D21 support</td> + * </tr> + * <tr> + * <td>42124B</td> + * <td>06/2013</td> + * <td>Corrected documentation typos</td> + * </tr> + * <tr> + * <td>42124A</td> + * <td>06/2013</td> + * <td>Initial release</td> + * </tr> + * </table> + */ + +#endif /* WDT_H_INCLUDED */ diff --git a/src/ArduinoZeroTemplate.c b/src/ArduinoZeroTemplate.c index 2d0e0ebd842e39f2b82dd73571e86ca9079b58cd..65169f5702727a128e0e5064e27a0df7dc541651 100644 --- a/src/ArduinoZeroTemplate.c +++ b/src/ArduinoZeroTemplate.c @@ -63,7 +63,7 @@ void ArduinoZeroTemplate(void) // DAC example. All configuration needed is already done in Init. DAC is 10 bits and can convert in 350 ksps dac_chan_write(&dac0_instance_struct, DAC_CHANNEL_0, 1023); // 1023 is the value and is also maximum value. - + SerialUSB.begin(115200); while (true) diff --git a/src/sam.h b/src/sam.h new file mode 100644 index 0000000000000000000000000000000000000000..80a1c486cda80fa9ddd3dc896e11824ae8e9a006 --- /dev/null +++ b/src/sam.h @@ -0,0 +1,567 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2015, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ +#ifndef _SAM_INCLUDED_ +#define _SAM_INCLUDED_ + +#define part_is_defined(part) (defined(__ ## part ## __)) + +/* + * ---------------------------------------------------------------------------- + * SAMG family + * ---------------------------------------------------------------------------- + */ + +/* SAMG55 series */ +#define SAMG55J1 ( \ + part_is_defined( SAMG55J19 ) ) + +#define SAMG55G1 ( \ + part_is_defined( SAMG55G19 ) ) + +/* Entire SAMG55 series */ +#define SAMG55_SERIES (SAMG55J1 || SAMG55G1) + +/* SAMG54 series */ +#define SAMG54N1 ( \ + part_is_defined( SAMG54N19 ) ) + +#define SAMG54J1 ( \ + part_is_defined( SAMG54J19 ) ) + +#define SAMG54G1 ( \ + part_is_defined( SAMG54G19 ) ) + +/* Entire SAMG54 series */ +#define SAMG54_SERIES (SAMG54N1 || SAMG54J1 || SAMG54G1) + + + +/* Entire SAMG family */ +#define SAMG_SERIES ( SAMG55_SERIES || SAMG54_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAMD family + * ---------------------------------------------------------------------------- + */ + +/* SAMD10 series */ +#define SAMD10C14 ( \ + part_is_defined( SAMD10C14A ) ) + +#define SAMD10C13 ( \ + part_is_defined( SAMD10C13A ) ) + +#define SAMD10D13A ( \ + part_is_defined( SAMD10D13AS ) || \ + part_is_defined( SAMD10D13AM ) ) + +#define SAMD10D14A ( \ + part_is_defined( SAMD10D14AS ) || \ + part_is_defined( SAMD10D14AM ) ) + +/* Entire SAMD10 series */ +#define SAMD10_SERIES (SAMD10C14 || SAMD10C13 || SAMD10D13A || SAMD10D14A) + +/* SAMD11 series */ +#define SAMD11C14 ( \ + part_is_defined( SAMD11C14A ) ) + +#define SAMD11D14A ( \ + part_is_defined( SAMD11D14AS ) || \ + part_is_defined( SAMD11D14AM ) ) + +/* Entire SAMD11 series */ +#define SAMD11_SERIES (SAMD11C14 || SAMD11D14A) + +/* SAMD21 series */ +#define SAMD21J17 ( \ + part_is_defined( SAMD21J17A ) ) + +#define SAMD21G17A ( \ + part_is_defined( SAMD21G17AU ) ) + +#define SAMD21E15B ( \ + part_is_defined( SAMD21E15BU ) ) + +#define SAMD21E15 ( \ + part_is_defined( SAMD21E15A ) || \ + part_is_defined( SAMD21E15B ) || \ + part_is_defined( SAMD21E15L ) ) + +#define SAMD21E16 ( \ + part_is_defined( SAMD21E16A ) || \ + part_is_defined( SAMD21E16B ) || \ + part_is_defined( SAMD21E16L ) ) + +#define SAMD21E17 ( \ + part_is_defined( SAMD21E17A ) ) + +#define SAMD21E18 ( \ + part_is_defined( SAMD21E18A ) ) + +#define SAMD21E16B ( \ + part_is_defined( SAMD21E16BU ) ) + +#define SAMD21J15 ( \ + part_is_defined( SAMD21J15A ) || \ + part_is_defined( SAMD21J15B ) ) + +#define SAMD21J16 ( \ + part_is_defined( SAMD21J16A ) || \ + part_is_defined( SAMD21J16B ) ) + +#define SAMD21G16 ( \ + part_is_defined( SAMD21G16A ) || \ + part_is_defined( SAMD21G16B ) ) + +#define SAMD21G17 ( \ + part_is_defined( SAMD21G17A ) ) + +#define SAMD21G18A ( \ + part_is_defined( SAMD21G18AU ) ) + +#define SAMD21G15 ( \ + part_is_defined( SAMD21G15A ) || \ + part_is_defined( SAMD21G15B ) ) + +#define SAMD21G18 ( \ + part_is_defined( SAMD21G18A ) ) + +#define SAMD21J18 ( \ + part_is_defined( SAMD21J18A ) ) + +#define SAMD51G18A ( \ + part_is_defined( SAMD51G18A ) ) + +#define SAMD51G19A ( \ + part_is_defined( SAMD51G19A ) ) + +#define SAMD51J19A ( \ + part_is_defined( SAMD51J19A ) ) + +#define SAMD51J20A ( \ + part_is_defined( SAMD51J20A ) ) + +#define SAMD51N19A ( \ + part_is_defined( SAMD51N19A ) ) + +#define SAMD51N20A ( \ + part_is_defined( SAMD51N20A ) ) + +#define SAMD51P19A ( \ + part_is_defined( SAMD51P19A ) ) + +#define SAMD51P20A ( \ + part_is_defined( SAMD51P20A ) ) + + +/* Entire SAMD21 series */ +#define SAMD21_SERIES (SAMD21J17 || SAMD21G17A || SAMD21E15B || SAMD21E15 || SAMD21E16 || SAMD21E17 || SAMD21E18 || SAMD21E16B || SAMD21J15 || SAMD21J16 || SAMD21G16 || SAMD21G17 || SAMD21G18A || SAMD21G15 || SAMD21G18 || SAMD21J18) + +/* Entire SAMD51 series */ +#define SAMD51_SERIES (SAMD51G18A || SAMD51G19A || SAMD51J19A || SAMD51J20A || SAMD51N19A || SAMD51N20A || SAMD51P19A || SAMD51P20A) + +/* Entire SAMD family */ +#define SAMD_SERIES (SAMD10_SERIES || SAMD11_SERIES || SAMD21_SERIES || SAMD51_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAML family + * ---------------------------------------------------------------------------- + */ + +/* SAML21 series */ +#define SAML21E18A ( \ + part_is_defined( SAML21E18A ) ) +#define SAML21G18A ( \ + part_is_defined( SAML21G18A ) ) +#define SAML21J18A ( \ + part_is_defined( SAML21J18A ) ) + +#define SAML21E15B ( \ + part_is_defined( SAML21E15B ) ) +#define SAML21E16B ( \ + part_is_defined( SAML21E16B ) ) +#define SAML21E17B ( \ + part_is_defined( SAML21E17B ) ) +#define SAML21E18B ( \ + part_is_defined( SAML21E18B ) ) +#define SAML21G16B ( \ + part_is_defined( SAML21G16B ) ) +#define SAML21G17B ( \ + part_is_defined( SAML21G17B ) ) +#define SAML21G18B ( \ + part_is_defined( SAML21G18B ) ) +#define SAML21J16B ( \ + part_is_defined( SAML21J16B ) ) +#define SAML21J17B ( \ + part_is_defined( SAML21J17B ) ) +#define SAML21J18B ( \ + part_is_defined( SAML21J18B ) ) +#define SAML21J18BU ( \ + part_is_defined( SAML21J18BU ) ) + +/* Entire SAML21A series */ +#define SAML21_SERIES (SAML21E18A || SAML21G18A || SAML21J18A) + +/* Entire SAML21B series */ +#define SAML21B_SERIES (SAML21E15B || SAML21E16B || SAML21E17B || SAML21E18B || SAML21G16B || SAML21G17B || SAML21G18B || SAML21J16B || SAML21J17B || SAML21J18B || SAML21J18BU) + +/* Entire SAMD family */ +#define SAML_SERIES (SAML21A_SERIES || SAML21B_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAMC family + * ---------------------------------------------------------------------------- + */ + +/* SAMC21 series */ +#define SAMC21E15A ( \ + part_is_defined( SAMC21E15A ) ) +#define SAMC21E16A ( \ + part_is_defined( SAMC21E16A ) ) +#define SAMC21E17A ( \ + part_is_defined( SAMC21E17A ) ) +#define SAMC21E18A ( \ + part_is_defined( SAMC21E18A ) ) +#define SAMC21G15A ( \ + part_is_defined( SAMC21G15A ) ) +#define SAMC21G16A ( \ + part_is_defined( SAMC21G16A ) ) +#define SAMC21G17A ( \ + part_is_defined( SAMC21G17A ) ) +#define SAMC21G18A ( \ + part_is_defined( SAMC21G18A ) ) +#define SAMC21J15A ( \ + part_is_defined( SAMC21J15A ) ) +#define SAMC21J16A ( \ + part_is_defined( SAMC21J16A ) ) +#define SAMC21J17A ( \ + part_is_defined( SAMC21J17A ) ) +#define SAMC21J18A ( \ + part_is_defined( SAMC21J18A ) ) +#define SAMC21J18AU ( \ + part_is_defined( SAMC21J18AU ) ) + + +/* Entire SAMC21 series */ +#define SAMC21_SERIES (SAMC21E15A || SAMC21E16A || SAMC21E17A || SAMC21E18A || SAMC21G15A || SAMC21G16A || SAMC21G17A || SAMC21G18A || SAMC21J15A || SAMC21J16A || SAMC21J17A || SAMC21J18A || SAMC21J18AU) + +/* Entire SAMC family */ +#define SAMC_SERIES SAMC21_SERIES + + +/* + * ---------------------------------------------------------------------------- + * SAMS family + * ---------------------------------------------------------------------------- + */ + +/* SAMS70 series */ +#define SAMS70Q2 ( \ + part_is_defined( SAMS70Q20 ) || \ + part_is_defined( SAMS70Q21 ) ) + +#define SAMS70Q1 ( \ + part_is_defined( SAMS70Q19 ) ) + +#define SAMS70N2 ( \ + part_is_defined( SAMS70N20 ) || \ + part_is_defined( SAMS70N21 ) ) + +#define SAMS70N1 ( \ + part_is_defined( SAMS70N19 ) ) + +#define SAMS70J2 ( \ + part_is_defined( SAMS70J20 ) || \ + part_is_defined( SAMS70J21 ) ) + +#define SAMS70J1 ( \ + part_is_defined( SAMS70J19 ) ) + +/* Entire SAMS70 series */ +#define SAMS70_SERIES (SAMS70Q2 || SAMS70Q1 || SAMS70N2 || SAMS70N1 || SAMS70J2 || SAMS70J1) + +/* Entire SAMS family */ +#define SAMS_SERIES (SAMS70_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAME family + * ---------------------------------------------------------------------------- + */ + +/* SAME70 series */ +#define SAME70N1 ( \ + part_is_defined( SAME70N19 ) ) + +#define SAME70N2 ( \ + part_is_defined( SAME70N20 ) || \ + part_is_defined( SAME70N21 ) ) + +#define SAME70J1 ( \ + part_is_defined( SAME70J19 ) ) + +#define SAME70J2 ( \ + part_is_defined( SAME70J20 ) || \ + part_is_defined( SAME70J21 ) ) + +#define SAME70Q1 ( \ + part_is_defined( SAME70Q19 ) ) + +#define SAME70Q2 ( \ + part_is_defined( SAME70Q20 ) || \ + part_is_defined( SAME70Q21 ) ) + +/* Entire SAME70 series */ +#define SAME70_SERIES (SAME70N1 || SAME70N2 || SAME70J1 || SAME70J2 || SAME70Q1 || SAME70Q2) + +/* Entire SAME family */ +#define SAME_SERIES (SAME70_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAM3 family + * ---------------------------------------------------------------------------- + */ + +/* SAM3U series */ +#define SAM3U1 ( \ + part_is_defined( SAM3U1E ) || \ + part_is_defined( SAM3U1C ) ) + +#define SAM3U2 ( \ + part_is_defined( SAM3U2E ) || \ + part_is_defined( SAM3U2C ) ) + +#define SAM3U4 ( \ + part_is_defined( SAM3U4E ) || \ + part_is_defined( SAM3U4C ) ) + +/* Entire SAM3U series */ +#define SAM3U_SERIES (SAM3U1 || SAM3U2 || SAM3U4) + +/* SAM3XA series */ +#define SAM3A4 ( \ + part_is_defined( SAM3A4C ) ) + +#define SAM3X4 ( \ + part_is_defined( SAM3X4C ) || \ + part_is_defined( SAM3X4E ) ) + +#define SAM3A8 ( \ + part_is_defined( SAM3A8C ) ) + +#define SAM3X8 ( \ + part_is_defined( SAM3X8C ) || \ + part_is_defined( SAM3X8E ) || \ + part_is_defined( SAM3X8H ) ) + +/* Entire SAM3XA series */ +#define SAM3XA_SERIES (SAM3A4 || SAM3X4 || SAM3A8 || SAM3X8) + +/* Entire SAM3 family */ +#define SAM3_SERIES (SAM3U_SERIES || SAM3XA_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAMR family + * ---------------------------------------------------------------------------- + */ + +/* SAMR21 series */ +#define SAMR21E16 ( \ + part_is_defined( SAMR21E16A ) ) + +#define SAMR21E18 ( \ + part_is_defined( SAMR21E18A ) ) + +#define SAMR21G16 ( \ + part_is_defined( SAMR21G16A ) ) + +#define SAMR21G17 ( \ + part_is_defined( SAMR21G17A ) ) + +#define SAMR21G18 ( \ + part_is_defined( SAMR21G18A ) ) + +#define SAMR21E17 ( \ + part_is_defined( SAMR21E17A ) ) + +/* Entire SAMR21 series */ +#define SAMR21_SERIES (SAMR21E16 || SAMR21E18 || SAMR21G16 || SAMR21G17 || SAMR21G18 || SAMR21E17) + +/* Entire SAMR family */ +#define SAMR_SERIES (SAMR21_SERIES) + +/* + * ---------------------------------------------------------------------------- + * SAM4 family + * ---------------------------------------------------------------------------- + */ + +/* SAM4N series */ +#define SAM4N8 ( \ + part_is_defined( SAM4N8A ) || \ + part_is_defined( SAM4N8B ) || \ + part_is_defined( SAM4N8C ) ) + +#define SAM4N16 ( \ + part_is_defined( SAM4N16B ) || \ + part_is_defined( SAM4N16C ) ) + +/* Entire SAM4N series */ +#define SAM4N_SERIES (SAM4N8 || SAM4N16) + +/* SAM4S series */ +#define SAM4S8 ( \ + part_is_defined( SAM4S8C ) || \ + part_is_defined( SAM4S8B ) ) + +#define SAM4S2 ( \ + part_is_defined( SAM4S2A ) || \ + part_is_defined( SAM4S2B ) || \ + part_is_defined( SAM4S2C ) ) + +#define SAM4S4 ( \ + part_is_defined( SAM4S4A ) || \ + part_is_defined( SAM4S4B ) || \ + part_is_defined( SAM4S4C ) ) + +#define SAM4SD16 ( \ + part_is_defined( SAM4SD16B ) || \ + part_is_defined( SAM4SD16C ) ) + +#define SAM4S16 ( \ + part_is_defined( SAM4S16C ) || \ + part_is_defined( SAM4S16B ) ) + +#define SAM4SD32 ( \ + part_is_defined( SAM4SD32B ) || \ + part_is_defined( SAM4SD32C ) ) + +#define SAM4SA16 ( \ + part_is_defined( SAM4SA16B ) || \ + part_is_defined( SAM4SA16C ) ) + +/* Entire SAM4S series */ +#define SAM4S_SERIES (SAM4S8 || SAM4S2 || SAM4S4 || SAM4SD16 || SAM4S16 || SAM4SD32 || SAM4SA16) + +/* SAM4E series */ +#define SAM4E16 ( \ + part_is_defined( SAM4E16E ) || \ + part_is_defined( SAM4E16C ) ) + +#define SAM4E8 ( \ + part_is_defined( SAM4E8E ) || \ + part_is_defined( SAM4E8C ) ) + +/* Entire SAM4E series */ +#define SAM4E_SERIES (SAM4E16 || SAM4E8) + +/* SAM4C series */ +#define SAM4C4C_ ( \ + part_is_defined( SAM4C4C_0 ) || \ + part_is_defined( SAM4C4C_1 ) ) + +#define SAM4C8C_ ( \ + part_is_defined( SAM4C8C_0 ) || \ + part_is_defined( SAM4C8C_1 ) ) + +#define SAM4C16C_ ( \ + part_is_defined( SAM4C16C_0 ) || \ + part_is_defined( SAM4C16C_1 ) ) + +#define SAM4C32C_ ( \ + part_is_defined( SAM4C32C_0 ) || \ + part_is_defined( SAM4C32C_1 ) ) + +#define SAM4C32E_ ( \ + part_is_defined( SAM4C32E_0 ) || \ + part_is_defined( SAM4C32E_1 ) ) + +/* Entire SAM4C series */ +#define SAM4C_SERIES (SAM4C4C_ || SAM4C8C_ || SAM4C16C_ || SAM4C32C_ || SAM4C32E_) + +/* Entire SAM4 family */ +#define SAM4_SERIES (SAM4N_SERIES || SAM4S_SERIES || SAM4E_SERIES || SAM4C_SERIES) + +/* + * ---------------------------------------------------------------------------- + * Whole SAM product line + * ---------------------------------------------------------------------------- + */ + +#define SAM (SAM4_SERIES || SAMR_SERIES || SAM3_SERIES || SAMS_SERIES || SAME_SERIES || SAMD_SERIES || SAML_SERIES || SAMG_SERIES ||SAMC_SERIES) + +/* + * ---------------------------------------------------------------------------- + * Header inclusion + * ---------------------------------------------------------------------------- + */ + +#if SAMG_SERIES +#include "samg.h" +#endif /* SAMG_SERIES */ + +#if SAME_SERIES +#include "same.h" +#endif /* SAME_SERIES */ + +#if SAMD_SERIES +#include "samd.h" +#endif /* SAMD_SERIES */ + +#if SAML_SERIES +#include "saml.h" +#endif /* SAML_SERIES */ + +#if SAMC_SERIES +#include "samc.h" +#endif /* SAMC_SERIES */ + +#if SAMS_SERIES +#include "sams.h" +#endif /* SAMS_SERIES */ + +#if SAM3_SERIES +#include "sam3.h" +#endif /* SAM3_SERIES */ + +#if SAMR_SERIES +#include "samr.h" +#endif /* SAMR_SERIES */ + +#if SAM4_SERIES +#include "sam4.h" +#endif /* SAM4_SERIES */ + +#endif