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