aboutsummaryrefslogtreecommitdiffstats
path: root/src/gadc/gadc.h
blob: 94321192ec0a247890e15ed6a96c45f3a89d8eb5 (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
/*
 * 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    src/gadc/gadc.h
 *
 * @addtogroup GADC
 *
 * @brief	Module to abstract the very variable ADC interfaces of the underlying systems
 *
 * @details	The reason why uGFX 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 */
		#define	GADC_HSADC_RUNNING			0x0002		/**< @brief The High Speed ADC is currently running */
		#define	GADC_HSADC_GOTBUFFER		0x0004		/**< @brief A buffer is ready for processing */
		#define	GADC_HSADC_STALL			0x0008		/**< @brief The High Speed ADC has stalled due to no free buffers */
		/** @} */
} 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)(void);

/*===========================================================================*/
/* 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
 *
 * @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				ChibiOS ONLY: Due to a bug in ChibiOS each buffer on the free-list must contain an even number of
 * 						samples and for multi-channel devices it must hold a number of samples that is evenly divisible
 * 						by 2 times the number of active channels.
 * @note				The physdev parameter may be used to turn on more than one ADC channel.
 * 						Each channel is then interleaved into the provided buffer. Make sure your buffers all hold
 * 						a number of samples evenly divisible by the number of active channels.
 * 						As an example, if physdev turns on 2 devices then the buffer contains
 * 						alternate device samples and the buffer must contain multiples of 2 samples.
 * 						The exact meaning of physdev is hardware dependent.
 * @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 100 samples/buffer, frequency = 5kHz) then the maximum
 * 						frequency for low speed conversions will be 50Hz.
 * @note				Only a single sample format is supported - that provided by the GADC driver. That sample
 * 						format applies to both high speed and low speed sampling.
 *
 * @api
 */
void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency);

#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 blocked thread and the GEVENT
 * 						sub-system at the same time.
 *
 * @api
 */
void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn);

/**
 * @brief		Get a filled buffer from the ADC
 * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
 *
 * @param[in] ms	The maximum amount of time in milliseconds to wait for data if some is not currently available.
 *
 * @note		After processing the data, your application must return the buffer to the free-list so that
 * 				it can be used again. This can be done using @p gfxBufferRelease().
 * @note		A buffer may be returned to the free-list before you have finished processing it provided you finish
 * 				processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
 * 				of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
 * 				in the queue as long as possible before they are re-used.
 * @note		The function ending with "I" is the interrupt class function.
 * @api
 * @{
 */
GDataBuffer *gadcHighSpeedGetData(delaytime_t ms);
GDataBuffer *gadcHighSpeedGetDataI(void);
/** @} */

/**
 * @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	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 device stalling or 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 internal memory allocation fails
 *
 * @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	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 */
/** @} */