📄 lh79524_timer0_driver.c
字号:
pregs->ctrl = temp;
/* Set the new time base */
temp = pregs->ctrl;
/* Clear the current count clock bit field B[4:2] */
temp &= ~_SBF(2,7);
/* Set up the new clock rate - set B[4:2] */
temp |= _SBF(2,arg);
/* Update the config structure */
pdev->cfg.clock_rate = _SBF(2,arg);
/* Restore the intial timer state (start/stop) */
pregs->ctrl = (temp | running);
}
break;
/* Set the clock rate */
case TIMER_GET_CLK_RATE:
/* Sanity check */
if ((void*)arg == NULL)
{
status = _ERROR;
break;
}
/* Return the driver interrupt service routine */
*(INT_32*)arg = pdev->cfg.clock_rate;
break;
/* Enable PWM mode */
case TIMER_SET_PWM_MODE:
/* Get the current contents on the register */
temp = pregs->cmp_cap_ctrl;
/* Clear the CMP1 and CMP0 fields B[13:12] and B[11:10] */
temp &= ~(_SBF(12,3) | _SBF(10,3));
temp |= _SBF(15,1) | /* PWM bit set B[15] = 1 */
_SBF(14,1) | /* TC bit set B[14] = 1 */
_SBF(12,2) | /* CMP1 B[13:12] = 10 */
_SBF(10,1); /* CMP0 B[11:10] = 01 */
/* Update the register */
pregs->cmp_cap_ctrl = temp;
/* EJA - hack need to fix */
#define TIMER_MUX_REG (0xFFFE500C)
/* Set up the pin muxing */
*(volatile long*)TIMER_MUX_REG = 0;
*(volatile long*)TIMER_MUX_REG |= _SBF(1,2);
break;
/* Enable free running counter mode */
case TIMER_SET_CNT_MODE:
/* Get the current contents on the register */
temp = pregs->cmp_cap_ctrl;
/* Clear the CMP1 and CMP0 fields B[13:12] and B[11:10] */
temp &= ~(_SBF(12,3) | _SBF(10,3));
temp |= _SBF(15,0) | /* PWM bit set B[15] = 0 */
_SBF(14,0); /* TC bit set B[14] = 0 */
/* Update the register */
pregs->cmp_cap_ctrl = temp;
break;
/* Enable Periodic counter mode */
case TIMER_SET_PERIODIC_MODE:
timer0_set_interval(pregs, (UNS_32)arg, pdev->cfg.sys_clk);
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;
/* Set the timer compare and capture control register */
case TIMER0_SET_CMP_CAP_CTRL:
pregs->cmp_cap_ctrl = arg;
break;
/* Get the timer compare and capture control register */
case TIMER0_GET_CMP_CAP_CTRL:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cmp_cap_ctrl;
break;
/* Set the timer capture2 register */
case TIMER0_SET_CAP2:
break;
/* Get the timer capture2 register */
case TIMER0_GET_CAP2:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cap2;
break;
/* Set the timer capture3 register */
case TIMER0_SET_CAP3:
pregs->cap3 = arg;
break;
/* Get the timer capture3 register */
case TIMER0_GET_CAP3:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cap3;
break;
/* Set the timer capture4 register */
case TIMER0_SET_CAP4:
pregs->cap4 = arg;
break;
/* Get the timer capture4 register */
case TIMER0_GET_CAP4:
if ((void*)arg == NULL)
{
status = _ERROR;
}
*(INT_32*)arg = pregs->cap4;
break;
default:
status = _ERROR;
break;
}
/* Return the io control status */
return (status);
}
/************************************************************************
*
* Function: timer0_isr
*
* Purpose:
* Services the interrupt for a timer0.
*
* Processing:
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* None
*
* Notes:
* None
*
************************************************************************/
void timer0_isr (void)
{
/* Call the default handler */
timer0_default_isr ((INT_32)pdriver[0]);
}
/************************************************************************
*
* Function: timer0_default_handler
*
* Purpose:
* Services the interrupt for a timer0.
*
* Processing:
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* None
*
* Notes:
* None
*
************************************************************************/
static void timer0_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) timer0_ioctl (devid, TIMER_STOP, 0);
/* Clear the timer */
(void) timer0_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) timer0_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 TIMER0, 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 timer0_set_interval(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 < TM0_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 &= ~TM0_CTRL_SEL(TM0_CTRL_CTCLK);
timer_regs->ctrl |= TM0_CTRL_SEL(best_prescale_index);
timer_regs->cmp_cap_ctrl = TM0_CMPCAP_TC;
return usec;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -