adc.c
Go to the documentation of this file.
1 /*
2  * $Id: adc.c,v 1.4 2004/03/13 19:55:34 troth Exp $
3  *
4  ****************************************************************************
5  *
6  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7  * Copyright (C) 2003, 2004 Keith Gudger
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  ****************************************************************************
24  */
25 
26 /**
27  * \file adc.c
28  * \brief Module to simulate the AVR's ADC module.
29  *
30  */
31 
32 #include <config.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "avrerror.h"
39 #include "avrmalloc.h"
40 #include "avrclass.h"
41 #include "utils.h"
42 #include "callback.h"
43 #include "op_names.h"
44 
45 #include "storage.h"
46 #include "flash.h"
47 
48 #include "vdevs.h"
49 #include "memory.h"
50 #include "stack.h"
51 #include "register.h"
52 #include "sram.h"
53 #include "eeprom.h"
54 #include "timers.h"
55 #include "ports.h"
56 #include "adc.h"
57 
58 #include "avrcore.h"
59 
60 #include "intvects.h"
61 
62 /****************************************************************************\
63  *
64  * ADC Interrupts
65  *
66 \****************************************************************************/
67 
68 static void adc_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
69  void *data);
70 static uint8_t adc_intr_read (VDevice *dev, int addr);
71 static void adc_intr_write (VDevice *dev, int addr, uint8_t val);
72 static void adc_intr_reset (VDevice *dev);
73 static int adc_intr_cb (uint64_t time, AvrClass *data);
74 static int adc_clk_incr_cb (uint64_t ck, AvrClass *data);
75 
76 /** \brief Allocate a new ADC interrupt */
77 
78 VDevice *
79 adc_int_create (int addr, char *name, int rel_addr, void *data)
80 {
81  return (VDevice *)adc_intr_new (addr, name, rel_addr);
82 }
83 
84 ADCIntr_T *
85 adc_intr_new (int addr, char *name, int rel_addr)
86 {
87  ADCIntr_T *adc;
88 
89  adc = avr_new (ADCIntr_T, 1);
90  adc_intr_construct (adc, addr, name, rel_addr);
91  class_overload_destroy ((AvrClass *)adc, adc_intr_destroy);
92 
93  return adc;
94 }
95 
96 /** \brief Constructor for adc interrupt object. */
97 
98 void
99 adc_intr_construct (ADCIntr_T *adc, int addr, char *name, int rel_addr)
100 {
101  if (adc == NULL)
102  avr_error ("passed null ptr");
103 
104  vdev_construct ((VDevice *)adc, adc_intr_read, adc_intr_write,
105  adc_intr_reset, adc_iadd_addr);
106 
107  if (rel_addr)
108  adc->rel_addr = rel_addr;
109  adc_iadd_addr ((VDevice *)adc, addr, name, 0, NULL);
110 
111  adc_intr_reset ((VDevice *)adc);
112 }
113 
114 static void
115 adc_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
116 {
117  ADCIntr_T *adc = (ADCIntr_T *)vdev;
118 
119  if (strncmp ("ADCSR", name, 5) == 0)
120  {
121  adc->adcsr_addr = addr;
122  }
123 
124  else if (strncmp ("ADMUX", name, 5) == 0)
125  {
126  adc->admux_addr = addr;
127  }
128 
129  else
130  {
131  avr_error ("invalid ADC register name: '%s' @ 0x%04x", name, addr);
132  }
133 }
134 
135 /** \brief Destructor for adc interrupt object. */
136 
137 void
138 adc_intr_destroy (void *adc)
139 {
140  if (adc == NULL)
141  return;
142 
143  vdev_destroy (adc);
144 }
145 
146 static uint8_t
147 adc_intr_read (VDevice *dev, int addr)
148 {
149  ADCIntr_T *adc = (ADCIntr_T *)dev;
150 
151  if (addr == adc->adcsr_addr)
152  return (adc->adcsr);
153 
154  else if (addr == adc->admux_addr)
155  return (adc->admux);
156 
157  else
158  avr_error ("Bad address: 0x%04x", addr);
159 
160  return 0; /* will never get here */
161 }
162 
163 static void
164 adc_intr_write (VDevice *dev, int addr, uint8_t val)
165 {
166  ADCIntr_T *adc = (ADCIntr_T *)dev;
167  CallBack *cb;
168  ADC_T *adc_d;
169 
170  adc_d =
171  (ADC_T *)avr_core_get_vdev_by_addr ((AvrCore *)
172  vdev_get_core ((VDevice *)adc),
173  adc->rel_addr);
174 
175  if (addr == adc->adcsr_addr)
176  {
177  if (val & mask_ADIF) /* clears interrupt flag */
178  adc->adcsr = val & ~mask_ADIF;
179  else
180  adc->adcsr = val;
181 
182  if ((val & mask_ADSC) && (val & mask_ADEN))
183  {
184  if ((adc->intr_cb == NULL))
185  {
186  /* we need to install the intr_cb function */
187  cb = callback_new (adc_intr_cb, (AvrClass *)adc);
188  adc->intr_cb = cb;
189  avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
190  }
191  if ((adc_d->clk_cb == NULL))
192  {
193  /* we need to install the clk_cb function */
194  cb = callback_new (adc_clk_incr_cb, (AvrClass *)adc_d);
195  adc_d->clk_cb = cb;
196  avr_core_clk_cb_add ((AvrCore *)
197  vdev_get_core ((VDevice *)adc_d), cb);
198  }
199  adc_d->adc_count = 13;
200  switch ((adc->adcsr) & (mask_ADPS0 | mask_ADPS1 | mask_ADPS2))
201  {
202  case ADC_CK_0:
203  case ADC_CK_2:
204  adc_d->divisor = 2;
205  break;
206  case ADC_CK_4:
207  adc_d->divisor = 4;
208  break;
209  case ADC_CK_8:
210  adc_d->divisor = 8;
211  break;
212  case ADC_CK_16:
213  adc_d->divisor = 16;
214  break;
215  case ADC_CK_32:
216  adc_d->divisor = 32;
217  break;
218  case ADC_CK_64:
219  adc_d->divisor = 64;
220  break;
221  case ADC_CK_128:
222  adc_d->divisor = 128;
223  break;
224  default:
225  avr_error ("The impossible happened!");
226  }
227  }
228  else
229  {
230  adc->intr_cb = NULL; /* no interrupt are enabled, remove
231  the callback */
232  }
233  }
234 
235  else if (addr == adc->admux_addr)
236  {
237  adc->admux = val;
238  }
239 
240  else
241  {
242  avr_error ("Bad address: 0x%04x", addr);
243  }
244 }
245 
246 static void
247 adc_intr_reset (VDevice *dev)
248 {
249  ADCIntr_T *adc = (ADCIntr_T *)dev;
250 
251  adc->intr_cb = NULL;
252 
253  adc->adcsr = 0;
254  adc->admux = 0;
255 }
256 
257 static int
258 adc_intr_cb (uint64_t time, AvrClass *data)
259 {
260  ADCIntr_T *adc = (ADCIntr_T *)data;
261 
262  if (adc->intr_cb == NULL)
263  return CB_RET_REMOVE;
264 
265  if ((adc->adcsr & mask_ADEN) && (adc->adcsr & mask_ADIE)
266  && (adc->adcsr & mask_ADIF))
267  {
268  /* an enabled interrupt occured */
269  AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)adc);
270  avr_core_irq_raise (core, irq_vect_table_index (ADC));
271  adc->adcsr &= ~mask_ADIF;
272  }
273 
274  return CB_RET_RETAIN;
275 }
276 
277 /****************************************************************************\
278  *
279  * ADC
280  *
281 \****************************************************************************/
282 
283 static void adc_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
284  void *data);
285 static uint8_t adc_read (VDevice *dev, int addr);
286 static void adc_write (VDevice *dev, int addr, uint8_t val);
287 static void adc_reset (VDevice *dev);
288 
289 /** \brief Allocate a new ADC structure. */
290 
291 VDevice *
292 adc_create (int addr, char *name, int rel_addr, void *data)
293 {
294  uint8_t *data_ptr = (uint8_t *) data;
295  if (data)
296  return (VDevice *)adc_new (addr, name, (uint8_t) * data_ptr,
297  rel_addr);
298  else
299  avr_error ("Attempted A/D create with NULL data pointer");
300  return 0;
301 }
302 
303 ADC_T *
304 adc_new (int addr, char *name, uint8_t uier, int rel_addr)
305 {
306  ADC_T *adc;
307 
308  adc = avr_new (ADC_T, 1);
309  adc_construct (adc, addr, name, uier, rel_addr);
310  class_overload_destroy ((AvrClass *)adc, adc_destroy);
311 
312  return adc;
313 }
314 
315 /** \brief Constructor for ADC object. */
316 
317 void
318 adc_construct (ADC_T *adc, int addr, char *name, uint8_t uier, int rel_addr)
319 {
320  if (adc == NULL)
321  avr_error ("passed null ptr");
322 
323  vdev_construct ((VDevice *)adc, adc_read, adc_write, adc_reset,
324  adc_add_addr);
325 
326  if (rel_addr)
327  adc->rel_addr = rel_addr;
328  adc_add_addr ((VDevice *)adc, addr, name, 0, NULL);
329 
330  adc_reset ((VDevice *)adc);
331  adc->u_divisor = uier ? 12 : 1;
332 }
333 static void
334 adc_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
335 {
336  ADC_T *adc = (ADC_T *)vdev;
337 
338  if (strncmp ("ADCL", name, 4) == 0)
339  {
340  adc->adcl_addr = addr;
341  }
342 
343  else if (strncmp ("ADCH", name, 4) == 0)
344  {
345  adc->adch_addr = addr;
346  }
347 
348  else
349  {
350  avr_error ("invalid ADC register name: '%s' @ 0x%04x", name, addr);
351  }
352 }
353 
354 /** \brief Destructor for ADC object. */
355 
356 void
357 adc_destroy (void *adc)
358 {
359  if (adc == NULL)
360  return;
361 
362  vdev_destroy (adc);
363 }
364 
365 static uint8_t
366 adc_read (VDevice *dev, int addr)
367 {
368  ADC_T *adc = (ADC_T *)dev;
369 
370  if (addr == adc->adcl_addr)
371  return adc->adcl;
372 
373  else if (addr == adc->adch_addr)
374  return adc->adch;
375 
376  else
377  avr_error ("Bad address: 0x%04x", addr);
378 
379  return 0; /* will never get here */
380 }
381 
382 static void
383 adc_write (VDevice *dev, int addr, uint8_t val)
384 {
385  avr_error ("Bad ADC write address: 0x%04x", addr);
386 }
387 
388 static void
389 adc_reset (VDevice *dev)
390 {
391  ADC_T *adc = (ADC_T *)dev;
392 
393  adc->clk_cb = NULL;
394 
395  adc->adcl = 0;
396  adc->adch = 0;
397 
398  adc->adc_count = 0;
399  adc->adc_in = 0;
400  adc->divisor = 0;
401 }
402 
403 static int
404 adc_clk_incr_cb (uint64_t ck, AvrClass *data)
405 {
406  ADC_T *adc = (ADC_T *)data;
407  uint8_t last = adc->adc_count;
408  ADCIntr_T *adc_ti;
409 
410  adc_ti =
411  (ADCIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
412  vdev_get_core ((VDevice *)
413  adc),
414  adc->rel_addr);
415 
416  if (adc->clk_cb == NULL)
417  return CB_RET_REMOVE;
418 
419  if (adc->divisor <= 0)
420  avr_error ("Bad divisor value: %d", adc->divisor);
421 
422  /* decrement clock if ck is a multiple of divisor */
423  adc->adc_count -= ((ck % (adc->divisor * adc->u_divisor)) == 0);
424 
425  if (adc->adc_count != last) /* we've changed the counter */
426  {
427  if (adc->adc_count == 0)
428  {
429  adc_ti->adcsr |= mask_ADIF;
430  adc_ti->adcsr &= ~mask_ADSC;
431  adc->adc_in = adc_port_rd (adc_ti->admux);
432  adc->adcl = (adc->adc_in) & 0xff; /* update adcl to what we
433  read */
434  adc->adch = ((adc->adc_in) >> 8) & 0x03; /* update adch */
435  if (adc_ti->adcsr & mask_ADFR) /* free running mode */
436  adc->adc_count = 13;
437  else
438  {
439  adc->clk_cb = NULL;
440  return CB_RET_REMOVE;
441  }
442  }
443  }
444  return CB_RET_RETAIN;
445 }
446 
447 /* FIXME: TRoth/2003-11-29: These will eventually need to be plugged into an
448  external connection interface. */
449 
450 uint16_t
451 adc_port_rd (uint8_t mux)
452 {
453  int data;
454  char line[80];
455 
456  while (1)
457  {
458  fprintf (stderr, "\nEnter data to read into the ADC for channel %d: ",
459  mux);
460 
461  /* try to read in a line of input */
462  if (fgets (line, sizeof (line), stdin) == NULL)
463  continue;
464 
465  /* try to parse the line for a byte of data */
466  if (sscanf (line, "%d\n", &data) != 1)
467  continue;
468 
469  break;
470  }
471  return (uint16_t) (data & 0x3ff);
472 }
473 
474 void
475 adc_port_wr (uint8_t val)
476 {
477  fprintf (stderr, "wrote 0x%02x to ADC\n", val);
478 }
#define avr_new(type, count)
Macro for allocating memory.
Definition: avrmalloc.c:57
VDevice * adc_int_create(int addr, char *name, int rel_addr, void *data)
Allocate a new ADC interrupt.
Definition: adc.c:79
void avr_core_async_cb_add(AvrCore *core, CallBack *cb)
Add a new asynchronous callback to list.
VDevice * avr_core_get_vdev_by_addr(AvrCore *core, int addr)
Returns the VDevice which handles the address addr.
void vdev_destroy(void *dev)
Destructor for a VDevice.
Definition: device.c:105
void adc_destroy(void *adc)
Destructor for ADC object.
Definition: adc.c:357
void avr_core_irq_raise(AvrCore *core, unsigned int irq)
Raises an irq by adding it&#39;s data to the irq_pending list.
Definition: avrcore.c:854
AvrClass * vdev_get_core(VDevice *dev)
Get the core field.
void vdev_construct(VDevice *dev, VDevFP_Read rd, VDevFP_Write wr, VDevFP_Reset reset, VDevFP_AddAddr add_addr)
Constructor for a VDevice.
Definition: device.c:89
void adc_construct(ADC_T *adc, int addr, char *name, uint8_t uier, int rel_addr)
Constructor for ADC object.
Definition: adc.c:318
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
void adc_intr_destroy(void *adc)
Destructor for adc interrupt object.
Definition: adc.c:138
void avr_core_clk_cb_add(AvrCore *core, CallBack *cb)
Add a new clock callback to list.
void adc_intr_construct(ADCIntr_T *adc, int addr, char *name, int rel_addr)
Constructor for adc interrupt object.
Definition: adc.c:99
VDevice * adc_create(int addr, char *name, int rel_addr, void *data)
Allocate a new ADC structure.
Definition: adc.c:292
void class_overload_destroy(AvrClass *klass, AvrClassFP_Destroy destroy)
Overload the default destroy method.
Definition: avrclass.c:92

Automatically generated by Doxygen 1.8.12 on Mon Apr 3 2017.