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 ( _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
174 /**
175 * Peripheral reflex system channel selection. Only applicable if @p prsEnable
176 * is enabled.
177 */
178 IDAC_PRSSEL_TypeDef prsSel;
179
180 /** Enable/disable current sink mode. */
181 bool sinkEnable;
182 } IDAC_Init_TypeDef;
183
184 /** Default configuration for IDAC initialization structure. */
185 #if defined(_IDAC_CTRL_OUTMODE_MASK)
186 #define IDAC_INIT_DEFAULT \
187 { \
188 false, /**< Leave IDAC disabled when initialization done. */ \
189 idacOutputPin, /**< Output to IDAC output pin. */ \
190 false, /**< Disable PRS triggering. */ \
191 idacPRSSELCh0, /**< Select PRS ch0 (if PRS triggering enabled). */ \
192 false /**< Disable current sink mode. */ \
193 }
194 #elif (_IDAC_CTRL_APORTOUTSEL_MASK)
195 #define IDAC_INIT_DEFAULT \
196 { \
197 false, /**< Leave IDAC disabled when initialization done. */ \
198 idacOutputAPORT1XCH0, /**< Output to APORT. */ \
199 false, /**< Disable PRS triggering. */ \
200 idacPRSSELCh0, /**< Select PRS ch0 (if PRS triggering enabled). */ \
201 false /**< Disable current sink mode. */ \
202 }
203 #endif
204
205 /*******************************************************************************
206 ***************************** PROTOTYPES **********************************
207 ******************************************************************************/
208
209 void IDAC_Init(IDAC_TypeDef *idac, const IDAC_Init_TypeDef *init);
210 void IDAC_Enable(IDAC_TypeDef *idac, bool enable);
211 void IDAC_Reset(IDAC_TypeDef *idac);
212 void IDAC_MinimalOutputTransitionMode(IDAC_TypeDef *idac, bool enable);
213 void IDAC_RangeSet(IDAC_TypeDef *idac, const IDAC_Range_TypeDef range);
214 void IDAC_StepSet(IDAC_TypeDef *idac, const uint32_t step);
215 void IDAC_OutEnable(IDAC_TypeDef *idac, bool enable);
216
217 #if defined(_IDAC_IEN_MASK)
218 /***************************************************************************//**
219 * @brief
220 * Clear one or more pending IDAC interrupts.
221 *
222 * @param[in] idac
223 * Pointer to IDAC peripheral register block.
224 *
225 * @param[in] flags
226 * Pending IDAC interrupt source(s) to clear. Use one or more valid
227 * interrupt flags for the IDAC module (IDAC_IF_nnn) OR'ed together.
228 ******************************************************************************/
IDAC_IntClear(IDAC_TypeDef * idac,uint32_t flags)229 __STATIC_INLINE void IDAC_IntClear(IDAC_TypeDef *idac, uint32_t flags)
230 {
231 idac->IFC = flags;
232 }
233
234 /***************************************************************************//**
235 * @brief
236 * Disable one or more IDAC interrupts.
237 *
238 * @param[in] idac
239 * Pointer to IDAC peripheral register block.
240 *
241 * @param[in] flags
242 * IDAC interrupt source(s) to disable. Use one or more valid
243 * interrupt flags for the IDAC module (IDAC_IF_nnn) OR'ed together.
244 ******************************************************************************/
IDAC_IntDisable(IDAC_TypeDef * idac,uint32_t flags)245 __STATIC_INLINE void IDAC_IntDisable(IDAC_TypeDef *idac, uint32_t flags)
246 {
247 idac->IEN &= ~flags;
248 }
249
250 /***************************************************************************//**
251 * @brief
252 * Enable one or more IDAC interrupts.
253 *
254 * @note
255 * Depending on the use, a pending interrupt may already be set prior to
256 * enabling the interrupt. To ignore a pending interrupt, consider using
257 * IDAC_IntClear() prior to enabling the interrupt.
258 *
259 * @param[in] idac
260 * Pointer to IDAC peripheral register block.
261 *
262 * @param[in] flags
263 * IDAC interrupt source(s) to enable. Use one or more valid
264 * interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
265 ******************************************************************************/
IDAC_IntEnable(IDAC_TypeDef * idac,uint32_t flags)266 __STATIC_INLINE void IDAC_IntEnable(IDAC_TypeDef *idac, uint32_t flags)
267 {
268 idac->IEN |= flags;
269 }
270
271 /***************************************************************************//**
272 * @brief
273 * Get pending IDAC interrupt flags.
274 *
275 * @note
276 * Event bits are not cleared by the use of this function.
277 *
278 * @param[in] idac
279 * Pointer to IDAC peripheral register block.
280 *
281 * @return
282 * IDAC interrupt source(s) pending. Returns one or more valid
283 * interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
284 ******************************************************************************/
IDAC_IntGet(IDAC_TypeDef * idac)285 __STATIC_INLINE uint32_t IDAC_IntGet(IDAC_TypeDef *idac)
286 {
287 return idac->IF;
288 }
289
290 /***************************************************************************//**
291 * @brief
292 * Get enabled and pending IDAC interrupt flags.
293 * Useful for handling more interrupt sources in the same interrupt handler.
294 *
295 * @param[in] idac
296 * Pointer to IDAC peripheral register block.
297 *
298 * @note
299 * Interrupt flags are not cleared by the use of this function.
300 *
301 * @return
302 * Pending and enabled IDAC interrupt sources.
303 * Return value is the bitwise AND combination of
304 * - the OR combination of enabled interrupt sources in IDACx_IEN_nnn
305 * register (IDACx_IEN_nnn) and
306 * - the OR combination of valid interrupt flags of IDAC module
307 * (IDACx_IF_nnn).
308 ******************************************************************************/
IDAC_IntGetEnabled(IDAC_TypeDef * idac)309 __STATIC_INLINE uint32_t IDAC_IntGetEnabled(IDAC_TypeDef *idac)
310 {
311 uint32_t ien;
312
313 /* Stores flags in temporary variable in order to define explicit order
314 * of volatile accesses. */
315 ien = idac->IEN;
316
317 /* Bitwise AND of pending and enabled interrupts. */
318 return idac->IF & ien;
319 }
320
321 /***************************************************************************//**
322 * @brief
323 * Set one or more pending IDAC interrupts from SW.
324 *
325 * @param[in] idac
326 * Pointer to IDAC peripheral register block.
327 *
328 * @param[in] flags
329 * IDAC interrupt source(s) to set to pending. Use one or more valid
330 * interrupt flags for IDAC module (IDAC_IF_nnn) OR'ed together.
331 ******************************************************************************/
IDAC_IntSet(IDAC_TypeDef * idac,uint32_t flags)332 __STATIC_INLINE void IDAC_IntSet(IDAC_TypeDef *idac, uint32_t flags)
333 {
334 idac->IFS = flags;
335 }
336 #endif
337
338 /** @} (end addtogroup idac) */
339
340 #ifdef __cplusplus
341 }
342 #endif
343
344 #endif /* defined(IDAC_COUNT) && (IDAC_COUNT > 0) */
345
346 #endif /* EM_IDAC_H */
347