1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 
7 /***********************************************************************************************************************
8  * Includes
9  **********************************************************************************************************************/
10 #include <string.h>
11 #include "r_dac.h"
12 
13 /***********************************************************************************************************************
14  * Macro definitions
15  **********************************************************************************************************************/
16 
17 /* D/A Control Register Mask */
18 /** Driver ID (DTC in ASCII), used to identify Digital to Analog Converter (DAC) configuration  */
19 #define DAC_OPEN                                     (0x44414300)
20 #define DAC_DAADSCR_REG_DAADST_BIT_POS               (0x07U)
21 #define DAC_DAADUSR_REG_MASK                         BSP_FEATURE_DAC_AD_SYNC_UNIT_MASK
22 #define DAC_DADPR_REG_DPSEL_BIT_POS                  (0x07U)
23 #define DAC_DAAMPCR_AMP_CTRL_BITS                    (0x06U) /* 6th bit for channel 0; 7th bit for channel 1 */
24 #define DAC_DACR_DAOE_BITS                           (0x06U) /* 6th bit for channel 0; 7th bit for channel 1 */
25 #define DAC_DAASWCR_DAASW0_MASK                      (0x40)
26 #define DAC_DAASWCR_DAASW1_MASK                      (0x80)
27 #if 0x01U == BSP_FEATURE_DAC_AD_SYNC_UNIT_MASK
28  #define DAC_ADC_UNIT                                (0)
29 #elif 0x02U == BSP_FEATURE_DAC_AD_SYNC_UNIT_MASK
30  #define DAC_ADC_UNIT                                (1)
31 #endif
32 #define DAC_MAX_CHANNELS_PER_UNIT                    (2U)
33 
34 /* Conversion time with Output Amplifier. See hardware manual (see Table 60.44
35  *'D/A conversion characteristics' of the RA6M3 manual R01UH0886EJ0100). */
36 #define DAC_CONVERSION_TIME_WITH_OUTPUT_AMPLIFIER    (0x04U) /* Unit: Microseconds. */
37 
38 #define DAC_VREF_DISCHARGING_DELAY_US                (10)
39 #define DAC_INTERNAL_VREF_WAIT_TIME_US               (5)
40 
41 /***********************************************************************************************************************
42  * Typedef definitions
43  **********************************************************************************************************************/
44 
45 /***********************************************************************************************************************
46  * Private function prototypes
47  **********************************************************************************************************************/
48 
49 /***********************************************************************************************************************
50  * Global variables
51  **********************************************************************************************************************/
52 
53 const dac_api_t g_dac_on_dac =
54 {
55     .open  = R_DAC_Open,
56     .write = R_DAC_Write,
57     .start = R_DAC_Start,
58     .stop  = R_DAC_Stop,
59     .close = R_DAC_Close,
60 };
61 
62 /***********************************************************************************************************************
63  * Private global variables
64  **********************************************************************************************************************/
65 
66 /*******************************************************************************************************************//**
67  * @addtogroup DAC
68  * @{
69  **********************************************************************************************************************/
70 
71 /***********************************************************************************************************************
72  * Functions
73  **********************************************************************************************************************/
74 
75 /******************************************************************************************************************//**
76  * Perform required initialization described in hardware manual.  Implements @ref dac_api_t::open.
77  * Configures a single DAC channel, starts the channel, and provides a handle for use with the
78  * DAC API Write and Close functions.  Must be called once prior to calling any other DAC API
79  * functions.  After a channel is opened, Open should not be called again for the same channel
80  * without calling Close first.
81  *
82  * @retval FSP_SUCCESS                     The channel was successfully opened.
83  * @retval FSP_ERR_ASSERTION               Parameter check failure due to one or more reasons below:
84  *                                         1. One or both of the following parameters may be NULL: p_api_ctrl or p_cfg
85  *                                         2. data_format value in p_cfg is out of range.
86  *                                         3. Extended configuration structure is set to NULL for
87  *                                            MCU supporting charge pump.
88  * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT  Channel ID requested in p_cfg may not available on the devices.
89  * @retval FSP_ERR_ALREADY_OPEN            The control structure is already opened.
90  *
91  **********************************************************************************************************************/
R_DAC_Open(dac_ctrl_t * p_api_ctrl,dac_cfg_t const * const p_cfg)92 fsp_err_t R_DAC_Open (dac_ctrl_t * p_api_ctrl, dac_cfg_t const * const p_cfg)
93 {
94     dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
95 
96     /* Validate the input parameter. */
97 #if DAC_CFG_PARAM_CHECKING_ENABLE
98     FSP_ASSERT(NULL != p_cfg);
99     FSP_ASSERT(NULL != p_ctrl);
100     FSP_ERROR_RETURN(p_cfg->channel < (uint8_t) BSP_FEATURE_DAC_MAX_CHANNELS, FSP_ERR_IP_CHANNEL_NOT_PRESENT);
101     FSP_ERROR_RETURN(false == p_ctrl->channel_opened, FSP_ERR_ALREADY_OPEN);
102  #if (BSP_FEATURE_DAC_HAS_CHARGEPUMP || BSP_FEATURE_DAC_HAS_DAVREFCRP)
103     FSP_ASSERT(NULL != p_cfg->p_extend)
104  #endif
105 #endif
106 
107 #if (BSP_FEATURE_DAC_MAX_CHANNELS > 2U)
108     uint8_t unit = p_cfg->channel / DAC_MAX_CHANNELS_PER_UNIT;
109     p_ctrl->p_reg = (R_DAC_Type *) ((uint32_t) R_DAC0 + (unit * ((uint32_t) R_DAC1 - (uint32_t) R_DAC0)));
110 #else
111     p_ctrl->p_reg = R_DAC;
112 #endif
113 
114     p_ctrl->channel_index = p_cfg->channel % DAC_MAX_CHANNELS_PER_UNIT;
115 
116     /* Power on the DAC device. */
117     R_BSP_MODULE_START(FSP_IP_DAC, p_cfg->channel / DAC_MAX_CHANNELS_PER_UNIT);
118 
119     /* Added this to a separate block to avoid redeclaration of
120      * critical section variable under module start macro. */
121     {
122         FSP_CRITICAL_SECTION_DEFINE;
123         FSP_CRITICAL_SECTION_ENTER;
124 
125         /* Stop the channel. */
126         (0U == p_ctrl->channel_index) ? (p_ctrl->p_reg->DACR_b.DAOE0 = 0U) : (p_ctrl->p_reg->DACR_b.DAOE1 = 0U);
127 
128         FSP_CRITICAL_SECTION_EXIT;
129     }
130 
131     dac_extended_cfg_t * p_extend = (dac_extended_cfg_t *) p_cfg->p_extend;
132 
133     /* Configure data format: left or right justified. */
134     p_ctrl->p_reg->DADPR = (uint8_t) ((uint8_t) p_extend->data_format << (uint8_t) DAC_DADPR_REG_DPSEL_BIT_POS);
135 
136 #if BSP_FEATURE_DAC_HAS_DA_AD_SYNCHRONIZE
137  #if BSP_FEATURE_DAC_AD_SYNC_UNIT_MASK
138 
139     /* DA/AD Synchronization. Described in hardware manual (see Section 48.2.7
140      * 'D/A A/D Synchronous Unit Select Register (DAADUSR)' and Section 48.2.4
141      * 'D/A A/D Synchronous Start Control Register (DAADSCR)'of the RA6M3 manual R01UH0886EJ0100). */
142 
143     /* D/A A/D Synchronous Unit Select Register: Select ADC Unit for synchronization with this DAC channel */
144     if ((0U == p_ctrl->p_reg->DAADSCR) && (p_cfg->ad_da_synchronized))
145     {
146         /* For correctly writing to this register:
147          * 1. ADC module stop bit must be cleared.
148          * 2. DAADSCR.DAADST must be cleared.
149          *
150          * If ADC module is started, this will have no effect.
151          *
152          * If ADC module is not started yet, this will start it for enabling write to DAADUSR.
153          * Since the ad_da_synchronized is set to true in the configuration structure
154          * the ADC module is believed to be started at a later point in the application.
155          */
156         R_BSP_MODULE_START(FSP_IP_ADC, (uint16_t) DAC_ADC_UNIT);
157 
158         p_ctrl->p_reg->DAADUSR = (uint8_t) BSP_FEATURE_DAC_AD_SYNC_UNIT_MASK;
159 
160         /* Configure D/A-A/D Synchronous Start Control Register(DAADSCR). */
161         p_ctrl->p_reg->DAADSCR = (uint8_t) (1U << (uint8_t) DAC_DAADSCR_REG_DAADST_BIT_POS);
162     }
163  #else
164 
165     /* Configure D/A-A/D Synchronous Start Control Register(DAADSCR). */
166     p_ctrl->p_reg->DAADSCR = (uint8_t) (p_cfg->ad_da_synchronized << (uint8_t) DAC_DAADSCR_REG_DAADST_BIT_POS);
167  #endif
168 #endif
169 
170 #if BSP_FEATURE_DAC_HAS_OUTPUT_AMPLIFIER
171     p_ctrl->output_amplifier_enabled = p_extend->output_amplifier_enabled;
172 #endif
173 
174 #if BSP_FEATURE_DAC_HAS_INTERNAL_OUTPUT
175     p_ctrl->internal_output_enabled = p_extend->internal_output_enabled;
176 #endif
177 
178     /* Set the reference voltage. */
179 #if BSP_FEATURE_DAC_HAS_DAVREFCR
180 
181     /* D/A Reference Voltage Select. Described in hardware manual (see Section 36.2.5
182      * 'D/A VREF Control Register (DAVREFCR) and Section 36.3.2
183      * 'Notes on Using the Internal Reference Voltage as the Reference Voltage of the RA4M1 manual R01UH0887EJ0110). */
184 
185     /* Clear REF bits before changing the value of these bits. */
186     p_ctrl->p_reg->DAVREFCR = 0x00;
187     if (DAC_VREF_IVREF_AVSS0 == p_extend->ref_volt_sel)
188     {
189         p_ctrl->p_reg->DADR[0] = 0x00U;
190 
191         /* Discharge for 10 us. */
192         R_BSP_SoftwareDelay(DAC_VREF_DISCHARGING_DELAY_US, BSP_DELAY_UNITS_MICROSECONDS);
193         p_ctrl->p_reg->DAVREFCR     = (uint8_t) p_extend->ref_volt_sel;
194         p_ctrl->p_reg->DACR_b.DAOE0 = 1U;
195 
196         /* Wait 5 us, the stabilization wait time of the internal reference voltage. */
197         R_BSP_SoftwareDelay(DAC_INTERNAL_VREF_WAIT_TIME_US, BSP_DELAY_UNITS_MICROSECONDS);
198     }
199     else
200     {
201         p_ctrl->p_reg->DAVREFCR = (uint8_t) p_extend->ref_volt_sel;
202     }
203     FSP_REGISTER_READ(p_ctrl->p_reg->DAVREFCR)
204 #endif
205 
206 #if (1U == BSP_FEATURE_DAC_HAS_CHARGEPUMP)
207     p_ctrl->p_reg->DAPC = (uint8_t) p_extend->enable_charge_pump;
208 #endif
209 
210     /* Initialize the channel state information. */
211     p_ctrl->channel        = p_cfg->channel;
212     p_ctrl->channel_opened = DAC_OPEN;
213 
214     return FSP_SUCCESS;
215 }
216 
217 /******************************************************************************************************************//**
218  * Write data to the D/A converter and enable the output if it has not been enabled.
219  *
220  * @retval   FSP_SUCCESS           Data is successfully written to the D/A Converter.
221  * @retval   FSP_ERR_ASSERTION     p_api_ctrl is NULL.
222  * @retval   FSP_ERR_NOT_OPEN      Channel associated with p_ctrl has not been opened.
223  **********************************************************************************************************************/
R_DAC_Write(dac_ctrl_t * p_api_ctrl,uint16_t value)224 fsp_err_t R_DAC_Write (dac_ctrl_t * p_api_ctrl, uint16_t value)
225 {
226     dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
227 
228 #if DAC_CFG_PARAM_CHECKING_ENABLE
229 
230     /* Validate the handle parameter */
231     FSP_ASSERT(NULL != p_ctrl);
232 
233     /* Validate that the channel is opened. */
234     FSP_ERROR_RETURN(p_ctrl->channel_opened, FSP_ERR_NOT_OPEN);
235 #endif
236 
237     /* Write the value to D/A converter. */
238     p_ctrl->p_reg->DADR[p_ctrl->channel_index] = value;
239 
240     return FSP_SUCCESS;
241 }
242 
243 /******************************************************************************************************************//**
244  * Start the D/A conversion output if it has not been started.
245  *
246  * @retval   FSP_SUCCESS           The channel is started successfully.
247  * @retval   FSP_ERR_ASSERTION     p_api_ctrl is NULL.
248  * @retval   FSP_ERR_IN_USE        Attempt to re-start a channel.
249  * @retval   FSP_ERR_NOT_OPEN      Channel associated with p_ctrl has not been opened.
250  **********************************************************************************************************************/
R_DAC_Start(dac_ctrl_t * p_api_ctrl)251 fsp_err_t R_DAC_Start (dac_ctrl_t * p_api_ctrl)
252 {
253     dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
254 
255 #if DAC_CFG_PARAM_CHECKING_ENABLE
256 
257     /* Validate the handle parameter */
258     FSP_ASSERT(NULL != p_ctrl);
259 
260     /* Validate that the channel is opened. */
261     FSP_ERROR_RETURN(p_ctrl->channel_opened, FSP_ERR_NOT_OPEN);
262 
263     /* Check if the channel is not already started */
264     bool channel_started = false;
265 
266     channel_started =
267         ((0U == p_ctrl->channel_index) ? ((bool) p_ctrl->p_reg->DACR_b.DAOE0) : (bool) (p_ctrl->p_reg->DACR_b.DAOE1));
268 
269     FSP_ERROR_RETURN(!channel_started, FSP_ERR_IN_USE);
270 #endif
271 
272 #if BSP_FEATURE_DAC_HAS_OUTPUT_AMPLIFIER
273 
274     /* Initialize output amplifier. Described in hardware manual (see Section 48.6.5
275      * 'Initialization Procedure with the Output Amplifier' of the RA6M3 manual R01UH0878EJ0100). */
276     if (p_ctrl->output_amplifier_enabled)
277     {
278         /* Store value intended to be amplified during DAC output */
279         uint16_t value = p_ctrl->p_reg->DADR[p_ctrl->channel_index];
280 
281         /* Clear the D/A Data Register for the requested channel. */
282         p_ctrl->p_reg->DADR[p_ctrl->channel_index] = 0x00U;
283 
284         FSP_CRITICAL_SECTION_DEFINE;
285         FSP_CRITICAL_SECTION_ENTER;
286 
287         if (0U == p_ctrl->channel_index)
288         {
289             p_ctrl->p_reg->DACR_b.DAOE0     = 0U; /* Disable channel 0 */
290             p_ctrl->p_reg->DAASWCR_b.DAASW0 = 1U; /* Enable D/A Amplifier Stabilization Wait for channel 0 */
291             p_ctrl->p_reg->DAAMPCR_b.DAAMP0 = 1U; /* Enable amplifier control for channel 0 */
292             p_ctrl->p_reg->DACR_b.DAOE0     = 1U; /* Enable channel 0 to start D/A conversion of 0x00 */
293         }
294         else
295         {
296             p_ctrl->p_reg->DACR_b.DAOE1     = 0U; /* Disable channel 1 */
297             p_ctrl->p_reg->DAASWCR_b.DAASW1 = 1U; /* Enable D/A Amplifier Stabilization Wait for channel 1 */
298             p_ctrl->p_reg->DAAMPCR_b.DAAMP1 = 1U; /* Enable amplifier control for channel 1 */
299             p_ctrl->p_reg->DACR_b.DAOE1     = 1U; /* Enable channel 1 to start D/A conversion of 0x00 */
300         }
301 
302         FSP_CRITICAL_SECTION_EXIT;
303 
304         /* The System clock will be running at this point. It is safe to use this function. */
305         R_BSP_SoftwareDelay((uint32_t) DAC_CONVERSION_TIME_WITH_OUTPUT_AMPLIFIER, BSP_DELAY_UNITS_MICROSECONDS);
306 
307         FSP_CRITICAL_SECTION_ENTER;
308 
309         /* Disable D/A Amplifier Stabilization Wait for channel 0 or 1 */
310         (0U ==
311          p_ctrl->channel_index) ? (p_ctrl->p_reg->DAASWCR_b.DAASW0 = 0U) : (p_ctrl->p_reg->DAASWCR_b.DAASW1 = 0U);
312 
313         FSP_CRITICAL_SECTION_EXIT;
314 
315         /* Revert value intended to be amplified during DAC output. */
316         p_ctrl->p_reg->DADR[p_ctrl->channel_index] = value;
317     }
318     else
319 #endif
320     {
321         FSP_CRITICAL_SECTION_DEFINE;
322         FSP_CRITICAL_SECTION_ENTER;
323 
324         if (0U == p_ctrl->channel_index)
325         {
326 #if BSP_FEATURE_DAC_HAS_INTERNAL_OUTPUT
327             p_ctrl->p_reg->DACR_b.DAOE0     = 0U;                              /* Disable channel 0 */
328             p_ctrl->p_reg->DAASWCR_b.DAASW0 = p_ctrl->internal_output_enabled; /* Disable channel 0 internal output. */
329 #endif
330 
331             /* Enable channel 0 to start D/A conversion of 0x00 */
332             p_ctrl->p_reg->DACR_b.DAOE0 = 1U;
333         }
334         else
335         {
336 #if BSP_FEATURE_DAC_HAS_INTERNAL_OUTPUT
337             p_ctrl->p_reg->DACR_b.DAOE1     = 0U;                              /* Disable channel 1 */
338             p_ctrl->p_reg->DAASWCR_b.DAASW1 = p_ctrl->internal_output_enabled; /* Disable channel 1 internal output. */
339 #endif
340 
341             /* Enable channel 1 to start D/A conversion of 0x00 */
342             p_ctrl->p_reg->DACR_b.DAOE1 = 1U;
343         }
344 
345         FSP_CRITICAL_SECTION_EXIT;
346     }
347 
348     return FSP_SUCCESS;
349 }
350 
351 /******************************************************************************************************************//**
352  * Stop the D/A conversion and disable the output signal.
353  *
354  * @retval  FSP_SUCCESS           The control is successfully stopped.
355  * @retval  FSP_ERR_ASSERTION     p_api_ctrl is NULL.
356  * @retval  FSP_ERR_NOT_OPEN      Channel associated with p_ctrl has not been opened.
357  **********************************************************************************************************************/
R_DAC_Stop(dac_ctrl_t * p_api_ctrl)358 fsp_err_t R_DAC_Stop (dac_ctrl_t * p_api_ctrl)
359 {
360     dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
361 
362 #if DAC_CFG_PARAM_CHECKING_ENABLE
363 
364     /* Validate the handle parameter */
365     FSP_ASSERT(NULL != p_ctrl);
366 
367     /* Validate that the channel is opened. */
368     FSP_ERROR_RETURN(p_ctrl->channel_opened, FSP_ERR_NOT_OPEN);
369 #endif
370 
371     FSP_CRITICAL_SECTION_DEFINE;
372     FSP_CRITICAL_SECTION_ENTER;
373 
374     /* Stop the channel */
375     (0U == p_ctrl->channel_index) ? (p_ctrl->p_reg->DACR_b.DAOE0 = 0U) : (p_ctrl->p_reg->DACR_b.DAOE1 = 0U);
376 
377     FSP_CRITICAL_SECTION_EXIT;
378 
379     return FSP_SUCCESS;
380 }
381 
382 /******************************************************************************************************************//**
383  * Stop the D/A conversion, stop output, and close the DAC channel.
384  *
385  * @retval   FSP_SUCCESS           The channel is successfully closed.
386  * @retval   FSP_ERR_ASSERTION     p_api_ctrl is NULL.
387  * @retval   FSP_ERR_NOT_OPEN      Channel associated with p_ctrl has not been opened.
388  **********************************************************************************************************************/
R_DAC_Close(dac_ctrl_t * p_api_ctrl)389 fsp_err_t R_DAC_Close (dac_ctrl_t * p_api_ctrl)
390 {
391     dac_instance_ctrl_t * p_ctrl = (dac_instance_ctrl_t *) p_api_ctrl;
392 
393 #if DAC_CFG_PARAM_CHECKING_ENABLE
394 
395     /* Validate the handle parameter */
396     FSP_ASSERT(NULL != p_ctrl);
397 
398     /* Validate that the channel is opened. */
399     FSP_ERROR_RETURN(p_ctrl->channel_opened, FSP_ERR_NOT_OPEN);
400 #endif
401 
402     /* Module Stop is not needed here as this module does not have channel specific Start/Stop control.
403      * For more than 1 channels used (on selected MCUs), a module stop will disable both the channels. */
404 
405     FSP_CRITICAL_SECTION_DEFINE;
406     FSP_CRITICAL_SECTION_ENTER;
407 
408     /* Stop the channel, clear the amplifier stabilization wait bit and
409      * clear the output amplifier control register for the associated channel. */
410     if (0U == p_ctrl->channel_index)
411     {
412         p_ctrl->p_reg->DACR_b.DAOE0     = 0U; /* Disable channel 0 */
413         p_ctrl->p_reg->DAAMPCR_b.DAAMP0 = 0U; /* Disable amplifier control for channel 0 */
414     }
415     else
416     {
417         p_ctrl->p_reg->DACR_b.DAOE1     = 0U; /* Disable channel 1 */
418         p_ctrl->p_reg->DAAMPCR_b.DAAMP1 = 0U; /* Disable amplifier control for channel 1 */
419     }
420 
421     FSP_CRITICAL_SECTION_EXIT;
422 
423     /* Update the channel state information. */
424     p_ctrl->channel_opened = 0U;
425 
426     return FSP_SUCCESS;
427 }
428 
429 /*******************************************************************************************************************//**
430  * @} (end addtogroup DAC)
431  **********************************************************************************************************************/
432 
433 /***********************************************************************************************************************
434  * Private Functions
435  **********************************************************************************************************************/
436