You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OpenChronos/driver/timer.c

588 lines
16 KiB
C

// *************************************************************************************************
//
// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 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.
//
// Neither the name of Texas Instruments Incorporated 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 AND CONTRIBUTORS
// "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
// OWNER OR CONTRIBUTORS 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.
//
// *************************************************************************************************
// Timer service routines.
// *************************************************************************************************
// *************************************************************************************************
// Include section
// system
#include "project.h"
// driver
#include "timer.h"
#include "ports.h"
#include "buzzer.h"
#include "vti_ps.h"
#include "vti_as.h"
#include "display.h"
// logic
#include "clock.h"
#include "battery.h"
#include "stopwatch.h"
#include "alarm.h"
#include "altitude.h"
#include "display.h"
#include "rfsimpliciti.h"
#include "simpliciti.h"
#include "acceleration.h"
#ifdef CONFIG_PROUT
#include "prout.h"
#endif
#ifdef CONFIG_VARIO
#include "vario.h"
#endif
//pfs
#ifndef ELIMINATE_BLUEROBIN
#include "bluerobin.h"
#endif
#include "temperature.h"
#ifdef CONFIG_EGGTIMER
#include "eggtimer.h"
#endif
// *************************************************************************************************
// Prototypes section
void Timer0_Init(void);
void Timer0_Stop(void);
void Timer0_A1_Start(void);
void Timer0_A1_Stop(void);
void Timer0_A3_Start(u16 ticks);
void Timer0_A3_Stop(void);
void Timer0_A4_Delay(u16 ticks);
void (*fptr_Timer0_A3_function)(void);
// *************************************************************************************************
// Defines section
// *************************************************************************************************
// Global Variable section
struct timer sTimer;
// *************************************************************************************************
// Extern section
extern void BRRX_TimerTask_v(void);
extern void to_lpm(void);
// *************************************************************************************************
// @fn Timer0_Init
// @brief Set Timer0 to a period of 1 or 2 sec. IRQ TACCR0 is asserted when timer overflows.
// @param none
// @return none
// *************************************************************************************************
void Timer0_Init(void)
{
// Set interrupt frequency to 1Hz
TA0CCR0 = 32768 - 1;
// Enable timer interrupt
TA0CCTL0 |= CCIE;
// Clear and start timer now
// Continuous mode: Count to 0xFFFF and restart from 0 again - 1sec timing will be generated by ISR
TA0CTL |= TASSEL0 + MC1 + TACLR;
}
// *************************************************************************************************
// @fn Timer0_Start
// @brief Start Timer0.
// @param none
// @return none
// *************************************************************************************************
void Timer0_Start(void)
{
// Start Timer0 in continuous mode
TA0CTL |= MC_2;
}
// *************************************************************************************************
// @fn Timer0_Stop
// @brief Stop and reset Timer0.
// @param none
// @return none
// *************************************************************************************************
void Timer0_Stop(void)
{
// Stop Timer0
TA0CTL &= ~MC_2;
// Set Timer0 count register to 0x0000
TA0R = 0;
}
// *************************************************************************************************
// @fn Timer0_A3_Start
// @brief Trigger IRQ every "ticks" microseconds
// @param ticks (1 tick = 1/32768 sec)
// @return none
// *************************************************************************************************
void Timer0_A3_Start(u16 ticks)
{
u16 value;
// Store timer ticks in global variable
sTimer.timer0_A3_ticks = ticks;
// Delay based on current counter value
value = TA0R + ticks;
// Update CCR
TA0CCR3 = value;
// Reset IRQ flag
TA0CCTL3 &= ~CCIFG;
// Enable timer interrupt
TA0CCTL3 |= CCIE;
}
// *************************************************************************************************
// @fn Timer0_A3_Stop
// @brief Stop Timer0_A3.
// @param none
// @return none
// *************************************************************************************************
void Timer0_A3_Stop(void)
{
// Clear timer interrupt
TA0CCTL3 &= ~CCIE;
}
// *************************************************************************************************
// @fn Timer0_A4_Delay
// @brief Wait for some microseconds
// @param ticks (1 tick = 1/32768 sec)
// @return none
// *************************************************************************************************
void Timer0_A4_Delay(u16 ticks)
{
u16 value;
// Exit immediately if Timer0 not running - otherwise we'll get stuck here
if ((TA0CTL & (BIT4 | BIT5)) == 0) return;
// Disable timer interrupt
TA0CCTL4 &= ~CCIE;
// Clear delay_over flag
sys.flag.delay_over = 0;
// Add delay to current timer value
value = TA0R + ticks;
// Update CCR
TA0CCR4 = value;
// Reset IRQ flag
TA0CCTL4 &= ~CCIFG;
// Enable timer interrupt
TA0CCTL4 |= CCIE;
// Wait for timer IRQ
while (1)
{
// Delay in LPM
to_lpm();
#ifdef USE_WATCHDOG
// Service watchdog
WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL;
#endif
// Redraw stopwatch display
if (is_stopwatch()) display_stopwatch(LINE2, DISPLAY_LINE_UPDATE_PARTIAL);
// Check stop condition
if (sys.flag.delay_over) break;
}
}
// *************************************************************************************************
// @fn TIMER0_A0_ISR
// @brief IRQ handler for TIMER0_A0 IRQ
// Timer0_A0 1/1sec clock tick (serviced by function TIMER0_A0_ISR)
// Timer0_A1 (serviced by function TIMER0_A1_5_ISR)
// Timer0_A2 1/100 sec Stopwatch (serviced by function TIMER0_A1_5_ISR)
// Timer0_A3 Configurable periodic IRQ (serviced by function TIMER0_A1_5_ISR)
// Timer0_A4 One-time delay (serviced by function TIMER0_A1_5_ISR)
// @param none
// @return none
// *************************************************************************************************
//pfs
#ifdef __GNUC__
#include <signal.h>
interrupt (TIMER0_A0_VECTOR) TIMER0_A0_ISR(void)
#else
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
#endif
{
static u8 button_lock_counter = 0;
static u8 button_beep_counter = 0;
// Disable IE
TA0CCTL0 &= ~CCIE;
// Reset IRQ flag
TA0CCTL0 &= ~CCIFG;
// Add 1 sec to TACCR0 register (IRQ will be asserted at 0x7FFF and 0xFFFF = 1 sec intervals)
TA0CCR0 += 32768;
// Enable IE
TA0CCTL0 |= CCIE;
// Add 1 second to global time
clock_tick();
// Set clock update flag
display.flag.update_time = 1;
// While SimpliciTI stack operates or BlueRobin searches, freeze system state
//pfs
#ifdef ELIMINATE_BLUEROBIN
if (is_rf())
#else
if (is_rf() || is_bluerobin_searching())
#endif
{
// SimpliciTI automatic timeout
if (sRFsmpl.timeout == 0)
{
simpliciti_flag |= SIMPLICITI_TRIGGER_STOP;
}
else
{
sRFsmpl.timeout--;
}
// Exit from LPM3 on RETI
_BIC_SR_IRQ(LPM3_bits);
return;
}
// -------------------------------------------------------------------
// Service modules that require 1/min processing
if (sTime.drawFlag >= 2)
{
// Measure battery voltage to keep track of remaining battery life
request.flag.voltage_measurement = 1;
// Check if alarm needs to be turned on
check_alarm();
}
// -------------------------------------------------------------------
// Service active modules that require 1/s processing
// Generate alarm signal
if (sAlarm.state == ALARM_ON)
{
// Decrement alarm duration counter
if (sAlarm.duration-- > 0)
{
request.flag.buzzer = 1;
}
else
{
sAlarm.duration = ALARM_ON_DURATION;
stop_alarm();
}
}
#ifdef CONFIG_PROUT
if (is_prout()) prout_tick();
#endif
#ifdef CONFIG_VARIO
if(is_vario()) vario_tick();
#endif
// Do a temperature measurement each second while menu item is active
if (is_temp_measurement()) request.flag.temperature_measurement = 1;
// Do a pressure measurement each second while menu item is active
#ifdef CONFIG_ALTITUDE
if (is_altitude_measurement())
{
// Countdown altitude measurement timeout while menu item is active
sAlt.timeout--;
// Stop measurement when timeout has elapsed
if (sAlt.timeout == 0)
{
stop_altitude_measurement();
// Show ---- m/ft
display_chars(LCD_SEG_L1_3_0, (u8*)"----", SEG_ON);
// Clear up/down arrow
display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF);
display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF);
}
// In case we missed the IRQ due to debouncing, get data now
if ((PS_INT_IN & PS_INT_PIN) == PS_INT_PIN) request.flag.altitude_measurement = 1;
}
#endif
// Count down timeout
if (is_acceleration_measurement())
{
// Countdown acceleration measurement timeout
sAccel.timeout--;
// Stop measurement when timeout has elapsed
if (sAccel.timeout == 0) as_stop();
// If DRDY is (still) high, request data again
if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1;
}
//pfs
#ifndef ELIMINATE_BLUEROBIN
// If BlueRobin transmitter is connected, get data from API
if (is_bluerobin()) get_bluerobin_data();
#endif
// If battery is low, decrement display counter
if (sys.flag.low_battery)
{
if (sBatt.lobatt_display-- == 0)
{
message.flag.prepare = 1;
message.flag.type_lobatt = 1;
sBatt.lobatt_display = BATTERY_LOW_MESSAGE_CYCLE;
}
}
// If a message has to be displayed, set display flag
if (message.all_flags)
{
if (message.flag.prepare)
{
message.flag.prepare = 0;
message.flag.show = 1;
}
else if (message.flag.erase) // message cycle is over, so erase it
{
message.flag.erase = 0;
display.flag.full_update = 1;
}
}
// -------------------------------------------------------------------
// Check idle timeout, set timeout flag
if (sys.flag.idle_timeout_enabled)
{
if (sTime.system_time - sTime.last_activity > INACTIVITY_TIME) sys.flag.idle_timeout = 1; //setFlag(sysFlag_g, SYS_TIMEOUT_IDLE);
}
// -------------------------------------------------------------------
// Detect continuous button high states
if (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED)
{
if (button_beep_counter++ > LEFT_BUTTON_LONG_TIME)
{
// Toggle no_beep buttons flag
sys.flag.no_beep = ~sys.flag.no_beep;
// Show "beep / nobeep" message synchronously with next second tick
message.flag.prepare = 1;
if (sys.flag.no_beep) message.flag.type_no_beep_on = 1;
else message.flag.type_no_beep_off = 1;
// Reset button beep counter
button_beep_counter = 0;
}
} else if (BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED) // Trying to lock/unlock buttons?
{
if (button_lock_counter++ > LEFT_BUTTON_LONG_TIME)
{
// Toggle lock / unlock buttons flag
sys.flag.lock_buttons = ~sys.flag.lock_buttons;
// Show "buttons are locked/unlocked" message synchronously with next second tick
message.flag.prepare = 1;
if (sys.flag.lock_buttons) message.flag.type_locked = 1;
else message.flag.type_unlocked = 1;
// Reset button lock counter
button_lock_counter = 0;
}
}
else // Trying to create a long button press?
{
// Reset button lock counter
button_lock_counter = 0;
if (BUTTON_STAR_IS_PRESSED)
{
sButton.star_timeout++;
// Check if button was held low for some seconds
if (sButton.star_timeout > LEFT_BUTTON_LONG_TIME)
{
button.flag.star_long = 1;
sButton.star_timeout = 0;
}
}
else
{
sButton.star_timeout = 0;
}
if (BUTTON_NUM_IS_PRESSED)
{
sButton.num_timeout++;
// Check if button was held low for some seconds
if (sButton.num_timeout > LEFT_BUTTON_LONG_TIME)
{
button.flag.num_long = 1;
sButton.num_timeout = 0;
}
}
else
{
sButton.num_timeout = 0;
}
}
// Exit from LPM3 on RETI
_BIC_SR_IRQ(LPM3_bits);
}
// *************************************************************************************************
// @fn Timer0_A1_5_ISR
// @brief IRQ handler for timer IRQ.
// Timer0_A0 1/1sec clock tick (serviced by function TIMER0_A0_ISR)
// Timer0_A1 BlueRobin timer
// Timer0_A2 1/100 sec Stopwatch
// Timer0_A3 Configurable periodic IRQ (used by button_repeat and buzzer)
// Timer0_A4 One-time delay
// @param none
// @return none
// *************************************************************************************************
//pfs
#ifdef __GNUC__
#include <signal.h>
interrupt (TIMER0_A1_VECTOR) TIMER0_A1_5_ISR(void)
#else
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_5_ISR(void)
#endif
{
u16 value;
switch (TA0IV)
{
//pfs
#ifndef ELIMINATE_BLUEROBIN
// Timer0_A1 BlueRobin timer
case 0x02: // Timer0_A1 handler
BRRX_TimerTask_v();
break;
#endif
// Timer0_A2 1/1 or 1/100 sec Stopwatch
case 0x04: // Timer0_A2 handler
// Disable IE
TA0CCTL2 &= ~CCIE;
// Reset IRQ flag
TA0CCTL2 &= ~CCIFG;
// Load CCR register with next capture point
update_stopwatch_timer();
#ifdef CONFIG_EGGTIMER
update_eggtimer_timer();
#endif
// Enable timer interrupt
TA0CCTL2 |= CCIE;
// Increase stopwatch counter
stopwatch_tick();
#ifdef CONFIG_EGGTIMER
eggtimer_tick();
#endif
break;
// Timer0_A3 Configurable periodic IRQ (used by button_repeat and buzzer)
case 0x06: // Disable IE
TA0CCTL3 &= ~CCIE;
// Reset IRQ flag
TA0CCTL3 &= ~CCIFG;
// Store new value in CCR
value = TA0R + sTimer.timer0_A3_ticks; //timer0_A3_ticks_g;
// Load CCR register with next capture point
TA0CCR3 = value;
// Enable timer interrupt
TA0CCTL3 |= CCIE;
// Call function handler
fptr_Timer0_A3_function();
break;
// Timer0_A4 One-time delay
case 0x08: // Disable IE
TA0CCTL4 &= ~CCIE;
// Reset IRQ flag
TA0CCTL4 &= ~CCIFG;
// Set delay over flag
sys.flag.delay_over = 1;
break;
}
// Exit from LPM3 on RETI
_BIC_SR_IRQ(LPM3_bits);
}