ChibiOS/HAL  6.1.0
hal_adc.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 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  */
56 void adcInit(void) {
57 
58  adc_lld_init();
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  */
68 void adcObjectInit(ADCDriver *adcp) {
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
79  osalMutexObjectInit(&adcp->mutex);
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  *
93  * @api
94  */
95 void adcStart(ADCDriver *adcp, const ADCConfig *config) {
96 
97  osalDbgCheck(adcp != NULL);
98 
99  osalSysLock();
100  osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
101  "invalid state");
102  adcp->config = config;
103  adc_lld_start(adcp);
104  adcp->state = ADC_READY;
105  osalSysUnlock();
106 }
107 
108 /**
109  * @brief Deactivates the ADC peripheral.
110  *
111  * @param[in] adcp pointer to the @p ADCDriver object
112  *
113  * @api
114  */
115 void adcStop(ADCDriver *adcp) {
116 
117  osalDbgCheck(adcp != NULL);
118 
119  osalSysLock();
120 
121  osalDbgAssert((adcp->state == ADC_STOP) || (adcp->state == ADC_READY),
122  "invalid state");
123 
124  adc_lld_stop(adcp);
125  adcp->config = NULL;
126  adcp->state = ADC_STOP;
127 
128  osalSysUnlock();
129 }
130 
131 /**
132  * @brief Starts an ADC conversion.
133  * @details Starts an asynchronous conversion operation.
134  * @note The buffer is organized as a matrix of M*N elements where M is the
135  * channels number configured into the conversion group and N is the
136  * buffer depth. The samples are sequentially written into the buffer
137  * with no gaps.
138  *
139  * @param[in] adcp pointer to the @p ADCDriver object
140  * @param[in] grpp pointer to a @p ADCConversionGroup object
141  * @param[out] samples pointer to the samples buffer
142  * @param[in] depth buffer depth (matrix rows number). The buffer depth
143  * must be one or an even number.
144  *
145  * @api
146  */
148  const ADCConversionGroup *grpp,
149  adcsample_t *samples,
150  size_t depth) {
151 
152  osalSysLock();
153  adcStartConversionI(adcp, grpp, samples, depth);
154  osalSysUnlock();
155 }
156 
157 /**
158  * @brief Starts an ADC conversion.
159  * @details Starts an asynchronous conversion operation.
160  * @post The callbacks associated to the conversion group will be invoked
161  * on buffer fill and error events.
162  * @note The buffer is organized as a matrix of M*N elements where M is the
163  * channels number configured into the conversion group and N is the
164  * buffer depth. The samples are sequentially written into the buffer
165  * with no gaps.
166  *
167  * @param[in] adcp pointer to the @p ADCDriver object
168  * @param[in] grpp pointer to a @p ADCConversionGroup object
169  * @param[out] samples pointer to the samples buffer
170  * @param[in] depth buffer depth (matrix rows number). The buffer depth
171  * must be one or an even number.
172  *
173  * @iclass
174  */
176  const ADCConversionGroup *grpp,
177  adcsample_t *samples,
178  size_t depth) {
179 
181  osalDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) &&
182  (depth > 0U) && ((depth == 1U) || ((depth & 1U) == 0U)));
183  osalDbgAssert((adcp->state == ADC_READY) ||
184  (adcp->state == ADC_COMPLETE) ||
185  (adcp->state == ADC_ERROR),
186  "not ready");
187 
188  adcp->samples = samples;
189  adcp->depth = depth;
190  adcp->grpp = grpp;
191  adcp->state = ADC_ACTIVE;
193 }
194 
195 /**
196  * @brief Stops an ongoing conversion.
197  * @details This function stops the currently ongoing conversion and returns
198  * the driver in the @p ADC_READY state. If there was no conversion
199  * being processed then the function does nothing.
200  *
201  * @param[in] adcp pointer to the @p ADCDriver object
202  *
203  * @api
204  */
206 
207  osalDbgCheck(adcp != NULL);
208 
209  osalSysLock();
210  osalDbgAssert((adcp->state == ADC_READY) || (adcp->state == ADC_ACTIVE),
211  "invalid state");
212  if (adcp->state != ADC_READY) {
214  adcp->grpp = NULL;
215  adcp->state = ADC_READY;
216  _adc_reset_s(adcp);
217  }
218  osalSysUnlock();
219 }
220 
221 /**
222  * @brief Stops an ongoing conversion.
223  * @details This function stops the currently ongoing conversion and returns
224  * the driver in the @p ADC_READY state. If there was no conversion
225  * being processed then the function does nothing.
226  *
227  * @param[in] adcp pointer to the @p ADCDriver object
228  *
229  * @iclass
230  */
232 
234  osalDbgCheck(adcp != NULL);
235  osalDbgAssert((adcp->state == ADC_READY) ||
236  (adcp->state == ADC_ACTIVE) ||
237  (adcp->state == ADC_COMPLETE),
238  "invalid state");
239 
240  if (adcp->state != ADC_READY) {
242  adcp->grpp = NULL;
243  adcp->state = ADC_READY;
244  _adc_reset_i(adcp);
245  }
246 }
247 
248 #if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
249 /**
250  * @brief Performs an ADC conversion.
251  * @details Performs a synchronous conversion operation.
252  * @note The buffer is organized as a matrix of M*N elements where M is the
253  * channels number configured into the conversion group and N is the
254  * buffer depth. The samples are sequentially written into the buffer
255  * with no gaps.
256  *
257  * @param[in] adcp pointer to the @p ADCDriver object
258  * @param[in] grpp pointer to a @p ADCConversionGroup object
259  * @param[out] samples pointer to the samples buffer
260  * @param[in] depth buffer depth (matrix rows number). The buffer depth
261  * must be one or an even number.
262  * @return The operation result.
263  * @retval MSG_OK Conversion finished.
264  * @retval MSG_RESET The conversion has been stopped using
265  * @p acdStopConversion() or @p acdStopConversionI(),
266  * the result buffer may contain incorrect data.
267  * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
268  * error.
269  *
270  * @api
271  */
273  const ADCConversionGroup *grpp,
274  adcsample_t *samples,
275  size_t depth) {
276  msg_t msg;
277 
278  osalSysLock();
279  osalDbgAssert(adcp->thread == NULL, "already waiting");
280  adcStartConversionI(adcp, grpp, samples, depth);
281  msg = osalThreadSuspendS(&adcp->thread);
282  osalSysUnlock();
283  return msg;
284 }
285 #endif /* ADC_USE_WAIT == TRUE */
286 
287 #if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
288 /**
289  * @brief Gains exclusive access to the ADC peripheral.
290  * @details This function tries to gain ownership to the ADC bus, if the bus
291  * is already being used then the invoking thread is queued.
292  * @pre In order to use this function the option
293  * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
294  *
295  * @param[in] adcp pointer to the @p ADCDriver object
296  *
297  * @api
298  */
300 
301  osalDbgCheck(adcp != NULL);
302 
303  osalMutexLock(&adcp->mutex);
304 }
305 
306 /**
307  * @brief Releases exclusive access to the ADC peripheral.
308  * @pre In order to use this function the option
309  * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
310  *
311  * @param[in] adcp pointer to the @p ADCDriver object
312  *
313  * @api
314  */
316 
317  osalDbgCheck(adcp != NULL);
318 
319  osalMutexUnlock(&adcp->mutex);
320 }
321 #endif /* ADC_USE_MUTUAL_EXCLUSION == TRUE */
322 
323 #endif /* HAL_USE_ADC == TRUE */
324 
325 /** @} */
static void osalMutexObjectInit(mutex_t *mp)
Initializes s mutex_t object.
Definition: osal.h:681
void adcObjectInit(ADCDriver *adcp)
Initializes the standard part of a ADCDriver structure.
Definition: hal_adc.c:68
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition: osal.c:185
#define _adc_reset_i(adcp)
Resumes a thread waiting for a conversion completion.
Definition: hal_adc.h:97
void adcStartConversion(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Starts an ADC conversion.
Definition: hal_adc.c:147
void adcStop(ADCDriver *adcp)
Deactivates the ADC peripheral.
Definition: hal_adc.c:115
void adcAcquireBus(ADCDriver *adcp)
Gains exclusive access to the ADC peripheral.
Definition: hal_adc.c:299
const ADCConversionGroup * grpp
Current conversion group pointer or NULL.
Definition: hal_adc_lld.h:164
HAL subsystem header.
#define osalDbgCheckClassI()
I-Class state check.
Definition: osal.h:292
void adc_lld_start(ADCDriver *adcp)
Configures and activates the ADC peripheral.
Definition: hal_adc_lld.c:80
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition: osal.c:384
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
thread_reference_t thread
Waiting thread.
Definition: hal_adc_lld.h:169
void adcReleaseBus(ADCDriver *adcp)
Releases exclusive access to the ADC peripheral.
Definition: hal_adc.c:315
Conversion group configuration structure.
Definition: hal_adc_lld.h:113
#define _adc_reset_s(adcp)
Resumes a thread waiting for a conversion completion.
Definition: hal_adc.h:107
int32_t msg_t
Type of a message.
Definition: osal.h:160
void adcStart(ADCDriver *adcp, const ADCConfig *config)
Configures and activates the ADC peripheral.
Definition: hal_adc.c:95
void adc_lld_stop_conversion(ADCDriver *adcp)
Stops an ongoing conversion.
Definition: hal_adc_lld.c:134
Structure representing an ADC driver.
Definition: hal_adc_lld.h:144
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
msg_t adcConvert(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Performs an ADC conversion.
Definition: hal_adc.c:272
adcstate_t state
Driver state.
Definition: hal_adc_lld.h:148
void adcStopConversion(ADCDriver *adcp)
Stops an ongoing conversion.
Definition: hal_adc.c:205
void adcStartConversionI(ADCDriver *adcp, const ADCConversionGroup *grpp, adcsample_t *samples, size_t depth)
Starts an ADC conversion.
Definition: hal_adc.c:175
uint16_t adcsample_t
ADC sample data type.
Definition: hal_adc_lld.h:63
mutex_t mutex
Mutex protecting the peripheral.
Definition: hal_adc_lld.h:175
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
void adcStopConversionI(ADCDriver *adcp)
Stops an ongoing conversion.
Definition: hal_adc.c:231
void adc_lld_stop(ADCDriver *adcp)
Deactivates the ADC peripheral.
Definition: hal_adc_lld.c:101
void adc_lld_init(void)
Low level ADC driver initialization.
Definition: hal_adc_lld.c:65
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition: osal.c:404
size_t depth
Current samples buffer depth or 0.
Definition: hal_adc_lld.h:160
Driver configuration structure.
Definition: hal_adc_lld.h:137
adcsample_t * samples
Current samples buffer pointer or NULL.
Definition: hal_adc_lld.h:156
void adc_lld_start_conversion(ADCDriver *adcp)
Starts an ADC conversion.
Definition: hal_adc_lld.c:122
void adcInit(void)
ADC Driver initialization.
Definition: hal_adc.c:56
const ADCConfig * config
Current configuration data.
Definition: hal_adc_lld.h:152