comparison packages/io/adc/current/src/adc.c @ 2512:be7755f32fd0

Add Generic ADC support. See Changelogs for details.
author nickg
date Fri, 08 Aug 2008 10:47:04 +0000
parents
children 74dbf4c3f2e1
comparison
equal deleted inserted replaced
2511:1f18f909a18e 2512:be7755f32fd0
1 /*==========================================================================
2 //
3 // adc.c
4 //
5 // Generic ADC driver layer
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2008 eCosCentric Limited
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //==========================================================================
38 //#####DESCRIPTIONBEGIN####
39 //
40 // Author(s): nickg
41 // Date: 2008-03-31
42 // Description: Implements generic layer of ADC drivers.
43 //
44 //####DESCRIPTIONEND####
45 //
46 //========================================================================*/
47
48 #include <cyg/io/adc.h>
49
50 //==========================================================================
51 // Diagnostic support
52 //
53 // Switch the #if to 1 to generate some diagnostic messages.
54
55 #if 0
56
57 #include <cyg/infra/diag.h>
58
59 #define adc_diag( __fmt, ... ) diag_printf("ADC: %30s[%4d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ );
60 #define adc_dump_buf( __buf, __size ) diag_dump_buf( __buf, __size )
61 #else
62 #define adc_diag( __fmt, ... )
63 #define adc_dump_buf( __buf, __size )
64 #endif
65
66 //==========================================================================
67 // Main device table entry functions
68
69 static Cyg_ErrNo adc_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len);
70 static Cyg_ErrNo adc_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);
71 static cyg_bool adc_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
72 static Cyg_ErrNo adc_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf, cyg_uint32 *len);
73 static Cyg_ErrNo adc_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len);
74
75 DEVIO_TABLE(cyg_io_adc_devio,
76 adc_write,
77 adc_read,
78 adc_select,
79 adc_get_config,
80 adc_set_config
81 );
82
83 //==========================================================================
84 // Device interface functions
85
86 //--------------------------------------------------------------------------
87 // Device write
88 //
89 // Not supported
90
91 static Cyg_ErrNo adc_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len)
92 {
93 adc_diag("write not supported\n");
94 return -EDEVNOSUPP;
95 }
96
97 //--------------------------------------------------------------------------
98 // Device Read
99 //
100 // Returns a whole number of samples from a channel
101
102 static Cyg_ErrNo adc_read(cyg_io_handle_t handle, void *abuf, cyg_uint32 *len)
103 {
104 Cyg_ErrNo res = ENOERR;
105 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
106 cyg_adc_channel *chan = (cyg_adc_channel *)t->priv;
107 cyg_adc_device *dev = chan->device;
108
109 cyg_adc_sample_t *buf = (cyg_adc_sample_t *)abuf;
110 cyg_uint32 size = 0;
111
112 adc_diag("chan %d buf %p len %u\n", chan->channel, abuf, *len);
113
114 // Check that supplied buffer address is aligned to sample size.
115 if( (((CYG_ADDRESS)buf) & (sizeof(cyg_adc_sample_t)-1)) != 0 )
116 return -EIO;
117
118 // Check that channel is enabled
119 if( !chan->enabled )
120 return -EIO;
121
122 cyg_drv_mutex_lock( &dev->lock );
123 cyg_drv_dsr_lock();
124 {
125 while( (*len-size) >= sizeof(cyg_adc_sample_t) )
126 {
127 if( chan->put != chan->get )
128 {
129 // A sample is available, transfer it to the buffer.
130
131 int next = chan->get+1;
132 cyg_drv_isr_lock();
133 {
134 *buf++ = chan->buf[chan->get];
135 if( next == chan->len )
136 next = 0;
137 chan->get = next;
138 }
139 cyg_drv_isr_unlock();
140 size += sizeof(cyg_adc_sample_t);
141
142 adc_diag("chan %d sample %d -> %04x\n", chan->channel, size, buf[-1] );
143 }
144 else
145 {
146 // If there is no data available, either wait or
147 // return EAGAIN.
148
149 if( !chan->blocking )
150 {
151 // If non-blocking, return what we have. If
152 // nothing, return EAGAIN.
153 *len = size;
154 if( size == 0 )
155 res = -EAGAIN;
156 break;
157 }
158 // Otherwise, we must wait for data to arrive.
159
160 adc_diag("wait for sample\n");
161 chan->waiting = true;
162 if( !cyg_drv_cond_wait( &chan->wait ) )
163 {
164 // Abort the wait, return EINTR
165 adc_diag("abort\n");
166 *len = size;
167 res = -EINTR;
168 break;
169 }
170
171 adc_diag("wake up\n");
172 // Loop back round to pick up any samples now
173 // available.
174 }
175 }
176 }
177 cyg_drv_dsr_unlock();
178 cyg_drv_mutex_unlock( &dev->lock );
179
180 return res;
181 }
182
183 //--------------------------------------------------------------------------
184 // Select support
185 //
186 // If select support is enabled, check for pending samples.
187
188 static cyg_bool adc_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
189 {
190 #ifdef CYGPKG_IO_ADC_SELECT_SUPPORT
191
192 cyg_bool res = false;
193 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
194 cyg_adc_channel *chan = (cyg_adc_channel *)t->priv;
195 cyg_adc_device *dev = chan->device;
196
197 // Check that channel is enabled. If not, return false.
198 if( !chan->enabled )
199 return false;
200
201 // Only read select is supported
202 if( which == CYG_FREAD )
203 {
204 cyg_drv_mutex_lock( &dev->lock );
205 cyg_drv_dsr_lock();
206 {
207 cyg_drv_isr_lock();
208 if( chan->put == chan->get )
209 {
210 // There is no data in the buffer, register the select.
211
212 cyg_selrecord( info, &chan->selinfo );
213 }
214 else
215 {
216 res = true;
217 }
218 cyg_drv_isr_unlock();
219 }
220 cyg_drv_dsr_unlock();
221 cyg_drv_mutex_unlock( &dev->lock );
222
223 }
224
225 return res;
226
227 #else
228
229 return true;
230
231 #endif
232 }
233
234 //--------------------------------------------------------------------------
235 // Get config
236 //
237 // Return various configuration options.
238
239 static Cyg_ErrNo adc_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len)
240 {
241 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
242 cyg_adc_channel *chan = (cyg_adc_channel *)t->priv;
243 cyg_adc_info_t *buf = (cyg_adc_info_t *)xbuf;
244 Cyg_ErrNo res = ENOERR;
245
246 adc_diag("chan %d\n", chan->channel );
247 switch( key )
248 {
249 case CYG_IO_GET_CONFIG_ADC_RATE:
250 *buf = chan->device->config;
251 break;
252
253 case CYG_IO_GET_CONFIG_READ_BLOCKING:
254 if (*len < sizeof(cyg_uint32))
255 return -EINVAL;
256 *(cyg_uint32*)xbuf = (chan->blocking) ? 1 : 0;
257 break;
258
259
260 default:
261 res = -EINVAL;
262 }
263
264 return res;
265 }
266
267 //--------------------------------------------------------------------------
268 // Set config
269 //
270 // Set configuration options.
271
272 static Cyg_ErrNo adc_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len)
273 {
274
275 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
276 cyg_adc_channel *chan = (cyg_adc_channel *)t->priv;
277 cyg_adc_info_t *buf = (cyg_adc_info_t *)xbuf;
278 Cyg_ErrNo res = ENOERR;
279
280 adc_diag("chan %d\n", chan->channel );
281
282 switch( key )
283 {
284 case CYG_IO_SET_CONFIG_ADC_RATE:
285 chan->device->config = *buf;
286 chan->device->funs->set_rate( chan, buf->rate );
287 break;
288
289 case CYG_IO_SET_CONFIG_ADC_ENABLE:
290 chan->enabled = true;
291 chan->device->funs->enable( chan );
292 break;
293
294 case CYG_IO_SET_CONFIG_ADC_DISABLE:
295 chan->enabled = false;
296 chan->device->funs->disable( chan );
297 break;
298
299 case CYG_IO_SET_CONFIG_READ_BLOCKING:
300 if (*len < sizeof(cyg_uint32))
301 return -EINVAL;
302
303 chan->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
304 break;
305
306 default:
307 res = -EINVAL;
308 }
309
310 return res;
311 }
312
313 //==========================================================================
314 // Callbacks from hardware driver to generic layer
315
316 //--------------------------------------------------------------------------
317 // Initialize generic device structure
318
319 __externC void cyg_adc_device_init( cyg_adc_device *device )
320 {
321 if( device->init )
322 return;
323
324 adc_diag("\n");
325
326 device->init = true;
327 cyg_drv_mutex_init( &device->lock );
328 }
329
330 //--------------------------------------------------------------------------
331 // Initialize generic channel structure
332
333 __externC void cyg_adc_channel_init(cyg_adc_channel *chan)
334 {
335 if( chan->init )
336 return;
337
338 adc_diag("chan %d\n", chan->channel );
339
340 chan->init = true;
341 cyg_drv_cond_init( &chan->wait, &chan->device->lock );
342 chan->enabled = false;
343 chan->waiting = false;
344 chan->wakeup = false;
345 chan->blocking = true;
346 chan->overflow = 0;
347
348 #ifdef CYGPKG_IO_ADC_SELECT_SUPPORT
349 cyg_selinit( &chan->selinfo );
350 #endif
351
352 }
353
354 //--------------------------------------------------------------------------
355 // Add a new sample to the buffer
356 //
357 // This function is called from the ISR to store a sample in the
358 // buffer.
359
360 __externC cyg_uint32 cyg_adc_receive_sample(cyg_adc_channel *chan, cyg_adc_sample_t sample)
361 {
362 cyg_uint32 res = 0;
363 int next = chan->put+1;
364
365 adc_diag("chan %d sample %04x\n", chan->channel, sample );
366
367 // Ignore this sample if the channel is not enabled.
368 if( !chan->enabled )
369 return 0;
370
371 if( next == chan->len )
372 next = 0;
373
374 if( next == chan->get )
375 {
376 // The buffer is full. Record an overflow and arrange to
377 // replace the oldest sample with the new one.
378
379 adc_diag("chan %d overflow\n", chan->channel);
380 chan->overflow++;
381
382 chan->get++;
383 if( chan->get == chan->len )
384 chan->get = 0;
385 }
386
387 // If this is the first sample into the buffer, wake any waiting
388 // selectors. Also do this if there are any threads waiting for
389 // data.
390 if( chan->put == chan->get || chan->waiting )
391 res |= CYG_ISR_CALL_DSR, chan->wakeup = true;
392
393 // Store the new sample
394 chan->buf[chan->put] = sample;
395 chan->put = next;
396
397 return res;
398 }
399
400 //--------------------------------------------------------------------------
401 // Wakeup a channel
402 //
403 // This function is called from the DSR if the channel wakeup field is
404 // set. It satisfies any select operations or any waiting readers.
405
406 __externC void cyg_adc_wakeup(cyg_adc_channel *chan )
407 {
408 adc_diag("chan %d\n", chan->channel );
409
410 #ifdef CYGPKG_IO_ADC_SELECT_SUPPORT
411 cyg_selwakeup( &chan->selinfo );
412 #endif
413
414 chan->waiting = false;
415 cyg_drv_cond_signal( &chan->wait );
416
417 chan->wakeup = false;
418 }
419
420 //==========================================================================
421 // End of adc.c