- Main Page
- Related Pages
- Files

# adc.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: adc.c,v 1.4 2004/03/13 19:55:34 troth Exp $
    00003  *
    00004  ****************************************************************************
    00005  *
    00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
    00007  * Copyright (C) 2003, 2004  Keith Gudger
    00008  *
    00009  * This program is free software; you can redistribute it and/or modify
    00010  * it under the terms of the GNU General Public License as published by
    00011  * the Free Software Foundation; either version 2 of the License, or
    00012  * (at your option) any later version.
    00013  *
    00014  * This program is distributed in the hope that it will be useful,
    00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00017  * GNU General Public License for more details.
    00018  *
    00019  * You should have received a copy of the GNU General Public License
    00020  * along with this program; if not, write to the Free Software
    00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00022  *
    00023  ****************************************************************************
    00024  */
    00025
    00026 /**
    00027  * \file adc.c
    00028  * \brief Module to simulate the AVR's ADC module.
    00029  *
    00030  */
    00031
    00032 #include <config.h>
    00033
    00034 #include <stdio.h>
    00035 #include <stdlib.h>
    00036 #include <string.h>
    00037
    00038 #include "avrerror.h"
    00039 #include "avrmalloc.h"
    00040 #include "avrclass.h"
    00041 #include "utils.h"
    00042 #include "callback.h"
    00043 #include "op_names.h"
    00044
    00045 #include "storage.h"
    00046 #include "flash.h"
    00047
    00048 #include "vdevs.h"
    00049 #include "memory.h"
    00050 #include "stack.h"
    00051 #include "register.h"
    00052 #include "sram.h"
    00053 #include "eeprom.h"
    00054 #include "timers.h"
    00055 #include "ports.h"
    00056 #include "adc.h"
    00057
    00058 #include "avrcore.h"
    00059
    00060 #include "intvects.h"
    00061
    00062 /****************************************************************************\
    00063  *
    00064  * ADC Interrupts
    00065  *
    00066 \****************************************************************************/
    00067
    00068 static void adc_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00069                            void *data);
    00070 static uint8_t adc_intr_read (VDevice *dev, int addr);
    00071 static void adc_intr_write (VDevice *dev, int addr, uint8_t val);
    00072 static void adc_intr_reset (VDevice *dev);
    00073 static int adc_intr_cb (uint64_t time, AvrClass *data);
    00074 static int adc_clk_incr_cb (uint64_t ck, AvrClass *data);
    00075
    00076 /** \brief Allocate a new ADC interrupt */
    00077
    00078 VDevice *
    00079 adc_int_create (int addr, char *name, int rel_addr, void *data)
    00080 {
    00081     return (VDevice *)adc_intr_new (addr, name, rel_addr);
    00082 }
    00083
    00084 ADCIntr_T *
    00085 adc_intr_new (int addr, char *name, int rel_addr)
    00086 {
    00087     ADCIntr_T *adc;
    00088
    00089     adc = avr_new (ADCIntr_T, 1);
    00090     adc_intr_construct (adc, addr, name, rel_addr);
    00091     class_overload_destroy ((AvrClass *)adc, adc_intr_destroy);
    00092
    00093     return adc;
    00094 }
    00095
    00096 /** \brief Constructor for adc interrupt object. */
    00097
    00098 void
    00099 adc_intr_construct (ADCIntr_T *adc, int addr, char *name, int rel_addr)
    00100 {
    00101     if (adc == NULL)
    00102         avr_error ("passed null ptr");
    00103
    00104     vdev_construct ((VDevice *)adc, adc_intr_read, adc_intr_write,
    00105                     adc_intr_reset, adc_iadd_addr);
    00106
    00107     if (rel_addr)
    00108         adc->rel_addr = rel_addr;
    00109     adc_iadd_addr ((VDevice *)adc, addr, name, 0, NULL);
    00110
    00111     adc_intr_reset ((VDevice *)adc);
    00112 }
    00113
    00114 static void
    00115 adc_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
    00116 {
    00117     ADCIntr_T *adc = (ADCIntr_T *)vdev;
    00118
    00119     if (strncmp ("ADCSR", name, 5) == 0)
    00120     {
    00121         adc->adcsr_addr = addr;
    00122     }
    00123
    00124     else if (strncmp ("ADMUX", name, 5) == 0)
    00125     {
    00126         adc->admux_addr = addr;
    00127     }
    00128
    00129     else
    00130     {
    00131         avr_error ("invalid ADC register name: '%s' @ 0x%04x", name, addr);
    00132     }
    00133 }
    00134
    00135 /** \brief Destructor for adc interrupt object. */
    00136
    00137 void
    00138 adc_intr_destroy (void *adc)
    00139 {
    00140     if (adc == NULL)
    00141         return;
    00142
    00143     vdev_destroy (adc);
    00144 }
    00145
    00146 static uint8_t
    00147 adc_intr_read (VDevice *dev, int addr)
    00148 {
    00149     ADCIntr_T *adc = (ADCIntr_T *)dev;
    00150
    00151     if (addr == adc->adcsr_addr)
    00152         return (adc->adcsr);
    00153
    00154     else if (addr == adc->admux_addr)
    00155         return (adc->admux);
    00156
    00157     else
    00158         avr_error ("Bad address: 0x%04x", addr);
    00159
    00160     return 0;                   /* will never get here */
    00161 }
    00162
    00163 static void
    00164 adc_intr_write (VDevice *dev, int addr, uint8_t val)
    00165 {
    00166     ADCIntr_T *adc = (ADCIntr_T *)dev;
    00167     CallBack *cb;
    00168     ADC_T *adc_d;
    00169
    00170     adc_d =
    00171         (ADC_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00172                                             vdev_get_core ((VDevice *)adc),
    00173                                             adc->rel_addr);
    00174
    00175     if (addr == adc->adcsr_addr)
    00176     {
    00177         if (val & mask_ADIF)    /* clears interrupt flag */
    00178             adc->adcsr = val & ~mask_ADIF;
    00179         else
    00180             adc->adcsr = val;
    00181
    00182         if ((val & mask_ADSC) && (val & mask_ADEN))
    00183         {
    00184             if ((adc->intr_cb == NULL))
    00185             {
    00186                 /* we need to install the intr_cb function */
    00187                 cb = callback_new (adc_intr_cb, (AvrClass *)adc);
    00188                 adc->intr_cb = cb;
    00189                 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
    00190             }
    00191             if ((adc_d->clk_cb == NULL))
    00192             {
    00193                 /* we need to install the clk_cb function */
    00194                 cb = callback_new (adc_clk_incr_cb, (AvrClass *)adc_d);
    00195                 adc_d->clk_cb = cb;
    00196                 avr_core_clk_cb_add ((AvrCore *)
    00197                                      vdev_get_core ((VDevice *)adc_d), cb);
    00198             }
    00199             adc_d->adc_count = 13;
    00200             switch ((adc->adcsr) & (mask_ADPS0 | mask_ADPS1 | mask_ADPS2))
    00201             {
    00202                 case ADC_CK_0:
    00203                 case ADC_CK_2:
    00204                     adc_d->divisor = 2;
    00205                     break;
    00206                 case ADC_CK_4:
    00207                     adc_d->divisor = 4;
    00208                     break;
    00209                 case ADC_CK_8:
    00210                     adc_d->divisor = 8;
    00211                     break;
    00212                 case ADC_CK_16:
    00213                     adc_d->divisor = 16;
    00214                     break;
    00215                 case ADC_CK_32:
    00216                     adc_d->divisor = 32;
    00217                     break;
    00218                 case ADC_CK_64:
    00219                     adc_d->divisor = 64;
    00220                     break;
    00221                 case ADC_CK_128:
    00222                     adc_d->divisor = 128;
    00223                     break;
    00224                 default:
    00225                     avr_error ("The impossible happened!");
    00226             }
    00227         }
    00228         else
    00229         {
    00230             adc->intr_cb = NULL; /* no interrupt are enabled, remove
    00231                                     the callback */
    00232         }
    00233     }
    00234
    00235     else if (addr == adc->admux_addr)
    00236     {
    00237         adc->admux = val;
    00238     }
    00239
    00240     else
    00241     {
    00242         avr_error ("Bad address: 0x%04x", addr);
    00243     }
    00244 }
    00245
    00246 static void
    00247 adc_intr_reset (VDevice *dev)
    00248 {
    00249     ADCIntr_T *adc = (ADCIntr_T *)dev;
    00250
    00251     adc->intr_cb = NULL;
    00252
    00253     adc->adcsr = 0;
    00254     adc->admux = 0;
    00255 }
    00256
    00257 static int
    00258 adc_intr_cb (uint64_t time, AvrClass *data)
    00259 {
    00260     ADCIntr_T *adc = (ADCIntr_T *)data;
    00261
    00262     if (adc->intr_cb == NULL)
    00263         return CB_RET_REMOVE;
    00264
    00265     if ((adc->adcsr & mask_ADEN) && (adc->adcsr & mask_ADIE)
    00266         && (adc->adcsr & mask_ADIF))
    00267     {
    00268         /* an enabled interrupt occured */
    00269         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)adc);
    00270         avr_core_irq_raise (core, irq_vect_table_index (ADC));
    00271         adc->adcsr &= ~mask_ADIF;
    00272     }
    00273
    00274     return CB_RET_RETAIN;
    00275 }
    00276
    00277 /****************************************************************************\
    00278  *
    00279  * ADC
    00280  *
    00281 \****************************************************************************/
    00282
    00283 static void adc_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00284                           void *data);
    00285 static uint8_t adc_read (VDevice *dev, int addr);
    00286 static void adc_write (VDevice *dev, int addr, uint8_t val);
    00287 static void adc_reset (VDevice *dev);
    00288
    00289 /** \brief Allocate a new ADC structure. */
    00290
    00291 VDevice *
    00292 adc_create (int addr, char *name, int rel_addr, void *data)
    00293 {
    00294     uint8_t *data_ptr = (uint8_t *) data;
    00295     if (data)
    00296         return (VDevice *)adc_new (addr, name, (uint8_t) * data_ptr,
    00297                                    rel_addr);
    00298     else
    00299         avr_error ("Attempted A/D create with NULL data pointer");
    00300     return 0;
    00301 }
    00302
    00303 ADC_T *
    00304 adc_new (int addr, char *name, uint8_t uier, int rel_addr)
    00305 {
    00306     ADC_T *adc;
    00307
    00308     adc = avr_new (ADC_T, 1);
    00309     adc_construct (adc, addr, name, uier, rel_addr);
    00310     class_overload_destroy ((AvrClass *)adc, adc_destroy);
    00311
    00312     return adc;
    00313 }
    00314
    00315 /** \brief Constructor for ADC object. */
    00316
    00317 void
    00318 adc_construct (ADC_T *adc, int addr, char *name, uint8_t uier, int rel_addr)
    00319 {
    00320     if (adc == NULL)
    00321         avr_error ("passed null ptr");
    00322
    00323     vdev_construct ((VDevice *)adc, adc_read, adc_write, adc_reset,
    00324                     adc_add_addr);
    00325
    00326     if (rel_addr)
    00327         adc->rel_addr = rel_addr;
    00328     adc_add_addr ((VDevice *)adc, addr, name, 0, NULL);
    00329
    00330     adc_reset ((VDevice *)adc);
    00331     adc->u_divisor = uier ? 12 : 1;
    00332 }
    00333 static void
    00334 adc_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
    00335 {
    00336     ADC_T *adc = (ADC_T *)vdev;
    00337
    00338     if (strncmp ("ADCL", name, 4) == 0)
    00339     {
    00340         adc->adcl_addr = addr;
    00341     }
    00342
    00343     else if (strncmp ("ADCH", name, 4) == 0)
    00344     {
    00345         adc->adch_addr = addr;
    00346     }
    00347
    00348     else
    00349     {
    00350         avr_error ("invalid ADC register name: '%s' @ 0x%04x", name, addr);
    00351     }
    00352 }
    00353
    00354 /** \brief Destructor for ADC object. */
    00355
    00356 void
    00357 adc_destroy (void *adc)
    00358 {
    00359     if (adc == NULL)
    00360         return;
    00361
    00362     vdev_destroy (adc);
    00363 }
    00364
    00365 static uint8_t
    00366 adc_read (VDevice *dev, int addr)
    00367 {
    00368     ADC_T *adc = (ADC_T *)dev;
    00369
    00370     if (addr == adc->adcl_addr)
    00371         return adc->adcl;
    00372
    00373     else if (addr == adc->adch_addr)
    00374         return adc->adch;
    00375
    00376     else
    00377         avr_error ("Bad address: 0x%04x", addr);
    00378
    00379     return 0;                   /* will never get here */
    00380 }
    00381
    00382 static void
    00383 adc_write (VDevice *dev, int addr, uint8_t val)
    00384 {
    00385     avr_error ("Bad ADC write address: 0x%04x", addr);
    00386 }
    00387
    00388 static void
    00389 adc_reset (VDevice *dev)
    00390 {
    00391     ADC_T *adc = (ADC_T *)dev;
    00392
    00393     adc->clk_cb = NULL;
    00394
    00395     adc->adcl = 0;
    00396     adc->adch = 0;
    00397
    00398     adc->adc_count = 0;
    00399     adc->adc_in = 0;
    00400     adc->divisor = 0;
    00401 }
    00402
    00403 static int
    00404 adc_clk_incr_cb (uint64_t ck, AvrClass *data)
    00405 {
    00406     ADC_T *adc = (ADC_T *)data;
    00407     uint8_t last = adc->adc_count;
    00408     ADCIntr_T *adc_ti;
    00409
    00410     adc_ti =
    00411         (ADCIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
    00412                                                 vdev_get_core ((VDevice *)
    00413                                                                adc),
    00414                                                 adc->rel_addr);
    00415
    00416     if (adc->clk_cb == NULL)
    00417         return CB_RET_REMOVE;
    00418
    00419     if (adc->divisor <= 0)
    00420         avr_error ("Bad divisor value: %d", adc->divisor);
    00421
    00422     /* decrement clock if ck is a multiple of divisor */
    00423     adc->adc_count -= ((ck % (adc->divisor * adc->u_divisor)) == 0);
    00424
    00425     if (adc->adc_count != last) /* we've changed the counter */
    00426     {
    00427         if (adc->adc_count == 0)
    00428         {
    00429             adc_ti->adcsr |= mask_ADIF;
    00430             adc_ti->adcsr &= ~mask_ADSC;
    00431             adc->adc_in = adc_port_rd (adc_ti->admux);
    00432             adc->adcl = (adc->adc_in) & 0xff; /* update adcl to what we
    00433                                                  read */
    00434             adc->adch = ((adc->adc_in) >> 8) & 0x03; /* update adch */
    00435             if (adc_ti->adcsr & mask_ADFR) /* free running mode */
    00436                 adc->adc_count = 13;
    00437             else
    00438             {
    00439                 adc->clk_cb = NULL;
    00440                 return CB_RET_REMOVE;
    00441             }
    00442         }
    00443     }
    00444     return CB_RET_RETAIN;
    00445 }
    00446
    00447 /* FIXME: TRoth/2003-11-29: These will eventually need to be plugged into an
    00448    external connection interface. */
    00449
    00450 uint16_t
    00451 adc_port_rd (uint8_t mux)
    00452 {
    00453     int data;
    00454     char line[80];
    00455
    00456     while (1)
    00457     {
    00458         fprintf (stderr, "\nEnter data to read into the ADC for channel %d: ",
    00459                  mux);
    00460
    00461         /* try to read in a line of input */
    00462         if (fgets (line, sizeof (line), stdin) == NULL)
    00463             continue;
    00464
    00465         /* try to parse the line for a byte of data */
    00466         if (sscanf (line, "%d\n", &data) != 1)
    00467             continue;
    00468
    00469         break;
    00470     }
    00471     return (uint16_t) (data & 0x3ff);
    00472 }
    00473
    00474 void
    00475 adc_port_wr (uint8_t val)
    00476 {
    00477     fprintf (stderr, "wrote 0x%02x to ADC\n", val);
    00478 }

Automatically generated by Doxygen 1.5.5 on 7 Nov 2008.