1 /***************************************************************************//**
2  * @file
3  * @brief Current Digital to Analog Converter (IDAC) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef EM_IDAC_H
32 #define EM_IDAC_H
33 
34 #include "em_device.h"
35 
36 #if defined(IDAC_COUNT) && (IDAC_COUNT > 0)
37 #include <stdbool.h>
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /***************************************************************************//**
44  * @addtogroup idac IDAC - Current DAC
45  * @brief
46  *  Current Digital-to-Analog Converter (IDAC) Peripheral API.
47  *
48  * @details
49  *  IDAC can source or sink a configurable constant current,
50  *  which can be output on, or sinked from pin or ADC. Current
51  *  is configurable with several ranges of various step sizes.
52  *  IDAC can be used with PRS and can operate down to EM3.
53  *
54  *  The following steps are necessary for basic operation:
55  *
56  *  Clock enable:
57  *  @include em_idac_clock_enable.c
58  *
59  *  Initialize peripheral with default settings and modify selected fields,
60  *  such as output select:
61  *  @if DOXYDOC_P1_DEVICE
62  *  @include em_idac_init_adc.c
63  *  @endif
64  *  @if DOXYDOC_P2_DEVICE
65  *  @include em_idac_init_aport.c
66  *  @endif
67  *
68  *  Set output:
69  *  @include em_idac_basic_usage.c
70  *
71  * @{
72  ******************************************************************************/
73 
74 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
75 
76 /** Validation of IDAC register block pointer reference for assert statements. */
77 #define IDAC_REF_VALID(ref)    ((ref) == IDAC0)
78 
79 /** @endcond */
80 
81 /*******************************************************************************
82  ********************************   ENUMS   ************************************
83  ******************************************************************************/
84 
85 /** Output mode. */
86 typedef enum {
87 #if defined(_IDAC_CTRL_OUTMODE_MASK)
88   idacOutputPin     = IDAC_CTRL_OUTMODE_PIN,     /**< Output to IDAC OUT pin. */
89   idacOutputADC     = IDAC_CTRL_OUTMODE_ADC      /**< Output to ADC. */
90 #elif defined(_IDAC_CTRL_APORTOUTSEL_MASK)
91   idacOutputAPORT1XCH0 = IDAC_CTRL_APORTOUTSEL_APORT1XCH0, /**< Output to APORT 1X CH0. */
92   idacOutputAPORT1YCH1 = IDAC_CTRL_APORTOUTSEL_APORT1YCH1, /**< Output to APORT 1Y CH1. */
93   idacOutputAPORT1XCH2 = IDAC_CTRL_APORTOUTSEL_APORT1XCH2, /**< Output to APORT 1X CH2. */
94   idacOutputAPORT1YCH3 = IDAC_CTRL_APORTOUTSEL_APORT1YCH3, /**< Output to APORT 1Y CH3. */
95   idacOutputAPORT1XCH4 = IDAC_CTRL_APORTOUTSEL_APORT1XCH4, /**< Output to APORT 1X CH4. */
96   idacOutputAPORT1YCH5 = IDAC_CTRL_APORTOUTSEL_APORT1YCH5, /**< Output to APORT 1Y CH5. */
97   idacOutputAPORT1XCH6 = IDAC_CTRL_APORTOUTSEL_APORT1XCH6, /**< Output to APORT 1X CH6. */
98   idacOutputAPORT1YCH7 = IDAC_CTRL_APORTOUTSEL_APORT1YCH7, /**< Output to APORT 1Y CH7. */
99   idacOutputAPORT1XCH8 = IDAC_CTRL_APORTOUTSEL_APORT1XCH8, /**< Output to APORT 1X CH8. */
100   idacOutputAPORT1YCH9 = IDAC_CTRL_APORTOUTSEL_APORT1YCH9, /**< Output to APORT 1Y CH9. */
101   idacOutputAPORT1XCH10 = IDAC_CTRL_APORTOUTSEL_APORT1XCH10, /**< Output to APORT 1X CH10. */
102   idacOutputAPORT1YCH11 = IDAC_CTRL_APORTOUTSEL_APORT1YCH11, /**< Output to APORT 1Y CH11. */
103   idacOutputAPORT1XCH12 = IDAC_CTRL_APORTOUTSEL_APORT1XCH12, /**< Output to APORT 1X CH12. */
104   idacOutputAPORT1YCH13 = IDAC_CTRL_APORTOUTSEL_APORT1YCH13, /**< Output to APORT 1Y CH13. */
105   idacOutputAPORT1XCH14 = IDAC_CTRL_APORTOUTSEL_APORT1XCH14, /**< Output to APORT 1X CH14. */
106   idacOutputAPORT1YCH15 = IDAC_CTRL_APORTOUTSEL_APORT1YCH15, /**< Output to APORT 1Y CH15. */
107   idacOutputAPORT1XCH16 = IDAC_CTRL_APORTOUTSEL_APORT1XCH16, /**< Output to APORT 1X CH16. */
108   idacOutputAPORT1YCH17 = IDAC_CTRL_APORTOUTSEL_APORT1YCH17, /**< Output to APORT 1Y CH17. */
109   idacOutputAPORT1XCH18 = IDAC_CTRL_APORTOUTSEL_APORT1XCH18, /**< Output to APORT 1X CH18. */
110   idacOutputAPORT1YCH19 = IDAC_CTRL_APORTOUTSEL_APORT1YCH19, /**< Output to APORT 1Y CH19. */
111   idacOutputAPORT1XCH20 = IDAC_CTRL_APORTOUTSEL_APORT1XCH20, /**< Output to APORT 1X CH20. */
112   idacOutputAPORT1YCH21 = IDAC_CTRL_APORTOUTSEL_APORT1YCH21, /**< Output to APORT 1Y CH21. */
113   idacOutputAPORT1XCH22 = IDAC_CTRL_APORTOUTSEL_APORT1XCH22, /**< Output to APORT 1X CH22. */
114   idacOutputAPORT1YCH23 = IDAC_CTRL_APORTOUTSEL_APORT1YCH23, /**< Output to APORT 1Y CH23. */
115   idacOutputAPORT1XCH24 = IDAC_CTRL_APORTOUTSEL_APORT1XCH24, /**< Output to APORT 1X CH24. */
116   idacOutputAPORT1YCH25 = IDAC_CTRL_APORTOUTSEL_APORT1YCH25, /**< Output to APORT 1Y CH25. */
117   idacOutputAPORT1XCH26 = IDAC_CTRL_APORTOUTSEL_APORT1XCH26, /**< Output to APORT 1X CH26. */
118   idacOutputAPORT1YCH27 = IDAC_CTRL_APORTOUTSEL_APORT1YCH27, /**< Output to APORT 1Y CH27. */
119   idacOutputAPORT1XCH28 = IDAC_CTRL_APORTOUTSEL_APORT1XCH28, /**< Output to APORT 1X CH28. */
120   idacOutputAPORT1YCH29 = IDAC_CTRL_APORTOUTSEL_APORT1YCH29, /**< Output to APORT 1Y CH29. */
121   idacOutputAPORT1XCH30 = IDAC_CTRL_APORTOUTSEL_APORT1XCH30, /**< Output to APORT 1X CH30. */
122   idacOutputAPORT1YCH31 = IDAC_CTRL_APORTOUTSEL_APORT1YCH31, /**< Output to APORT 1Y CH31. */
123 #endif
124 } IDAC_OutMode_TypeDef;
125 
126 /** Selects which Peripheral Reflex System (PRS) signal to use when
127     PRS is set to control IDAC output. */
128 typedef enum {
129   idacPRSSELCh0 = IDAC_CTRL_PRSSEL_PRSCH0,      /**< PRS channel 0. */
130   idacPRSSELCh1 = IDAC_CTRL_PRSSEL_PRSCH1,      /**< PRS channel 1. */
131   idacPRSSELCh2 = IDAC_CTRL_PRSSEL_PRSCH2,      /**< PRS channel 2. */
132   idacPRSSELCh3 = IDAC_CTRL_PRSSEL_PRSCH3,      /**< PRS channel 3. */
133 #if defined(IDAC_CTRL_PRSSEL_PRSCH4)
134   idacPRSSELCh4 = IDAC_CTRL_PRSSEL_PRSCH4,      /**< PRS channel 4. */
135   idacPRSSELCh5 = IDAC_CTRL_PRSSEL_PRSCH5,      /**< PRS channel 5. */
136 #endif
137 #if defined(IDAC_CTRL_PRSSEL_PRSCH6)
138   idacPRSSELCh6 = IDAC_CTRL_PRSSEL_PRSCH6,      /**< PRS channel 6. */
139   idacPRSSELCh7 = IDAC_CTRL_PRSSEL_PRSCH7,      /**< PRS channel 7. */
140   idacPRSSELCh8 = IDAC_CTRL_PRSSEL_PRSCH8,      /**< PRS channel 8. */
141   idacPRSSELCh9 = IDAC_CTRL_PRSSEL_PRSCH9,      /**< PRS channel 9. */
142   idacPRSSELCh10 = IDAC_CTRL_PRSSEL_PRSCH10,    /**< PRS channel 10 */
143   idacPRSSELCh11 = IDAC_CTRL_PRSSEL_PRSCH11,    /**< PRS channel 11 */
144 #endif
145 } IDAC_PRSSEL_TypeDef;
146 
147 /** Selects which current range to use. */
148 typedef enum {
149   idacCurrentRange0 = IDAC_CURPROG_RANGESEL_RANGE0, /**< current range 0. */
150   idacCurrentRange1 = IDAC_CURPROG_RANGESEL_RANGE1, /**< current range 1. */
151   idacCurrentRange2 = IDAC_CURPROG_RANGESEL_RANGE2, /**< current range 2. */
152   idacCurrentRange3 = IDAC_CURPROG_RANGESEL_RANGE3, /**< current range 3. */
153 } IDAC_Range_TypeDef;
154 
155 /*******************************************************************************
156  *******************************   STRUCTS   ***********************************
157  ******************************************************************************/
158 
159 /** IDAC initialization structure, common for both channels. */
160 typedef struct {
161   /** Enable IDAC. */
162   bool                  enable;
163 
164   /** Output mode */
165   IDAC_OutMode_TypeDef  outMode;
166 
167   /**
168    * Enables Peripheral reflex system (PRS) to control IDAC output. If false,
169    * IDAC output is controlled by writing to IDAC_OUTEN in IDAC_CTRL or
170    * by calling IDAC_OutEnable().
171    */
172   bool                  prsEnable;
173 #if defined(_IDAC_CTRL_MAINOUTENPRS_MASK)
174   /**
175    * Enables Peripheral reflex system (PRS) to control IDAC OUTPAD output. If false,
176    * IDAC output is controlled by writing to IDAC_MAINOUTEN in IDAC_CTRL or
177    * by calling IDAC_OutpadEnable().
178    */
179   bool                  prsEnableMain;
180 #endif
181 
182   /**
183    * Peripheral reflex system channel selection. Only applicable if @p prsEnable
184    * is enabled.
185    */
186   IDAC_PRSSEL_TypeDef   prsSel;
187 
188   /** Enable/disable current sink mode. */
189   bool                  sinkEnable;
190 } IDAC_Init_TypeDef;
191 
192 /** Default configuration for IDAC initialization structure. */
193 #if defined(_IDAC_CTRL_OUTMODE_MASK)
194 #define IDAC_INIT_DEFAULT                                                \
195   {                                                                      \
196     false,         /**< Leave IDAC disabled when initialization done. */ \
197     idacOutputPin, /**< Output to IDAC output pin. */                    \
198     false,         /**< Disable PRS triggering. */                       \
199     idacPRSSELCh0, /**< Select PRS ch0 (if PRS triggering enabled). */   \
200     false          /**< Disable current sink mode. */                    \
201   }
202 #elif defined(_IDAC_CTRL_MAINOUTEN_MASK)
203 #define IDAC_INIT_DEFAULT                                                \
204   {                                                                      \
205     false,         /**< Leave IDAC disabled when initialization done. */ \
206     idacOutputAPORT1XCH0, /**< Output to APORT. */                       \
207     false,         /**< Disable APORT PRS triggering. */                 \
208     false,         /**< Disable MAIN PRS triggering. */                  \
209     idacPRSSELCh0, /**< Select PRS ch0 (if PRS triggering enabled). */   \
210     false          /**< Disable current sink mode. */                    \
211   }
212 #elif (_IDAC_CTRL_APORTOUTSEL_MASK)
213 #define IDAC_INIT_DEFAULT                                                \
214   {                                                                      \
215     false,         /**< Leave IDAC disabled when initialization done. */ \
216     idacOutputAPORT1XCH0, /**< Output to APORT. */                       \
217     false,         /**< Disable PRS triggering. */                       \
218     idacPRSSELCh0, /**< Select PRS ch0 (if PRS triggering enabled). */   \
219     false          /**< Disable current sink mode. */                    \
220   }
221 #endif
222 
223 /*******************************************************************************
224  *****************************   PROTOTYPES   **********************************
225  ******************************************************************************/
226 
227 void IDAC_Init(IDAC_TypeDef *idac, const IDAC_Init_TypeDef *init);
228 void IDAC_Enable(IDAC_TypeDef *idac, bool enable);
229 void IDAC_Reset(IDAC_TypeDef *idac);
230 void IDAC_MinimalOutputTransitionMode(IDAC_TypeDef *idac, bool enable);
231 void IDAC_RangeSet(IDAC_TypeDef *idac, const IDAC_Range_TypeDef range);
232 void IDAC_StepSet(IDAC_TypeDef *idac, const uint32_t step);
233 void IDAC_OutEnable(IDAC_TypeDef *idac, bool enable);
234 #if defined(_IDAC_CTRL_MAINOUTEN_MASK)
235 void IDAC_OutpadEnable(IDAC_TypeDef *idac, bool enable);
236 #endif
237 
238 #if defined(_IDAC_IEN_MASK)
239 /***************************************************************************//**
240  * @brief
241  *   Clear one or more pending IDAC interrupts.
242  *
243  * @param[in] idac
244  *   Pointer to IDAC peripheral register block.
245  *
246  * @param[in] flags
247  *   Pending IDAC interrupt source(s) to clear. Use one or more valid
248  *   interrupt flags for the IDAC module (IDAC_IF_nnn) OR'ed together.
249  ******************************************************************************/
IDAC_IntClear(IDAC_TypeDef * idac,uint32_t flags)250 __STATIC_INLINE void IDAC_IntClear(IDAC_TypeDef *idac, uint32_t flags)
251 {
252   idac->IFC = flags;
253 }
254 
255 /***************************************************************************//**
256  * @brief
257  *   Disable one or more IDAC interrupts.
258  *
259  * @param[in] idac
260  *   Pointer to IDAC peripheral register block.
261  *
262  * @param[in] flags
263  *   IDAC interrupt source(s) to disable. Use one or more valid
264  *   interrupt flags for the IDAC module (IDAC_IF_nnn) OR'ed together.
265  ******************************************************************************/
IDAC_IntDisable(IDAC_TypeDef * idac,uint32_t flags)266 __STATIC_INLINE void IDAC_IntDisable(IDAC_TypeDef *idac, uint32_t flags)
267 {
268   idac->IEN &= ~flags;
269 }
270 
271 /***************************************************************************//**
272  * @brief
273  *   Enable one or more IDAC interrupts.
274  *
275  * @note
276  *   Depending on the use, a pending interrupt may already be set prior to
277  *   enabling the interrupt. To ignore a pending interrupt, consider using
278  *   IDAC_IntClear() prior to enabling the interrupt.
279  *
280  * @param[in] idac
281  *   Pointer to IDAC peripheral register block.
282  *
283  * @param[in] flags
284  *   IDAC interrupt source(s) to enable. Use one or more valid
285  *   interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
286  ******************************************************************************/
IDAC_IntEnable(IDAC_TypeDef * idac,uint32_t flags)287 __STATIC_INLINE void IDAC_IntEnable(IDAC_TypeDef *idac, uint32_t flags)
288 {
289   idac->IEN |= flags;
290 }
291 
292 /***************************************************************************//**
293  * @brief
294  *   Get pending IDAC interrupt flags.
295  *
296  * @note
297  *   Event bits are not cleared by the use of this function.
298  *
299  * @param[in] idac
300  *   Pointer to IDAC peripheral register block.
301  *
302  * @return
303  *   IDAC interrupt source(s) pending. Returns one or more valid
304  *   interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
305  ******************************************************************************/
IDAC_IntGet(IDAC_TypeDef * idac)306 __STATIC_INLINE uint32_t IDAC_IntGet(IDAC_TypeDef *idac)
307 {
308   return idac->IF;
309 }
310 
311 /***************************************************************************//**
312  * @brief
313  *   Get enabled and pending IDAC interrupt flags.
314  *   Useful for handling more interrupt sources in the same interrupt handler.
315  *
316  * @param[in] idac
317  *   Pointer to IDAC peripheral register block.
318  *
319  * @note
320  *   Interrupt flags are not cleared by the use of this function.
321  *
322  * @return
323  *   Pending and enabled IDAC interrupt sources.
324  *   Return value is the bitwise AND combination of
325  *   - the OR combination of enabled interrupt sources in IDACx_IEN_nnn
326  *     register (IDACx_IEN_nnn) and
327  *   - the OR combination of valid interrupt flags of IDAC module
328  *     (IDACx_IF_nnn).
329  ******************************************************************************/
IDAC_IntGetEnabled(IDAC_TypeDef * idac)330 __STATIC_INLINE uint32_t IDAC_IntGetEnabled(IDAC_TypeDef *idac)
331 {
332   uint32_t ien;
333 
334   /* Stores flags in temporary variable in order to define explicit order
335    * of volatile accesses. */
336   ien = idac->IEN;
337 
338   /* Bitwise AND of pending and enabled interrupts. */
339   return idac->IF & ien;
340 }
341 
342 /***************************************************************************//**
343  * @brief
344  *   Set one or more pending IDAC interrupts from SW.
345  *
346  * @param[in] idac
347  *   Pointer to IDAC peripheral register block.
348  *
349  * @param[in] flags
350  *   IDAC interrupt source(s) to set to pending. Use one or more valid
351  *   interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
352  ******************************************************************************/
IDAC_IntSet(IDAC_TypeDef * idac,uint32_t flags)353 __STATIC_INLINE void IDAC_IntSet(IDAC_TypeDef *idac, uint32_t flags)
354 {
355   idac->IFS = flags;
356 }
357 #endif
358 
359 /** @} (end addtogroup idac) */
360 
361 #ifdef __cplusplus
362 }
363 #endif
364 
365 #endif /* defined(IDAC_COUNT) && (IDAC_COUNT > 0) */
366 
367 #endif /* EM_IDAC_H */
368