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