crashtest-r0ket/core/timer16/timer16.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;
}