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.2 on 1 Dec 2007.