Logo Search packages:      
Sourcecode: linux version File versions  Download package

tmrHw.c

Go to the documentation of this file.
/*****************************************************************************
* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available at
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*****************************************************************************/

/****************************************************************************/
/**
*  @file    tmrHw.c
*
*  @brief   Low level Timer driver routines
*
*  @note
*
*   These routines provide basic timer functionality only.
*/
/****************************************************************************/

/* ---- Include Files ---------------------------------------------------- */

#include <csp/errno.h>
#include <csp/stdint.h>

#include <csp/tmrHw.h>
#include <mach/csp/tmrHw_reg.h>

#define tmrHw_ASSERT(a)                     if (!(a)) *(char *)0 = 0
#define tmrHw_MILLISEC_PER_SEC              (1000)

#define tmrHw_LOW_1_RESOLUTION_COUNT        (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
#define tmrHw_LOW_1_MAX_MILLISEC            (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT)
#define tmrHw_LOW_16_RESOLUTION_COUNT       (tmrHw_LOW_1_RESOLUTION_COUNT / 16)
#define tmrHw_LOW_16_MAX_MILLISEC           (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT)
#define tmrHw_LOW_256_RESOLUTION_COUNT      (tmrHw_LOW_1_RESOLUTION_COUNT / 256)
#define tmrHw_LOW_256_MAX_MILLISEC          (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT)

#define tmrHw_HIGH_1_RESOLUTION_COUNT       (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
#define tmrHw_HIGH_1_MAX_MILLISEC           (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT)
#define tmrHw_HIGH_16_RESOLUTION_COUNT      (tmrHw_HIGH_1_RESOLUTION_COUNT / 16)
#define tmrHw_HIGH_16_MAX_MILLISEC          (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT)
#define tmrHw_HIGH_256_RESOLUTION_COUNT     (tmrHw_HIGH_1_RESOLUTION_COUNT / 256)
#define tmrHw_HIGH_256_MAX_MILLISEC         (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT)

static void ResetTimer(tmrHw_ID_t timerId)
    __attribute__ ((section(".aramtext")));
static int tmrHw_divide(int num, int denom)
    __attribute__ ((section(".aramtext")));

/****************************************************************************/
/**
*  @brief   Get timer capability
*
*  This function returns various capabilities/attributes of a timer
*
*  @return  Capability
*
*/
/****************************************************************************/
00067 uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId, /*  [ IN ] Timer Id */
                          tmrHw_CAPABILITY_e capability     /*  [ IN ] Timer capability */
) {
      switch (capability) {
      case tmrHw_CAPABILITY_CLOCK:
            return (timerId <=
                  1) ? tmrHw_LOW_RESOLUTION_CLOCK :
                tmrHw_HIGH_RESOLUTION_CLOCK;
      case tmrHw_CAPABILITY_RESOLUTION:
            return 32;
      default:
            return 0;
      }
      return 0;
}

/****************************************************************************/
/**
*  @brief   Resets a timer
*
*  This function initializes  timer
*
*  @return  void
*
*/
/****************************************************************************/
00093 static void ResetTimer(tmrHw_ID_t timerId /*  [ IN ] Timer Id */
) {
      /* Reset timer */
      pTmrHw[timerId].LoadValue = 0;
      pTmrHw[timerId].CurrentValue = 0xFFFFFFFF;
      pTmrHw[timerId].Control = 0;
      pTmrHw[timerId].BackgroundLoad = 0;
      /* Always configure as a 32 bit timer */
      pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT;
      /* Clear interrupt only if raw status interrupt is set */
      if (pTmrHw[timerId].RawInterruptStatus) {
            pTmrHw[timerId].InterruptClear = 0xFFFFFFFF;
      }
}

/****************************************************************************/
/**
*  @brief   Sets counter value for an interval in ms
*
*  @return   On success: Effective counter value set
*            On failure: 0
*
*/
/****************************************************************************/
00117 static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId,  /*  [ IN ] Timer Id */
                               tmrHw_INTERVAL_t msec  /*  [ IN ] Interval in milli-second */
) {
      uint32_t scale = 0;
      uint32_t count = 0;

      if (timerId == 0 || timerId == 1) {
            if (msec <= tmrHw_LOW_1_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
                  scale = tmrHw_LOW_1_RESOLUTION_COUNT;
            } else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
                  scale = tmrHw_LOW_16_RESOLUTION_COUNT;
            } else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
                  scale = tmrHw_LOW_256_RESOLUTION_COUNT;
            } else {
                  return 0;
            }

            count = msec * scale;
            /* Set counter value */
            pTmrHw[timerId].LoadValue = count;
            pTmrHw[timerId].BackgroundLoad = count;

      } else if (timerId == 2 || timerId == 3) {
            if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
                  scale = tmrHw_HIGH_1_RESOLUTION_COUNT;
            } else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
                  scale = tmrHw_HIGH_16_RESOLUTION_COUNT;
            } else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) {
                  pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
                  scale = tmrHw_HIGH_256_RESOLUTION_COUNT;
            } else {
                  return 0;
            }

            count = msec * scale;
            /* Set counter value */
            pTmrHw[timerId].LoadValue = count;
            pTmrHw[timerId].BackgroundLoad = count;
      }
      return count / scale;
}

/****************************************************************************/
/**
*  @brief   Configures a periodic timer in terms of timer interrupt rate
*
*  This function initializes a periodic timer to generate specific number of
*  timer interrupt per second
*
*  @return   On success: Effective timer frequency
*            On failure: 0
*
*/
/****************************************************************************/
00176 tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /*  [ IN ] Timer Id */
                              tmrHw_RATE_t rate /*  [ IN ] Number of timer interrupt per second */
) {
      uint32_t resolution = 0;
      uint32_t count = 0;
      ResetTimer(timerId);

      /* Set timer mode periodic */
      pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
      /* Set timer in highest resolution */
      pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;

      if (rate && (timerId == 0 || timerId == 1)) {
            if (rate > tmrHw_LOW_RESOLUTION_CLOCK) {
                  return 0;
            }
            resolution = tmrHw_LOW_RESOLUTION_CLOCK;
      } else if (rate && (timerId == 2 || timerId == 3)) {
            if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) {
                  return 0;
            } else {
                  resolution = tmrHw_HIGH_RESOLUTION_CLOCK;
            }
      } else {
            return 0;
      }
      /* Find the counter value */
      count = resolution / rate;
      /* Set counter value */
      pTmrHw[timerId].LoadValue = count;
      pTmrHw[timerId].BackgroundLoad = count;

      return resolution / count;
}

/****************************************************************************/
/**
*  @brief   Configures a periodic timer to generate timer interrupt after
*           certain time interval
*
*  This function initializes a periodic timer to generate timer interrupt
*  after every time interval in millisecond
*
*  @return   On success: Effective interval set in milli-second
*            On failure: 0
*
*/
/****************************************************************************/
00225 tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,     /*  [ IN ] Timer Id */
                                    tmrHw_INTERVAL_t msec   /*  [ IN ] Interval in milli-second */
) {
      ResetTimer(timerId);

      /* Set timer mode periodic */
      pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;

      return SetTimerPeriod(timerId, msec);
}

/****************************************************************************/
/**
*  @brief   Configures a periodic timer to generate timer interrupt just once
*           after certain time interval
*
*  This function initializes a periodic timer to generate a single ticks after
*  certain time interval in millisecond
*
*  @return   On success: Effective interval set in milli-second
*            On failure: 0
*
*/
/****************************************************************************/
00250 tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,      /*  [ IN ] Timer Id */
                                     tmrHw_INTERVAL_t msec  /*  [ IN ] Interval in milli-second */
) {
      ResetTimer(timerId);

      /* Set timer mode oneshot */
      pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
      pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT;

      return SetTimerPeriod(timerId, msec);
}

/****************************************************************************/
/**
*  @brief   Configures a timer to run as a free running timer
*
*  This function initializes a timer to run as a free running timer
*
*  @return   Timer resolution (count / sec)
*
*/
/****************************************************************************/
00272 tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,  /*  [ IN ] Timer Id */
                               uint32_t divider /*  [ IN ] Dividing the clock frequency */
) {
      uint32_t scale = 0;

      ResetTimer(timerId);
      /* Set timer as free running mode */
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC;
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;

      if (divider >= 64) {
            pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
            scale = 256;
      } else if (divider >= 8) {
            pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
            scale = 16;
      } else {
            pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
            scale = 1;
      }

      if (timerId == 0 || timerId == 1) {
            return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale);
      } else if (timerId == 2 || timerId == 3) {
            return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale);
      }

      return 0;
}

/****************************************************************************/
/**
*  @brief   Starts a timer
*
*  This function starts a preconfigured timer
*
*  @return  -1     - On Failure
*            0     - On Success
*
*/
/****************************************************************************/
00313 int tmrHw_startTimer(tmrHw_ID_t timerId   /*  [ IN ] Timer id */
) {
      pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE;
      return 0;
}

/****************************************************************************/
/**
*  @brief   Stops a timer
*
*  This function stops a running timer
*
*  @return  -1     - On Failure
*            0     - On Success
*
*/
/****************************************************************************/
00330 int tmrHw_stopTimer(tmrHw_ID_t timerId    /*  [ IN ] Timer id */
) {
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE;
      return 0;
}

/****************************************************************************/
/**
*  @brief   Gets current timer count
*
*  This function returns the current timer value
*
*  @return  Current downcounting timer value
*
*/
/****************************************************************************/
00346 uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId     /*  [ IN ] Timer id */
) {
      /* return 32 bit timer value */
      switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) {
      case tmrHw_CONTROL_FREE_RUNNING:
            if (pTmrHw[timerId].CurrentValue) {
                  return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue;
            }
            break;
      case tmrHw_CONTROL_PERIODIC:
      case tmrHw_CONTROL_ONESHOT:
            return pTmrHw[timerId].BackgroundLoad -
                pTmrHw[timerId].CurrentValue;
      }
      return 0;
}

/****************************************************************************/
/**
*  @brief   Gets timer count rate
*
*  This function returns the number of counts per second
*
*  @return  Count rate
*
*/
/****************************************************************************/
00373 tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId    /*  [ IN ] Timer id */
) {
      uint32_t divider = 0;

      switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) {
      case tmrHw_CONTROL_PRESCALE_1:
            divider = 1;
            break;
      case tmrHw_CONTROL_PRESCALE_16:
            divider = 16;
            break;
      case tmrHw_CONTROL_PRESCALE_256:
            divider = 256;
            break;
      default:
            tmrHw_ASSERT(0);
      }

      if (timerId == 0 || timerId == 1) {
            return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider);
      } else {
            return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider);
      }
      return 0;
}

/****************************************************************************/
/**
*  @brief   Enables timer interrupt
*
*  This function enables the timer interrupt
*
*  @return   N/A
*
*/
/****************************************************************************/
00409 void tmrHw_enableInterrupt(tmrHw_ID_t timerId   /*  [ IN ] Timer id */
) {
      pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE;
}

/****************************************************************************/
/**
*  @brief   Disables timer interrupt
*
*  This function disable the timer interrupt
*
*  @return   N/A
*
*/
/****************************************************************************/
00424 void tmrHw_disableInterrupt(tmrHw_ID_t timerId  /*  [ IN ] Timer id */
) {
      pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE;
}

/****************************************************************************/
/**
*  @brief   Clears the interrupt
*
*  This function clears the timer interrupt
*
*  @return   N/A
*
*  @note
*     Must be called under the context of ISR
*/
/****************************************************************************/
00441 void tmrHw_clearInterrupt(tmrHw_ID_t timerId    /*  [ IN ] Timer id */
) {
      pTmrHw[timerId].InterruptClear = 0x1;
}

/****************************************************************************/
/**
*  @brief   Gets the interrupt status
*
*  This function returns timer interrupt status
*
*  @return   Interrupt status
*/
/****************************************************************************/
00455 tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId    /*  [ IN ] Timer id */
) {
      if (pTmrHw[timerId].InterruptStatus) {
            return tmrHw_INTERRUPT_STATUS_SET;
      } else {
            return tmrHw_INTERRUPT_STATUS_UNSET;
      }
}

/****************************************************************************/
/**
*  @brief   Indentifies a timer causing interrupt
*
*  This functions returns a timer causing interrupt
*
*  @return  0xFFFFFFFF   : No timer causing an interrupt
*           ! 0xFFFFFFFF : timer causing an interrupt
*  @note
*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
*/
/****************************************************************************/
00476 tmrHw_ID_t tmrHw_getInterruptSource(void  /*  void */
) {
      int i;

      for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) {
            if (pTmrHw[i].InterruptStatus) {
                  return i;
            }
      }

      return 0xFFFFFFFF;
}

/****************************************************************************/
/**
*  @brief   Displays specific timer registers
*
*
*  @return  void
*
*/
/****************************************************************************/
00498 void tmrHw_printDebugInfo(tmrHw_ID_t timerId,   /*  [ IN ] Timer id */
                    int (*fpPrint) (const char *, ...)      /*  [ IN ] Print callback function */
) {
      (*fpPrint) ("Displaying register contents \n\n");
      (*fpPrint) ("Timer %d: Load value              0x%X\n", timerId,
                pTmrHw[timerId].LoadValue);
      (*fpPrint) ("Timer %d: Background load value   0x%X\n", timerId,
                pTmrHw[timerId].BackgroundLoad);
      (*fpPrint) ("Timer %d: Control                 0x%X\n", timerId,
                pTmrHw[timerId].Control);
      (*fpPrint) ("Timer %d: Interrupt clear         0x%X\n", timerId,
                pTmrHw[timerId].InterruptClear);
      (*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId,
                pTmrHw[timerId].RawInterruptStatus);
      (*fpPrint) ("Timer %d: Interrupt status        0x%X\n", timerId,
                pTmrHw[timerId].InterruptStatus);
}

/****************************************************************************/
/**
*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
*
*  @return   N/A
*/
/****************************************************************************/
00523 void tmrHw_udelay(tmrHw_ID_t timerId,     /*  [ IN ] Timer id */
              unsigned long usecs /*  [ IN ] usec to delay */
) {
      tmrHw_RATE_t usec_tick_rate;
      tmrHw_COUNT_t start_time;
      tmrHw_COUNT_t delta_time;

      start_time = tmrHw_GetCurrentCount(timerId);
      usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000);
      delta_time = usecs * usec_tick_rate;

      /* Busy wait */
      while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time))
            ;
}

/****************************************************************************/
/**
*  @brief   Local Divide function
*
*  This function does the divide
*
*  @return divide value
*
*/
/****************************************************************************/
00549 static int tmrHw_divide(int num, int denom)
{
      int r;
      int t = 1;

      /* Shift denom and t up to the largest value to optimize algorithm */
      /* t contains the units of each divide */
      while ((denom & 0x40000000) == 0) { /* fails if denom=0 */
            denom = denom << 1;
            t = t << 1;
      }

      /* Intialize the result */
      r = 0;

      do {
            /* Determine if there exists a positive remainder */
            if ((num - denom) >= 0) {
                  /* Accumlate t to the result and calculate a new remainder */
                  num = num - denom;
                  r = r + t;
            }
            /* Continue to shift denom and shift t down to 0 */
            denom = denom >> 1;
            t = t >> 1;
      } while (t != 0);
      return r;
}

Generated by  Doxygen 1.6.0   Back to index