1 /******************************************************************************
2 * Filename: aux_adc.c
3 * Revised: 2020-02-14 11:30:20 +0100 (Fri, 14 Feb 2020)
4 * Revision: 56760
5 *
6 * Description: Driver for the AUX Time to Digital Converter interface.
7 *
8 * Copyright (c) 2015 - 2017, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38
39 #include "aux_adc.h"
40 #include "../inc/hw_memmap.h"
41 #include "../inc/hw_aux_sysif.h"
42 #include "../inc/hw_fcfg1.h"
43 #include "adi.h"
44 #include "event.h"
45
46 //*****************************************************************************
47 //
48 // Handle support for DriverLib in ROM:
49 // This section will undo prototype renaming made in the header file
50 //
51 //*****************************************************************************
52 #if !defined(DOXYGEN)
53 #undef AUXADCDisable
54 #define AUXADCDisable NOROM_AUXADCDisable
55 #undef AUXADCEnableAsync
56 #define AUXADCEnableAsync NOROM_AUXADCEnableAsync
57 #undef AUXADCEnableSync
58 #define AUXADCEnableSync NOROM_AUXADCEnableSync
59 #undef AUXADCDisableInputScaling
60 #define AUXADCDisableInputScaling NOROM_AUXADCDisableInputScaling
61 #undef AUXADCFlushFifo
62 #define AUXADCFlushFifo NOROM_AUXADCFlushFifo
63 #undef AUXADCReadFifo
64 #define AUXADCReadFifo NOROM_AUXADCReadFifo
65 #undef AUXADCPopFifo
66 #define AUXADCPopFifo NOROM_AUXADCPopFifo
67 #undef AUXADCGetAdjustmentGain
68 #define AUXADCGetAdjustmentGain NOROM_AUXADCGetAdjustmentGain
69 #undef AUXADCGetAdjustmentOffset
70 #define AUXADCGetAdjustmentOffset NOROM_AUXADCGetAdjustmentOffset
71 #undef AUXADCValueToMicrovolts
72 #define AUXADCValueToMicrovolts NOROM_AUXADCValueToMicrovolts
73 #undef AUXADCMicrovoltsToValue
74 #define AUXADCMicrovoltsToValue NOROM_AUXADCMicrovoltsToValue
75 #undef AUXADCAdjustValueForGainAndOffset
76 #define AUXADCAdjustValueForGainAndOffset NOROM_AUXADCAdjustValueForGainAndOffset
77 #undef AUXADCUnadjustValueForGainAndOffset
78 #define AUXADCUnadjustValueForGainAndOffset NOROM_AUXADCUnadjustValueForGainAndOffset
79 #endif
80
81 //*****************************************************************************
82 //
83 // Disables the ADC
84 //
85 //*****************************************************************************
86 void
AUXADCDisable(void)87 AUXADCDisable(void)
88 {
89 // Disable the ADC reference
90 ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, ADI_4_AUX_ADCREF0_EN_M | ADI_4_AUX_ADCREF0_REF_ON_IDLE_M | ADI_4_AUX_ADCREF0_SRC_M);
91
92 // Assert reset and disable the ADC
93 ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M | ADI_4_AUX_ADC0_SMPL_MODE_M | ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_M);
94
95 // Ensure that scaling is enabled by default before next use of the ADC
96 ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
97
98 // Flush the FIFO before disabling the clocks
99 HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 1; // CMD: EN(1) -> FLUSH(3)
100 HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 0; // CMD: FLUSH(3) -> EN(1)
101
102 // Disable the ADC clock (no need to wait since IOB_WUC_ADCCLKCTL_ACK goes low immediately)
103 HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = 0;
104
105 // Disable the ADC data interface
106 HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = 0;
107 }
108
109 //*****************************************************************************
110 //
111 // Enables the ADC for asynchronous operation
112 //
113 //*****************************************************************************
114 void
AUXADCEnableAsync(uint32_t refSource,uint32_t trigger)115 AUXADCEnableAsync(uint32_t refSource, uint32_t trigger)
116 {
117 // Enable the ADC reference, with the following options:
118 // - SRC: Set when using relative reference
119 // - REF_ON_IDLE: Always cleared since there is no idle state in asynchronous operation
120 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, refSource | ADI_4_AUX_ADCREF0_EN_M);
121
122 // Enable the ADC clock
123 HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = AUX_SYSIF_ADCCLKCTL_REQ_M;
124 while (!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) & AUX_SYSIF_ADCCLKCTL_ACK_M));
125
126 // Enable the ADC data interface
127 if (trigger == AUXADC_TRIGGER_MANUAL) {
128 // Manual trigger: No need to configure event routing from GPT
129 HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT | AUX_ANAIF_ADCCTL_CMD_EN;
130 } else {
131 // GPT trigger: Configure event routing via MCU_EV to the AUX domain
132 HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
133 HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
134 }
135
136 // Configure the ADC
137 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_SMPL_MODE_M);
138
139 // Release reset and enable the ADC
140 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M);
141 }
142
143 //*****************************************************************************
144 //
145 // Enables the ADC for synchronous operation
146 //
147 //*****************************************************************************
148 void
AUXADCEnableSync(uint32_t refSource,uint32_t sampleTime,uint32_t trigger)149 AUXADCEnableSync(uint32_t refSource, uint32_t sampleTime, uint32_t trigger)
150 {
151 // Enable the ADC reference, with the following options:
152 // - SRC: Set when using relative reference
153 // - REF_ON_IDLE: Set when using fixed reference and sample time < 21.3 us
154 uint8_t adcref0 = refSource | ADI_4_AUX_ADCREF0_EN_M;
155 if (!refSource && (sampleTime < AUXADC_SAMPLE_TIME_21P3_US)) {
156 adcref0 |= ADI_4_AUX_ADCREF0_REF_ON_IDLE_M;
157 }
158 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, adcref0);
159
160 // Enable the ADC clock
161 HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = AUX_SYSIF_ADCCLKCTL_REQ_M;
162 while (!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) & AUX_SYSIF_ADCCLKCTL_ACK_M));
163
164 // Enable the ADC data interface
165 if (trigger == AUXADC_TRIGGER_MANUAL) {
166 // Manual trigger: No need to configure event routing from GPT
167 HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT | AUX_ANAIF_ADCCTL_CMD_EN;
168 } else {
169 // GPT trigger: Configure event routing via MCU_EV to the AUX domain
170 HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
171 HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
172 }
173
174 // Configure the ADC
175 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, sampleTime << ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_S);
176
177 // Release reset and enable the ADC
178 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M);
179 }
180
181 //*****************************************************************************
182 //
183 // Disables scaling of the ADC input
184 //
185 //*****************************************************************************
186 void
AUXADCDisableInputScaling(void)187 AUXADCDisableInputScaling(void)
188 {
189 ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
190 }
191
192 //*****************************************************************************
193 //
194 // Flushes the ADC FIFO
195 //
196 //*****************************************************************************
197 void
AUXADCFlushFifo(void)198 AUXADCFlushFifo(void)
199 {
200 HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 1; // CMD: EN(1) -> FLUSH(3)
201 HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 0; // CMD: FLUSH(3) -> EN(1)
202 }
203
204 //*****************************************************************************
205 //
206 // Waits for and returns the first sample in the ADC FIFO
207 //
208 //*****************************************************************************
209 uint32_t
AUXADCReadFifo(void)210 AUXADCReadFifo(void) {
211
212 // Wait until there is at least one sample in the FIFO
213 while (HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFOSTAT) & AUX_ANAIF_ADCFIFOSTAT_EMPTY_M);
214
215 // Return the first sample from the FIFO
216 return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
217 }
218
219 //*****************************************************************************
220 //
221 // Returns the first sample in the ADC FIFO, without waiting
222 //
223 //*****************************************************************************
224 uint32_t
AUXADCPopFifo(void)225 AUXADCPopFifo(void) {
226
227 // Return the first sample from the FIFO. If the FIFO is empty, this
228 // generates ADC FIFO underflow
229 return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
230 }
231
232 //*****************************************************************************
233 //
234 // Returns the gain value used when adjusting for ADC gain/offset
235 //
236 //*****************************************************************************
237 int32_t
AUXADCGetAdjustmentGain(uint32_t refSource)238 AUXADCGetAdjustmentGain(uint32_t refSource)
239 {
240 int32_t gain;
241 if (refSource == AUXADC_REF_FIXED) {
242 // AUXADC_REF_FIXED ==> ABS_GAIN
243 gain = (HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_ABS_GAIN) & FCFG1_SOC_ADC_ABS_GAIN_SOC_ADC_ABS_GAIN_TEMP1_M) >> FCFG1_SOC_ADC_ABS_GAIN_SOC_ADC_ABS_GAIN_TEMP1_S;
244 } else {
245 // AUXADC_REF_VDDS_REL ==> REL_GAIN
246 gain = (HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_REL_GAIN) & FCFG1_SOC_ADC_REL_GAIN_SOC_ADC_REL_GAIN_TEMP1_M) >> FCFG1_SOC_ADC_REL_GAIN_SOC_ADC_REL_GAIN_TEMP1_S;
247 }
248 return gain;
249 }
250
251 //*****************************************************************************
252 //
253 // Returns the offset value used when adjusting for ADC gain/offset
254 //
255 //*****************************************************************************
256 int32_t
AUXADCGetAdjustmentOffset(uint32_t refSource)257 AUXADCGetAdjustmentOffset(uint32_t refSource)
258 {
259 int8_t offset;
260 if ( refSource == AUXADC_REF_FIXED ) {
261 // AUXADC_REF_FIXED ==> ABS_OFFSET
262 offset = HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_OFFSET_INT) >> FCFG1_SOC_ADC_OFFSET_INT_SOC_ADC_ABS_OFFSET_TEMP1_S;
263 } else {
264 // AUXADC_REF_VDDS_REL ==> REL_OFFSET
265 offset = HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_OFFSET_INT) >> FCFG1_SOC_ADC_OFFSET_INT_SOC_ADC_REL_OFFSET_TEMP1_S;
266 }
267 return offset;
268 }
269
270 //*****************************************************************************
271 //
272 // Converts an "ideal" ADC value to microvolts
273 //
274 //*****************************************************************************
275 int32_t
AUXADCValueToMicrovolts(int32_t fixedRefVoltage,int32_t adcValue)276 AUXADCValueToMicrovolts(int32_t fixedRefVoltage, int32_t adcValue)
277 {
278 // Chop off 4 bits during calculations to avoid 32-bit overflow
279 fixedRefVoltage >>= 4;
280 return (((adcValue * fixedRefVoltage) + 2047) / 4095) << 4;
281 }
282
283 //*****************************************************************************
284 //
285 // Converts a number of microvolts to corresponding "ideal" ADC value
286 //
287 //*****************************************************************************
288 int32_t
AUXADCMicrovoltsToValue(int32_t fixedRefVoltage,int32_t microvolts)289 AUXADCMicrovoltsToValue(int32_t fixedRefVoltage, int32_t microvolts)
290 {
291 // Chop off 4 bits during calculations to avoid 32-bit overflow
292 fixedRefVoltage >>= 4;
293 microvolts >>= 4;
294 return ((microvolts * 4095) + (fixedRefVoltage / 2)) / fixedRefVoltage;
295 }
296
297 //*****************************************************************************
298 //
299 // Performs ADC value gain and offset adjustment
300 //
301 //*****************************************************************************
302 int32_t
AUXADCAdjustValueForGainAndOffset(int32_t adcValue,int32_t gain,int32_t offset)303 AUXADCAdjustValueForGainAndOffset(int32_t adcValue, int32_t gain, int32_t offset)
304 {
305 // Apply gain and offset adjustment
306 adcValue = (((adcValue + offset) * gain) + 16384) / 32768;
307
308 // Saturate
309 if (adcValue < 0) {
310 return 0;
311 } else if (adcValue > 4095) {
312 return 4095;
313 } else {
314 return adcValue;
315 }
316 }
317
318 //*****************************************************************************
319 //
320 // Performs the inverse of the ADC value gain and offset adjustment
321 //
322 //*****************************************************************************
323 int32_t
AUXADCUnadjustValueForGainAndOffset(int32_t adcValue,int32_t gain,int32_t offset)324 AUXADCUnadjustValueForGainAndOffset(int32_t adcValue, int32_t gain, int32_t offset)
325 {
326 // Apply inverse gain and offset adjustment
327 adcValue = (((adcValue * 32768) + (gain / 2)) / gain) - offset;
328
329 // Saturate
330 if (adcValue < 0) {
331 return 0;
332 } else if (adcValue > 4095) {
333 return 4095;
334 } else {
335 return adcValue;
336 }
337 }
338