1 /***************************************************************************//**
2  * @file
3  * @brief Digital to Analog Converter (DAC) 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_DAC_H
32 #define EM_DAC_H
33 
34 #include "em_device.h"
35 
36 #if defined(DAC_COUNT) && (DAC_COUNT > 0)
37 
38 #include "sl_assert.h"
39 #include <stdbool.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /***************************************************************************//**
46  * @addtogroup dac
47  * @{
48  ******************************************************************************/
49 
50 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
51 
52 /** Validation of DAC register block pointer reference for assert statements. */
53 #define DAC_REF_VALID(ref)    ((ref) == DAC0)
54 
55 /** @endcond */
56 
57 /*******************************************************************************
58  ********************************   ENUMS   ************************************
59  ******************************************************************************/
60 
61 /** Conversion mode. */
62 typedef enum {
63   dacConvModeContinuous = _DAC_CTRL_CONVMODE_CONTINUOUS, /**< Continuous mode. */
64   dacConvModeSampleHold = _DAC_CTRL_CONVMODE_SAMPLEHOLD, /**< Sample/hold mode. */
65   dacConvModeSampleOff  = _DAC_CTRL_CONVMODE_SAMPLEOFF   /**< Sample/shut off mode. */
66 } DAC_ConvMode_TypeDef;
67 
68 /** Output mode. */
69 typedef enum {
70   dacOutputDisable = _DAC_CTRL_OUTMODE_DISABLE, /**< Output to pin and ADC disabled. */
71   dacOutputPin     = _DAC_CTRL_OUTMODE_PIN,     /**< Output to pin only. */
72   dacOutputADC     = _DAC_CTRL_OUTMODE_ADC,     /**< Output to ADC only */
73   dacOutputPinADC  = _DAC_CTRL_OUTMODE_PINADC   /**< Output to pin and ADC. */
74 } DAC_Output_TypeDef;
75 
76 /** Peripheral Reflex System signal used to trigger single sample. */
77 typedef enum {
78   dacPRSSELCh0 = _DAC_CH0CTRL_PRSSEL_PRSCH0, /**< PRS channel 0. */
79   dacPRSSELCh1 = _DAC_CH0CTRL_PRSSEL_PRSCH1, /**< PRS channel 1. */
80   dacPRSSELCh2 = _DAC_CH0CTRL_PRSSEL_PRSCH2, /**< PRS channel 2. */
81   dacPRSSELCh3 = _DAC_CH0CTRL_PRSSEL_PRSCH3, /**< PRS channel 3. */
82 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH4)
83   dacPRSSELCh4 = _DAC_CH0CTRL_PRSSEL_PRSCH4, /**< PRS channel 4. */
84 #endif
85 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH5)
86   dacPRSSELCh5 = _DAC_CH0CTRL_PRSSEL_PRSCH5, /**< PRS channel 5. */
87 #endif
88 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH6)
89   dacPRSSELCh6 = _DAC_CH0CTRL_PRSSEL_PRSCH6, /**< PRS channel 6. */
90 #endif
91 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH7)
92   dacPRSSELCh7 = _DAC_CH0CTRL_PRSSEL_PRSCH7, /**< PRS channel 7. */
93 #endif
94 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH8)
95   dacPRSSELCh8 = _DAC_CH0CTRL_PRSSEL_PRSCH8, /**< PRS channel 8. */
96 #endif
97 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH9)
98   dacPRSSELCh9 = _DAC_CH0CTRL_PRSSEL_PRSCH9, /**< PRS channel 9. */
99 #endif
100 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH10)
101   dacPRSSELCh10 = _DAC_CH0CTRL_PRSSEL_PRSCH10, /**< PRS channel 10. */
102 #endif
103 #if defined(_DAC_CH0CTRL_PRSSEL_PRSCH11)
104   dacPRSSELCh11 = _DAC_CH0CTRL_PRSSEL_PRSCH11, /**< PRS channel 11. */
105 #endif
106 } DAC_PRSSEL_TypeDef;
107 
108 /** Reference voltage for DAC. */
109 typedef enum {
110   dacRef1V25 = _DAC_CTRL_REFSEL_1V25, /**< Internal 1.25V bandgap reference. */
111   dacRef2V5  = _DAC_CTRL_REFSEL_2V5,  /**< Internal 2.5V bandgap reference. */
112   dacRefVDD  = _DAC_CTRL_REFSEL_VDD   /**< VDD reference. */
113 } DAC_Ref_TypeDef;
114 
115 /** Refresh interval. */
116 typedef enum {
117   dacRefresh8  = _DAC_CTRL_REFRSEL_8CYCLES,  /**< Refresh every 8 prescaled cycles. */
118   dacRefresh16 = _DAC_CTRL_REFRSEL_16CYCLES, /**< Refresh every 16 prescaled cycles. */
119   dacRefresh32 = _DAC_CTRL_REFRSEL_32CYCLES, /**< Refresh every 32 prescaled cycles. */
120   dacRefresh64 = _DAC_CTRL_REFRSEL_64CYCLES  /**< Refresh every 64 prescaled cycles. */
121 } DAC_Refresh_TypeDef;
122 
123 /*******************************************************************************
124  *******************************   STRUCTS   ***********************************
125  ******************************************************************************/
126 
127 /** DAC initialization structure, common for both channels. */
128 typedef struct {
129   /** Refresh interval. Only used if REFREN bit set for a DAC channel. */
130   DAC_Refresh_TypeDef  refresh;
131 
132   /** Reference voltage to use. */
133   DAC_Ref_TypeDef      reference;
134 
135   /** Output mode. */
136   DAC_Output_TypeDef   outMode;
137 
138   /** Conversion mode. */
139   DAC_ConvMode_TypeDef convMode;
140 
141   /**
142    * Prescaler used to get DAC clock. Derived as follows:
143    * DACclk=HFPERclk/(2^prescale). The DAC clock should be <= 1MHz.
144    */
145   uint8_t              prescale;
146 
147   /** Enable/disable use of low pass filter on output. */
148   bool                 lpEnable;
149 
150   /** Enable/disable reset of prescaler on ch0 start. */
151   bool                 ch0ResetPre;
152 
153   /** Enable/disable output enable control by CH1 PRS signal. */
154   bool                 outEnablePRS;
155 
156   /** Enable/disable sine mode. */
157   bool                 sineEnable;
158 
159   /** Select if single ended or differential mode. */
160   bool                 diff;
161 } DAC_Init_TypeDef;
162 
163 /** Default configuration for DAC initialization structure. */
164 #define DAC_INIT_DEFAULT                                               \
165   {                                                                    \
166     dacRefresh8,            /* Refresh every 8 prescaled cycles. */    \
167     dacRef1V25,             /* 1.25V internal reference. */            \
168     dacOutputPin,           /* Output to pin only. */                  \
169     dacConvModeContinuous,  /* Continuous mode. */                     \
170     0,                      /* No prescaling. */                       \
171     false,                  /* Do not enable low pass filter. */       \
172     false,                  /* Do not reset prescaler on ch0 start. */ \
173     false,                  /* DAC output enable always on. */         \
174     false,                  /* Disable sine mode. */                   \
175     false                   /* Single ended mode. */                   \
176   }
177 
178 /** DAC channel initialization structure. */
179 typedef struct {
180   /** Enable channel. */
181   bool               enable;
182 
183   /**
184    * Peripheral reflex system trigger enable. If false, channel is triggered
185    * by writing to CHnDATA.
186    */
187   bool               prsEnable;
188 
189   /**
190    * Enable/disable automatic refresh of channel. Refresh interval must be
191    * defined in common control initialization, see DAC_Init() for more
192    * information.
193    */
194   bool               refreshEnable;
195 
196   /**
197    * Peripheral reflex system trigger selection. Only applicable if @p prsEnable
198    * is enabled.
199    */
200   DAC_PRSSEL_TypeDef prsSel;
201 } DAC_InitChannel_TypeDef;
202 
203 /** Default configuration for DAC channel initialization structure. */
204 #define DAC_INITCHANNEL_DEFAULT                                              \
205   {                                                                          \
206     false,            /* Leave channel disabled when initialization done. */ \
207     false,            /* Disable PRS triggering. */                          \
208     false,            /* Channel not refreshed automatically. */             \
209     dacPRSSELCh0      /* Select PRS ch0 (if PRS triggering enabled). */      \
210   }
211 
212 /*******************************************************************************
213  *****************************   PROTOTYPES   **********************************
214  ******************************************************************************/
215 
216 void DAC_Enable(DAC_TypeDef *dac, unsigned int ch, bool enable);
217 void DAC_Init(DAC_TypeDef *dac, const DAC_Init_TypeDef *init);
218 void DAC_InitChannel(DAC_TypeDef *dac,
219                      const DAC_InitChannel_TypeDef *init,
220                      unsigned int ch);
221 void DAC_ChannelOutputSet(DAC_TypeDef *dac,
222                           unsigned int channel,
223                           uint32_t     value);
224 
225 /***************************************************************************//**
226  * @brief
227  *   Set the output signal of DAC channel 0 to a given value.
228  *
229  * @details
230  *   This function sets the output signal of DAC channel 0 by writing @p value
231  *   to the CH0DATA register.
232  *
233  * @param[in] dac
234  *   Pointer to DAC peripheral register block.
235  *
236  * @param[in] value
237  *   Value to write to the channel 0 output register CH0DATA.
238  ******************************************************************************/
DAC_Channel0OutputSet(DAC_TypeDef * dac,uint32_t value)239 __STATIC_INLINE void DAC_Channel0OutputSet(DAC_TypeDef *dac,
240                                            uint32_t     value)
241 {
242   EFM_ASSERT(value <= _DAC_CH0DATA_MASK);
243   dac->CH0DATA = value;
244 }
245 
246 /***************************************************************************//**
247  * @brief
248  *   Set the output signal of DAC channel 1 to a given value.
249  *
250  * @details
251  *   Sets the output signal of DAC channel 1 by writing @p value
252  *   to the CH1DATA register.
253  *
254  * @param[in] dac
255  *   Pointer to DAC peripheral register block.
256  *
257  * @param[in] value
258  *   Value to write to the channel 1 output register CH1DATA.
259  ******************************************************************************/
DAC_Channel1OutputSet(DAC_TypeDef * dac,uint32_t value)260 __STATIC_INLINE void DAC_Channel1OutputSet(DAC_TypeDef *dac,
261                                            uint32_t     value)
262 {
263   EFM_ASSERT(value <= _DAC_CH1DATA_MASK);
264   dac->CH1DATA = value;
265 }
266 
267 /***************************************************************************//**
268  * @brief
269  *   Clear one or more pending DAC interrupts.
270  *
271  * @param[in] dac
272  *   Pointer to DAC peripheral register block.
273  *
274  * @param[in] flags
275  *   Pending DAC interrupt source to clear. Use a bitwise logic OR combination
276  *   of valid interrupt flags for the DAC module (DAC_IF_nnn).
277  ******************************************************************************/
DAC_IntClear(DAC_TypeDef * dac,uint32_t flags)278 __STATIC_INLINE void DAC_IntClear(DAC_TypeDef *dac, uint32_t flags)
279 {
280   dac->IFC = flags;
281 }
282 
283 /***************************************************************************//**
284  * @brief
285  *   Disable one or more DAC interrupts.
286  *
287  * @param[in] dac
288  *   Pointer to DAC peripheral register block.
289  *
290  * @param[in] flags
291  *   DAC interrupt sources to disable. Use a bitwise logic OR combination of
292  *   valid interrupt flags for the DAC module (DAC_IF_nnn).
293  ******************************************************************************/
DAC_IntDisable(DAC_TypeDef * dac,uint32_t flags)294 __STATIC_INLINE void DAC_IntDisable(DAC_TypeDef *dac, uint32_t flags)
295 {
296   dac->IEN &= ~flags;
297 }
298 
299 /***************************************************************************//**
300  * @brief
301  *   Enable one or more DAC interrupts.
302  *
303  * @note
304  *   Depending on the use, a pending interrupt may already be set prior to
305  *   enabling the interrupt. To ignore a pending interrupt, consider using
306  *   DAC_IntClear() prior to enabling the interrupt.
307  *
308  * @param[in] dac
309  *   Pointer to DAC peripheral register block.
310  *
311  * @param[in] flags
312  *   DAC interrupt sources to enable. Use a bitwise logic OR combination of
313  *   valid interrupt flags for the DAC module (DAC_IF_nnn).
314  ******************************************************************************/
DAC_IntEnable(DAC_TypeDef * dac,uint32_t flags)315 __STATIC_INLINE void DAC_IntEnable(DAC_TypeDef *dac, uint32_t flags)
316 {
317   dac->IEN |= flags;
318 }
319 
320 /***************************************************************************//**
321  * @brief
322  *   Get pending DAC interrupt flags.
323  *
324  * @note
325  *   Event bits are not cleared by the use of this function.
326  *
327  * @param[in] dac
328  *   Pointer to DAC peripheral register block.
329  *
330  * @return
331  *   DAC interrupt sources pending. A bitwise logic OR combination of valid
332  *   interrupt flags for the DAC module (DAC_IF_nnn).
333  ******************************************************************************/
DAC_IntGet(DAC_TypeDef * dac)334 __STATIC_INLINE uint32_t DAC_IntGet(DAC_TypeDef *dac)
335 {
336   return dac->IF;
337 }
338 
339 /***************************************************************************//**
340  * @brief
341  *   Get enabled and pending DAC interrupt flags.
342  *   Useful for handling more interrupt sources in the same interrupt handler.
343  *
344  * @param[in] dac
345  *   Pointer to DAC peripheral register block.
346  *
347  * @note
348  *   Interrupt flags are not cleared by the use of this function.
349  *
350  * @return
351  *   Pending and enabled DAC interrupt sources.
352  *   Return value is the bitwise AND combination of
353  *   - the OR combination of enabled interrupt sources in DACx_IEN_nnn
354  *     register (DACx_IEN_nnn) and
355  *   - the OR combination of valid interrupt flags of the DAC module
356  *     (DACx_IF_nnn).
357  ******************************************************************************/
DAC_IntGetEnabled(DAC_TypeDef * dac)358 __STATIC_INLINE uint32_t DAC_IntGetEnabled(DAC_TypeDef *dac)
359 {
360   uint32_t ien;
361 
362   /* Store DAC->IEN in temporary variable in order to define explicit order
363    * of volatile accesses. */
364   ien = dac->IEN;
365 
366   /* Bitwise AND of pending and enabled interrupts. */
367   return dac->IF & ien;
368 }
369 
370 /***************************************************************************//**
371  * @brief
372  *   Set one or more pending DAC interrupts from SW.
373  *
374  * @param[in] dac
375  *   Pointer to DAC peripheral register block.
376  *
377  * @param[in] flags
378  *   DAC interrupt sources to set to pending. Use a bitwise logic OR combination
379  *   of valid interrupt flags for the DAC module (DAC_IF_nnn).
380  ******************************************************************************/
DAC_IntSet(DAC_TypeDef * dac,uint32_t flags)381 __STATIC_INLINE void DAC_IntSet(DAC_TypeDef *dac, uint32_t flags)
382 {
383   dac->IFS = flags;
384 }
385 
386 uint8_t DAC_PrescaleCalc(uint32_t dacFreq, uint32_t hfperFreq);
387 void DAC_Reset(DAC_TypeDef *dac);
388 
389 /** @} (end addtogroup dac) */
390 
391 #ifdef __cplusplus
392 }
393 #endif
394 
395 #endif /* defined(DAC_COUNT) && (DAC_COUNT > 0) */
396 #endif /* EM_DAC_H */
397