Welcome to mirror list, hosted at ThFree Co, Russian Federation.

adc_common_v2.c « common « stm32 « lib - github.com/thirdpin/libopencm3.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7fd264768ca640d5044742f3c7c0db78189479c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis

@author @htmlonly © @endhtmlonly
2015 Karl Palsson <karlp@tweak.net.au>

This library supports one style of the Analog to Digital Conversion System in
the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.

The style of ADC Peripheral supported by this code is found in the F0, L0 and
F30x series devices (at the time of writing)

LGPL License Terms @ref lgpl_license
 */

/*
 * This file is part of the libopencm3 project.
 *
 * Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

/**@{*/

#include <libopencm3/stm32/adc.h>


/** @brief ADC Read the End-of-Conversion Flag
 *
 * This flag is set by hardware at the end of each regular conversion of a
 * channel when a new data is available in the ADCx_DR register.
 *
 * @param[in] adc Unsigned int32. ADC block register address base
 * @ref adc_reg_base
 * @returns bool. End of conversion flag.
 */
bool adc_eoc(uint32_t adc)
{
	return ADC_ISR(adc) & ADC_ISR_EOC;
}

/** @brief ADC Read the End-of-Sequence Flag for Regular Conversions
 *
 * This flag is set after all channels of an regular group have been
 * converted.
 *
 * @param[in] adc Unsigned int32. ADC block register address base
 * @ref adc_reg_base
 * @returns bool. End of conversion flag.
 */
bool adc_eos(uint32_t adc)
{
	return ADC_ISR(adc) & ADC_ISR_EOS;
}

/**
 * Turn on the ADC (async)
 * @sa adc_wait_power_on
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_power_on_async(uint32_t adc)
{
	ADC_CR(adc) |= ADC_CR_ADEN;
}

/**
 * Is the ADC powered up and ready?
 * @sa adc_power_on_async
 * @param adc ADC Block register address base @ref adc_reg_base
 * @return true if adc is ready for use
 */
bool adc_is_power_on(uint32_t adc)
{
	return ADC_ISR(adc) & ADC_ISR_ADRDY;
}

/**
 * Turn on the ADC
 * @sa adc_power_on_async
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_power_on(uint32_t adc)
{
	adc_power_on_async(adc);
	while (!adc_is_power_on(adc));
}

/**
 * Turn off the ADC (async)
 * This will actually block if it needs to turn off a currently running
 * conversion, as per ref man. (Handles injected on hardware that supports
 * injected conversions.
 * @sa adc_wait_power_off
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_power_off_async(uint32_t adc)
{
	if (adc_is_power_off(adc)) {
		return;
	}

	uint32_t checks = ADC_CR_ADSTART;
	uint32_t stops = ADC_CR_ADSTP;
#if defined(ADC_CR_JADSTART)
	checks |= ADC_CR_JADSTART;
	stops |= ADC_CR_JADSTP;
#endif
	if (ADC_CR(adc) & checks) {
		ADC_CR(adc) |= stops;
		while (ADC_CR(adc) & checks);
	}
	ADC_CR(adc) |= ADC_CR_ADDIS;
}

/**
 * Is the ADC powered down?
 * @sa adc_power_off_async
 * @param adc ADC Block register address base @ref adc_reg_base
 */
bool adc_is_power_off(uint32_t adc)
{
	return !(ADC_CR(adc) & ADC_CR_ADEN);
}

/**
 * Turn off the ADC
 * This will actually block if it needs to turn off a currently running
 * conversion, as per ref man.
 * @sa adc_power_off_async
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_power_off(uint32_t adc)
{
	adc_power_off_async(adc);
	while (!adc_is_power_off(adc));
}

/**
 * Start the ADC calibration and immediately return.
 * @sa adc_calibrate
 * @sa adc_is_calibrating
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_calibrate_async(uint32_t adc)
{
	ADC_CR(adc) |= ADC_CR_ADCAL;
}

/**
 * Is the ADC Calibrating?
 * @param adc ADC Block register address base @ref adc_reg_base
 * @return true if the adc is currently calibrating
 */
bool adc_is_calibrating(uint32_t adc)
{
	return ADC_CR(adc) & ADC_CR_ADCAL;
}

/**
 * Start ADC calibration and wait for it to finish
 * @param adc ADC Block register address base @ref adc_reg_base
 */
void adc_calibrate(uint32_t adc)
{
	adc_calibrate_async(adc);
	while (adc_is_calibrating(adc));
}

/**
 * Enable Continuous Conversion Mode
 * In this mode the ADC starts a new conversion of a single channel or a channel
 * group immediately following completion of the previous channel group
 * conversion.
 *
 * @param[in] adc ADC block register address base @ref adc_reg_base
 */
void adc_set_continuous_conversion_mode(uint32_t adc)
{
	ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
}

/**
 * Enable Single Conversion Mode
 * In this mode the ADC performs a conversion of one channel or a channel group
 * and stops.
 *
 * @param[in] adc ADC block register address base @ref adc_reg_base
 */
void adc_set_single_conversion_mode(uint32_t adc)
{
	ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
}

/** @brief ADC Set Resolution
 *
 * ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
 * corresponding reduction in conversion time.
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 * @param[in] resolution Unsigned int16. Resolution value (@ref adc_api_res)
 */
void adc_set_resolution(uint32_t adc, uint16_t resolution)
{
	ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_RES_MASK) | resolution;
}

/** @brief ADC Set the Data as Left Aligned
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_set_left_aligned(uint32_t adc)
{
	ADC_CFGR1(adc) |= ADC_CFGR1_ALIGN;
}

/** @brief ADC Set the Data as Right Aligned
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_set_right_aligned(uint32_t adc)
{
	ADC_CFGR1(adc) &= ~ADC_CFGR1_ALIGN;
}

/** @brief ADC Enable DMA Transfers
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_enable_dma(uint32_t adc)
{
	ADC_CFGR1(adc) |= ADC_CFGR1_DMAEN;
}

/** @brief ADC Disable DMA Transfers
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_disable_dma(uint32_t adc)
{
	ADC_CFGR1(adc) &= ~ADC_CFGR1_DMAEN;
}

/** @brief ADC Enable the Overrun Interrupt
 *
 * The overrun interrupt is generated when data is not read from a result
 * register before the next conversion is written. If DMA is enabled, all
 * transfers are terminated and any conversion sequence is aborted.
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_enable_overrun_interrupt(uint32_t adc)
{
	ADC_IER(adc) |= ADC_IER_OVRIE;
}

/** @brief ADC Disable the Overrun Interrupt
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_disable_overrun_interrupt(uint32_t adc)
{
	ADC_IER(adc) &= ~ADC_IER_OVRIE;
}

/** @brief ADC Read the Overrun Flag
 *
 * The overrun flag is set when data is not read from a result register before
 * the next conversion is written. If DMA is enabled, all transfers are
 * terminated and any conversion sequence is aborted.
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
bool adc_get_overrun_flag(uint32_t adc)
{
	return ADC_ISR(adc) & ADC_ISR_OVR;
}

/** @brief ADC Clear Overrun Flags
 *
 * The overrun flag is cleared. Note that if an overrun occurs, DMA is
 * terminated.
 * The flag must be cleared and the DMA stream and ADC reinitialised to resume
 * conversions (see the reference manual).
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_clear_overrun_flag(uint32_t adc)
{
	ADC_ISR(adc) = ADC_ISR_OVR;
}

/** @brief ADC Enable Regular End-Of-Conversion Interrupt
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_enable_eoc_interrupt(uint32_t adc)
{
	ADC_IER(adc) |= ADC_IER_EOCIE;
}

/** @brief ADC Disable Regular End-Of-Conversion Interrupt
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_disable_eoc_interrupt(uint32_t adc)
{
	ADC_IER(adc) &= ~ADC_IER_EOCIE;
}

/** @brief ADC Read from the Regular Conversion Result Register
 *
 * The result read back is 12 bits, right or left aligned within the first
 * 16 bits.
 *
 * @param[in] adc Unsigned int32. ADC block register address base
 * @ref adc_reg_base
 * @returns Unsigned int32 conversion result.
 */
uint32_t adc_read_regular(uint32_t adc)
{
	return ADC_DR(adc);
}

/**
 * Enable the temperature sensor (only)
 * The channel this is available on is unfortunately not
 * consistent, even though the bit used to enable it is.
 * @sa adc_disable_temperature_sensor
 */
void adc_enable_temperature_sensor(void)
{
	ADC_CCR(ADC1) |= ADC_CCR_TSEN;
}

/**
 * Disable the temperature sensor (only)
 * @sa adc_enable_temperature_sensor
 */
void adc_disable_temperature_sensor(void)
{
	ADC_CCR(ADC1) &= ~ADC_CCR_TSEN;
}

/**
 * Enable the internal voltage reference (only)
 * The channel this is available on is unfortunately not
 * consistent, even though the bit used to enable it is.
 * FIXME - on f3, you can actually have it on ADC34 as well!
 * @sa adc_disable_vrefint
 */
void adc_enable_vrefint(void)
{
	ADC_CCR(ADC1) |= ADC_CCR_VREFEN;
}

/**
 * Disable the internal voltage reference (only)
 * @sa adc_enable_vrefint
 */
void adc_disable_vrefint(void)
{
	ADC_CCR(ADC1) &= ~ADC_CCR_VREFEN;
}

/** @brief ADC Software Triggered Conversion on Regular Channels
 *
 * This starts conversion on a set of defined regular channels.
 * Depending on the configuration bits EXTEN, a conversion will start
 * immediately (software trigger configuration) or once a regular hardware
 * trigger event occurs (hardware trigger configuration)
 *
 * @param[in] adc ADC block register address base @ref adc_reg_base
 */
void adc_start_conversion_regular(uint32_t adc)
{
	/* Start conversion on regular channels. */
	ADC_CR(adc) |= ADC_CR_ADSTART;
}

/** @brief Enable circular mode for DMA transfers
 *
 * For this to work it needs to be ebabled on the DMA side as well.
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_enable_dma_circular_mode(uint32_t adc)
{
	ADC_CFGR1(adc) |= ADC_CFGR1_DMACFG;
}

/** @brief Disable circular mode for DMA transfers
 *
 * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
 */
void adc_disable_dma_circular_mode(uint32_t adc)
{
	ADC_CFGR1(adc) &= ~ADC_CFGR1_DMACFG;
}

/**@}*/