ChibiOS/HAL  7.0.3
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_ERROR),
185  "not ready");
186 
187  adcp->samples = samples;
188  adcp->depth = depth;
189  adcp->grpp = grpp;
190  adcp->state = ADC_ACTIVE;
192 }
193 
194 /**
195  * @brief Stops an ongoing conversion.
196  * @details This function stops the currently ongoing conversion and returns
197  * the driver in the @p ADC_READY state. If there was no conversion
198  * being processed then the function does nothing.
199  *
200  * @param[in] adcp pointer to the @p ADCDriver object
201  *
202  * @api
203  */
205 
206  osalDbgCheck(adcp != NULL);
207 
208  osalSysLock();
209  osalDbgAssert((adcp->state == ADC_READY) || (adcp->state == ADC_ACTIVE),
210  "invalid state");
211  if (adcp->state != ADC_READY) {
213  adcp->grpp = NULL;
214  adcp->state = ADC_READY;
215  _adc_reset_s(adcp);
216  }
217  osalSysUnlock();
218 }
219 
220 /**
221  * @brief Stops an ongoing conversion.
222  * @details This function stops the currently ongoing conversion and returns
223  * the driver in the @p ADC_READY state. If there was no conversion
224  * being processed then the function does nothing.
225  *
226  * @param[in] adcp pointer to the @p ADCDriver object
227  *
228  * @iclass
229  */
231 
233  osalDbgCheck(adcp != NULL);
234  osalDbgAssert((adcp->state == ADC_READY) ||
235  (adcp->state == ADC_ACTIVE) ||
236  (adcp->state == ADC_COMPLETE),
237  "invalid state");
238 
239  if (adcp->state != ADC_READY) {
241  adcp->grpp = NULL;
242  adcp->state = ADC_READY;
243  _adc_reset_i(adcp);
244  }
245 }
246 
247 #if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
248 /**
249  * @brief Performs an ADC conversion.
250  * @details Performs a synchronous conversion operation.
251  * @note The buffer is organized as a matrix of M*N elements where M is the
252  * channels number configured into the conversion group and N is the
253  * buffer depth. The samples are sequentially written into the buffer
254  * with no gaps.
255  *
256  * @param[in] adcp pointer to the @p ADCDriver object
257  * @param[in] grpp pointer to a @p ADCConversionGroup object
258  * @param[out] samples pointer to the samples buffer
259  * @param[in] depth buffer depth (matrix rows number). The buffer depth
260  * must be one or an even number.
261  * @return The operation result.
262  * @retval MSG_OK Conversion finished.
263  * @retval MSG_RESET The conversion has been stopped using
264  * @p acdStopConversion() or @p acdStopConversionI(),
265  * the result buffer may contain incorrect data.
266  * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
267  * error.
268  *
269  * @api
270  */
272  const ADCConversionGroup *grpp,
273  adcsample_t *samples,
274  size_t depth) {
275  msg_t msg;
276 
277  osalSysLock();
278  osalDbgAssert(adcp->thread == NULL, "already waiting");
279  adcStartConversionI(adcp, grpp, samples, depth);
280  msg = osalThreadSuspendS(&adcp->thread);
281  osalSysUnlock();
282  return msg;
283 }
284 #endif /* ADC_USE_WAIT == TRUE */
285 
286 #if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
287 /**
288  * @brief Gains exclusive access to the ADC peripheral.
289  * @details This function tries to gain ownership to the ADC bus, if the bus
290  * is already being used then the invoking thread is queued.
291  * @pre In order to use this function the option
292  * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
293  *
294  * @param[in] adcp pointer to the @p ADCDriver object
295  *
296  * @api
297  */
299 
300  osalDbgCheck(adcp != NULL);
301 
302  osalMutexLock(&adcp->mutex);
303 }
304 
305 /**
306  * @brief Releases exclusive access to the ADC peripheral.
307  * @pre In order to use this function the option
308  * @p ADC_USE_MUTUAL_EXCLUSION must be enabled.
309  *
310  * @param[in] adcp pointer to the @p ADCDriver object
311  *
312  * @api
313  */
315 
316  osalDbgCheck(adcp != NULL);
317 
318  osalMutexUnlock(&adcp->mutex);
319 }
320 #endif /* ADC_USE_MUTUAL_EXCLUSION == TRUE */
321 
322 #endif /* HAL_USE_ADC == TRUE */
323 
324 /** @} */
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:235
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
Driver configuration structure.
Definition: hal_adc.h:151
void adcAcquireBus(ADCDriver *adcp)
Gains exclusive access to the ADC peripheral.
Definition: hal_adc.c:298
mutex_t mutex
Mutex protecting the peripheral.
Definition: hal_adc.h:190
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
size_t depth
Current samples buffer depth or 0.
Definition: hal_adc.h:175
thread_reference_t thread
Waiting thread.
Definition: hal_adc.h:184
void adcReleaseBus(ADCDriver *adcp)
Releases exclusive access to the ADC peripheral.
Definition: hal_adc.c:314
#define _adc_reset_s(adcp)
Resumes a thread waiting for a conversion completion.
Definition: hal_adc.h:245
int32_t msg_t
Type of a message.
Definition: osal.h:160
adcsample_t * samples
Current samples buffer pointer or NULL.
Definition: hal_adc.h:171
void adcStart(ADCDriver *adcp, const ADCConfig *config)
Configures and activates the ADC peripheral.
Definition: hal_adc.c:95
Conversion group configuration structure.
Definition: hal_adc.h:127
void adc_lld_stop_conversion(ADCDriver *adcp)
Stops an ongoing conversion.
Definition: hal_adc_lld.c:134
#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:271
Structure representing an ADC driver.
Definition: hal_adc.h:159
void adcStopConversion(ADCDriver *adcp)
Stops an ongoing conversion.
Definition: hal_adc.c:204
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
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:230
void adc_lld_stop(ADCDriver *adcp)
Deactivates the ADC peripheral.
Definition: hal_adc_lld.c:101
const ADCConversionGroup * grpp
Current conversion group pointer or NULL.
Definition: hal_adc.h:179
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
const ADCConfig * config
Current configuration data.
Definition: hal_adc.h:167
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
adcstate_t state
Driver state.
Definition: hal_adc.h:163