📄 lh79524_timer_driver.c
字号:
pregs->ctrl = temp;
break;
/* Enable free running counter operation */
case TIMER_SET_CNT_MODE:
/* Get the current contents on the register */
temp = pregs->ctrl;
/* Clear the CMP1 and CMP0 fields B[13:12] and B[11:10] */
temp &= ~(_SBF(12,3) | _SBF(10,3));
temp |= _SBF(14,0) | /* PWM bit set B[14] = 0 */
_SBF(13,0); /* TC bit set B[13] = 0 */
/* Update the register */
pregs->ctrl = temp;
break;
/* Mask interrupts at the source */
case TIMER_DISABLE_INT:
/* Get the current state */
temp = pregs->int_ctrl;
/* Mask off the interrupt */
temp &= ~arg;
/* Update the interrupt control register */
pregs->int_ctrl = temp;
break;
/* Unmask interrupts at the source */
case TIMER_ENABLE_INT:
/* Get the current state */
temp = pregs->int_ctrl;
/* UnMask the interrupt */
temp |= arg;
/* Update the interrupt control register */
pregs->int_ctrl = temp;
/* Update the driver control object */
pdev->imask = temp;
break;
/* Return pointer to device isr */
case TIMER_GET_ISR:
/* Sanity check */
if ((void*)arg == NULL)
{
status = _ERROR;
break;
}
/* Return the driver interrupt service routine */
*(INT_32**)arg = (void*)pdev->irq_hdlr;
break;
/* Bind a callback method to be used by the timer isr */
case TIMER_SET_CALLBACK:
/* Save the interrupt callback method */
pdev->callback = (PFI)arg;
break;
/* Set the timer status register */
case TIMER_SET_STATUS:
pregs->status = arg;
break;
/* Get the timer status register */
case TIMER_GET_STATUS:
/* Sanity check */
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->status;
break;
/* Set the timer status register */
case TIMER_SET_COUNT:
pregs->cnt = arg;
break;
/* Get the timer status register */
case TIMER_GET_COUNT:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cnt;
break;
/* Set the timer status register */
case TIMER_SET_CMP0:
pregs->cmp0 = arg;
break;
/* Get the timer status register */
case TIMER_GET_CMP0:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cmp0;
break;
/* Set the timer status register */
case TIMER_SET_CMP1:
pregs->cmp1 = arg;
break;
/* Get the timer status register */
case TIMER_GET_CMP1:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cmp1;
break;
/* Set the timer status register */
case TIMER_SET_CAP0:
pregs->cap0 = arg;
break;
/* Get the timer status register */
case TIMER_GET_CAP0:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cap0;
break;
/* Set the timer status register */
case TIMER_SET_CAP1:
pregs->cap1 = arg;
break;
/* Get the timer status register */
case TIMER_GET_CAP1:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cap1;
break;
default:
status = _ERROR;
break;
}
/* Return the io control status */
return (status);
}
/***********************************************************************
*
* Function: timer_wait_us
*
* Purpose: Delay for usec microSeconds
*
* Processing:
* If the timer argument is a valid timer, stop the timer and use
* the timer_set_delay function to program the timer underflow to
* the needed delay and then restart the timer. Monitor the raw
* timer count value until the value underflows. Stop the timer and
* then clear the pending timer interrupt.
*
* Parameters:
* timer : Must be TIMER1 or TIMER2
* usec : the delay time in microseconds
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* This function is intended for simple non-interruptable delays
* with accurate timing. Using this function will change the
* settings of the timer the function is used with. For very small
* times with a low CPU and bus clock speed, the timing may be
* inaccurate. Use with care.
*
**********************************************************************/
void timer_wait_us(TIMER_REGS_T *timer_regs,
UNS_32 usec,
UNS_32 xtal_in)
{
if((timer_regs == TIMER1) || (timer_regs == TIMER2))
{
/* stop timer */
timer_regs->ctrl &= ~TM12_CTRL_CS;
/* set the desired interval */
timer_set_interval(timer_regs, usec, xtal_in);
/* clear counter register */
timer_regs->ctrl |= TM12_CTRL_CCL;
/* clear inetrrupt */
timer_regs->status = _BIT(TM12_INTCTRL_CMP1);
/* start timer */
timer_regs->ctrl |= TM12_CTRL_CS | TM12_CTRL_CCL;
/* wait of campare 1 event */
while ( (timer_regs->status & TM12_INTCTRL_CMP1) == 0)
;
/* clear compare interrupt */
timer_regs->status = _BIT(TM12_INTCTRL_CMP1);
/* stop timer */
timer_regs->ctrl &= ~TM12_CTRL_CS;
}
}
/***********************************************************************
*
* Function: timer_wait_ms
*
* Purpose:
* Wait for the specified number of milliseconds
*
* Processing:
* Call timer_wait_us() with a value of 1000 usec for the number of
* times specified by the msec argument.
*
* Parameters:
* timer: Must be one of TIMER1 or TIMER2
* msec: the delay time in milliseconds
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void timer_wait_ms(TIMER_REGS_T *timer_regs,
UNS_32 msec,
UNS_32 xtal_in)
{
UNS_32 elapsed_ms;
for (elapsed_ms = 0; elapsed_ms < msec; elapsed_ms++)
{
timer_wait_us(timer_regs, 1000, xtal_in);
}
}
/************************************************************************
*
* Function: timer1_isr
*
* Purpose:
* Services the interrupt for a timer1.
*
* Processing:
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* None
*
* Notes:
* None
*
************************************************************************/
static void timer1_isr (void)
{
/* Call the default handler */
timer_default_isr ((INT_32)pdriver[0]);
}
/************************************************************************
*
* Function: timer1_isr
*
* Purpose:
* Services the interrupt for a timer1.
*
* Processing:
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* None
*
* Notes:
* None
*
************************************************************************/
static void timer2_isr (void)
{
/* Call the default handler */
timer_default_isr ((INT_32)pdriver[1]);
}
/************************************************************************
*
* Function: timer_default_handler
*
* Purpose:
* Services the interrupt for a timer0.
*
* Processing:
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* None
*
* Notes:
* None
*
************************************************************************/
static void timer_default_isr (INT_32 devid)
{
REGS_T* pregs = NULL;
DRIVER_T* pdev = NULL;
/* Attach to the base address of the driver */
pdev = (DRIVER_T*)devid;
/* Attach to the base address of the selected timer */
pregs = (REGS_T*)pdev->regs;
/* Stop the timer */
(void) timer_ioctl (devid, TIMER_STOP, 0);
/* Clear the timer */
(void) timer_ioctl (devid, TIMER_CLEAR_CNT, 0);
/* Check if the counter has expired */
if (pdev->callback != NULL)
{
/* Execute the callback method */
(*(PFI)pdev->callback) ();
}
/* Clear the interrupt at the source */
pregs->status = pdev->imask;
/* Start the timer */
(void) timer_ioctl (devid, TIMER_START, 0);
}
/***********************************************************************
*
* Function: timer_set_interval
*
* Purpose:
* Initialize the specified timer as an interval timer that clears
* itself after the specified interval
*
* Processing:
* Set the TC bit of the ctrl register and set CMP1 and the prescaler
* bits in the control register to values appropriate to the timer
* interval. Find these values by trying every prescaler and CMP1
* combination and determining which gives the smallest difference
* from the requested interval. Return _ERROR if the clock source
* cannot generate a periodic time base.
*
* Parameters:
* timer: either TIMER1 or TIMER2
* (see LH79524_timer_driver.h)
* usec: the requested interval in microseconds
* xtal_in: On board oscillator clock
*
* Outputs: None.
*
* Returns:
* the actual timer interval in microseconds that can be obtained with
* the specified clock source or _ERROR if usec is out of range
*
* Notes:
* If the interval is too short, the function will set the interval
* to the minimum available. If the interval is too long, the
* interval will be set to the maximum. Users of this function should
* check the return code to make sure the interval is close enough
* to the requested interval.
*
**********************************************************************/
static INT_32 timer_set_interval(TIMER_REGS_T* timer_regs,
UNS_32 usec,
UNS_32 xtal_in)
{
INT_32 counts, new_counts;
UNS_32 new_usec, best_usec, hclk;
UNS_32 prescale_index, best_prescale_index;
UNS_32 max_interval, min_interval;
INT_32 delta, best_delta;
hclk = RCPC_GET_HCLK(xtal_in);
max_interval = (UNS_32)(((UNS_64)_BIT(16) *
(UNS_64)USECS_PER_SEC) /
((UNS_64)hclk / (UNS_64)128));
if (usec > max_interval)
usec = max_interval;
min_interval = 2 * USECS_PER_SEC / hclk;
if (usec < min_interval)
usec = min_interval;
best_delta = usec;
/* minimize the error in timing the interval*/
for (best_prescale_index = 0, prescale_index = 0, best_usec = 0;
prescale_index < TM12_CTRL_CTCLK;
prescale_index++)
{
new_counts = (UNS_32)((UNS_64)usec *
(UNS_64)(hclk / (1 << (prescale_index + 1))) /
(UNS_64)USECS_PER_SEC) - 1;
if (new_counts <= 0)
new_counts = 1;
new_counts &= _BITMASK(16); /* cmp1 register 16 bits.*/
new_usec = USECS_PER_SEC / (hclk /
(_BIT(prescale_index + 1) * new_counts));
delta = usec - new_usec;
if (delta < 0)
delta = -delta;
if (delta <= best_delta) /* use <= to maximize prescale*/
{
best_delta = delta;
best_prescale_index = prescale_index;
best_usec = new_usec;
counts = new_counts;
}
} /* end for*/
/* counts and best_prescale_index are initialized */
timer_regs->cmp1 = counts;
timer_regs->ctrl &= ~TM12_CTRL_SEL(TM12_CTRL_CTCLK);
timer_regs->ctrl |= TM12_CTRL_SEL(best_prescale_index) |
TM12_CTRL_TC;
return usec;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -