Main Page | File List | Globals | Related Pages

adc.c

Go to the documentation of this file.
00001 /* 00002 * $Id: adc.c,v 1.2 2003/12/01 09:10:13 troth Exp $ 00003 * 00004 **************************************************************************** 00005 * 00006 * simulavr - A simulator for the Atmel AVR family of microcontrollers. 00007 * Copyright (C) 2003 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 00037 #include "avrerror.h" 00038 #include "avrmalloc.h" 00039 #include "avrclass.h" 00040 #include "utils.h" 00041 #include "callback.h" 00042 #include "op_names.h" 00043 00044 #include "storage.h" 00045 #include "flash.h" 00046 00047 #include "vdevs.h" 00048 #include "memory.h" 00049 #include "stack.h" 00050 #include "register.h" 00051 #include "sram.h" 00052 #include "eeprom.h" 00053 #include "timers.h" 00054 #include "ports.h" 00055 #include "adc.h" 00056 00057 #include "avrcore.h" 00058 00059 #include "intvects.h" 00060 00061 /****************************************************************************\ 00062 * 00063 * ADC Interrupts 00064 * 00065 \****************************************************************************/ 00066 00067 static uint8_t adc_intr_read (VDevice *dev, int addr); 00068 static void adc_intr_write (VDevice *dev, int addr, uint8_t val); 00069 static void adc_intr_reset (VDevice *dev); 00070 static char *adc_intr_reg_name (VDevice *dev, int addr); 00071 static int adc_intr_cb (uint64_t time, AvrClass *data); 00072 static int adc_clk_incr_cb (uint64_t ck, AvrClass *data); 00073 00074 /** \brief Allocate a new ADC interrupt */ 00075 00076 ADCIntr_T * 00077 adc_intr_new (uint8_t uier) 00078 { 00079 ADCIntr_T *adc; 00080 00081 adc = avr_new (ADCIntr_T, 1); 00082 adc_intr_construct (adc, uier); 00083 class_overload_destroy ((AvrClass *)adc, adc_intr_destroy); 00084 00085 return adc; 00086 } 00087 00088 /** \brief Constructor for adc interrupt object. */ 00089 00090 void 00091 adc_intr_construct (ADCIntr_T *adc, uint8_t uier) 00092 { 00093 char *name = "ADCIntr"; 00094 00095 if (adc == NULL) 00096 avr_error ("passed null ptr"); 00097 00098 if (uier) 00099 vdev_construct ((VDevice *)adc, name, ADC_INTR_BASE_U, ADC_INTR_SIZE, 00100 adc_intr_read, adc_intr_write, adc_intr_reset, 00101 adc_intr_reg_name); 00102 else 00103 vdev_construct ((VDevice *)adc, name, ADC_INTR_BASE_A, ADC_INTR_SIZE, 00104 adc_intr_read, adc_intr_write, adc_intr_reset, 00105 adc_intr_reg_name); 00106 00107 adc_intr_reset ((VDevice *)adc); 00108 } 00109 00110 /** \brief Destructor for adc interrupt object. */ 00111 00112 void 00113 adc_intr_destroy (void *adc) 00114 { 00115 if (adc == NULL) 00116 return; 00117 00118 vdev_destroy (adc); 00119 } 00120 00121 static uint8_t 00122 adc_intr_read (VDevice *dev, int addr) 00123 { 00124 ADCIntr_T *adc = (ADCIntr_T *)dev; 00125 00126 switch (addr - vdev_get_base (dev)) 00127 { 00128 case ADC_INTR_ADCSR_ADDR: 00129 return (adc->adcsr); 00130 case ADC_INTR_ADMUX_ADDR: 00131 return (adc->admux); 00132 default: 00133 avr_error ("Bad address: 0x%04x", addr); 00134 } 00135 return 0; /* will never get here */ 00136 } 00137 00138 static void 00139 adc_intr_write (VDevice *dev, int addr, uint8_t val) 00140 { 00141 ADCIntr_T *adc = (ADCIntr_T *)dev; 00142 CallBack *cb; 00143 ADC_T *adc_d; 00144 00145 adc_d = 00146 (ADC_T *)avr_core_get_vdev_by_name ((AvrCore *) 00147 vdev_get_core ((VDevice *)adc), 00148 "ADC"); 00149 00150 switch (addr - vdev_get_base (dev)) 00151 { 00152 case ADC_INTR_ADCSR_ADDR: 00153 if (val & mask_ADIF) /* clears interrupt flag */ 00154 adc->adcsr = val & ~mask_ADIF; 00155 else 00156 adc->adcsr = val; 00157 00158 if ((val & mask_ADSC) && (val & mask_ADEN)) 00159 { 00160 if ((adc->intr_cb == NULL)) 00161 { 00162 /* we need to install the intr_cb function */ 00163 cb = callback_new (adc_intr_cb, (AvrClass *)adc); 00164 adc->intr_cb = cb; 00165 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), 00166 cb); 00167 } 00168 if ((adc_d->clk_cb == NULL)) 00169 { 00170 /* we need to install the clk_cb function */ 00171 cb = callback_new (adc_clk_incr_cb, (AvrClass *)adc_d); 00172 adc_d->clk_cb = cb; 00173 avr_core_clk_cb_add ((AvrCore *)vdev_get_core (dev), cb); 00174 } 00175 adc_d->adc_count = 13; 00176 switch ((adc->adcsr) & (mask_ADPS0 | mask_ADPS1 | mask_ADPS2)) 00177 { 00178 case ADC_CK_0: 00179 case ADC_CK_2: 00180 adc_d->divisor = 2; 00181 break; 00182 case ADC_CK_4: 00183 adc_d->divisor = 4; 00184 break; 00185 case ADC_CK_8: 00186 adc_d->divisor = 8; 00187 break; 00188 case ADC_CK_16: 00189 adc_d->divisor = 16; 00190 break; 00191 case ADC_CK_32: 00192 adc_d->divisor = 32; 00193 break; 00194 case ADC_CK_64: 00195 adc_d->divisor = 64; 00196 break; 00197 case ADC_CK_128: 00198 adc_d->divisor = 128; 00199 break; 00200 default: 00201 avr_error ("The impossible happened!"); 00202 } 00203 } 00204 else 00205 { 00206 adc->intr_cb = NULL; /* no interrupt are enabled, remove 00207 the callback */ 00208 } 00209 break; 00210 case ADC_INTR_ADMUX_ADDR: 00211 adc->admux = val; 00212 break; 00213 default: 00214 avr_error ("Bad address: 0x%04x", addr); 00215 } 00216 } 00217 00218 static void 00219 adc_intr_reset (VDevice *dev) 00220 { 00221 ADCIntr_T *adc = (ADCIntr_T *)dev; 00222 00223 adc->intr_cb = NULL; 00224 00225 adc->adcsr = 0; 00226 adc->admux = 0; 00227 } 00228 00229 static char * 00230 adc_intr_reg_name (VDevice *dev, int addr) 00231 { 00232 switch (addr - vdev_get_base (dev)) 00233 { 00234 case ADC_INTR_ADCSR_ADDR: 00235 return ("ADSCR"); 00236 case ADC_INTR_ADMUX_ADDR: 00237 return ("ADMUX"); 00238 default: 00239 avr_error ("Bad address: 0x%04x", addr); 00240 } 00241 return NULL; /* will never get here */ 00242 } 00243 00244 static int 00245 adc_intr_cb (uint64_t time, AvrClass *data) 00246 { 00247 ADCIntr_T *adc = (ADCIntr_T *)data; 00248 00249 if (adc->intr_cb == NULL) 00250 return CB_RET_REMOVE; 00251 00252 if ((adc->adcsr & mask_ADEN) && (adc->adcsr & mask_ADIE) 00253 && (adc->adcsr & mask_ADIF)) 00254 { 00255 /* an enabled interrupt occured */ 00256 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)adc); 00257 avr_core_irq_raise (core, irq_vect_table_index (ADC)); 00258 adc->adcsr &= ~mask_ADIF; 00259 } 00260 00261 return CB_RET_RETAIN; 00262 } 00263 00264 /****************************************************************************\ 00265 * 00266 * ADC 00267 * 00268 \****************************************************************************/ 00269 00270 static uint8_t adc_read (VDevice *dev, int addr); 00271 static void adc_write (VDevice *dev, int addr, uint8_t val); 00272 static void adc_reset (VDevice *dev); 00273 static char *adc_reg_name (VDevice *dev, int addr); 00274 00275 /** \brief Allocate a new ADC structure. */ 00276 00277 ADC_T * 00278 adc_new (uint8_t uier) 00279 { 00280 ADC_T *adc; 00281 00282 adc = avr_new (ADC_T, 1); 00283 adc_construct (adc, uier); 00284 class_overload_destroy ((AvrClass *)adc, adc_destroy); 00285 00286 return adc; 00287 } 00288 00289 /** \brief Constructor for ADC object. */ 00290 00291 void 00292 adc_construct (ADC_T *adc, uint8_t uier) 00293 { 00294 char *name = "ADC"; 00295 00296 if (adc == NULL) 00297 avr_error ("passed null ptr"); 00298 00299 if (uier) 00300 vdev_construct ((VDevice *)adc, name, ADC_BASE_U, ADC_SIZE, adc_read, 00301 adc_write, adc_reset, adc_reg_name); 00302 else 00303 vdev_construct ((VDevice *)adc, name, ADC_BASE_A, ADC_SIZE, adc_read, 00304 adc_write, adc_reset, adc_reg_name); 00305 00306 adc_reset ((VDevice *)adc); 00307 adc->u_divisor = uier ? 12 : 1; 00308 } 00309 00310 /** \brief Destructor for ADC object. */ 00311 00312 void 00313 adc_destroy (void *adc) 00314 { 00315 if (adc == NULL) 00316 return; 00317 00318 vdev_destroy (adc); 00319 } 00320 00321 static uint8_t 00322 adc_read (VDevice *dev, int addr) 00323 { 00324 ADC_T *adc = (ADC_T *)dev; 00325 00326 switch (addr - vdev_get_base (dev)) 00327 { 00328 case ADC_ADCL_ADDR: 00329 return adc->adcl; 00330 case ADC_ADCH_ADDR: 00331 return adc->adch; 00332 default: 00333 avr_error ("Bad address: 0x%04x", addr); 00334 } 00335 return 0; /* will never get here */ 00336 } 00337 00338 static void 00339 adc_write (VDevice *dev, int addr, uint8_t val) 00340 { 00341 avr_error ("Bad ADC write address: 0x%04x", addr); 00342 } 00343 00344 static void 00345 adc_reset (VDevice *dev) 00346 { 00347 ADC_T *adc = (ADC_T *)dev; 00348 00349 adc->clk_cb = NULL; 00350 00351 adc->adcl = 0; 00352 adc->adch = 0; 00353 adc->adc_count = 0; 00354 adc->adc_in = 0; 00355 adc->divisor = 0; 00356 } 00357 00358 static char * 00359 adc_reg_name (VDevice *dev, int addr) 00360 { 00361 switch (addr - vdev_get_base (dev)) 00362 { 00363 case ADC_ADCL_ADDR: 00364 return "ADCL"; 00365 case ADC_ADCH_ADDR: 00366 return "ADCH"; 00367 default: 00368 avr_error ("Bad address: 0x%04x", addr); 00369 } 00370 return NULL; 00371 } 00372 00373 static int 00374 adc_clk_incr_cb (uint64_t ck, AvrClass *data) 00375 { 00376 ADC_T *adc = (ADC_T *)data; 00377 uint8_t last = adc->adc_count; 00378 ADCIntr_T *adc_ti; 00379 00380 adc_ti = 00381 (ADCIntr_T *)avr_core_get_vdev_by_name ((AvrCore *) 00382 vdev_get_core ((VDevice *) 00383 adc), 00384 "ADCIntr"); 00385 00386 if (adc->clk_cb == NULL) 00387 return CB_RET_REMOVE; 00388 00389 if (adc->divisor <= 0) 00390 avr_error ("Bad divisor value: %d", adc->divisor); 00391 00392 /* decrement clock if ck is a multiple of divisor */ 00393 adc->adc_count -= ((ck % (adc->divisor * adc->u_divisor)) == 0); 00394 00395 if (adc->adc_count != last) /* we've changed the counter */ 00396 { 00397 if (adc->adc_count == 0) 00398 { 00399 adc_ti->adcsr |= mask_ADIF; 00400 adc_ti->adcsr &= ~mask_ADSC; 00401 adc->adc_in = adc_port_rd (adc_ti->admux); 00402 adc->adcl = (adc->adc_in) & 0xff; /* update adcl to what we 00403 read */ 00404 adc->adch = ((adc->adc_in) >> 8) & 0x03; /* update adch */ 00405 if (adc_ti->adcsr & mask_ADFR) /* free running mode */ 00406 adc->adc_count = 13; 00407 else 00408 { 00409 adc->clk_cb = NULL; 00410 return CB_RET_REMOVE; 00411 } 00412 } 00413 } 00414 return CB_RET_RETAIN; 00415 } 00416 00417 /* FIXME: TRoth/2003-11-29: These will eventually need to be plugged into an 00418 external connection interface. */ 00419 00420 uint16_t 00421 adc_port_rd (uint8_t mux) 00422 { 00423 int data; 00424 char line[80]; 00425 00426 while (1) 00427 { 00428 fprintf (stderr, "\nEnter data to read into the ADC for channel %d: ", 00429 mux); 00430 00431 /* try to read in a line of input */ 00432 if (fgets (line, sizeof (line), stdin) == NULL) 00433 continue; 00434 00435 /* try to parse the line for a byte of data */ 00436 if (sscanf (line, "%d\n", &data) != 1) 00437 continue; 00438 00439 break; 00440 } 00441 return (uint16_t) (data & 0x3ff); 00442 } 00443 00444 void 00445 adc_port_wr (uint8_t val) 00446 { 00447 fprintf (stderr, "wrote 0x%02x to ADC\n", val); 00448 }

Automatically generated by Doxygen 1.3.8 on 11 Aug 2004.