1 /**
2  * \file
3  *
4  * \brief SAM Analog Comparator Driver
5  *
6  * Copyright (c) 2012-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 #ifndef AC_H_INCLUDED
47 #define AC_H_INCLUDED
48 
49 /**
50  * \defgroup asfdoc_sam0_ac_group SAM Analog Comparator (AC) Driver
51  *
52  * This driver for Atmel&reg; | SMART ARM&reg;-based microcontrollers
53  * provides an interface for the configuration
54  * and management of the device's Analog Comparator functionality, for the
55  * comparison of analog voltages against a known reference voltage to determine
56  * its relative level. The following driver API modes are covered by this
57  * manual:
58  * - Polled APIs
59  * \if AC_CALLBACK_MODE
60  * - Callback APIs
61  * \endif
62  *
63  * The following peripherals are used by this module:
64  *  - AC (Analog Comparator)
65  *
66  * The following devices can use this module:
67  *  - Atmel | SMART SAM D20/D21
68  *  - Atmel | SMART SAM R21
69  *  - Atmel | SMART SAM D10/D11
70  *  - Atmel | SMART SAM L21/L22
71  *  - Atmel | SMART SAM DA1
72  *  - Atmel | SMART SAM C20/C21
73  *  - Atmel | SMART SAM HA1
74  *
75  * The outline of this documentation is as follows:
76  *  - \ref asfdoc_sam0_ac_prerequisites
77  *  - \ref asfdoc_sam0_ac_module_overview
78  *  - \ref asfdoc_sam0_ac_special_considerations
79  *  - \ref asfdoc_sam0_ac_extra_info
80  *  - \ref asfdoc_sam0_ac_examples
81  *  - \ref asfdoc_sam0_ac_api_overview
82  *
83  *
84  * \section asfdoc_sam0_ac_prerequisites Prerequisites
85  *
86  * There are no prerequisites for this module.
87  *
88  *
89  * \section asfdoc_sam0_ac_module_overview Module Overview
90  *
91  * The Analog Comparator module provides an interface for the comparison of one
92  * or more analog voltage inputs (sourced from external or internal inputs)
93  * against a known reference voltage, to determine if the unknown voltage is
94  * higher or lower than the reference. Additionally, window functions are
95  * provided so that two comparators can be connected together to determine if
96  * an input is below, inside, above, or outside the two reference points of the
97  * window.
98  *
99  * Each comparator requires two analog input voltages, a positive and negative
100  * channel input. The result of the comparison is a binary \c true if the
101  * comparator's positive channel input is higher than the comparator's negative
102  * input channel, and \c false if otherwise.
103  *
104  *
105  * \subsection asfdoc_sam0_ac_module_features Driver Feature Macro Definition
106  * <table>
107  *    <tr>
108  *      <th>Driver Feature Macro</th>
109  *      <th>Supported devices</th>
110  *    </tr>
111  *    <tr>
112  *      <td>FEATURE_AC_HYSTERESIS_LEVEL</td>
113  *      <td>SAM L21/L22/C20/C21</td>
114  *    </tr>
115  *    <tr>
116  *      <td>FEATURE_AC_SYNCBUSY_SCHEME_VERSION_2</td>
117  *      <td>SAM L21/L22/C20/C21</td>
118  *    </tr>
119  *    <tr>
120  *      <td>FEATURE_AC_RUN_IN_STANDY_EACH_COMPARATOR</td>
121  *      <td>SAM L21/L22/C20/C21</td>
122  *    </tr>
123  *    <tr>
124  *      <td>FEATURE_AC_RUN_IN_STANDY_PAIR_COMPARATOR</td>
125  *      <td>SAM D20/L22/D21/D10/D11/R21/DA1/HA1</td>
126  *    </tr>
127  * </table>
128  * \note The specific features are only available in the driver when the
129  * selected device supports those features.
130  *
131  * \subsection asfdoc_sam0_ac_module_overview_pairs Window Comparators and Comparator Pairs
132  * Each comparator module contains one or more comparator pairs, a set of two
133  * distinct comparators which can be used independently or linked together for
134  * Window Comparator mode. In this latter mode, the two comparator units in a
135  * comparator pair are linked together to allow the module to detect if an input
136  * voltage is below, inside, above, or outside a window set by the upper and
137  * lower threshold voltages set by the two comparators. If not required, window
138  * comparison mode can be turned off and the two comparator units can be
139  * configured and used separately.
140  *
141  * \subsection asfdoc_sam0_ac_module_overview_pos_neg_mux Positive and Negative Input MUXes
142  * Each comparator unit requires two input voltages, a positive and a negative
143  * channel (note that these names refer to the logical operation that the unit
144  * performs, and both voltages should be above GND), which are then compared with
145  * one another. Both the positive and the negative channel inputs are connected to
146  * a pair of multiplexers (MUXes), which allows one of several possible inputs to be
147  * selected for each comparator channel.
148  *
149  * The exact channels available for each comparator differ for the positive and
150  * the negative inputs, but the same MUX choices are available for all comparator
151  * units (i.e. all positive MUXes are identical, all negative MUXes are
152  * identical). This allows the user application to select which voltages are
153  * compared to one another.
154  *
155  * When used in window mode, both comparators in the window pair should have
156  * their positive channel input MUXes configured to the same input channel, with
157  * the negative channel input MUXes used to set the lower and upper window
158  * bounds.
159  *
160  * \subsection asfdoc_sam0_ac_module_overview_output_filtering Output Filtering
161  * The output of each comparator unit can either be used directly with no
162  * filtering (giving a lower latency signal, with potentially more noise around
163  * the comparison threshold) or be passed through a multiple stage
164  * digital majority filter. Several filter lengths are available, with the
165  * longer stages producing a more stable result, at the expense of a higher
166  * latency.
167  *
168  * When output filtering is used in single shot mode, a single trigger of the
169  * comparator will automatically perform the required number of samples to
170  * produce a correctly filtered result.
171  *
172  * \subsection asfdoc_sam0_ac_module_overview_input_hysteresis Input Hysteresis
173  * To prevent unwanted noise around the threshold where the comparator unit's
174  * positive and negative input channels are close in voltage to one another, an
175  * optional hysteresis can be used to widen the point at which the output result
176  * flips. This mode will prevent a change in the comparison output unless the
177  * inputs cross one another beyond the hysteresis gap introduces by this mode.
178  *
179  * \subsection asfdoc_sam0_ac_module_overview_sampling Single Shot and Continuous Sampling Modes
180  * Comparators can be configured to run in either Single Shot or Continuous
181  * sampling modes; when in Single Shot mode, the comparator will only perform a
182  * comparison (and any resulting filtering, see
183  * \ref asfdoc_sam0_ac_module_overview_output_filtering) when triggered via a
184  * software or event trigger. This mode improves the power efficiency of the
185  * system by only performing comparisons when actually required by the
186  * application.
187  *
188  * For systems requiring a lower latency or more frequent comparisons,
189  * continuous mode will place the comparator into continuous sampling mode,
190  * which increases the module's power consumption, but decreases the latency
191  * between each comparison result by automatically performing a comparison on
192  * every cycle of the module's clock.
193  *
194  * \subsection asfdoc_sam0_ac_module_overview_events Events
195  * Each comparator unit is capable of being triggered by both software and
196  * hardware triggers. Hardware input events allow for other peripherals to
197  * automatically trigger a comparison on demand - for example, a timer output
198  * event could be used to trigger comparisons at a desired regular interval.
199  *
200  * The module's output events can similarly be used to trigger other hardware
201  * modules each time a new comparison result is available. This scheme allows
202  * for reduced levels of CPU usage in an application and lowers the overall
203  * system response latency by directly triggering hardware peripherals from one
204  * another without requiring software intervention.
205  *
206  * \note The connection of events between modules requires the use of the
207  *       \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)"
208  *       to route output event of one module to the input event of another.
209  *       For more information on event routing, refer to the event driver
210  *       documentation.
211  *
212  * \subsection asfdoc_sam0_ac_module_overview_physical Physical Connection
213  * Physically, the modules are interconnected within the device as shown in
214  * \ref asfdoc_sam0_ac_module_int_connections "the diagram below".
215  *
216  * \anchor asfdoc_sam0_ac_module_int_connections
217  * \dot
218  * digraph overview {
219  *  rankdir = LR;
220  *  splines = false;
221  *
222  *  pos_src1_1 [label="GPIO Pins", shape=none, height=0];
223  *  neg_src1_1 [label="GPIO Pins", shape=none, height=0];
224  *  neg_src1_2 [label="Internal DAC", shape=none, height=0];
225  *  neg_src1_3 [label="Internal Refs", shape=none, height=0];
226  *  pos_src2_1 [label="GPIO Pins", shape=none, height=0];
227  *  neg_src2_1 [label="GPIO Pins", shape=none, height=0];
228  *  neg_src2_2 [label="Internal DAC", shape=none, height=0];
229  *  neg_src2_3 [label="Internal Refs", shape=none, height=0];
230  *  res_out1 [label="", style=invisible];
231  *  res_out2 [label="", style=invisible];
232  *  res_window [label="", style=invisible];
233  *
234  *  mux_pos1 [label="", shape=polygon, sides=4, distortion=0.6, orientation=90, style=filled, fillcolor=black, height=0.9, width=0.2];
235  *  mux_neg1 [label="", shape=polygon, sides=4, distortion=0.6, orientation=90, style=filled, fillcolor=black, height=0.9, width=0.2];
236  *  mux_neg2 [label="", shape=polygon, sides=4, distortion=0.6, orientation=90, style=filled, fillcolor=black, height=0.9, width=0.2];
237  *  mux_pos2 [label="", shape=polygon, sides=4, distortion=0.6, orientation=90, style=filled, fillcolor=black, height=0.9, width=0.2];
238  *  ac1 [label="AC 1", shape=triangle, orientation=-90, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
239  *  ac2 [label="AC 2", shape=triangle, orientation=-90, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
240  *
241  *  window_comp [label="Window\nLogic", shape=rectangle style=filled fillcolor=lightgray];
242  *
243  *  edge [dir="forward"];
244  *
245  *  pos_src1_1:e -> mux_pos1:w;
246  *  mux_pos1:e -> ac1:nw [label="+"];
247  *  neg_src1_1:e -> mux_neg1:nw;
248  *  neg_src1_2:e -> mux_neg1:w;
249  *  neg_src1_3:e -> mux_neg1:sw;
250  *  mux_neg1:e -> ac1:sw [label="-"];
251  *  ac1:e -> res_out1 [label="Comparator 1 Result"];
252  *
253  *  pos_src2_1:e -> mux_pos2:w;
254  *  mux_pos2:e -> ac2:sw [label="+"];
255  *  neg_src2_1:e -> mux_neg2:nw;
256  *  neg_src2_2:e -> mux_neg2:w;
257  *  neg_src2_3:e -> mux_neg2:sw;
258  *  mux_neg2:e -> ac2:nw [label="-"];
259  *  ac2:e -> res_out2 [label="Comparator 2 Result"];
260  *
261  *  ac1:e -> window_comp:nw;
262  *  ac2:e -> window_comp:sw;
263  *  window_comp:e -> res_window:w [label="Window Result"];
264  *
265  *  {rank=same; pos_src1_1 neg_src1_1 neg_src1_2 neg_src1_3 pos_src2_1 neg_src2_1 neg_src2_2 neg_src2_3 }
266  *  {rank=same; mux_pos1 mux_neg1 mux_pos2 mux_neg2 }
267  *  {rank=same; ac1 ac2 }
268  *  {rank=same; res_out1 res_out2 res_window }
269  * }
270  * \enddot
271  *
272  *
273  * \section asfdoc_sam0_ac_special_considerations Special Considerations
274  *
275  * The number of comparator pairs (and, thus, window comparators) within a
276  * single hardware instance of the Analog Comparator module is device-specific.
277  * Some devices will contain a single comparator pair, while others may have two
278  * pairs; refer to your device specific datasheet for details.
279  *
280  *
281  * \section asfdoc_sam0_ac_extra_info Extra Information
282  *
283  * For extra information, see \ref asfdoc_sam0_ac_extra. This includes:
284  *  - \ref asfdoc_sam0_ac_extra_acronyms
285  *  - \ref asfdoc_sam0_ac_extra_dependencies
286  *  - \ref asfdoc_sam0_ac_extra_errata
287  *  - \ref asfdoc_sam0_ac_extra_history
288  *
289  *
290  * \section asfdoc_sam0_ac_examples Examples
291  *
292  * For a list of examples related to this driver, see
293  * \ref asfdoc_sam0_ac_exqsg.
294  *
295  *
296  * \section asfdoc_sam0_ac_api_overview API Overview
297  * @{
298  */
299 
300 #include <compiler.h>
301 #include <clock.h>
302 
303 #ifdef __cplusplus
304 extern "C" {
305 #endif
306 
307 /**
308  * \name Driver Feature Definition
309  * Define AC driver feature set according to different device family.
310  * @{
311  */
312 #if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || defined(__DOXYGEN__)
313    /** Setting of hysteresis level */
314 #  define FEATURE_AC_HYSTERESIS_LEVEL
315    /** SYNCBUSY scheme version 2 */
316 #  define FEATURE_AC_SYNCBUSY_SCHEME_VERSION_2
317 #endif
318 
319 #if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || defined(__DOXYGEN__)
320  	/** Run in standby feature for each comparator */
321 #  define FEATURE_AC_RUN_IN_STANDY_EACH_COMPARATOR
322 #else
323  	/** Run in standby feature for comparator pair */
324 #  define FEATURE_AC_RUN_IN_STANDY_PAIR_COMPARATOR
325 #endif
326 /* @} */
327 
328 #if !defined(__DOXYGEN__)
329 /* Forward declaration of struct */
330 struct ac_module;
331 
332 extern struct ac_module *_ac_instance[AC_INST_NUM];
333 #endif
334 
335 
336 /**
337  * \name AC Window Channel Status Flags
338  *
339  * AC window channel status flags, returned by \ref ac_win_get_status().
340  *
341  * @{
342  */
343 
344  /** Unknown output state; the comparator window channel was not ready. */
345 #define AC_WIN_STATUS_UNKNOWN         (1UL << 0)
346 /** Window Comparator's input voltage is above the window */
347 #define AC_WIN_STATUS_ABOVE           (1UL << 1)
348 /** Window Comparator's input voltage is inside the window */
349 #define AC_WIN_STATUS_INSIDE          (1UL << 2)
350 /** Window Comparator's input voltage is below the window */
351 #define AC_WIN_STATUS_BELOW           (1UL << 3)
352 /**
353  * This state reflects the window interrupt flag. When the interrupt flag
354  * should be set is configured in \ref ac_win_set_config(). This state needs
355  * to be cleared by the of \ref ac_win_clear_status().
356  */
357 #define AC_WIN_STATUS_INTERRUPT_SET   (1UL << 4)
358 /** @} */
359 
360 /**
361  * \name AC Channel Status Flags
362  *
363  * AC channel status flags, returned by \ref ac_chan_get_status().
364  *
365  * @{
366  */
367 
368 /** Unknown output state; the comparator channel was not ready. */
369 #define AC_CHAN_STATUS_UNKNOWN        (1UL << 0)
370 /** Comparator's negative input pin is higher in voltage than the positive
371  *  input pin. */
372 #define AC_CHAN_STATUS_NEG_ABOVE_POS  (1UL << 1)
373 /** Comparator's positive input pin is higher in voltage than the negative
374  *  input pin. */
375 #define AC_CHAN_STATUS_POS_ABOVE_NEG  (1UL << 2)
376 /**
377  * This state reflects the channel interrupt flag. When the interrupt flag
378  * should be set is configured in ac_chan_set_config(). This state needs
379  * to be cleared by the of ac_chan_clear_status().
380  */
381 #define AC_CHAN_STATUS_INTERRUPT_SET  (1UL << 3)
382 /** @} */
383 
384 /** Type definition for a AC module callback function. */
385 typedef void (*ac_callback_t)(struct ac_module *const module_inst);
386 
387 /** Enum for possible callback types for the AC module. */
388 enum ac_callback {
389 	/** Callback for comparator 0 */
390 	AC_CALLBACK_COMPARATOR_0 = 0,
391 	/** Callback for comparator 1 */
392 	AC_CALLBACK_COMPARATOR_1 = 1,
393 	/** Callback for window 0 */
394 	AC_CALLBACK_WINDOW_0     = 4,
395 #if (AC_NUM_CMP > 2)
396 	/** Callback for comparator 2 */
397 	AC_CALLBACK_COMPARATOR_2 = 2,
398 	/** Callback for comparator 3 */
399 	AC_CALLBACK_COMPARATOR_3 = 3,
400 	/** Callback for window 1 */
401 	AC_CALLBACK_WINDOW_1     = 5,
402 	/** Number of available callbacks */
403 #endif /* (AC_NUM_CMP == 2) */
404 #if !defined(__DOXYGEN__)
405 	AC_CALLBACK_N,
406 #endif /* !defined(__DOXYGEN__) */
407 };
408 
409 #ifdef FEATURE_AC_HYSTERESIS_LEVEL
410 /** Enum for possible hysteresis level types for AC module. */
411 enum ac_hysteresis_level {
412 	/** Hysteresis level of 50mV */
413 	AC_HYSTERESIS_LEVEL_50 = 0,
414 	/** Hysteresis level of 70mV */
415 	AC_HYSTERESIS_LEVEL_70,
416 	/** Hysteresis level of 90mV */
417 	AC_HYSTERESIS_LEVEL_90,
418 	/** Hysteresis level of 110mV */
419 	AC_HYSTERESIS_LEVEL_110
420 };
421 #endif
422 
423 /**
424  * \brief AC comparator channel selection enum.
425  *
426  * Enum for the possible comparator channels.
427  */
428 enum ac_chan_channel {
429 	/** Comparator channel 0 (Pair 0, Comparator 0) */
430 	AC_CHAN_CHANNEL_0 = 0,
431 	/** Comparator channel 1 (Pair 0, Comparator 1) */
432 	AC_CHAN_CHANNEL_1 = 1,
433 #if defined(__DOXYGEN__) || (AC_NUM_CMP > 2)
434 	/** Comparator channel 2 (Pair 1, Comparator 0) */
435 	AC_CHAN_CHANNEL_2 = 2,
436 	/** Comparator channel 3 (Pair 1, Comparator 1) */
437 	AC_CHAN_CHANNEL_3 = 3,
438 #endif
439 };
440 
441 /**
442  * \brief AC channel input sampling mode configuration enum.
443  *
444  * Enum for the possible channel sampling modes of an Analog Comparator channel.
445  */
446 enum ac_chan_sample_mode {
447 	/** Continuous sampling mode; when the channel is enabled the comparator
448 	 *  output is available for reading at any time */
449 	AC_CHAN_MODE_CONTINUOUS    = 0,
450 	/** Single shot mode; when used the comparator channel must be triggered to
451 	 *  perform a comparison before reading the result */
452 	AC_CHAN_MODE_SINGLE_SHOT   = AC_COMPCTRL_SINGLE,
453 };
454 
455 /**
456  * \brief AC channel positive comparator pin input configuration enum.
457  *
458  * Enum for the possible channel positive pin input of an Analog Comparator
459  * channel.
460  */
461 enum ac_chan_pos_mux {
462 	/** Positive comparator input is connected to physical AC input pin 0 */
463 	AC_CHAN_POS_MUX_PIN0       = AC_COMPCTRL_MUXPOS_PIN0,
464 	/** Positive comparator input is connected to physical AC input pin 1 */
465 	AC_CHAN_POS_MUX_PIN1       = AC_COMPCTRL_MUXPOS_PIN1,
466 	/** Positive comparator input is connected to physical AC input pin 2 */
467 	AC_CHAN_POS_MUX_PIN2       = AC_COMPCTRL_MUXPOS_PIN2,
468 	/** Positive comparator input is connected to physical AC input pin 3 */
469 	AC_CHAN_POS_MUX_PIN3       = AC_COMPCTRL_MUXPOS_PIN3,
470 };
471 
472 /**
473  * \brief AC channel negative comparator pin input configuration enum.
474  *
475  * Enum for the possible channel negative pin input of an Analog Comparator
476  * channel.
477  */
478 enum ac_chan_neg_mux {
479 	/** Negative comparator input is connected to physical AC input pin 0 */
480 	AC_CHAN_NEG_MUX_PIN0       = AC_COMPCTRL_MUXNEG_PIN0,
481 	/** Negative comparator input is connected to physical AC input pin 1 */
482 	AC_CHAN_NEG_MUX_PIN1       = AC_COMPCTRL_MUXNEG_PIN1,
483 	/** Negative comparator input is connected to physical AC input pin 2 */
484 	AC_CHAN_NEG_MUX_PIN2       = AC_COMPCTRL_MUXNEG_PIN2,
485 	/** Negative comparator input is connected to physical AC input pin 3 */
486 	AC_CHAN_NEG_MUX_PIN3       = AC_COMPCTRL_MUXNEG_PIN3,
487 	/** Negative comparator input is connected to the internal ground plane */
488 	AC_CHAN_NEG_MUX_GND        = AC_COMPCTRL_MUXNEG_GND,
489 	/** Negative comparator input is connected to the channel's internal V<SUB>CC</SUB>
490 	 *  plane voltage scalar */
491 	AC_CHAN_NEG_MUX_SCALED_VCC = AC_COMPCTRL_MUXNEG_VSCALE,
492 	/** Negative comparator input is connected to the internal band gap voltage
493 	 *  reference */
494 	AC_CHAN_NEG_MUX_BANDGAP    = AC_COMPCTRL_MUXNEG_BANDGAP,
495 #if !(SAML22)
496 	/**
497 	 * For SAM D20/D21/D10/D11/R21/DA1/HA1:
498 	 *     Negative comparator input is connected to the channel's internal DAC
499 	 *     channel 0 output.
500 	 * For SAM L21/C20/C21:
501 	 *     Negative comparator input is connected to the channel's internal DAC
502 	 *     channel 0 output for Comparator 0 or OPAMP output for Comparator 1.
503 	 */
504 	AC_CHAN_NEG_MUX_DAC0       = AC_COMPCTRL_MUXNEG_DAC,
505 #endif
506 };
507 
508 /**
509  * \brief AC channel output filtering configuration enum.
510  *
511  * Enum for the possible channel output filtering configurations of an Analog
512  * Comparator channel.
513  */
514 enum ac_chan_filter {
515 	/** No output filtering is performed on the comparator channel */
516 	AC_CHAN_FILTER_NONE        = AC_COMPCTRL_FLEN_OFF,
517 	/** Comparator channel output is passed through a Majority-of-Three
518 	 *  filter */
519 	AC_CHAN_FILTER_MAJORITY_3  = AC_COMPCTRL_FLEN_MAJ3,
520 	/** Comparator channel output is passed through a Majority-of-Five
521 	 *  filter */
522 	AC_CHAN_FILTER_MAJORITY_5  = AC_COMPCTRL_FLEN_MAJ5,
523 };
524 
525 /**
526  * \brief AC channel GPIO output routing configuration enum.
527  *
528  * Enum for the possible channel GPIO output routing configurations of an Analog
529  * Comparator channel.
530  */
531 enum ac_chan_output {
532 	/** Comparator channel output is not routed to a physical GPIO pin, and is
533 	 *  used internally only */
534 	AC_CHAN_OUTPUT_INTERNAL    = AC_COMPCTRL_OUT_OFF,
535 	/** Comparator channel output is routed to its matching physical GPIO pin,
536 	 *  via an asynchronous path */
537 	AC_CHAN_OUTPUT_ASYNCRONOUS = AC_COMPCTRL_OUT_ASYNC,
538 	/** Comparator channel output is routed to its matching physical GPIO pin,
539 	 *  via a synchronous path */
540 	AC_CHAN_OUTPUT_SYNCHRONOUS = AC_COMPCTRL_OUT_SYNC,
541 };
542 
543 /**
544  * \brief AC window channel selection enum.
545  *
546  * Enum for the possible window comparator channels.
547  */
548 enum ac_win_channel {
549 	/** Window channel 0 (Pair 0, Comparators 0 and 1) */
550 	AC_WIN_CHANNEL_0 = 0,
551 #if defined(__DOXYGEN__) || (AC_PAIRS > 1)
552 	/** Window channel 1 (Pair 1, Comparators 2 and 3) */
553 	AC_WIN_CHANNEL_1 = 1,
554 #endif
555 };
556 
557 /**
558  * \brief Channel interrupt selection enum.
559  *
560  * This enum is used to select when a channel interrupt should occur.
561  */
562 enum ac_chan_interrupt_selection {
563 	/** An interrupt will be generated when the comparator level is passed */
564 	AC_CHAN_INTERRUPT_SELECTION_TOGGLE          = AC_COMPCTRL_INTSEL_TOGGLE,
565 	/** An interrupt will be generated when the measurement goes above the
566 	 *  compare level
567 	 */
568 	AC_CHAN_INTERRUPT_SELECTION_RISING          = AC_COMPCTRL_INTSEL_RISING,
569 	/** An interrupt will be generated when the measurement goes below the
570 	 *  compare level
571 	 */
572 	AC_CHAN_INTERRUPT_SELECTION_FALLING         = AC_COMPCTRL_INTSEL_FALLING,
573 	/**
574 	 * An interrupt will be generated when a new measurement is complete.
575 	 * Interrupts will only be generated in single shot mode. This state needs
576 	 * to be cleared by the use of ac_chan_cleare_status()
577 	 */
578 	AC_CHAN_INTERRUPT_SELECTION_END_OF_COMPARE  = AC_COMPCTRL_INTSEL_EOC,
579 };
580 
581 /**
582  * \brief Window interrupt selection enum.
583  *
584  * This enum is used to select when a window interrupt should occur.
585  */
586 enum ac_win_interrupt_selection {
587 	/** Interrupt is generated when the compare value goes above the window */
588 	AC_WIN_INTERRUPT_SELECTION_ABOVE    = AC_WINCTRL_WINTSEL0_ABOVE,
589 	/** Interrupt is generated when the compare value goes inside the window */
590 	AC_WIN_INTERRUPT_SELECTION_INSIDE   = AC_WINCTRL_WINTSEL0_INSIDE,
591 	/** Interrupt is generated when the compare value goes below the window */
592 	AC_WIN_INTERRUPT_SELECTION_BELOW    = AC_WINCTRL_WINTSEL0_BELOW,
593 	/** Interrupt is generated when the compare value goes outside the window */
594 	AC_WIN_INTERRUPT_SELECTION_OUTSIDE  = AC_WINCTRL_WINTSEL0_OUTSIDE,
595 };
596 
597 /**
598  * \brief AC software device instance structure.
599  *
600  * AC software instance structure, used to retain software state information
601  * of an associated hardware module instance.
602  *
603  * \note The fields of this structure should not be altered by the user
604  *       application; they are reserved for module-internal use only.
605  */
606 struct ac_module {
607 #if !defined(__DOXYGEN__)
608 	/** Hardware module pointer of the associated Analog Comparator peripheral. */
609 	Ac *hw;
610 #  if AC_CALLBACK_MODE == true
611 	/** Array of callbacks */
612 	ac_callback_t callback[AC_CALLBACK_N];
613 	/** Bit mask for callbacks registered */
614 	uint8_t register_callback_mask;
615 	/** Bit mask for callbacks enabled */
616 	uint8_t enable_callback_mask;
617 #  endif
618 #endif
619 };
620 
621 /**
622  * \brief AC event enable/disable structure.
623  *
624  * Event flags for the Analog Comparator module. This is used to enable and
625  * disable events via \ref ac_enable_events() and \ref ac_disable_events().
626  */
627 struct ac_events {
628 	/** If \c true, an event will be generated when a comparator window state
629 	 *  changes */
630 	bool generate_event_on_window[AC_PAIRS];
631 
632 	/** If \c true, an event will be generated when a comparator state
633 	 *  changes */
634 	bool generate_event_on_state[AC_NUM_CMP];
635 
636 	/** If \c true, a comparator will be sampled each time an event is
637 	 *  received */
638 	bool on_event_sample[AC_NUM_CMP];
639 };
640 
641 /**
642  * \brief Analog Comparator module configuration structure.
643  *
644  *  Configuration structure for a comparator channel, to configure the input and
645  *  output settings of the comparator.
646  */
647 struct ac_config {
648 #ifdef FEATURE_AC_RUN_IN_STANDY_PAIR_COMPARATOR
649 	/** If \c true, the comparator pairs will continue to sample during sleep
650 	 *  mode when triggered */
651 	bool run_in_standby[AC_PAIRS];
652 #endif
653 
654 #if (SAMD) || (SAMHA1) || (SAMR21)
655 	/** Digital source generator for AC GCLK */
656 	enum gclk_generator dig_source_generator;
657 	/** Analog source generator for AC GCLK */
658 	enum gclk_generator ana_source_generator;
659 #else
660 	/** Source generator for AC GCLK */
661 	enum gclk_generator source_generator;
662 #endif
663 };
664 
665 /**
666  * \brief Analog Comparator Comparator channel configuration structure.
667  *
668  *  Configuration structure for a comparator channel, to configure the input and
669  *  output settings of the comparator.
670  */
671 struct ac_chan_config {
672 	/** Sampling mode of the comparator channel */
673 	enum ac_chan_sample_mode sample_mode;
674 	/** Filtering mode for the comparator output, when the comparator is used
675 	 *  in a supported mode */
676 	enum ac_chan_filter filter;
677 	/** When \c true, hysteresis mode is enabled on the comparator inputs */
678 	bool enable_hysteresis;
679 #ifdef FEATURE_AC_RUN_IN_STANDY_EACH_COMPARATOR
680 	/** If \c true, the comparator will continue to sample during sleep
681 	 *  mode when triggered */
682 	bool run_in_standby;
683 #endif
684 #ifdef FEATURE_AC_HYSTERESIS_LEVEL
685 	/** Hysteresis level of the comparator channel */
686 	enum ac_hysteresis_level hysteresis_level;
687 #endif
688 	/** Output mode of the comparator, whether it should be available for
689 	 *  internal use, or asynchronously/synchronously linked to a
690 	 *  general-purpose input/output (GPIO) pin */
691 	enum ac_chan_output output_mode;
692 	/** Input multiplexer selection for the comparator's positive input pin */
693 	enum ac_chan_pos_mux positive_input;
694 	/** Input multiplexer selection for the comparator's negative input pin.
695 	 *  Any internal reference source, such as a bandgap reference voltage or
696 	 *  the DAC, must be configured and enabled prior to its use as a
697 	 *  comparator input.*/
698 	enum ac_chan_neg_mux negative_input;
699 	/** Scaled VCC voltage division factor for the channel, when a comparator
700 	 *  pin is connected to the V<SUB>CC</SUB> voltage scalar input. The formular is:
701 	 *      Vscale = Vdd * vcc_scale_factor / 64.
702 	 *  If the V<SUB>CC</SUB> voltage scalar is not selected as a comparator
703 	 *  channel pin's input, this value will be ignored. */
704 	uint8_t vcc_scale_factor;
705 	/** Interrupt criteria for the comparator channel, to select the condition
706 	 *  that will trigger a callback */
707 	enum ac_chan_interrupt_selection interrupt_selection;
708 };
709 
710 /**
711  * \brief Analog Comparator Window configuration structure.
712  */
713 struct ac_win_config {
714 	/** Interrupt criteria for the comparator window channel, to select the
715 	 *  condition that will trigger a callback */
716 	enum ac_win_interrupt_selection interrupt_selection;
717 };
718 
719 /**
720  * \name Configuration and Initialization
721  * @{
722  */
723 
724 enum status_code ac_reset(
725 		struct ac_module *const module_inst);
726 
727 enum status_code ac_init(
728 		struct ac_module *const module_inst,
729 		Ac *const hw,
730 		struct ac_config *const config);
731 
732 #if (AC_INST_NUM > 1) && !defined(__DOXYGEN__)
733 /**
734  * \internal Find the index of given AC module instance.
735  *
736  * \param[in] AC module instance pointer.
737  *
738  * \return Index of the given AC module instance.
739  */
_ac_get_inst_index(Ac * const hw)740 static uint8_t _ac_get_inst_index(
741 		Ac *const hw)
742 {
743 	/* List of available AC modules. */
744 	static Ac *const ac_modules[AC_INST_NUM] = AC_INSTS;
745 
746 	/* Find index for AC instance. */
747 	for (uint32_t i = 0; i < AC_INST_NUM; i++) {
748 		if (hw == ac_modules[i]) {
749 			return i;
750 		}
751 	}
752 
753 	/* Invalid data given. */
754 	Assert(false);
755 	return 0;
756 }
757 #endif /* (AC_INST_NUM > 1) && !defined(__DOXYGEN__) */
758 
759 /**
760  * \brief Determines if the hardware module(s) are currently synchronizing to the bus.
761  *
762  * Checks to see if the underlying hardware peripheral module(s) are currently
763  * synchronizing across multiple clock domains to the hardware bus. This
764  * function can be used to delay further operations on a module until such time
765  * that it is ready, to prevent blocking delays for synchronization in the
766  * user application.
767  *
768  * \param[in] module_inst  Pointer to the AC software instance struct
769  *
770  * \return Synchronization status of the underlying hardware module(s).
771  *
772  * \retval false If the module has completed synchronization
773  * \retval ture If the module synchronization is ongoing
774  */
ac_is_syncing(struct ac_module * const module_inst)775 static inline bool ac_is_syncing(
776         struct ac_module *const module_inst)
777 {
778 	/* Sanity check arguments */
779 	Assert(module_inst);
780 
781 	Ac *const ac_module = module_inst->hw;
782 
783 #ifdef FEATURE_AC_SYNCBUSY_SCHEME_VERSION_2
784 	if (ac_module->SYNCBUSY.reg & AC_SYNCBUSY_MASK) {
785 		return true;
786 	}
787 
788 	return false;
789 #else
790 	if (ac_module->STATUSB.reg & AC_STATUSB_SYNCBUSY) {
791 		return true;
792 	}
793 
794 	return false;
795 #endif
796 }
797 
798 /**
799  * \brief Initializes all members of an Analog Comparator configuration
800  * structure to safe defaults.
801  *
802  *  Initializes all members of a given Analog Comparator configuration
803  *  structure to safe known default values. This function should be called on
804  *  all new instances of these configuration structures before being modified
805  *  by the user application.
806  *
807  *  The default configuration is as follows:
808  *   \li All comparator pairs disabled during sleep mode (if has this feature)
809  *   \li Generator 0 is the default GCLK generator
810  *
811  *  \param[out] config  Configuration structure to initialize to default values
812  */
ac_get_config_defaults(struct ac_config * const config)813 static inline void ac_get_config_defaults(
814 		struct ac_config *const config)
815 {
816 	/* Sanity check arguments */
817 	Assert(config);
818 #ifdef FEATURE_AC_RUN_IN_STANDY_PAIR_COMPARATOR
819 	/* Default configuration values */
820 	for (uint32_t i = 0; i < AC_PAIRS; i++) {
821 		config->run_in_standby[i] = false;
822 	}
823 #endif
824 #if (SAMD) || (SAMHA1) || (SAMR21)
825 	config->dig_source_generator = GCLK_GENERATOR_0;
826 	config->ana_source_generator = GCLK_GENERATOR_3;
827 #else
828 	config->source_generator = GCLK_GENERATOR_0;
829 #endif
830 }
831 
832 /**
833  * \brief Enables an Analog Comparator that was previously configured.
834  *
835  * Enables an Analog Comparator that was previously configured via a
836  * call to \ref ac_init().
837  *
838  * \param[in] module_inst  Software instance for the Analog Comparator peripheral
839  */
ac_enable(struct ac_module * const module_inst)840 static inline void ac_enable(
841 		struct ac_module *const module_inst)
842 {
843 	/* Sanity check arguments */
844 	Assert(module_inst);
845 	Assert(module_inst->hw);
846 
847 	Ac *const ac_module = module_inst->hw;
848 
849 	while (ac_is_syncing(module_inst)) {
850 		/* Wait until synchronization is complete */
851 	}
852 
853 	/* Write the new comparator module control configuration */
854 	ac_module->CTRLA.reg |= AC_CTRLA_ENABLE;
855 }
856 
857 /**
858  * \brief Disables an Analog Comparator that was previously enabled.
859  *
860  * Disables an Analog Comparator that was previously started via a call to
861  * \ref ac_enable().
862  *
863  * \param[in] module_inst  Software instance for the Analog Comparator peripheral
864  */
ac_disable(struct ac_module * const module_inst)865 static inline void ac_disable(
866 		struct ac_module *const module_inst)
867 {
868 	/* Sanity check arguments */
869 	Assert(module_inst);
870 	Assert(module_inst->hw);
871 
872 	Ac *const ac_module = module_inst->hw;
873 
874 	while (ac_is_syncing(module_inst)) {
875 		/* Wait until synchronization is complete */
876 	}
877 
878 	/* Disbale interrupt */
879 	ac_module->INTENCLR.reg = AC_INTENCLR_MASK;
880 	/* Clear interrupt flag */
881 	ac_module->INTFLAG.reg = AC_INTFLAG_MASK;
882 
883 	/* Write the new comparator module control configuration */
884 	ac_module->CTRLA.reg &= ~AC_CTRLA_ENABLE;
885 }
886 
887 /**
888  * \brief Enables an Analog Comparator event input or output.
889  *
890  *  Enables one or more input or output events to or from the Analog Comparator
891  *  module. See \ref ac_events for a list of events this module
892  *  supports.
893  *
894  *  \note Events cannot be altered while the module is enabled.
895  *
896  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
897  *  \param[in] events       Struct containing flags of events to enable
898  */
ac_enable_events(struct ac_module * const module_inst,struct ac_events * const events)899 static inline void ac_enable_events(
900 		struct ac_module *const module_inst,
901 		struct ac_events *const events)
902 {
903 	/* Sanity check arguments */
904 	Assert(module_inst);
905 	Assert(module_inst->hw);
906 	Assert(events);
907 
908 	Ac *const ac_module = module_inst->hw;
909 
910 	uint32_t event_mask = 0;
911 
912 	/* Configure window output events for each comparator pair */
913 	for (uint8_t i = 0; i < AC_PAIRS; i++) {
914 		if (events->generate_event_on_window[i] == true) {
915 			event_mask |= (AC_EVCTRL_WINEO0 << i);
916 		}
917 	}
918 
919 	/* Configure sample input/output events for each comparator */
920 	for (uint8_t i = 0; i < AC_NUM_CMP; i++) {
921 		if (events->on_event_sample[i] == true) {
922 			event_mask |= (AC_EVCTRL_COMPEI0 << i);
923 		}
924 
925 		if (events->generate_event_on_state[i] == true) {
926 			event_mask |= (AC_EVCTRL_COMPEO0 << i);
927 		}
928 	}
929 
930 	ac_module->EVCTRL.reg |= event_mask;
931 }
932 
933 /**
934  * \brief Disables an Analog Comparator event input or output.
935  *
936  *  Disables one or more input or output events to or from the Analog Comparator
937  *  module. See \ref ac_events for a list of events this module
938  *  supports.
939  *
940  *  \note Events cannot be altered while the module is enabled.
941  *
942  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
943  *  \param[in] events       Struct containing flags of events to disable
944  */
ac_disable_events(struct ac_module * const module_inst,struct ac_events * const events)945 static inline void ac_disable_events(
946 		struct ac_module *const module_inst,
947 		struct ac_events *const events)
948 {
949 	/* Sanity check arguments */
950 	Assert(module_inst);
951 	Assert(module_inst->hw);
952 	Assert(events);
953 
954 	Ac *const ac_module = module_inst->hw;
955 
956 	uint32_t event_mask = 0;
957 
958 	/* Configure window output events for each comparator pair */
959 	for (uint8_t i = 0; i < AC_PAIRS; i++) {
960 		if (events->generate_event_on_window[i] == true) {
961 			event_mask |= (AC_EVCTRL_WINEO0 << i);
962 		}
963 	}
964 
965 	/* Configure sample input/output events for each comparator */
966 	for (uint8_t i = 0; i < AC_NUM_CMP; i++) {
967 		if (events->on_event_sample[i] == true) {
968 			event_mask |= (AC_EVCTRL_COMPEI0 << i);
969 		}
970 
971 		if (events->generate_event_on_state[i] == true) {
972 			event_mask |= (AC_EVCTRL_COMPEO0 << i);
973 		}
974 	}
975 
976 	ac_module->EVCTRL.reg &= ~event_mask;
977 }
978 
979 /** @} */
980 
981 
982 /**
983  * \name Channel Configuration and Initialization
984  * @{
985  */
986 
987 /**
988  * \brief Initializes all members of an Analog Comparator channel configuration
989  * structure to safe defaults.
990  *
991  *  Initializes all members of an Analog Comparator channel configuration
992  *  structure to safe defaults. This function should be called on all new
993  *  instances of these configuration structures before being modified by the
994  *  user application.
995  *
996  *  The default configuration is as follows:
997  *   \li Continuous sampling mode
998  *   \li Majority of five sample output filter
999  *   \li Comparator disabled during sleep mode (if has this feature)
1000  *   \li Hysteresis enabled on the input pins
1001  *   \li Hysteresis level of 50mV if having this feature
1002  *   \li Internal comparator output mode
1003  *   \li Comparator pin multiplexer 0 selected as the positive input
1004  *   \li Scaled V<SUB>CC</SUB> voltage selected as the negative input
1005  *   \li V<SUB>CC</SUB> voltage scaler set for a division factor of two
1006  *   \li Channel interrupt set to occur when the compare threshold is passed
1007  *
1008  *   \param[out] config  Channel configuration structure to initialize to
1009  *                       default values
1010  */
ac_chan_get_config_defaults(struct ac_chan_config * const config)1011 static inline void ac_chan_get_config_defaults(
1012 		struct ac_chan_config *const config)
1013 {
1014 	/* Sanity check arguments */
1015 	Assert(config);
1016 
1017 	/* Default configuration values */
1018 	config->sample_mode         = AC_CHAN_MODE_CONTINUOUS;
1019 	config->filter              = AC_CHAN_FILTER_MAJORITY_5;
1020 	config->enable_hysteresis   = true;
1021 #ifdef FEATURE_AC_RUN_IN_STANDY_EACH_COMPARATOR
1022 	config->run_in_standby      = false;
1023 #endif
1024 #ifdef FEATURE_AC_HYSTERESIS_LEVEL
1025 	config->hysteresis_level    = AC_HYSTERESIS_LEVEL_50;
1026 #endif
1027 	config->output_mode         = AC_CHAN_OUTPUT_INTERNAL;
1028 	config->positive_input      = AC_CHAN_POS_MUX_PIN0;
1029 	config->negative_input      = AC_CHAN_NEG_MUX_SCALED_VCC;
1030 	config->vcc_scale_factor    = 32;
1031 	config->interrupt_selection = AC_CHAN_INTERRUPT_SELECTION_TOGGLE;
1032 }
1033 
1034 enum status_code ac_chan_set_config(
1035 		struct ac_module *const module_inst,
1036 		const enum ac_chan_channel channel,
1037 		struct ac_chan_config *const config);
1038 
1039 /**
1040  * \brief Enables an Analog Comparator channel that was previously configured.
1041  *
1042  *  Enables an Analog Comparator channel that was previously
1043  *  configured via a call to \ref ac_chan_set_config().
1044  *
1045  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
1046  *  \param[in] channel      Comparator channel to enable
1047  */
ac_chan_enable(struct ac_module * const module_inst,const enum ac_chan_channel channel)1048 static inline void ac_chan_enable(
1049 		struct ac_module *const module_inst,
1050 		const enum ac_chan_channel channel)
1051 {
1052 	/* Sanity check arguments */
1053 	Assert(module_inst);
1054 	Assert(module_inst->hw);
1055 
1056 	Ac *const ac_module = module_inst->hw;
1057 
1058 	while (ac_is_syncing(module_inst)) {
1059 		/* Wait until synchronization is complete */
1060 	}
1061 
1062 	/* Write the new comparator module control configuration */
1063 	ac_module->COMPCTRL[(uint8_t)channel].reg |= AC_COMPCTRL_ENABLE;
1064 }
1065 
1066 /**
1067  * \brief Disables an Analog Comparator channel that was previously enabled.
1068  *
1069  *  Stops an Analog Comparator channel that was previously started via a call to
1070  *  \ref ac_chan_enable().
1071  *
1072  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
1073  *  \param[in] channel      Comparator channel to disable
1074  */
ac_chan_disable(struct ac_module * const module_inst,const enum ac_chan_channel channel)1075 static inline void ac_chan_disable(
1076 		struct ac_module *const module_inst,
1077 		const enum ac_chan_channel channel)
1078 {
1079 	/* Sanity check arguments */
1080 	Assert(module_inst);
1081 	Assert(module_inst->hw);
1082 
1083 	Ac *const ac_module = module_inst->hw;
1084 
1085 	while (ac_is_syncing(module_inst)) {
1086 		/* Wait until synchronization is complete */
1087 	}
1088 
1089 	/* Write the new comparator module control configuration */
1090 	ac_module->COMPCTRL[(uint8_t)channel].reg &= ~AC_COMPCTRL_ENABLE;
1091 }
1092 
1093 /** @} */
1094 
1095 
1096 /**
1097  * \name Channel Control
1098  * @{
1099  */
1100 
1101 /**
1102  * \brief Triggers a comparison on a comparator that is configured in single shot mode.
1103  *
1104  *  Triggers a single conversion on a comparator configured to compare on demand
1105  *  (single shot mode) rather than continuously.
1106  *
1107  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
1108  *  \param[in] channel      Comparator channel to trigger
1109  */
ac_chan_trigger_single_shot(struct ac_module * const module_inst,const enum ac_chan_channel channel)1110 static inline void ac_chan_trigger_single_shot(
1111 		struct ac_module *const module_inst,
1112 		const enum ac_chan_channel channel)
1113 {
1114 	/* Sanity check arguments */
1115 	Assert(module_inst);
1116 	Assert(module_inst->hw);
1117 
1118 	Ac *const ac_module = module_inst->hw;
1119 
1120 	/* Write the new comparator module control configuration */
1121 	ac_module->CTRLB.reg |= (AC_CTRLB_START0 << (uint8_t)channel);
1122 }
1123 
1124 /**
1125  * \brief Determines if a given comparator channel is ready for comparisons.
1126  *
1127  *  Checks a comparator channel to see if the comparator is currently ready to
1128  *  begin comparisons.
1129  *
1130  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
1131  *  \param[in] channel      Comparator channel to test
1132  *
1133  *  \return Comparator channel readiness state.
1134  */
ac_chan_is_ready(struct ac_module * const module_inst,const enum ac_chan_channel channel)1135 static inline bool ac_chan_is_ready(
1136 		struct ac_module *const module_inst,
1137 		const enum ac_chan_channel channel)
1138 {
1139 	/* Sanity check arguments */
1140 	Assert(module_inst);
1141 	Assert(module_inst->hw);
1142 
1143 	Ac *const ac_module = module_inst->hw;
1144 
1145 	return (ac_module->STATUSB.reg & (AC_STATUSB_READY0 << (uint8_t)channel));
1146 }
1147 
1148 /**
1149  * \brief Determines the output state of a comparator channel.
1150  *
1151  *  Retrieves the last comparison value (after filtering) of a given comparator.
1152  *  If the comparator was not ready at the time of the check, the comparison
1153  *  result will be indicated as being unknown.
1154  *
1155  *  \param[in] module_inst   Software instance for the Analog Comparator peripheral
1156  *  \param[in] channel       Comparator channel to test
1157  *
1158  *  \return Bit mask of comparator channel status flags.
1159  */
ac_chan_get_status(struct ac_module * const module_inst,const enum ac_chan_channel channel)1160 static inline uint8_t ac_chan_get_status(
1161 		struct ac_module *const module_inst,
1162 		const enum ac_chan_channel channel)
1163 {
1164 	/* Sanity check arguments */
1165 	Assert(module_inst);
1166 	Assert(module_inst->hw);
1167 
1168 	Ac *const ac_module = module_inst->hw;
1169 
1170 	uint8_t status_mask = 0;
1171 
1172 	if (ac_module->INTFLAG.reg & (1 << channel)) {
1173 		status_mask = AC_CHAN_STATUS_INTERRUPT_SET;
1174 	}
1175 
1176 	if (ac_chan_is_ready(module_inst, channel) == false) {
1177 		status_mask |= AC_CHAN_STATUS_UNKNOWN;
1178 		return status_mask;
1179 	}
1180 
1181 	if (ac_module->STATUSA.reg & (AC_STATUSA_STATE0 << (uint8_t)channel)) {
1182 		status_mask |= AC_CHAN_STATUS_POS_ABOVE_NEG;
1183 	} else {
1184 		status_mask |= AC_CHAN_STATUS_NEG_ABOVE_POS;
1185 	}
1186 	return status_mask;
1187 }
1188 
1189 /**
1190  * \brief Clears an interrupt status flag.
1191  *
1192  * This function is used to clear the AC_CHAN_STATUS_INTERRUPT_SET flag
1193  * it will clear the flag for the channel indicated by the channel argument.
1194  *
1195  * \param[in]  module_inst  Software instance for the Analog Comparator peripheral
1196  * \param[in]  channel      Comparator channel to clear
1197  */
ac_chan_clear_status(struct ac_module * const module_inst,const enum ac_chan_channel channel)1198 static inline void ac_chan_clear_status(
1199 		struct ac_module *const module_inst,
1200 		const enum ac_chan_channel channel)
1201 {
1202 	Assert(module_inst);
1203 	Assert(module_inst->hw);
1204 
1205 	module_inst->hw->INTFLAG.reg = (1 << channel);
1206 }
1207 /** @} */
1208 
1209 
1210 /**
1211  * \name Window Mode Configuration and Initialization
1212  * @{
1213  */
1214 
1215 /**
1216  * \brief Initializes an Analog Comparator window configuration structure to defaults.
1217  *
1218  *  Initializes a given Analog Comparator channel configuration structure to a
1219  *  set of known default values. This function should be called if window interrupts
1220  *  are needed and before ac_win_set_config().
1221  *
1222  *  The default configuration is as follows:
1223  *   \li Channel interrupt set to occur when the measurement is above the window
1224  *
1225  *   \param[out] config  Window configuration structure to initialize to
1226  *                       default values
1227  */
ac_win_get_config_defaults(struct ac_win_config * const config)1228 static inline void ac_win_get_config_defaults(
1229 		struct ac_win_config *const config)
1230 {
1231 	/* Sanity check arguments */
1232 	Assert(config);
1233 
1234 	/* Default configuration values */
1235 	config->interrupt_selection = AC_WIN_INTERRUPT_SELECTION_ABOVE;
1236 }
1237 
1238 enum status_code ac_win_set_config(
1239 		struct ac_module *const module_inst,
1240 		enum ac_win_channel const win_channel,
1241 		struct ac_win_config *const config);
1242 
1243 enum status_code ac_win_enable(
1244 		struct ac_module *const module_inst,
1245 		const enum ac_win_channel win_channel);
1246 
1247 void ac_win_disable(
1248 		struct ac_module *const module_inst,
1249 		const enum ac_win_channel win_channel);
1250 
1251 /** @} */
1252 
1253 
1254 /**
1255  * \name Window Mode Control
1256  * @{
1257  */
1258 
1259 /**
1260  * \brief Determines if a given Window Comparator is ready for comparisons.
1261  *
1262  *  Checks a Window Comparator to see if the both comparators used for window
1263  *  detection is currently ready to begin comparisons.
1264  *
1265  *  \param[in] module_inst  Software instance for the Analog Comparator peripheral
1266  *  \param[in] win_channel  Window Comparator channel to test
1267  *
1268  *  \return Window Comparator channel readiness state.
1269  */
ac_win_is_ready(struct ac_module * const module_inst,const enum ac_win_channel win_channel)1270 static inline bool ac_win_is_ready(
1271 		struct ac_module *const module_inst,
1272 		const enum ac_win_channel win_channel)
1273 {
1274 	/* Sanity check arguments */
1275 	Assert(module_inst);
1276 	Assert(module_inst->hw);
1277 
1278 	/* Convert a window channel index to the individual comparator channels */
1279 	enum ac_chan_channel win_pair_comp0 =
1280 			(enum ac_chan_channel)((uint8_t)win_channel * 2);
1281 	enum ac_chan_channel win_pair_comp1 =
1282 			(enum ac_chan_channel)(((uint8_t)win_channel * 2) + 1);
1283 
1284 	/* Check if the two comparators used in the window are ready */
1285 	bool win_pair_comp0_ready = ac_chan_is_ready(module_inst, win_pair_comp0);
1286 	bool win_pair_comp1_ready = ac_chan_is_ready(module_inst, win_pair_comp1);
1287 
1288 	/* If one or both window comparators not ready, return failure */
1289 	if ((win_pair_comp0_ready == false) || (win_pair_comp1_ready == false)) {
1290 		return false;
1291 	}
1292 
1293 	return true;
1294 }
1295 
1296 uint8_t ac_win_get_status(
1297 		struct ac_module *const module_inst,
1298 		const enum ac_win_channel win_channel);
1299 
1300 /**
1301  * \brief Clears an interrupt status flag.
1302  *
1303  * This function is used to clear the AC_WIN_STATUS_INTERRUPT_SET flag
1304  * it will clear the flag for the channel indicated by the win_channel argument.
1305  *
1306  * \param[in]  module_inst  Software instance for the Analog Comparator peripheral
1307  * \param[in]  win_channel      Window channel to clear
1308  */
ac_win_clear_status(struct ac_module * const module_inst,const enum ac_win_channel win_channel)1309 static inline void ac_win_clear_status(
1310 		struct ac_module *const module_inst,
1311 		const enum ac_win_channel win_channel)
1312 {
1313 	Assert(module_inst);
1314 	Assert(module_inst->hw);
1315 
1316 	module_inst->hw->INTFLAG.reg = (1 << (win_channel + AC_INTFLAG_WIN0_Pos));
1317 }
1318 /** @} */
1319 
1320 #ifdef __cplusplus
1321 }
1322 #endif
1323 
1324 /** @} */
1325 
1326 
1327 /**
1328  * \page asfdoc_sam0_ac_extra Extra Information for AC Driver
1329  *
1330  * \section asfdoc_sam0_ac_extra_acronyms Acronyms
1331  * Below is a table listing the acronyms used in this module, along with their
1332  * intended meanings.
1333  *
1334  * <table>
1335  *    <tr>
1336  *      <th>Acronym</th>
1337  *      <th>Description</th>
1338  *    </tr>
1339  *    <tr>
1340  *      <td>AC</td>
1341  *      <td>Analog Comparator</td>
1342  *    </tr>
1343  *    <tr>
1344  *      <td>DAC</td>
1345  *      <td>Digital-to-Analog Converter</td>
1346  *    </tr>
1347  *    <tr>
1348  *      <td>MUX</td>
1349  *      <td>Multiplexer</td>
1350  *    </tr>
1351  * </table>
1352  *
1353  *
1354  * \section asfdoc_sam0_ac_extra_dependencies Dependencies
1355  * This driver has the following dependencies:
1356  *
1357  *  - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
1358  *
1359  *
1360  * \section asfdoc_sam0_ac_extra_errata Errata
1361  * There are no errata related to this driver.
1362  *
1363  *
1364  * \section asfdoc_sam0_ac_extra_history Module History
1365  * An overview of the module history is presented in the table below, with
1366  * details on the enhancements and fixes made to the module since its first
1367  * release. The current version of this corresponds to the newest version in
1368  * the table.
1369  *
1370  * <table>
1371  *    <tr>
1372  *      <th>Changelog</th>
1373  *    </tr>
1374  *    <tr>
1375  *      <td>Initial Release</td>
1376  *    </tr>
1377  * </table>
1378  */
1379 
1380 /**
1381  * \page asfdoc_sam0_ac_exqsg Examples for AC Driver
1382  *
1383  * This is a list of the available Quick Start guides (QSGs) and example
1384  * applications for \ref asfdoc_sam0_ac_group. QSGs are simple examples with
1385  * step-by-step instructions to configure and use this driver in a selection of
1386  * use cases. Note that a QSG can be compiled as a standalone application or be
1387  * added to the user application.
1388  *
1389  *  - \subpage asfdoc_sam0_ac_basic_use_case
1390  * \if AC_CALLBACK_MODE
1391  *  - \subpage asfdoc_sam0_ac_callback_use_case
1392  * \endif
1393  *
1394  * \page asfdoc_sam0_ac_document_revision_history Document Revision History
1395  *
1396  * <table>
1397  *    <tr>
1398  *      <th>Doc. Rev.</th>
1399  *      <th>Date</th>
1400  *      <th>Comments</th>
1401  *    </tr>
1402  *    <tr>
1403  *      <td>42106F</td>
1404  *      <td>12/2015</td>
1405  *      <td>Fixed typos and legal disclaimer</td>
1406  *    </tr>
1407  *    <tr>
1408  *      <td>42106E</td>
1409  *      <td>08/2015</td>
1410  *      <td>Added support for SAM L21, SAM C20/C21, and SAM DA1</td>
1411  *    </tr>
1412  *    <tr>
1413  *      <td>42106D</td>
1414  *      <td>12/2014</td>
1415  *      <td>Added support for SAM R21 and SAM D10/D11</td>
1416  *    </tr>
1417  *    <tr>
1418  *      <td>42106C</td>
1419  *      <td>01/2014</td>
1420  *      <td>Added support for SAM D21</td>
1421  *    </tr>
1422  *    <tr>
1423  *      <td>42106B</td>
1424  *      <td>06/2013</td>
1425  *      <td>Added additional documentation on the event system. Corrected
1426  *          documentation typos.</td>
1427  *    </tr>
1428  *    <tr>
1429  *      <td>42106A</td>
1430  *      <td>06/2013</td>
1431  *      <td>Initial release</td>
1432  *    </tr>
1433  * </table>
1434  */
1435 
1436 #endif
1437