OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [adc/] [arm/] [lpc24xx/] [current/] [src/] [adc_lpc24xx.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      adc_lpc24xx.c
4
//
5
//      ADC driver for LPC24xx on chip ADC
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2008 Free Software Foundation, Inc.                        
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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    Uwe Kindler <uwe_kindler@web.de>
43
// Contributors:
44
// Date:         2008-09-21
45
// Purpose:
46
// Description:
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
 
53
//==========================================================================
54
//                                 INCLUDES
55
//==========================================================================
56
#include <pkgconf/system.h>
57
#include <pkgconf/devs_adc_arm_lpc24xx.h>
58
 
59
#include <cyg/infra/cyg_type.h>
60
#include <cyg/infra/cyg_ass.h>
61
#include <cyg/infra/diag.h>
62
#include <cyg/io/adc.h>
63
#include <cyg/hal/hal_arch.h>
64
#include <cyg/hal/hal_io.h>
65
#include <cyg/hal/hal_intr.h>
66
#include <cyg/hal/drv_api.h>
67
 
68
 
69
 
70
//==========================================================================
71
//                                DEFINES
72
//==========================================================================
73
 
74
//--------------------------------------------------------------------------
75
// Register definition
76
//
77
#define ADC_BASE        CYGARC_HAL_LPC24XX_REG_AD_BASE
78
#define ADC_CR         (ADC_BASE + 0x0000)
79
#define ADC_GDR        (ADC_BASE + 0x0004)
80
#define ADC_INTEN      (ADC_BASE + 0x000C)
81
#define ADC_DR(_chan_) (ADC_BASE + 0x0010 + ((_chan_) << 2))
82
#define ADC_STAT       (ADC_BASE + 0x0030)
83
 
84
#define DR_OVR         (0x01 << 30)
85
#define DR_DONE        (0x01 << 31)
86
#define CR_BURST       (0x01 << 16)
87
#define CR_PDN         (0x01 << 21)
88
 
89
 
90
#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
91
   #define debug1_printf(args...) diag_printf(args)
92
#else
93
   #define debug1_printf(args...)
94
#endif
95
 
96
#define LPC2XXX_CHAN_CNT 8 // maximum number of channels for LPC2xxx device
97
 
98
 
99
//==========================================================================
100
//                                  DATA TYPES
101
//==========================================================================
102
typedef struct lpc2xxx_adc_info
103
{
104
    cyg_uint32              base;       // base address of ADC peripheral
105
    cyg_vector_t            vector;     // interrupt vector number
106
    int                     intprio;    // interrupt priority of ADC interrupt
107
    cyg_handle_t            int_handle; // For initializing the interrupt
108
    cyg_interrupt           int_data;
109
    struct cyg_adc_channel* channel[LPC2XXX_CHAN_CNT]; // stores references to 
110
                                                       // channel objects
111
#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
112
    cyg_uint32              isr_cnt;     // number of ISR = number of samples
113
    cyg_uint32              zero_time;
114
#endif // CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
115
    cyg_uint8               chan_mask;  // mask that indicates channels used 
116
                                        // by ADC driver
117
} lpc2xxx_adc_info;
118
 
119
 
120
//==========================================================================
121
//                               DECLARATIONS
122
//==========================================================================
123
static bool lpc2xxx_adc_init(struct cyg_devtab_entry *tab);
124
static Cyg_ErrNo lpc2xxx_adc_lookup(struct cyg_devtab_entry **tab,
125
                                    struct cyg_devtab_entry  *sub_tab,
126
                                    const char               *name);
127
static void lpc2xxx_adc_enable( cyg_adc_channel *chan );
128
static void lpc2xxx_adc_disable( cyg_adc_channel *chan );
129
static void lpc2xxx_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate );
130
static cyg_uint32 lpc2xxx_adc_isr(cyg_vector_t vector, cyg_addrword_t data);
131
static void lpc2xxx_adc_dsr(cyg_vector_t vector,
132
                            cyg_ucount32 count,
133
                            cyg_addrword_t data);
134
 
135
 
136
//==========================================================================
137
// Instantiate data structures
138
 
139
// -------------------------------------------------------------------------
140
// Driver functions:
141
CYG_ADC_FUNCTIONS( lpc2xxx_adc_funs,
142
                   lpc2xxx_adc_enable,
143
                   lpc2xxx_adc_disable,
144
                   lpc2xxx_adc_set_rate );
145
 
146
// -------------------------------------------------------------------------
147
// Device instance:
148
static lpc2xxx_adc_info lpc2xxx_adc_info0 =
149
{
150
    .base               = CYGARC_HAL_LPC2XXX_REG_AD_BASE,
151
    .vector             = CYGNUM_HAL_INTERRUPT_TIMER1,
152
    .intprio            = CYGNUM_DEVS_ADC_ARM_LPC24XX_INTPRIO,
153
    .int_handle         = 0,
154
#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
155
    .isr_cnt            = 0,
156
#endif
157
    .chan_mask          = 0
158
};
159
 
160
CYG_ADC_DEVICE( lpc2xxx_adc_device,
161
                &lpc2xxx_adc_funs,
162
                &lpc2xxx_adc_info0,
163
                CYGNUM_DEVS_ADC_ARM_LPC24XX_DEFAULT_RATE);
164
 
165
// -------------------------------------------------------------------------
166
// Channel instances:
167
 
168
#define LPC2XXX_ADC_CHANNEL( __chan )                                    \
169
CYG_ADC_CHANNEL( lpc2xxx_adc_channel##__chan,                            \
170
                 __chan,                                                 \
171
                 CYGDAT_DEVS_ADC_ARM_LPC24XX_CHANNEL##__chan##_BUFSIZE,  \
172
                 &lpc2xxx_adc_device );                                  \
173
                                                                         \
174
DEVTAB_ENTRY( lpc2xxx_adc_channel##__chan##_device,                      \
175
              CYGDAT_DEVS_ADC_ARM_LPC24XX_CHANNEL##__chan##_NAME,        \
176
              0,                                                         \
177
              &cyg_io_adc_devio,                                         \
178
              lpc2xxx_adc_init,                                          \
179
              lpc2xxx_adc_lookup,                                        \
180
              &lpc2xxx_adc_channel##__chan );
181
 
182
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL0
183
LPC2XXX_ADC_CHANNEL(0);
184
#endif
185
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL1
186
LPC2XXX_ADC_CHANNEL(1);
187
#endif
188
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL2
189
LPC2XXX_ADC_CHANNEL(2);
190
#endif
191
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL3
192
LPC2XXX_ADC_CHANNEL(3);
193
#endif
194
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL4
195
LPC2XXX_ADC_CHANNEL(4);
196
#endif
197
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL5
198
LPC2XXX_ADC_CHANNEL(5);
199
#endif
200
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL6
201
LPC2XXX_ADC_CHANNEL(6);
202
#endif
203
#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX_CHANNEL7
204
LPC2XXX_ADC_CHANNEL(7);
205
#endif
206
 
207
//==========================================================================
208
// This function is called from the device IO infrastructure to initialize
209
// the device. It should perform any work needed to start up the device,
210
// short of actually starting the generation of samples. This function will
211
// be called for each channel, so if there is initialization that only needs
212
// to be done once, such as creating and interrupt object, then care should
213
// be taken to do this. This function should also call cyg_adc_device_init()
214
// to initialize the generic parts of the driver.
215
//==========================================================================
216
static bool lpc2xxx_adc_init(struct cyg_devtab_entry *tab)
217
{
218
    cyg_adc_channel  *chan   = (cyg_adc_channel *)tab->priv;
219
    cyg_adc_device   *device = chan->device;
220
    lpc2xxx_adc_info *info   = device->dev_priv;
221
 
222
    if (!info->int_handle)
223
    {
224
        cyg_drv_interrupt_create(info->vector,
225
                                 info->intprio,
226
                                (cyg_addrword_t)device,
227
                                &lpc2xxx_adc_isr,
228
                                &lpc2xxx_adc_dsr,
229
                                &(info->int_handle),
230
                                &(info->int_data));
231
        cyg_drv_interrupt_attach(info->int_handle);
232
        cyg_drv_interrupt_unmask(info->vector);
233
 
234
        //
235
        // The APB clock (PCLK) is divided by (this value plus one) to produce
236
        // the clock for the A/D converter, which should be less than or equal
237
        // to 4.5 MHz. Typically, software should program the smallest value in
238
        // this field that yields a clock of 4.5 MHz or slightly less, but in
239
        // certain cases (such as a high-impedance analog source) a slower
240
        // clock may be desirable.
241
        // Set clock division factor so ADC clock is <= 4.5 MHz
242
        //
243
        cyg_uint8 clkdiv = CYGNUM_HAL_ARM_LPC24XX_ADC_CLK / 4500001;
244
 
245
        //
246
        // Enable A/D converter and setup the configured sample size
247
        // The eCos ADC I/O manual says: Channels are initialized in a disabled
248
        // state and generate no samples - let's do this now
249
        // We initialize the device to operate in burst mode and we enable
250
        // conversion for all channels here
251
        //
252
        HAL_WRITE_UINT32(ADC_INTEN, 0);         // disables all interrupts
253
        HAL_WRITE_UINT32(ADC_CR, CR_BURST       // burst mode
254
                               | CR_PDN         // A/D converter is operational
255
                               | 0xFF           // enable all channels
256
                               | ((10 - CYGNUM_IO_ADC_SAMPLE_SIZE) << 17)
257
                               | (clkdiv << 8));// set clock divider
258
 
259
        //
260
        // setup the default sample rate
261
        //
262
        lpc2xxx_adc_set_rate(chan, chan->device->config.rate);
263
    } // if (!info->int_handle)
264
 
265
    cyg_adc_device_init(device); // initialize generic parts of driver
266
    return true;
267
}
268
 
269
 
270
//==========================================================================
271
// This function is called when a client looks up or opens a channel. It
272
// should call cyg_adc_channel_init() to initialize the generic part of
273
// the channel. It should also perform any operations needed to start the
274
// channel generating samples.
275
//==========================================================================
276
static Cyg_ErrNo lpc2xxx_adc_lookup(struct cyg_devtab_entry **tab,
277
                                    struct cyg_devtab_entry  *sub_tab,
278
                                    const char               *name)
279
{
280
    typedef struct adc_pin_cfg_st
281
    {
282
        cyg_uint8 port;
283
        cyg_uint8 pin;
284
        cyg_uint8 func;
285
    } adc_pin_cfg_t;
286
    static const adc_pin_cfg_t acd_pin_cfg_tbl[] =
287
    {
288
        {0, 23, 1},
289
        {0, 24, 1},
290
        {0, 25, 1},
291
        {0, 26, 1},
292
        {1, 30, 3},
293
        {1, 31, 3},
294
        {0, 12, 3},
295
        {0, 13, 3},
296
    };
297
    cyg_adc_channel  *chan     = (cyg_adc_channel *)(*tab)->priv;
298
    lpc2xxx_adc_info *info     = chan->device->dev_priv;
299
    adc_pin_cfg_t    *pin_cfg  = (adc_pin_cfg_t *)&acd_pin_cfg_tbl[chan->channel];
300
 
301
    //
302
    // This ADC driver is quite LP24xx specific. The pin function of each pin
303
    // is well defined in the LP24xx specification. Therefore we can setup
304
    // the pin function here. If someone decides that this driver can be used 
305
    // by other LPC2xxx or LPC3xxx variants too and that the driver should 
306
    // become more generic, then we might need to move the pin configuration 
307
    // out of this driver an into the variant / platform HAL
308
    //
309
    CYG_HAL_ARM_LPC24XX_PIN_CFG(pin_cfg->port, pin_cfg->pin, pin_cfg->func);
310
    info->channel[chan->channel] = chan;
311
    cyg_adc_channel_init(chan); // initialize generic parts of channel
312
 
313
    //
314
    // The generic ADC manual says: When a channel is first looked up or 
315
    // opened, then it is automatically enabled and samples start to
316
    // accumulate - so we start the channel now
317
    //
318
    chan->enabled = true;
319
    lpc2xxx_adc_enable(chan);
320
 
321
    return ENOERR;
322
}
323
 
324
 
325
//==========================================================================
326
// This function is called from the generic ADC package to enable the
327
// channel in response to a CYG_IO_SET_CONFIG_ADC_ENABLE config operation.
328
// It should take any steps needed to start the channel generating samples
329
//==========================================================================
330
static void lpc2xxx_adc_enable(cyg_adc_channel *chan)
331
{
332
    cyg_uint32        regval;
333
    lpc2xxx_adc_info *info      = chan->device->dev_priv;
334
 
335
    //
336
    // Enable interrupts for timer to start generation of samples in timer
337
    // ISR if this is the first channel that is enabled. If there are
338
    // already some channels enabled, then the interrupt is already enabled
339
    //
340
    if (!info->chan_mask)
341
    {
342
        HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
343
                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
344
#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 0
345
        info->zero_time = cyg_current_time() * 10;
346
#endif
347
        regval |= CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT;
348
        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
349
                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
350
    }
351
 
352
    info->chan_mask |= (0x01 << chan->channel);
353
}
354
 
355
 
356
//==========================================================================
357
// This function is called from the generic ADC package to enable the
358
// channel in response to a CYG_IO_SET_CONFIG_ADC_DISABLE config operation.
359
// It should take any steps needed to stop the channel generating samples.
360
//==========================================================================
361
static void lpc2xxx_adc_disable(cyg_adc_channel *chan)
362
{
363
    cyg_uint32        regval;
364
    lpc2xxx_adc_info *info  = chan->device->dev_priv;
365
 
366
    info->chan_mask &= ~(0x01 << chan->channel);
367
 
368
    //
369
    // If no channel is enabled the we disable interrupts now
370
    //
371
    if (!info->chan_mask)
372
    {
373
        HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
374
                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
375
        regval &= ~CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT;
376
        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
377
                        CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
378
    }
379
}
380
 
381
 
382
//==========================================================================
383
// This function is called from the generic ADC package to enable the
384
// channel in response to a CYG_IO_SET_CONFIG_ADC_RATE config operation.
385
// It should take any steps needed to change the sample rate of the channel,
386
// or of the entire device.
387
// We use a timer channel to generate the interrupts for sampling the
388
// analog channels
389
//==========================================================================
390
static void lpc2xxx_adc_set_rate( cyg_adc_channel *chan, cyg_uint32 rate)
391
{
392
    cyg_adc_device   *device = chan->device;
393
    cyg_uint32        regval;
394
 
395
    cyg_uint32 tmr_period = hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER1) /
396
                            rate;
397
    device->config.rate = rate;
398
 
399
    //
400
    // Disable and reset counter, set prescale register to 0 and
401
    // Set up match register
402
    //
403
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
404
                     CYGARC_HAL_LPC24XX_REG_TxTCR,
405
                     CYGARC_HAL_LPC24XX_REG_TxTCR_CTR_RESET);
406
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
407
                     CYGARC_HAL_LPC24XX_REG_TxPR, 0);
408
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
409
                     CYGARC_HAL_LPC24XX_REG_TxMR0, tmr_period);
410
    //
411
    // Reset on match and Enable counter
412
    //
413
    HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
414
                    CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
415
    regval |= CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET; // reset on match
416
    regval &= ~CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_STOP; // do not stop on match
417
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
418
                     CYGARC_HAL_LPC24XX_REG_TxMCR, regval);
419
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
420
                     CYGARC_HAL_LPC24XX_REG_TxTCR,
421
                     CYGARC_HAL_LPC24XX_REG_TxTCR_CTR_ENABLE);
422
}
423
 
424
 
425
//==========================================================================
426
// This function is the ISR attached to the ADC device's interrupt vector.
427
// It is responsible for reading samples from the channels and passing them
428
// on to the generic layer. It needs to check each channel for data, and call
429
// cyg_adc_receive_sample() for each new sample available, and then ready the
430
// device for the next interrupt.
431
//==========================================================================
432
static cyg_uint32 lpc2xxx_adc_isr(cyg_vector_t vector, cyg_addrword_t data)
433
{
434
    cyg_adc_device   *device = (cyg_adc_device *) data;
435
    lpc2xxx_adc_info *info   = (lpc2xxx_adc_info *)device->dev_priv;
436
    cyg_uint32        regval;
437
    cyg_uint32        res = 0;
438
    cyg_adc_sample_t  adcdata;
439
 
440
#if CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
441
    //
442
    // Print debug information for channel 1 - this is the channel that
443
    // triggers the interrupt and that is used for measuring lost samples
444
    //
445
    if (!(++info->isr_cnt % device->config.rate))
446
    {
447
        cyg_uint32 current_time_ms = cyg_current_time() * 10;
448
        debug1_printf("ms %d smpl. %d\n",
449
                      current_time_ms - info->zero_time, info->isr_cnt);
450
        info->zero_time = current_time_ms;
451
    } // if (!(info->isr_count % device->config.rate))
452
#endif // CYGPKG_DEVS_ADC_ARM_LPC24XX_DEBUG_LEVEL > 1
453
 
454
    cyg_uint8 active_channels = info->chan_mask;
455
    cyg_uint8 channel_no = 0;
456
    while (active_channels)
457
    {
458
        if (active_channels & 0x01)
459
        {
460
            HAL_READ_UINT32(ADC_DR(channel_no), regval);
461
            adcdata = (regval >> 6) & 0x3FF;
462
            res |= CYG_ISR_HANDLED
463
                |  cyg_adc_receive_sample(info->channel[channel_no],
464
                                          adcdata);
465
        } // if (active_channels & 0x01)
466
        active_channels >>= 1;
467
        channel_no++;
468
    } // while (active_channels)
469
 
470
    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER1_BASE +
471
                     CYGARC_HAL_LPC24XX_REG_TxIR,
472
                     CYGARC_HAL_LPC24XX_REG_TxIR_MR0);  // Clear interrupt
473
    cyg_drv_interrupt_acknowledge(info->vector);
474
    return res;
475
}
476
 
477
 
478
//==========================================================================
479
// This function is the DSR attached to the ADC device's interrupt vector.
480
// It is called by the kernel if the ISR return value contains the
481
// CYG_ISR_HANDLED bit. It needs to call cyg_adc_wakeup() for each channel
482
// that has its wakeup field set.
483
//==========================================================================
484
static void lpc2xxx_adc_dsr(cyg_vector_t vector,
485
                            cyg_ucount32 count,
486
                            cyg_addrword_t data)
487
{
488
    cyg_adc_device   *device          = (cyg_adc_device *) data;
489
    lpc2xxx_adc_info *info            = device->dev_priv;
490
    cyg_uint8         active_channels = info->chan_mask;
491
    cyg_uint8         chan_no         = 0;
492
 
493
    while (active_channels)
494
    {
495
        if (active_channels & 0x01)
496
        {
497
            if(info->channel[chan_no]->wakeup)
498
            {
499
                cyg_adc_wakeup(info->channel[chan_no]);
500
            }
501
        }
502
        chan_no++;
503
        active_channels >>= 1;
504
    }
505
}
506
 
507
 
508
//---------------------------------------------------------------------------
509
// eof adc_lpc24xx.c

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.