ChibiOS 21.11.5
hal_adc.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file hal_adc.c
19 * @brief ADC Driver code.
20 *
21 * @addtogroup ADC
22 * @{
23 */
24
25#include "hal.h"
26
27#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__)
28
29/*===========================================================================*/
30/* Driver local definitions. */
31/*===========================================================================*/
32
33/*===========================================================================*/
34/* Driver exported variables. */
35/*===========================================================================*/
36
37/*===========================================================================*/
38/* Driver local variables and types. */
39/*===========================================================================*/
40
41/*===========================================================================*/
42/* Driver local functions. */
43/*===========================================================================*/
44
45/*===========================================================================*/
46/* Driver exported functions. */
47/*===========================================================================*/
48
49/**
50 * @brief ADC Driver initialization.
51 * @note This function is implicitly invoked by @p halInit(), there is
52 * no need to explicitly initialize the driver.
53 *
54 * @init
55 */
56void adcInit(void) {
57
59}
60
61/**
62 * @brief Initializes the standard part of a @p ADCDriver structure.
63 *
64 * @param[out] adcp pointer to the @p ADCDriver object
65 *
66 * @init
67 */
69
70 adcp->state = ADC_STOP;
71 adcp->config = NULL;
72 adcp->samples = NULL;
73 adcp->depth = 0;
74 adcp->grpp = NULL;
75#if ADC_USE_WAIT == TRUE
76 adcp->thread = NULL;
77#endif
78#if ADC_USE_MUTUAL_EXCLUSION == TRUE
80#endif
81#if defined(ADC_DRIVER_EXT_INIT_HOOK)
82 ADC_DRIVER_EXT_INIT_HOOK(adcp);
83#endif
84}
85
86/**
87 * @brief Configures and activates the ADC peripheral.
88 *
89 * @param[in] adcp pointer to the @p ADCDriver object
90 * @param[in] config pointer to the @p ADCConfig object. Depending on
91 * the implementation the value can be @p NULL.
92 * @return The operation status.
93 *
94 * @api
95 */
96msg_t adcStart(ADCDriver *adcp, const ADCConfig *config) {
97 msg_t msg;
98
99 osalDbgCheck(adcp != NULL);
100
101 osalSysLock();
102 osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
103 "invalid state");
104 adcp->config = config;
105
106#if defined(ADC_LLD_ENHANCED_API)
107 msg = adc_lld_start(adcp);
108 if (msg == HAL_RET_SUCCESS) {
109 adcp->state = ADC_READY;
110 }
111 else {
112 adcp->state = ADC_STOP;
113 }
114#else
115 adc_lld_start(adcp);
116 adcp->state = ADC_READY;
117 msg = HAL_RET_SUCCESS;
118#endif
119
121
122 return msg;
123}
124
125/**
126 * @brief Deactivates the ADC peripheral.
127 *
128 * @param[in] adcp pointer to the @p ADCDriver object
129 *
130 * @api
131 */
132void adcStop(ADCDriver *adcp) {
133
134 osalDbgCheck(adcp != NULL);
135
136 osalSysLock();
137
138 osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
139 "invalid state");
140
141 adc_lld_stop(adcp);
142 adcp->config = NULL;
143 adcp->state = ADC_STOP;
144
146}
147
148/**
149 * @brief Starts an ADC conversion.
150 * @details Starts an asynchronous conversion operation.
151 * @note The buffer is organized as a matrix of M*N elements where M is the
152 * channels number configured into the conversion group and N is the
153 * buffer depth. The samples are sequentially written into the buffer
154 * with no gaps.
155 *
156 * @param[in] adcp pointer to the @p ADCDriver object
157 * @param[in] grpp pointer to a @p ADCConversionGroup object
158 * @param[out] samples pointer to the samples buffer
159 * @param[in] depth buffer depth (matrix rows number). The buffer depth
160 * must be one or an even number.
161 *
162 * @api
163 */
165 const ADCConversionGroup *grpp,
166 adcsample_t *samples,
167 size_t depth) {
168
169 osalSysLock();
170 adcStartConversionI(adcp, grpp, samples, depth);
172}
173
174/**
175 * @brief Starts an ADC conversion.
176 * @details Starts an asynchronous conversion operation.
177 * @post The callbacks associated to the conversion group will be invoked
178 * on buffer fill and error events.
179 * @note The buffer is organized as a matrix of M*N elements where M is the
180 * channels number configured into the conversion group and N is the
181 * buffer depth. The samples are sequentially written into the buffer
182 * with no gaps.
183 *
184 * @param[in] adcp pointer to the @p ADCDriver object
185 * @param[in] grpp pointer to a @p ADCConversionGroup object
186 * @param[out] samples pointer to the samples buffer
187 * @param[in] depth buffer depth (matrix rows number). The buffer depth
188 * must be one or an even number.
189 *
190 * @iclass
191 */
193 const ADCConversionGroup *grpp,
194 adcsample_t *samples,
195 size_t depth) {
196
198 osalDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) &&
199 (depth > 0U) && ((depth == 1U) || ((depth & 1U) == 0U)));
200 osalDbgAssert((adcp->state == ADC_READY) ||
201 (adcp->state == ADC_ERROR),
202 "not ready");
203
204 adcp->samples = samples;
205 adcp->depth = depth;
206 adcp->grpp = grpp;
207 adcp->state = ADC_ACTIVE;
209}
210
211/**
212 * @brief Stops an ongoing conversion.
213 * @details This function stops the currently ongoing conversion and returns
214 * the driver in the @p ADC_READY state. If there was no conversion
215 * being processed then the function does nothing.
216 *
217 * @param[in] adcp pointer to the @p ADCDriver object
218 *
219 * @api
220 */
222
223 osalDbgCheck(adcp != NULL);
224
225 osalSysLock();
226 osalDbgAssert((adcp->state == ADC_READY) || (adcp->state == ADC_ACTIVE),
227 "invalid state");
228 if (adcp->state != ADC_READY) {
230 adcp->grpp = NULL;
231 adcp->state = ADC_READY;
232 _adc_reset_s(adcp);
233 }
235}
236
237/**
238 * @brief Stops an ongoing conversion.
239 * @details This function stops the currently ongoing conversion and returns
240 * the driver in the @p ADC_READY state. If there was no conversion
241 * being processed then the function does nothing.
242 *
243 * @param[in] adcp pointer to the @p ADCDriver object
244 *
245 * @iclass
246 */
248
250 osalDbgCheck(adcp != NULL);
251 osalDbgAssert((adcp->state == ADC_READY) ||
252 (adcp->state == ADC_ACTIVE) ||
253 (adcp->state == ADC_COMPLETE),
254 "invalid state");
255
256 if (adcp->state != ADC_READY) {
258 adcp->grpp = NULL;
259 adcp->state = ADC_READY;
260 _adc_reset_i(adcp);
261 }
262}
263
264#if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
265/**
266 * @brief Performs an ADC conversion.
267 * @details Performs a synchronous conversion operation.
268 * @note The buffer is organized as a matrix of M*N elements where M is the
269 * channels number configured into the conversion group and N is the
270 * buffer depth. The samples are sequentially written into the buffer
271 * with no gaps.
272 * @note If the configured callback starts another conversion before this
273 * function returns then the behavior is undefined.
274 *
275 * @param[in] adcp pointer to the @p ADCDriver object
276 * @param[in] grpp pointer to a @p ADCConversionGroup object
277 * @param[out] samples pointer to the samples buffer
278 * @param[in] depth buffer depth (matrix rows number). The buffer depth
279 * must be one or an even number.
280 * @return The operation result.
281 * @retval MSG_OK Conversion finished.
282 * @retval MSG_RESET The conversion has been stopped using
283 * @p adcStopConversion() or @p adcStopConversionI(),
284 * the result buffer may contain incorrect data.
285 * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
286 * error.
287 *
288 * @api
289 */
291 const ADCConversionGroup *grpp,
292 adcsample_t *samples,
293 size_t depth) {
294 msg_t msg;
295
296 osalSysLock();
297 osalDbgAssert(adcp->thread == NULL, "already waiting");
298 adcStartConversionI(adcp, grpp, samples, depth);
299 msg = osalThreadSuspendS(&adcp->thread);
301 return msg;
302}
303#endif /* ADC_USE_WAIT == TRUE */
304
305#if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
306/**
307 * @brief Gains exclusive access to the ADC peripheral.
308 * @details This function tries to gain ownership to the ADC bus, if the bus
309 * is already being used then the invoking thread is queued.
310 * @pre In order to use this function the option
311 * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
312 *
313 * @param[in] adcp pointer to the @p ADCDriver object
314 *
315 * @api
316 */
318
319 osalDbgCheck(adcp != NULL);
320
321 osalMutexLock(&adcp->mutex);
322}
323
324/**
325 * @brief Releases exclusive access to the ADC peripheral.
326 * @pre In order to use this function the option
327 * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
328 *
329 * @param[in] adcp pointer to the @p ADCDriver object
330 *
331 * @api
332 */
334
335 osalDbgCheck(adcp != NULL);
336
337 osalMutexUnlock(&adcp->mutex);
338}
339#endif /* ADC_USE_MUTUAL_EXCLUSION == TRUE */
340
341#endif /* HAL_USE_ADC == TRUE */
342
343/** @} */
void adc_lld_stop_conversion(ADCDriver *adcp)
Stops an ongoing conversion.
struct hal_adc_driver ADCDriver
Type of a structure representing an ADC driver.
Definition hal_adc.h:82
void adcStartConversionI(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Starts an ADC conversion.
Definition hal_adc.c:192
void adc_lld_init(void)
Low level ADC driver initialization.
Definition hal_adc_lld.c:65
msg_t adcStart(ADCDriver *adcp, const ADCConfig *config)
Configures and activates the ADC peripheral.
Definition hal_adc.c:96
void adcStop(ADCDriver *adcp)
Deactivates the ADC peripheral.
Definition hal_adc.c:132
void adc_lld_start_conversion(ADCDriver *adcp)
Starts an ADC conversion.
void adc_lld_stop(ADCDriver *adcp)
Deactivates the ADC peripheral.
void adcAcquireBus(ADCDriver *adcp)
Gains exclusive access to the ADC peripheral.
Definition hal_adc.c:317
struct hal_adc_configuration_group ADCConversionGroup
Conversion group configuration structure.
Definition hal_adc.h:97
#define _adc_reset_s(adcp)
Resumes a thread waiting for a conversion completion.
Definition hal_adc.h:257
struct hal_adc_config ADCConfig
Type of a structure representing an ADC driver configuration.
Definition hal_adc.h:87
void adc_lld_start(ADCDriver *adcp)
Configures and activates the ADC peripheral.
Definition hal_adc_lld.c:80
void adcStopConversionI(ADCDriver *adcp)
Stops an ongoing conversion.
Definition hal_adc.c:247
#define _adc_reset_i(adcp)
Resumes a thread waiting for a conversion completion.
Definition hal_adc.h:247
void adcStartConversion(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Starts an ADC conversion.
Definition hal_adc.c:164
void adcStopConversion(ADCDriver *adcp)
Stops an ongoing conversion.
Definition hal_adc.c:221
uint16_t adcsample_t
ADC sample data type.
Definition hal_adc_lld.h:72
void adcObjectInit(ADCDriver *adcp)
Initializes the standard part of a ADCDriver structure.
Definition hal_adc.c:68
void adcReleaseBus(ADCDriver *adcp)
Releases exclusive access to the ADC peripheral.
Definition hal_adc.c:333
msg_t adcConvert(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Performs an ADC conversion.
Definition hal_adc.c:290
void adcInit(void)
ADC Driver initialization.
Definition hal_adc.c:56
@ ADC_STOP
Definition hal_adc.h:72
@ ADC_ERROR
Definition hal_adc.h:76
@ ADC_READY
Definition hal_adc.h:73
@ ADC_COMPLETE
Definition hal_adc.h:75
@ ADC_ACTIVE
Definition hal_adc.h:74
#define HAL_RET_SUCCESS
Definition hal.h:93
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalMutexObjectInit(mutex_t *mp)
Initializes a mutex_t object.
Definition osal.h:753
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:183
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition osal.c:380
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition osal.c:400
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalDbgCheckClassI()
I-Class state check.
Definition osal.h:298
int32_t msg_t
Definition chearly.h:87
HAL subsystem header.
adcsample_t * samples
Current samples buffer pointer or NULL.
Definition hal_adc.h:180
const ADCConversionGroup * grpp
Current conversion group pointer or NULL.
Definition hal_adc.h:188
adcstate_t state
Driver state.
Definition hal_adc.h:172
size_t depth
Current samples buffer depth or 0.
Definition hal_adc.h:184
const ADCConfig * config
Current configuration data.
Definition hal_adc.h:176
thread_reference_t thread
Waiting thread.
Definition hal_adc.h:193
mutex_t mutex
Mutex protecting the peripheral.
Definition hal_adc.h:199