506 lines
16 KiB
C
506 lines
16 KiB
C
/**************************************************************************/
|
|
/*!
|
|
@file timer16.c
|
|
@author K. Townsend (microBuilder.eu)
|
|
|
|
@section DESCRIPTION
|
|
|
|
Generic code for both 16-bit timers.
|
|
|
|
@warning 16-bit timers are limited to roughly ~0.91ms (or 910uS) on
|
|
a system running at 72MHz since:
|
|
@code
|
|
1 mS = CFG_CPU_CCLK / 1000
|
|
= 72000000 / 1000
|
|
= 72000 'ticks'
|
|
@endcode
|
|
Meaning that 0xFFFF (65535) 'ticks' = 0.910208 milliseconds
|
|
or 910 microseconds.
|
|
|
|
@section Example
|
|
|
|
@code
|
|
#include "/core/cpu/cpu.h"
|
|
#include "/core/timer16/timer16.h"
|
|
|
|
// Instantiated in timer16.h
|
|
extern volatile uint32_t timer16_0_counter;
|
|
...
|
|
cpuInit();
|
|
|
|
// Initialise timer0 with a delay of 0xFFFF, which will cause the
|
|
// timer interrupt to fire every 65535 ticks and increment
|
|
// timer16_0_counter by 1
|
|
timer16Init(0, 0xFFFF);
|
|
|
|
// Enable the timer
|
|
timer16Enable(0);
|
|
|
|
// At this point timer16_0_counter should start incrementing by 1
|
|
// every 65535 ticks
|
|
@endcode
|
|
|
|
@section LICENSE
|
|
|
|
Software License Agreement (BSD License)
|
|
|
|
Copyright (c) 2010, microBuilder SARL
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
3. Neither the name of the copyright holders nor the
|
|
names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/**************************************************************************/
|
|
|
|
#include "timer16.h"
|
|
|
|
volatile uint32_t timer16_0_counter = 0;
|
|
volatile uint32_t timer16_1_counter = 0;
|
|
|
|
#ifdef CFG_PWM
|
|
volatile uint32_t pwmCounter = 0;
|
|
extern volatile uint32_t pwmMaxPulses; // See drivers/pwm/pwm.c
|
|
#endif
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Causes a blocking delay for the specified number of
|
|
clock ticks.
|
|
|
|
@note The exact duration of this delay depends on the speed of the
|
|
system clock, but it will invariably be short because of the
|
|
16-bit limitation. For example, on a system with a 72MHz
|
|
clock, a 1mS delay would be equal to 72,000 ticks, which is
|
|
already above the maximum 16-bit value of 65,535. Thus, the
|
|
maximum delay measured in mS with a 72MHz clock is ~0.91mS.
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to user (0..1)
|
|
@param[in] delayInTicks
|
|
The number of clock ticks to delay (0..65534)
|
|
|
|
@section Example
|
|
|
|
@code
|
|
#include "/core/cpu/cpu.h"
|
|
#include "/core/timer16/timer16.h"
|
|
|
|
int main(void)
|
|
{
|
|
cpuInit();
|
|
|
|
// Initialise timer 0 ... delay is provided but not used here
|
|
timer16Init(0, 0xFFFF);
|
|
|
|
// Enable the timer
|
|
timer16Enable(0);
|
|
|
|
while(1)
|
|
{
|
|
// Cause blocking delay for 36000 ticks (0.5mS @ 72MHz)
|
|
// Note: The delay must be 65534 or less (16-bit value)
|
|
timer16DelayTicks(0, 36000);
|
|
}
|
|
}
|
|
@endcode
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16DelayTicks(uint8_t timerNum, uint16_t delayInTicks)
|
|
{
|
|
// ToDo: Verify incoming value
|
|
|
|
if (timerNum == 0)
|
|
{
|
|
/* Reset the timer */
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERRESET_ENABLED;
|
|
|
|
/* Set the prescaler to zero */
|
|
TMR_TMR16B0PR = 0x00;
|
|
|
|
TMR_TMR16B0MR0 = delayInTicks;
|
|
|
|
/* Reset all interrupts */
|
|
TMR_TMR16B0IR = TMR_TMR16B0IR_MASK_ALL;
|
|
|
|
/* Stop timer on match (MR0) */
|
|
TMR_TMR16B0MCR = TMR_TMR16B0MCR_MR0_STOP_ENABLED;
|
|
|
|
/* Start timer */
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERENABLE_ENABLED;
|
|
|
|
/* Wait until the delay time has elapsed */
|
|
while (TMR_TMR16B0TCR & TMR_TMR16B0TCR_COUNTERENABLE_ENABLED);
|
|
}
|
|
|
|
else if (timerNum == 1)
|
|
{
|
|
/* Reset the timer */
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERRESET_ENABLED;
|
|
|
|
/* Set the prescaler to zero */
|
|
TMR_TMR16B1PR = 0x00;
|
|
|
|
TMR_TMR16B1MR0 = delayInTicks;
|
|
|
|
/* Reset all interrupts */
|
|
TMR_TMR16B1IR = TMR_TMR16B1IR_MASK_ALL;
|
|
|
|
/* Stop timer on match (MR0) */
|
|
TMR_TMR16B1MCR = TMR_TMR16B1MCR_MR0_STOP_ENABLED;
|
|
|
|
/* Start timer */
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERENABLE_ENABLED;
|
|
|
|
/* Wait until the delay time has elapsed */
|
|
while (TMR_TMR16B1TCR & TMR_TMR16B1TCR_COUNTERENABLE_ENABLED);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Causes a blocking delay for the specified number of
|
|
microseconds
|
|
|
|
@warning The maximum delay in uS will depend on the clock speed,
|
|
but running at 72MHz the maximum delay (MR = 0xFFFF)
|
|
would be 910uS (0xFFFF / 72 = 910), or 0.91 milliseconds.
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to user (0..1)
|
|
@param[in] delayInUs
|
|
The number of microseconds to wait
|
|
|
|
@section Example
|
|
|
|
@code
|
|
#include "/core/cpu/cpu.h"
|
|
#include "/core/timer16/timer16.h"
|
|
|
|
int main(void)
|
|
{
|
|
cpuInit();
|
|
|
|
// Initialise timer 0 ... delay is provided but not used here
|
|
timer16Init(0, 0xFFFF);
|
|
|
|
// Enable the timer
|
|
timer16Enable(0);
|
|
|
|
while(1)
|
|
{
|
|
// Cause blocking delay for 500 microseconds (0.5mS)
|
|
timer16DelayUS(0, 500);
|
|
}
|
|
}
|
|
@endcode
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16DelayUS(uint8_t timerNum, uint16_t delayInUS)
|
|
{
|
|
// ToDo: Check if the appropriate timer is enabled first?
|
|
|
|
if (timerNum == 0)
|
|
{
|
|
/* Reset the timer */
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERRESET_ENABLED;
|
|
|
|
/* Set the prescaler to zero */
|
|
TMR_TMR16B0PR = 0x00;
|
|
|
|
TMR_TMR16B0MR0 = delayInUS * ((CFG_CPU_CCLK/SCB_SYSAHBCLKDIV)/1000000);
|
|
|
|
/* Reset all interrupts */
|
|
TMR_TMR16B0IR = TMR_TMR16B0IR_MASK_ALL;
|
|
|
|
/* Stop timer on match (MR0) */
|
|
TMR_TMR16B0MCR = TMR_TMR16B0MCR_MR0_STOP_ENABLED;
|
|
|
|
/* Start timer */
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERENABLE_ENABLED;
|
|
|
|
/* Wait until the delay time has elapsed */
|
|
while (TMR_TMR16B0TCR & TMR_TMR16B0TCR_COUNTERENABLE_ENABLED);
|
|
}
|
|
|
|
else if (timerNum == 1)
|
|
{
|
|
/* Reset the timer */
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERRESET_ENABLED;
|
|
|
|
/* Set the prescaler to zero */
|
|
TMR_TMR16B1PR = 0x00;
|
|
|
|
TMR_TMR16B1MR0 = delayInUS * ((CFG_CPU_CCLK/SCB_SYSAHBCLKDIV)/1000000);
|
|
|
|
/* Reset all interrupts */
|
|
TMR_TMR16B1IR = TMR_TMR16B1IR_MASK_ALL;
|
|
|
|
/* Stop timer on match (MR0) */
|
|
TMR_TMR16B1MCR = TMR_TMR16B1MCR_MR0_STOP_ENABLED;
|
|
|
|
/* Start timer */
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERENABLE_ENABLED;
|
|
|
|
/* Wait until the delay time has elapsed */
|
|
while (TMR_TMR16B1TCR & TMR_TMR16B1TCR_COUNTERENABLE_ENABLED);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Interrupt handler for 16-bit timer 0
|
|
*/
|
|
/**************************************************************************/
|
|
void TIMER16_0_IRQHandler(void)
|
|
{
|
|
/* Clear the interrupt flag */
|
|
TMR_TMR16B0IR = TMR_TMR16B0IR_MR0;
|
|
|
|
/* Increment timer counter by 1 (it will automatically roll back to 0) */
|
|
timer16_0_counter++;
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Interrupt handler for 16-bit timer 1
|
|
*/
|
|
/**************************************************************************/
|
|
void TIMER16_1_IRQHandler(void)
|
|
{
|
|
/* Clear the interrupt flag */
|
|
TMR_TMR16B1IR = TMR_TMR16B1IR_MR0;
|
|
|
|
/* Increment timer counter by 1 (it will automatically roll back to 0) */
|
|
timer16_1_counter++;
|
|
|
|
#ifdef CFG_PWM
|
|
/* Check if the PWM output should be disabled after pwmMaxPulses pulses */
|
|
/* See "drivers/pwm/pwm.c" */
|
|
if (TMR_TMR16B1IR & TMR_TMR16B1IR_MR3)
|
|
{
|
|
/* Clear the interrupt flag */
|
|
TMR_TMR16B1IR = TMR_TMR16B1IR_MR3;
|
|
|
|
if (pwmMaxPulses > 0)
|
|
{
|
|
pwmCounter++;
|
|
if (pwmCounter == pwmMaxPulses)
|
|
{
|
|
/* Disable interrupt on MR3 */
|
|
TMR_TMR16B1MCR &= ~(TMR_TMR16B1MCR_MR3_INT_MASK);
|
|
/* Disable Timer */
|
|
TMR_TMR16B1TCR &= ~(TMR_TMR16B1TCR_COUNTERENABLE_MASK);
|
|
/* Reset the counter variables */
|
|
pwmCounter = 0;
|
|
pwmMaxPulses = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Enables the specified timer
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to enable (0..1)
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16Enable(uint8_t timerNum)
|
|
{
|
|
if ( timerNum == 0 )
|
|
{
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERENABLE_ENABLED;
|
|
}
|
|
|
|
else if (timerNum == 1)
|
|
{
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERENABLE_ENABLED;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Disables the specified timer
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to disable (0..1)
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16Disable(uint8_t timerNum)
|
|
{
|
|
if ( timerNum == 0 )
|
|
{
|
|
TMR_TMR16B0TCR = TMR_TMR16B0TCR_COUNTERENABLE_DISABLED;
|
|
}
|
|
|
|
else if (timerNum == 1)
|
|
{
|
|
TMR_TMR16B1TCR = TMR_TMR16B1TCR_COUNTERENABLE_DISABLED;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Resets the specified timer
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to reset (0..1)
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16Reset(uint8_t timerNum)
|
|
{
|
|
uint32_t regVal;
|
|
|
|
if ( timerNum == 0 )
|
|
{
|
|
regVal = TMR_TMR16B0TCR;
|
|
regVal |= TMR_TMR16B0TCR_COUNTERRESET_ENABLED;
|
|
TMR_TMR16B0TCR = regVal;
|
|
}
|
|
|
|
else if (timerNum == 1)
|
|
{
|
|
regVal = TMR_TMR16B1TCR;
|
|
regVal |= TMR_TMR16B1TCR_COUNTERRESET_ENABLED;
|
|
TMR_TMR16B1TCR = regVal;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
@brief Initialises the specified 16-bit timer, sets the timer
|
|
interval, resets the timer, and configures the interrupt
|
|
handler.
|
|
|
|
Initialises a 16-bit timer with the supplied timer interval (the
|
|
amount of time that passes between each timer 'tick'). Every time that
|
|
this interval elapses, the timer's interrupt will be fired and the
|
|
appropriate counter variable will be incremented by one (For example,
|
|
with CT16B0, 'timer16_0_counter' would be incremented).
|
|
|
|
@param[in] timerNum
|
|
The 16-bit timer to initiliase (0..1)
|
|
@param[in] timerInterval
|
|
The number of clock 'ticks' between resets (0..65534)
|
|
|
|
@warning Care needs to be taken when configuring the timers since
|
|
the pins are all multiplexed with other peripherals. This
|
|
code is provided as a starting point, but it will need to
|
|
be adjusted according to your own situation and
|
|
pin/peripheral requirements
|
|
*/
|
|
/**************************************************************************/
|
|
void timer16Init(uint8_t timerNum, uint16_t timerInterval)
|
|
{
|
|
// If timerInterval is invalid, use the default value
|
|
if (timerInterval < 1)
|
|
{
|
|
timerInterval = TIMER16_DEFAULTINTERVAL;
|
|
}
|
|
|
|
if ( timerNum == 0 )
|
|
{
|
|
/* Enable the clock for CT16B0 */
|
|
SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT16B0);
|
|
|
|
/* The physical pins associated with CT16B0 are not enabled by
|
|
default in order to avoid conflicts with other peripherals.
|
|
Pin 0.10 (CT16B0_MAT2), for example, can not be used while
|
|
debugging with a hardware debugger. If you require one or
|
|
more of these pins, simply uncomment the code below */
|
|
|
|
/* Configure PIO0.2 as Timer0_16 CAP0 */
|
|
// IOCON_PIO0_2 &= ~IOCON_PIO0_2_FUNC_MASK;
|
|
// IOCON_PIO0_2 |= IOCON_PIO0_2_FUNC_CT16B0_CAP0;
|
|
|
|
/* Configure PIO0.8 as Timer0_16 MAT0 */
|
|
// IOCON_PIO0_8 &= ~IOCON_PIO0_8_FUNC_MASK;
|
|
// IOCON_PIO0_8 |= IOCON_PIO0_8_FUNC_CT16B0_MAT0;
|
|
|
|
/* Configure PIO0.9 as Timer0_16 MAT1 */
|
|
// IOCON_PIO0_9 &= ~IOCON_PIO0_9_FUNC_MASK;
|
|
// IOCON_PIO0_9 |= IOCON_PIO0_9_FUNC_CT16B0_MAT1;
|
|
|
|
/* Configure PIO0.10 as Timer0_16 MAT3 */
|
|
// IOCON_JTAG_TCK_PIO0_10 &= ~IOCON_JTAG_TCK_PIO0_10_FUNC_MASK;
|
|
// IOCON_JTAG_TCK_PIO0_10 |= IOCON_JTAG_TCK_PIO0_10_FUNC_CT16B0_MAT2;
|
|
|
|
timer16_0_counter = 0;
|
|
TMR_TMR16B0MR0 = timerInterval;
|
|
|
|
/* Configure match control register to raise an interrupt and reset on MR0 */
|
|
TMR_TMR16B0MCR = (TMR_TMR16B0MCR_MR0_INT_ENABLED | TMR_TMR16B0MCR_MR0_RESET_ENABLED);
|
|
|
|
/* Enable the TIMER0 interrupt */
|
|
NVIC_EnableIRQ(TIMER_16_0_IRQn);
|
|
}
|
|
|
|
else if ( timerNum == 1 )
|
|
{
|
|
/* Enable the clock for CT16B1 */
|
|
SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT16B1);
|
|
|
|
/* The physical pins associated with CT16B0 are not enabled by
|
|
default in order to avoid conflicts with other peripherals.
|
|
Pin 0.10 (CT16B0_MAT2), for example, can not be used while
|
|
debugging with a hardware debugger. If you require one or
|
|
more of these pins, simply uncomment the code below */
|
|
|
|
/* Configure PIO1.8 as Timer1_16 CAP0 */
|
|
// IOCON_PIO1_8 &= ~IOCON_PIO1_8_FUNC_MASK;
|
|
// IOCON_PIO1_8 |= IOCON_PIO1_8_FUNC_CT16B1_CAP0;
|
|
|
|
/* Configure PIO1.9 as Timer1_16 MAT0 */
|
|
// IOCON_PIO1_9 &= ~IOCON_PIO1_9_FUNC_MASK;
|
|
// IOCON_PIO1_9 |= IOCON_PIO1_9_FUNC_CT16B1_MAT0;
|
|
|
|
/* Configure PIO1.10 as Timer1_16 MAT1 */
|
|
// IOCON_PIO1_10 &= ~IOCON_PIO1_10_FUNC_MASK;
|
|
// IOCON_PIO1_10 |= IOCON_PIO1_10_FUNC_CT16B1_MAT1;
|
|
|
|
timer16_1_counter = 0;
|
|
TMR_TMR16B1MR0 = timerInterval;
|
|
|
|
/* Configure match control register to raise an interrupt and reset on MR0 */
|
|
TMR_TMR16B1MCR = (TMR_TMR16B1MCR_MR0_INT_ENABLED | TMR_TMR16B1MCR_MR0_RESET_ENABLED);
|
|
|
|
/* Enable the TIMER1 Interrupt */
|
|
NVIC_EnableIRQ(TIMER_16_1_IRQn);
|
|
}
|
|
return;
|
|
}
|