aboutsummaryrefslogtreecommitdiffstats
path: root/include/gadc/gadc.h
blob: 1ad5ecb8dd4d0ec1d5cd7d7d60549526506dc71f (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
/*
 * This file is subject to the terms of the GFX License. If a copy of
 * the license was not distributed with this file, you can obtain one at:
 *
 *              http://ugfx.org/license.html
 */

/**
 * @file    include/gadc/gadc.h
 *
 * @addtogroup GADC
 *
 * @brief	Module to abstract the very variable ADC interfaces of the underlying systems
 *
 * @details	The reason why ChibiOS/GFX has it's own ADC abstraction is because
 *			the Chibi-OS drivers are very CPU specific and do not
 *			provide a way across all hardware platforms to create periodic
 *			ADC conversions. There are also issues with devices with different
 *			characteristics or periodic requirements on the same ADC
 *			device (but different channels). This layer attempts to solve these
 *			problems to provide a architecture neutral API. It also provides extra
 *			features such as multi-buffer chaining for high speed ADC sources.
 *			It provides one high speed virtual ADC device (eg a microphone) and
 *			numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
 *			temperature sensors etc). The high speed device has timer based polling
 *			to ensure exact conversion periods and a buffer management system.
 *			The low speed devices are assumed to be non-critical timing devices
 *			and do not have any buffer management.
 *			Note that while only one high speed device has been provided it can
 *			be used to read multiple physical ADC channels on the one physical
 *			ADC device.
 *			All callback routines are thread based unlike the Chibi-OS interrupt based
 *			routines.
 *
 * @{
 */

#ifndef _GADC_H
#define _GADC_H

#include "gfx.h"

#if GFX_USE_GADC || defined(__DOXYGEN__)

/* Include the driver defines */
#include "gadc_lld_config.h"

/*===========================================================================*/
/* Type definitions                                                          */
/*===========================================================================*/

// Event types for GADC
#define GEVENT_ADC			(GEVENT_GADC_FIRST+0)

/**
 * @brief   The High Speed ADC event structure.
 * @{
 */
typedef struct GEventADC_t {
	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
		/**
		 * @brief The type of this event (GEVENT_ADC)
		 */
		GEventType		type;
	#endif

	/**
	 * @brief The event flags
	 */
	uint16_t		flags;
		/**
		 * @brief   The event flag values.
		 * @{
		 */
		#define	GADC_HSADC_LOSTEVENT		0x0001		/**< @brief The last GEVENT_HSDADC event was lost */
		/** @} */
	/**
	 * @brief The number of conversions in the buffer
	 */
	size_t			count;
	/**
	 * @brief The buffer containing the conversion samples
	 */
	adcsample_t		*buffer;
} GEventADC;
/** @} */

/**
 * @brief A callback function (executed in a thread context) for a low speed conversion
 */
typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);

/**
 * @brief A callback function (executed in an ISR context) for a high speed conversion
 */
typedef void (*GADCISRCallbackFunction)(adcsample_t *buffer, size_t size);

/*===========================================================================*/
/* External declarations.                                                    */
/*===========================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief				Initialise the high speed ADC.
 * @details				Initialises but does not start the conversions.
 *
 * @param[in] physdev			A value passed to describe which physical ADC devices/channels to use.
 * @param[in] frequency			The frequency to create ADC conversions
 * @param[in] buffer			The static buffer to put the ADC samples into.
 * @param[in] bufcount			The total number of conversions that will fit in the buffer.
 * @param[in] samplesPerEvent	The number of conversions to do before returning an event.
 *
 * @note				If the high speed ADC is running it will be stopped. The Event subsystem is
 * 						disconnected from the high speed ADC and any binary semaphore event is forgotten.
 * @note				bufcount must be greater than countPerEvent (usually 2 or more times) otherwise
 * 						the buffer will be overwritten with new data while the application is still trying
 * 						to process the old data.
 * @note				Due to a bug/feature in Chibi-OS countPerEvent must be even. If bufcount is not
 * 						evenly divisable by countPerEvent, the remainder must also be even.
 * @note				The physdev parameter may be used to turn on more than one ADC channel.
 * 						Each channel is then interleaved into the provided buffer. Note 'bufcount'
 * 						and 'countPerEvent' parameters describe the number of conversions not the
 * 						number of samples.
 * 						As an example, if physdev turns on 2 devices then the buffer contains
 * 						alternate device samples and the buffer must contain 2 * bufcount samples.
 * 						The exact meaning of physdev is hardware dependent.
 * @note				The buffer is circular. When the end of the buffer is reached it will start
 * 						putting data into the beginning of the buffer again.
 * @note				The event listener must process the event (and the data in it) before the
 * 						next event occurs. If not, the following event will be lost.
 * @note				If bufcount is evenly divisable by countPerEvent, then every event will return
 * 						countPerEvent conversions. If bufcount is not evenly divisable, it will return
 * 						a block of samples containing less than countPerEvent samples when it reaches the
 * 						end of the buffer.
 * @note				While the high speed ADC is running, low speed conversions can only occur at
 * 						the frequency of the high speed events. Thus if high speed events are
 * 						being created at 50Hz (eg countPerEvent = 100, frequency = 5kHz) then the maximum
 * 						frequency for low speed conversions will be 50Hz.
 *
 * @api
 */
void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent);

#if GFX_USE_GEVENT || defined(__DOXYGEN__)
	/**
	 * @brief   			Turn on sending results to the GEVENT sub-system.
	 * @details				Returns a GSourceHandle to listen for GEVENT_ADC events.
	 *
	 * @note				The high speed ADC will not use the GEVENT system unless this is
	 * 						called first. This saves processing time if the application does
	 * 						not want to use the GEVENT sub-system for the high speed ADC.
	 * 						Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again.
	 * @note				The high speed ADC is capable of signalling via this method, an ISR callback and a
	 * 						binary semaphore at the same time.
	 *
	 * @return				The GSourceHandle
	 *
	 * @api
	 */
	GSourceHandle gadcHighSpeedGetSource(void);
#endif

/**
 * @brief				Allow retrieving of results from the high speed ADC using an ISR callback.
 *
 * @param[in] isrfn			The callback function (called in an ISR context).
 *
 * @note				Passing a NULL for isrfn will turn off signalling via this method as will calling
 * 						@p gadcHighSpeedInit().
 * @note				The high speed ADC is capable of signalling via this method, a binary semaphore and the GEVENT
 * 						sub-system at the same time.
 *
 * @api
 */
void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn);

/**
 * @brief				Allow retrieving of results from the high speed ADC using a Binary Semaphore and a static event buffer.
 *
 * @param[in] pbsem			The semaphore is signaled when data is available.
 * @param[in] pEvent		The static event buffer to place the result information.
 *
 * @note				Passing a NULL for pbsem or pEvent will turn off signalling via this method as will calling
 * 						@p gadcHighSpeedInit().
 * @note				The high speed ADC is capable of signalling via this method, an ISR callback and the GEVENT
 * 						sub-system at the same time.
 *
 * @api
 */
void gadcHighSpeedSetBSem(gfxSem *pbsem, GEventADC *pEvent);

/**
 * @brief   Start the high speed ADC conversions.
 * @pre		It must have been initialised first with @p gadcHighSpeedInit()
 *
 * @api
 */
void gadcHighSpeedStart(void);

/**
 * @brief   Stop the high speed ADC conversions.
 *
 * @api
 */
void gadcHighSpeedStop(void);

/**
 * @brief	Perform a single low speed ADC conversion
 * @details	Blocks until the conversion is complete
 * @pre		This should not be called from within a GTimer callback as this routine
 * 			blocks until the conversion is ready.
 *
 * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
 * @param[in] buffer		The static buffer to put the ADC samples into.
 *
 * @note	This may take a while to complete if the high speed ADC is running as the
 * 			conversion is interleaved with the high speed ADC conversions on a buffer
 * 			completion.
 * @note	The result buffer must be large enough to store one sample per device
 * 			described by the 'physdev' parameter.
 * @note	If calling this routine would exceed @p GADC_MAX_LOWSPEED_DEVICES simultaneous low
 * 			speed devices, the routine will wait for an available slot to complete the
 * 			conversion.
 * @note	Specifying more than one device in physdev is possible but discouraged as the
 * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
 * 			from over-running the high speed ADC include high speed samples being lost.
 *
 * @api
 */
void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);

/**
 * @brief	Perform a low speed ADC conversion with callback (in a thread context)
 * @details	Returns FALSE if there are no free low speed ADC slots. See @p GADC_MAX_LOWSPEED_DEVICES for details.
 *
 * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
 * @param[in] buffer		The static buffer to put the ADC samples into.
 * @param[in] fn			The callback function to call when the conversion is complete.
 * @param[in] param			A parameter to pass to the callback function.
 *
 * @return					FALSE if no free low speed ADC slots.
 *
 * @note	This may be safely called from within a GTimer callback.
 * @note	The callback may take a while to occur if the high speed ADC is running as the
 * 			conversion is interleaved with the high speed ADC conversions on a buffer
 * 			completion.
 * @note	The result buffer must be large enough to store one sample per device
 * 			described by the 'physdev' parameter.
 * @note	As this routine uses a low speed ADC, it asserts if you try to run more than @p GADC_MAX_LOWSPEED_DEVICES
 * 			at the same time.
 * @note	Specifying more than one device in physdev is possible but discouraged as the
 * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
 * 			from over-running the high speed ADC include high speed samples being lost.
 *
 * @api
 */
bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);

#ifdef __cplusplus
}
#endif

#endif /* GFX_USE_GADC */

#endif /* _GADC_H */
/** @} */