📄 emeter-rtc.c
字号:
//--------------------------------------------------------------------------
//
// Software for MSP430 based e-meters.
//
// You may not use the Program in non-TI devices.
//
// File: emeter-rtc.c
//
// Steve Underwood <steve-underwood@ti.com>
// Texas Instruments Hong Kong Ltd.
//
// $Id$
//
/*! \file emeter-structs.h */
//
//--------------------------------------------------------------------------
#include <stdint.h>
#include <stdlib.h>
#if !defined(__MSP430__)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#if defined(__GNUC__)
#include <signal.h>
#endif
#if defined(__MSP430__)
#include <io.h>
#endif
#include <emeter-toolkit.h>
#include "emeter.h"
#include "emeter-structs.h"
#if !defined(NULL)
#define NULL (void *) 0
#endif
/* We need a small seconds counter, so we can do things like a display update every 2 seconds. */
uint8_t seconds;
#if defined(__MSP430__)
#if defined(__MSP430_HAS_BT__) || defined(__MSP430_HAS_BT_RTC__)
ISR(BASICTIMER, one_second_ticker)
#else
ISR(WDT, one_second_ticker)
#endif
{
#if defined(POWER_DOWN_SUPPORT) && defined(POWER_UP_BY_SUPPLY_SENSING)
#if defined(__MSP430_HAS_COMPA__) || (defined(POWER_GOOD_SENSE) && defined(POWER_GOOD_THRESHOLD_HIGH))
int i;
int j;
#endif
#endif
kick_watchdog();
#if defined(RTC_SUPPORT)
#if defined(CORRECTED_RTC_SUPPORT)
/* Allow for RTC correction. */
if ((meter_status & SKIP_A_SECOND))
meter_status &= ~SKIP_A_SECOND;
else
rtc_bumper();
#else
rtc_bumper();
#endif
#endif
#if defined(CUSTOM_RTC_SUPPORT)
if ((meter_status & SKIP_A_SECOND))
meter_status &= ~SKIP_A_SECOND;
else
custom_rtc();
#endif
if (++seconds & 1)
meter_status |= TICKER; /* Kick every 2 seconds */
#if defined(RF_LINK_SUPPORT)
if (operating_mode == OPERATING_MODE_POWERFAIL && rf_timeout >= 0)
{
if (++rf_timeout == 5)
{
rf_timeout = 0;
/* Enable the USART */
U0ME |= (UTXE0 | URXE0);
#if defined(__MSP430_HAS_FLLPLUS__) || defined(__MSP430_HAS_FLLPLUS_SMALL__)
/* Speed up the clock to 8.388608MHz */
SCFI0 = FN_3 | FLLD_4;
SCFQCTL = 64 - 1;
#endif
#if defined(custom_rf_sniffer)
if (rf_timeout = custom_rf_sniffer())
{
/* We need to set up timer A to call back when the message exchange time
comes round */
/* Use timer A to time the period until the real messages are exchanged. */
TAR = 0;
TACCR0 = 55*rf_timeout;
TACCTL0 = 0;
TACTL = TACLR | MC_1 | ID_2 | TASSEL_1;
/* Stop the 5 second scans until the timed response is complete */
rf_timeout = -1;
}
#endif
/* Disable the USART */
U0ME &= ~(UTXE0 | URXE0);
#if defined(__MSP430_HAS_FLLPLUS__) || defined(__MSP430_HAS_FLLPLUS_SMALL__)
/* Slow the clock to 1MHz as quickly as possible. The FLL will not be active
in LPM3, so switch it off now, and force the FLL's RC oscillator to
about 1MHz. The exact frequency is not critical. */
_BIS_SR(SCG0); /* switch off FLL locking */
SCFI0 = FLLD_1;
SCFQCTL = (32 - 1) | SCFQ_M;
SCFI0 = 0x0;
SCFI1 = 0x37;
#endif
}
}
#endif
#if defined(POWER_DOWN_SUPPORT)
#if defined(POWER_UP_BY_VOLTAGE_PULSES)
/* One method to detect power being restored is to look
for pulses on an input pin, caused by the voltage signal. */
if (meter_status & POWER_DOWN)
{
pd_pin_debounce <<= 1;
if (power_up_voltage_pulse())
pd_pin_debounce |= 1;
#if defined(__MSP430__)
if ((pd_pin_debounce & 0xF) == 0xF)
_BIC_SR_IRQ(LPM3_bits);
#endif
}
else
{
#if defined(__MSP430__)
_BIC_SR_IRQ(LPM0_bits);
#endif
}
#endif
#if defined(POWER_UP_BY_SUPPLY_SENSING)
/* If the meter has a limp mode, where it can be powered from the live
or neutral only, getting wakeup voltage pulses is not so easy. Current
pulses are not much easier. Here we look for the pre-regulator power
supply voltage being of an adequate level. We use comparator A as the
sensor, and only switch it on for the minimum possible time. */
#if defined(__MSP430_HAS_COMPA__)
#if defined(__MSP430__)
if (operating_mode == OPERATING_MODE_POWERFAIL)
{
/* Select the lower comparator threshold for going to the LCD on, but other
functions off, condition. Current consumption should be low enough to not
be too significant for reasonable periods. */
CACTL1 = CAREF_1 | CAON;
/* We are required to start quickly, so we cannot do much
debouncing here */
power_down_debounce = POWER_RESTORE_DEBOUNCE;
i = CACTL2 & CAOUT;
while (--power_down_debounce >= 0)
{
j = CACTL2 & CAOUT;
if (i != j)
{
i = j;
power_down_debounce = POWER_RESTORE_DEBOUNCE;
}
}
if (!j)
{
/* This appears to be a real power-up. We have reached 4.2V. This
should be OK for running the internal LCD controller, as it only
takes a few uA. For a small LCD, as little as 2uA. */
operating_mode = OPERATING_MODE_LCD_ONLY;
#if defined(BASIC_LCD_SUPPORT)
display_power_4v2_message();
#endif
custom_lcd_wakeup_handler();
}
power_down_debounce = 0;
CACTL1 &= ~(CAON);
}
else if (operating_mode == OPERATING_MODE_LCD_ONLY)
{
/* Select the higher comparator threshold for power restored. That should
mean that if the MCU is woken up, it can definitely run for a while at
full speed, just from the charge on the main capacitor. */
CACTL1 = CAREF_2 | CAON;
/* We are required to start quickly, so we cannot do much
debouncing here. */
power_down_debounce = POWER_RESTORE_DEBOUNCE;
i = CACTL2 & CAOUT;
while (--power_down_debounce >= 0)
{
j = CACTL2 & CAOUT;
if (i != j)
{
i = j;
power_down_debounce = POWER_RESTORE_DEBOUNCE;
}
}
if (!j)
{
/* This appears to be a real power-up. */
#if defined(BASIC_LCD_SUPPORT)
display_power_normal_message();
#endif
_BIC_SR_IRQ(LPM3_bits);
}
else
{
/* The power hasn't reached the high water mark. See if it has
dropped back below the low water mark. */
CACTL1 = CAREF_1 | CAON;
/* We are required to start quickly, so we cannot do much
debouncing here. */
power_down_debounce = POWER_RESTORE_DEBOUNCE;
i = CACTL2 & CAOUT;
while (--power_down_debounce >= 0)
{
j = CACTL2 & CAOUT;
if (i != j)
{
i = j;
power_down_debounce = POWER_RESTORE_DEBOUNCE;
}
}
if (j)
{
/* This appears to be a real power drop. */
operating_mode = OPERATING_MODE_POWERFAIL;
custom_lcd_sleep_handler();
}
}
power_down_debounce = 0;
CACTL1 &= ~(CAON);
}
#endif
#else
/* Use an I/O pin to sense the power falling */
#if defined(__MSP430__)
if (operating_mode == OPERATING_MODE_POWERFAIL)
{
/* Select the higher comparator threshold for starting up. This ensures we should have
enough energy in the capacitors to keep the meter running until it works out what to
do next. */
POWER_GOOD_THRESHOLD_HIGH;
/* We are required to start quickly, so we cannot do much
debouncing here */
power_down_debounce = POWER_RESTORE_DEBOUNCE;
i = POWER_GOOD_SENSE;
while (--power_down_debounce >= 0)
{
j = POWER_GOOD_SENSE;
if (i != j)
{
i = j;
power_down_debounce = POWER_RESTORE_DEBOUNCE;
}
}
if (j)
{
/* This appears to be a real power-up. */
#if defined(BASIC_LCD_SUPPORT)
display_power_normal_message();
#endif
custom_lcd_wakeup_handler();
_BIC_SR_IRQ(LPM3_bits);
}
power_down_debounce = 0;
}
#endif
#endif
#endif
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
{
/* We need to kick things, to give the foreground activities a chance
to do their work. */
_BIC_SR_IRQ(LPM0_bits);
}
#endif
#endif
kick_watchdog();
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -