timers.c

Go to the documentation of this file.
00001 /*
00002  * $Id: timers.c,v 1.15 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) 2001, 2002, 2003, 2004  Theodore A. Roth
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 timers.c
00028  * \brief Module to simulate the AVR's on-board timer/counters.
00029  *
00030  * This currently only implements the timer/counter 0.
00031  */
00032 
00033 #include <config.h>
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 
00039 #include "avrerror.h"
00040 #include "avrmalloc.h"
00041 #include "avrclass.h"
00042 #include "utils.h"
00043 #include "callback.h"
00044 #include "op_names.h"
00045 
00046 #include "storage.h"
00047 #include "flash.h"
00048 
00049 #include "vdevs.h"
00050 #include "memory.h"
00051 #include "stack.h"
00052 #include "register.h"
00053 #include "sram.h"
00054 #include "eeprom.h"
00055 #include "timers.h"
00056 #include "ports.h"
00057 
00058 #include "avrcore.h"
00059 
00060 #include "intvects.h"
00061 
00062 #ifndef DOXYGEN
00063 
00064 /* *INDENT-OFF* */
00065 
00066 Timer16Def global_timer16_defs[] = {
00067     {
00068         .timer_name = "Timer1",
00069         .tcnth_name = "TCNT1H",
00070         .tcntl_name = "TCNT1L",
00071         .tccra_name = "TCCR1A",
00072         .tccrb_name = "TCCR1B",
00073         .base = 0x4c,
00074         .tof = bit_TOV1,
00075         .ocf_a = bit_OCF1A,
00076         .ocf_b = bit_OCF1B,
00077         .ocf_c = 8
00078     }
00079 };
00080 
00081 OCReg16Def global_ocreg16_defs[] = {
00082     {
00083         .ocrdev_name = "OCR1A",
00084         .ocrl_name = "OCR1AL",
00085         .ocrh_name = "OCR1AH",
00086         .base = 0x4a
00087     },
00088     {
00089         .ocrdev_name = "OCR1B",
00090         .ocrl_name = "OCR1BL",
00091         .ocrh_name = "OCR1BH",
00092         .base = 0x48
00093     },
00094     {
00095         .ocrdev_name = "OCR1C",
00096         .ocrl_name = "OCR1CL",
00097         .ocrh_name = "OCR1CH",
00098         .base = 0x78},
00099     {
00100         .ocrdev_name = "OCR3A",
00101         .ocrl_name = "OCR3AL",
00102         .ocrh_name = "OCR3A",
00103         .base = 0x86
00104     },
00105     {
00106         .ocrdev_name = "OCR3B",
00107         .ocrl_name = "OCR3BL",
00108         .ocrh_name = "OCR3BH",
00109         .base = 0x84
00110     },
00111     {
00112         .ocrdev_name = "OCR3C",
00113         .ocrl_name = "OCR3CL",
00114         .ocrh_name = "OCR3CH",
00115         .base = 0x82
00116     }
00117 };
00118 /* *INDENT-ON* */
00119 
00120 #endif /* not DOXYGEN */
00121 
00122 /****************************************************************************\
00123  *
00124  * Timer/Counter 0 
00125  *
00126 \****************************************************************************/
00127 
00128 static void timer_iadd_addr (VDevice *vdev, int addr, char *name,
00129                              int rel_addr, void *data);
00130 static uint8_t timer_intr_read (VDevice *dev, int addr);
00131 static void timer_intr_write (VDevice *dev, int addr, uint8_t val);
00132 static void timer_intr_reset (VDevice *dev);
00133 static int timer_intr_cb (uint64_t time, AvrClass *data);
00134 
00135 /** \brief Allocate a new timer interrupt */
00136 
00137 VDevice *
00138 timer_int_create (int addr, char *name, int rel_addr, void *data)
00139 {
00140     uint8_t *func_mask = (uint8_t *) data;
00141     if (data)
00142         return (VDevice *)timer_intr_new (addr, name, *func_mask);
00143     else
00144         avr_error ("Attempted timer interrupt create with NULL data pointer");
00145     return 0;
00146 }
00147 
00148 TimerIntr_T *
00149 timer_intr_new (int addr, char *name, uint8_t func_mask)
00150 {
00151     TimerIntr_T *ti;
00152 
00153     ti = avr_new (TimerIntr_T, 1);
00154     timer_intr_construct (ti, addr, name, func_mask);
00155     class_overload_destroy ((AvrClass *)ti, timer_intr_destroy);
00156 
00157     return ti;
00158 }
00159 
00160 /** \brief Constructor for timer interrupt object. */
00161 
00162 void
00163 timer_intr_construct (TimerIntr_T *ti, int addr, char *name,
00164                       uint8_t func_mask)
00165 {
00166     if (ti == NULL)
00167         avr_error ("passed null ptr");
00168 
00169     vdev_construct ((VDevice *)ti, timer_intr_read, timer_intr_write,
00170                     timer_intr_reset, timer_iadd_addr);
00171 
00172     ti->func_mask = func_mask;
00173 
00174     timer_iadd_addr ((VDevice *)ti, addr, name, 0, NULL);
00175 
00176     timer_intr_reset ((VDevice *)ti);
00177 }
00178 
00179 static void
00180 timer_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00181                  void *data)
00182 {
00183     TimerIntr_T *ti = (TimerIntr_T *)vdev;
00184 
00185     if (strncmp ("TIFR", name, 4) == 0)
00186     {
00187         ti->tifr_addr = addr;
00188     }
00189 
00190     else if (strncmp ("TIMSK", name, 5) == 0)
00191     {
00192         ti->timsk_addr = addr;
00193     }
00194 
00195     else
00196     {
00197         avr_error ("invalid Timer Interrupt register name: '%s' @ 0x%04x",
00198                    name, addr);
00199     }
00200 }
00201 
00202 /** \brief Destructor for timer interrupt object. */
00203 
00204 void
00205 timer_intr_destroy (void *ti)
00206 {
00207     if (ti == NULL)
00208         return;
00209 
00210     vdev_destroy (ti);
00211 }
00212 
00213 static uint8_t
00214 timer_intr_read (VDevice *dev, int addr)
00215 {
00216     TimerIntr_T *ti = (TimerIntr_T *)dev;
00217 
00218     if (addr == ti->timsk_addr)
00219     {
00220         return (ti->timsk & ti->func_mask);
00221     }
00222 
00223     else if (addr == ti->tifr_addr)
00224     {
00225         return (ti->tifr & ti->func_mask);
00226     }
00227 
00228     else
00229     {
00230         avr_error ("Bad address: 0x%04x", addr);
00231     }
00232 
00233     return 0;                   /* will never get here */
00234 }
00235 
00236 static void
00237 timer_intr_write (VDevice *dev, int addr, uint8_t val)
00238 {
00239     TimerIntr_T *ti = (TimerIntr_T *)dev;
00240     CallBack *cb;
00241 
00242     if (addr == ti->timsk_addr)
00243     {
00244         ti->timsk = (val & ti->func_mask);
00245         if (ti->timsk == 0)
00246         {
00247             ti->intr_cb = NULL; /* no interrupt are enabled, remove the
00248                                    callback */
00249         }
00250         else if (ti->intr_cb == NULL)
00251         {
00252             /* we need to install the intr_cb function */
00253             cb = callback_new (timer_intr_cb, (AvrClass *)ti);
00254             ti->intr_cb = cb;
00255             avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
00256         }
00257     }
00258 
00259     else if (addr == ti->tifr_addr)
00260     {
00261         ti->tifr &= ~(val & ti->func_mask);
00262     }
00263 
00264     else
00265     {
00266         avr_error ("Bad address: 0x%04x", addr);
00267     }
00268 }
00269 
00270 static void
00271 timer_intr_reset (VDevice *dev)
00272 {
00273     TimerIntr_T *ti = (TimerIntr_T *)dev;
00274 
00275     ti->intr_cb = NULL;
00276 
00277     ti->timsk = 0;
00278     ti->tifr = 0;
00279 }
00280 
00281 static int
00282 timer_intr_cb (uint64_t time, AvrClass *data)
00283 {
00284     TimerIntr_T *ti = (TimerIntr_T *)data;
00285     uint8_t intrs = ti->timsk & ti->tifr & ti->func_mask;
00286 
00287     if (ti->intr_cb == NULL)
00288         return CB_RET_REMOVE;
00289 
00290     if (intrs)
00291     {
00292         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)ti);
00293 
00294         /*
00295          * FIXME: Once an irq has been raised, the flag should be cleared,
00296          *   _BUT_ should it be done here? Might be a problem if there are
00297          *   many interrupts pending and then the user wants to clear one.
00298          */
00299 
00300         if (intrs & mask_TOV0)
00301         {
00302             avr_core_irq_raise (core, irq_vect_table_index (TIMER0_OVF));
00303             ti->tifr &= ~mask_TOV0;
00304         }
00305         else if (intrs & mask_ICF1)
00306         {
00307             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_CAPT));
00308             ti->tifr &= ~mask_ICF1;
00309         }
00310         else if (intrs & mask_OCF1B)
00311         {
00312             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPB));
00313             ti->tifr &= ~mask_OCF1B;
00314         }
00315         else if (intrs & mask_OCF1A)
00316         {
00317             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_COMPA));
00318             ti->tifr &= ~mask_OCF1A;
00319         }
00320         else if (intrs & mask_TOV1)
00321         {
00322             avr_core_irq_raise (core, irq_vect_table_index (TIMER1_OVF));
00323             ti->tifr &= ~mask_TOV1;
00324         }
00325         else
00326         {
00327             avr_error ("An invalid interrupt was flagged");
00328         }
00329     }
00330 
00331     return CB_RET_RETAIN;
00332 }
00333 
00334 /****************************************************************************\
00335  *
00336  * Timer/Counter 0 
00337  *
00338 \****************************************************************************/
00339 
00340 static void timer0_add_addr (VDevice *vdev, int addr, char *name,
00341                              int rel_addr, void *data);
00342 static uint8_t timer0_read (VDevice *dev, int addr);
00343 static void timer0_write (VDevice *dev, int addr, uint8_t val);
00344 static void timer0_reset (VDevice *dev);
00345 static int timer0_clk_incr_cb (uint64_t ck, AvrClass *data);
00346 
00347 /** \brief Allocate a new timer/counter 0. */
00348 
00349 VDevice *
00350 timer0_create (int addr, char *name, int rel_addr, void *data)
00351 {
00352     return (VDevice *)timer0_new (addr, name, rel_addr);
00353 }
00354 
00355 Timer0_T *
00356 timer0_new (int addr, char *name, int rel_addr)
00357 {
00358     Timer0_T *timer;
00359 
00360     timer = avr_new (Timer0_T, 1);
00361     timer0_construct (timer, addr, name, rel_addr);
00362     class_overload_destroy ((AvrClass *)timer, timer0_destroy);
00363 
00364     return timer;
00365 }
00366 
00367 /** \brief Constructor for timer/counter 0 object. */
00368 
00369 void
00370 timer0_construct (Timer0_T *timer, int addr, char *name, int rel_addr)
00371 {
00372     if (timer == NULL)
00373         avr_error ("passed null ptr");
00374 
00375     vdev_construct ((VDevice *)timer, timer0_read, timer0_write, timer0_reset,
00376                     timer0_add_addr);
00377 
00378     timer0_add_addr ((VDevice *)timer, addr, name, 0, NULL);
00379     if (rel_addr)
00380         timer->related_addr = rel_addr;
00381     timer0_reset ((VDevice *)timer);
00382 }
00383 
00384 /** \brief Destructor for timer/counter 0 object. */
00385 
00386 void
00387 timer0_destroy (void *timer)
00388 {
00389     if (timer == NULL)
00390         return;
00391 
00392     vdev_destroy (timer);
00393 }
00394 
00395 static void
00396 timer0_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00397                  void *data)
00398 {
00399     Timer0_T *ti = (Timer0_T *)vdev;
00400 
00401     if (strncmp ("TCNT", name, 4) == 0)
00402     {
00403         ti->tcnt_addr = addr;
00404     }
00405 
00406     else if (strncmp ("TCCR", name, 4) == 0)
00407     {
00408         ti->tccr_addr = addr;
00409     }
00410 
00411     else
00412     {
00413         avr_error ("invalid Timer register name: '%s' @ 0x%04x", name, addr);
00414     }
00415 }
00416 
00417 static uint8_t
00418 timer0_read (VDevice *dev, int addr)
00419 {
00420     Timer0_T *timer = (Timer0_T *)dev;
00421 
00422     if (addr == timer->tcnt_addr)
00423         return timer->tcnt;
00424 
00425     else if (addr == timer->tccr_addr)
00426         return timer->tccr;
00427 
00428     else
00429     {
00430         avr_error ("Bad address: 0x%04x", addr);
00431     }
00432 
00433     return 0;                   /* will never get here */
00434 }
00435 
00436 static void
00437 timer0_write (VDevice *dev, int addr, uint8_t val)
00438 {
00439     Timer0_T *timer = (Timer0_T *)dev;
00440     CallBack *cb;
00441 
00442     if (addr == timer->tcnt_addr)
00443     {
00444         timer->tcnt = val;
00445     }
00446 
00447     else if (addr == timer->tccr_addr)
00448     {
00449         /*
00450          * When the user writes toe TCCR, a callback is installed for either
00451          * clock generated increments or externally generated increments. The
00452          * two incrememtor callback are mutally exclusive, only one or the 
00453          * other can be installed at any given instant.
00454          */
00455 
00456         /* timer 0 only has clock select function. */
00457         timer->tccr = val & mask_CS;
00458 
00459         switch (timer->tccr)
00460         {
00461             case CS_STOP:
00462                 /* stop either of the installed callbacks */
00463                 timer->clk_cb = timer->ext_cb = NULL;
00464                 timer->divisor = 0;
00465                 return;
00466             case CS_EXT_FALL:
00467             case CS_EXT_RISE:
00468                 /* FIXME: not implemented yet */
00469                 avr_error ("external timer/counter sources is not implemented"
00470                            " yet");
00471                 return;
00472             case CS_CK:
00473                 timer->divisor = 1;
00474                 break;
00475             case CS_CK_8:
00476                 timer->divisor = 8;
00477                 break;
00478             case CS_CK_64:
00479                 timer->divisor = 64;
00480                 break;
00481             case CS_CK_256:
00482                 timer->divisor = 256;
00483                 break;
00484             case CS_CK_1024:
00485                 timer->divisor = 1024;
00486                 break;
00487             default:
00488                 avr_error ("The impossible happened!");
00489         }
00490         /* remove external incrementor if installed */
00491         if (timer->ext_cb)
00492             timer->ext_cb = NULL;
00493 
00494         /* install the clock incrementor callback (with flair!) */
00495         if (timer->clk_cb == NULL)
00496         {
00497             cb = callback_new (timer0_clk_incr_cb, (AvrClass *)timer);
00498             timer->clk_cb = cb;
00499             avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer),
00500                                  cb);
00501         }
00502     }
00503 
00504     else
00505     {
00506         avr_error ("Bad address: 0x%04x", addr);
00507     }
00508 }
00509 
00510 static void
00511 timer0_reset (VDevice *dev)
00512 {
00513     Timer0_T *timer = (Timer0_T *)dev;
00514 
00515     timer->clk_cb = NULL;
00516     timer->ext_cb = NULL;
00517 
00518     timer->tccr = 0;
00519     timer->tcnt = 0;
00520 
00521     timer->divisor = 0;
00522 }
00523 
00524 static int
00525 timer0_clk_incr_cb (uint64_t ck, AvrClass *data)
00526 {
00527     Timer0_T *timer = (Timer0_T *)data;
00528     uint8_t last = timer->tcnt;
00529     TimerIntr_T *ti;
00530 
00531     ti = (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
00532                                                    vdev_get_core ((VDevice *)
00533                                                                   timer),
00534                                                    timer->related_addr);
00535 
00536     if (timer->clk_cb == NULL)
00537         return CB_RET_REMOVE;
00538 
00539     if (timer->divisor <= 0)
00540         avr_error ("Bad divisor value: %d", timer->divisor);
00541 
00542     /* Increment clock if ck is a mutliple of divisor. Since divisor is always
00543        a power of 2, it's much faster to do the bitwise AND instead of using
00544        the integer modulus operator (%). */
00545     timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
00546 
00547     /* Check if tcnt rolled over and if so, set the overflow flag.  If
00548        overflow interrupts are set? what if they aren't? This is set
00549        irregardless of whether SREG-I or TOIE0 are set (overflow interrupt
00550        enabled) and thus allows the interrupt to be pending until manually
00551        cleared (writing a one to the TOV0 flag) or interrupts are enabled. My
00552        interpretation of the datasheets. See datasheet discussion of TIFR.
00553        TRoth */
00554     if ((timer->tcnt == 0) && (timer->tcnt != last))
00555         ti->tifr |= mask_TOV0;
00556 
00557     return CB_RET_RETAIN;
00558 }
00559 
00560 /****************************************************************************\
00561 *
00562 * Timer/Counter 1/3 (16 bit)
00563 *
00564 \****************************************************************************/
00565 
00566 /** \name 16 Bit Timer Functions */
00567 
00568 /*@{*/
00569 
00570 static void timer16_add_addr (VDevice *vdev, int addr, char *name,
00571                               int rel_addr, void *data);
00572 static void timer16_destroy (void *timer);
00573 static uint8_t timer16_read (VDevice *dev, int addr);
00574 static void timer16_write (VDevice *dev, int addr, uint8_t val);
00575 static void timer16_reset (VDevice *dev);
00576 static int timer16_clk_incr_cb (uint64_t time, AvrClass *data);
00577 static void timer16_handle_tccr_write (Timer16_T *timer);
00578 
00579 /** \brief Allocate a new 16 bit timer/counter. */
00580 
00581 VDevice *
00582 timer16_create (int addr, char *name, int rel_addr, void *data)
00583 {
00584     uint8_t *def_data = (uint8_t *) data;
00585     if (data)
00586         return (VDevice *)timer16_new (addr, name, rel_addr,
00587                                        global_timer16_defs[*def_data]);
00588     else
00589         avr_error ("Attempted timer 16 create with NULL data pointer");
00590     return 0;
00591 }
00592 
00593 Timer16_T *
00594 timer16_new (int addr, char *name, int rel_addr, Timer16Def timerdef)
00595 {
00596     Timer16_T *timer;
00597 
00598     timer = avr_new (Timer16_T, 1);
00599     timer16_construct (timer, addr, name, rel_addr, timerdef);
00600     class_overload_destroy ((AvrClass *)timer, timer16_destroy);
00601 
00602     return timer;
00603 }
00604 
00605 /** \brief Constructor for 16 bit timer/counter object. */
00606 
00607 void
00608 timer16_construct (Timer16_T *timer, int addr, char *name, int rel_addr,
00609                    Timer16Def timerdef)
00610 {
00611     if (timer == NULL)
00612         avr_error ("passed null ptr");
00613 
00614     vdev_construct ((VDevice *)timer, timer16_read, timer16_write,
00615                     timer16_reset, timer16_add_addr);
00616 
00617     timer->timerdef = timerdef;
00618 
00619     timer16_add_addr ((VDevice *)timer, addr, name, 0, NULL);
00620     if (rel_addr)
00621         timer->related_addr = rel_addr;
00622     timer16_reset ((VDevice *)timer);
00623 }
00624 
00625 static void
00626 timer16_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00627                   void *data)
00628 {
00629     Timer16_T *ti = (Timer16_T *)vdev;
00630 
00631     if (strncmp ("TCNTL", name, 5) == 0)
00632     {
00633         ti->tcntl_addr = addr;
00634     }
00635 
00636     else if (strncmp ("TCNTH", name, 5) == 0)
00637     {
00638         ti->tcnth_addr = addr;
00639     }
00640 
00641     else if (strncmp ("TCCRA", name, 5) == 0)
00642     {
00643         ti->tccra_addr = addr;
00644     }
00645 
00646     else if (strncmp ("TCCRB", name, 5) == 0)
00647     {
00648         ti->tccrb_addr = addr;
00649     }
00650 
00651     else if (strncmp ("TCCRC", name, 5) == 0)
00652     {
00653         ti->tccrc_addr = addr;
00654     }
00655 
00656     else
00657     {
00658         avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
00659                    addr);
00660     }
00661 }
00662 
00663 static void
00664 timer16_destroy (void *timer)
00665 {
00666     if (timer == NULL)
00667         return;
00668 
00669     vdev_destroy (timer);
00670 }
00671 
00672 static uint8_t
00673 timer16_read (VDevice *dev, int addr)
00674 {
00675     Timer16_T *timer = (Timer16_T *)dev;
00676 
00677     if (addr == timer->tcntl_addr)
00678     {
00679         timer->TEMP = (uint8_t) ((timer->tcnt) >> 8);
00680         return (timer->tcnt) & 0xFF;
00681     }
00682 
00683     else if (addr == timer->tcnth_addr)
00684     {
00685         return timer->TEMP;
00686     }
00687 
00688     else if (addr == timer->tccra_addr)
00689     {
00690         return timer->tccra;
00691     }
00692 
00693     else if (addr == timer->tccrb_addr)
00694     {
00695         return timer->tccrb;
00696     }
00697 
00698     else if (addr == timer->tccrc_addr)
00699     {
00700         return timer->tccrc;
00701     }
00702 
00703     else
00704     {
00705         avr_error ("Bad address: 0x%04x", addr);
00706     }
00707 
00708     return 0;                   /* will never get here */
00709 }
00710 
00711 static void
00712 timer16_write (VDevice *dev, int addr, uint8_t val)
00713 {
00714     Timer16_T *timer = (Timer16_T *)dev;
00715 
00716     if (addr == timer->tcntl_addr)
00717     {
00718         timer->tcnt = (((timer->TEMP) << 8) & 0xFF00) | val;
00719     }
00720 
00721     else if (addr == timer->tcnth_addr)
00722     {
00723         timer->TEMP = val;
00724     }
00725 
00726     else if (addr == timer->tccra_addr)
00727     {
00728         timer->tccra = val;
00729         timer16_handle_tccr_write (timer);
00730     }
00731 
00732     else if (addr == timer->tccrb_addr)
00733     {
00734         timer->tccrb = val;
00735         timer16_handle_tccr_write (timer);
00736     }
00737 
00738     else if (addr == timer->tccrc_addr)
00739     {
00740         timer->tccrc = val;
00741         timer16_handle_tccr_write (timer);
00742     }
00743 
00744     else
00745     {
00746         avr_error ("Bad address: 0x%04x", addr);
00747     }
00748 }
00749 
00750 static void
00751 timer16_reset (VDevice *dev)
00752 {
00753     Timer16_T *timer = (Timer16_T *)dev;
00754 
00755     timer->clk_cb = NULL;
00756     timer->ext_cb = NULL;
00757 
00758     timer->tccra = 0;
00759     timer->tccrb = 0;
00760     timer->tccrc = 0;
00761     timer->tcnt = 0;
00762 
00763     timer->divisor = 0;
00764 }
00765 
00766 static void
00767 timer_intr_set_flag (TimerIntr_T *ti, uint8_t bitnr)
00768 {
00769     ti->tifr |= bitnr;
00770 }
00771 
00772 static int
00773 timer16_clk_incr_cb (uint64_t ck, AvrClass *data)
00774 {
00775     Timer16_T *timer = (Timer16_T *)data;
00776     uint16_t last = timer->tcnt;
00777 
00778     if (!timer->ti)
00779         timer->ti =
00780             (TimerIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
00781                                                       vdev_get_core ((VDevice
00782                                                                       *)
00783                                                                      timer),
00784                                                       timer->related_addr);
00785 
00786     if (timer->clk_cb == NULL)
00787         return CB_RET_REMOVE;
00788 
00789     /* Increment clock if ck is a mutliple of divisor. Since divisor is always
00790        a power of 2, it's much faster to do the bitwise AND instead of using
00791        the integer modulus operator (%). */
00792     timer->tcnt += ((ck & (timer->divisor - 1)) == 0);
00793 
00794     if (timer->divisor <= 0)
00795         avr_error ("Bad divisor value: %d", timer->divisor);
00796 
00797     /* The following things only have to be checked if the counter value has
00798        changed */
00799     if (timer->tcnt != last)
00800     {
00801         /* An overflow occurred */
00802         if (timer->tcnt == 0)
00803             timer_intr_set_flag (timer->ti, mask_TOV1);
00804 
00805         /* The counter value matches one of the ocr values */
00806         if (timer->ocra && (timer->tcnt == timer->ocra->ocr))
00807         {
00808             timer_intr_set_flag (timer->ti, mask_OCF1A);
00809         }
00810 
00811         if (timer->ocrb && (timer->tcnt == timer->ocrb->ocr))
00812         {
00813             timer_intr_set_flag (timer->ti, mask_OCF1B);
00814         }
00815     }
00816     return CB_RET_RETAIN;
00817 }
00818 
00819 #if 0
00820 static void
00821 timer_intr_clear_flag (TimerIntr_T *ti, uint8_t bitnr)
00822 {
00823     ti->tifr &= ~(bitnr);
00824 }
00825 #endif
00826 
00827 static void
00828 timer16_handle_tccr_write (Timer16_T *timer)
00829 {
00830     int cs;
00831     CallBack *cb;
00832     /*
00833      * When the user writes toe TCCR, a callback is installed for either
00834      * clock generated increments or externally generated increments. The
00835      * two incrememtor callback are mutally exclusive, only one or the 
00836      * other can be installed at any given instant.
00837      */
00838 
00839     cs = timer->tccrb & 0x07;
00840 
00841     switch (cs)
00842     {
00843         case CS_STOP:
00844             /* stop either of the installed callbacks */
00845             timer->clk_cb = timer->ext_cb = NULL;
00846             timer->divisor = 0;
00847             return;
00848         case CS_EXT_FALL:
00849         case CS_EXT_RISE:
00850             /* FIXME: not implemented yet */
00851             avr_error ("external timer/counter sources is not implemented"
00852                        "yet");
00853             return;
00854         case CS_CK:
00855             timer->divisor = 1;
00856             break;
00857         case CS_CK_8:
00858             timer->divisor = 8;
00859             break;
00860         case CS_CK_64:
00861             timer->divisor = 64;
00862             break;
00863         case CS_CK_256:
00864             timer->divisor = 256;
00865             break;
00866         case CS_CK_1024:
00867             timer->divisor = 1024;
00868             break;
00869         default:
00870             avr_error ("The impossible happened!");
00871     }
00872     /* remove external incrementor if installed */
00873     if (timer->ext_cb)
00874         timer->ext_cb = NULL;
00875 
00876     /* install the clock incrementor callback (with flair!) */
00877     if (timer->clk_cb == NULL)
00878     {
00879         cb = callback_new (timer16_clk_incr_cb, (AvrClass *)timer);
00880         timer->clk_cb = cb;
00881         avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)timer), cb);
00882     }
00883 }
00884 
00885 /*@}*/
00886 
00887 /****************************************************************************\
00888  *
00889  * Timer16OCR(VDevice) : 16bit - Timer/Counter - Output Compare Register
00890  *
00891 \****************************************************************************/
00892 
00893 /** \name 16 Bit Output Compare Register Functions */
00894 
00895 /*@{*/
00896 
00897 static void ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00898                           void *data);
00899 static void ocreg16_destroy (void *ocr);
00900 static uint8_t ocreg16_read (VDevice *dev, int addr);
00901 static void ocreg16_write (VDevice *dev, int addr, uint8_t val);
00902 static void ocreg16_reset (VDevice *dev);
00903 
00904 /** \brief Allocate a new 16 bit Output Compare Register
00905   * \param ocrdef The definition struct for the \a OCR to be created
00906   */
00907 
00908 VDevice *
00909 ocreg16_create (int addr, char *name, int rel_addr, void *data)
00910 {
00911     uint8_t *def_data = (uint8_t *) data;
00912     if (data)
00913         return (VDevice *)ocreg16_new (addr, name,
00914                                        global_ocreg16_defs[*def_data]);
00915     else
00916         avr_error ("Attempted OCReg create with NULL data pointer");
00917     return 0;
00918 }
00919 
00920 OCReg16_T *
00921 ocreg16_new (int addr, char *name, OCReg16Def ocrdef)
00922 {
00923     OCReg16_T *ocreg;
00924 
00925     ocreg = avr_new (OCReg16_T, 1);
00926     ocreg16_construct (ocreg, addr, name, ocrdef);
00927     class_overload_destroy ((AvrClass *)ocreg, ocreg16_destroy);
00928 
00929     return ocreg;
00930 }
00931 
00932 /** \brief Constructor for 16 bit Output Compare Register object. */
00933 
00934 void
00935 ocreg16_construct (OCReg16_T *ocreg, int addr, char *name, OCReg16Def ocrdef)
00936 {
00937     if (ocreg == NULL)
00938         avr_error ("passed null ptr");
00939 
00940     vdev_construct ((VDevice *)ocreg, ocreg16_read, ocreg16_write,
00941                     ocreg16_reset, ocr_add_addr);
00942 
00943     ocreg->ocrdef = ocrdef;
00944 
00945     ocr_add_addr ((VDevice *)ocreg, addr, name, 0, NULL);
00946     ocreg16_reset ((VDevice *)ocreg);
00947 }
00948 
00949 static void
00950 ocr_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
00951 {
00952     OCReg16_T *ocreg = (OCReg16_T *)vdev;
00953 
00954     if ((strncmp ("OCRAL", name, 5) == 0) || (strncmp ("OCRBL", name, 5) == 0)
00955         || (strncmp ("OCRCL", name, 5) == 0))
00956     {
00957         ocreg->ocrl_addr = addr;
00958     }
00959 
00960     else if ((strncmp ("OCRAH", name, 5) == 0)
00961              || (strncmp ("OCRBH", name, 5) == 0)
00962              || (strncmp ("OCRCH", name, 5) == 0))
00963 
00964     {
00965         ocreg->ocrh_addr = addr;
00966     }
00967 
00968     else
00969     {
00970         avr_error ("invalid Timer16 register name: '%s' @ 0x%04x", name,
00971                    addr);
00972     }
00973 }
00974 
00975 static void
00976 ocreg16_destroy (void *ocreg)
00977 {
00978     if (ocreg == NULL)
00979         return;
00980 
00981     vdev_destroy (ocreg);
00982 }
00983 
00984 static uint8_t
00985 ocreg16_read (VDevice *dev, int addr)
00986 {
00987     OCReg16_T *ocreg = (OCReg16_T *)dev;
00988 
00989     if (addr == ocreg->ocrl_addr)
00990     {
00991         return (ocreg->ocr) & 0xFF;
00992     }
00993 
00994     else if (addr == ocreg->ocrh_addr)
00995     {
00996         return (ocreg->ocr) >> 8;
00997     }
00998 
00999     else
01000     {
01001         avr_error ("Bad address: 0x%04x", addr);
01002     }
01003 
01004     return 0;
01005 }
01006 
01007 static void
01008 ocreg16_write (VDevice *dev, int addr, uint8_t val)
01009 {
01010     OCReg16_T *ocreg = (OCReg16_T *)dev;
01011 
01012     if (addr == ocreg->ocrl_addr)
01013     {
01014         ocreg->ocr = (((ocreg->TEMP) << 8) & 0xFF00) | val;
01015     }
01016 
01017     else if (addr == ocreg->ocrh_addr)
01018     {
01019         ocreg->TEMP = val;
01020     }
01021 
01022     else
01023     {
01024         avr_error ("Bad address: 0x%04x", addr);
01025     }
01026 }
01027 
01028 static void
01029 ocreg16_reset (VDevice *dev)
01030 {
01031     OCReg16_T *ocreg = (OCReg16_T *)dev;
01032 
01033     ocreg->ocr = 0;
01034 }
01035 
01036 /*@}*/

Automatically generated by Doxygen 1.5.2 on 3 Dec 2007.