?? ce.c
字號(hào):
/***************************************************************************
* This code and information is provided "as is" without warranty of any *
* kind, either expressed or implied, including but not limited to the *
* implied warranties of merchantability and/or fitness for a particular *
* purpose. *
* *
* Copyright (C) 2005 Teridian Semiconductor Corp. All Rights Reserved. *
***************************************************************************/
//**************************************************************************
// DESCRIPTION: 71M652x POWER METER - COMPUTE ENGINE Interface.
//
// AUTHOR: MTF
//
// HISTORY: See end of file.
//**************************************************************************
// File: CE.C
//
#include "options.h" // controls the features
#include "irq.h" // interrupt disabling
#include "batmodes.h" // battery mode management
#include "ce_ce.h" // CE's microcode file.
#include "ce_dat.h" // CE's data area initialization file.
#include "wd.h" // used to manage the watchdog
#include "library.h" // to copy data around
#if TIMERS
#include "stm.h" // software timers. to wait till CE's data is valid
#endif
#include "main.h" // to get soft reset
#include "meter.h" // main meter code, to get creep logic
#include "pcnt.h" // pulse counting
#include "psoft.h" // software pulse generation
#include "eeprom.h" // EEPROM interface, used to save data on sag
//#include "oscope.h" // scope loop debugging code
#include "ce.h" // check the prototypes
#define FIRST_PASSES 2 // passes to ignore after the CE's filters settle
#define FULL_SCALE 0x00A6D45L // CE outputs full scale values; 683333.
#define CEB_DECIMATION 8 // software pulsing depends on this value
/*** Public functions declared within this module ***/
// See "ce.h".
/*** Public variables declared within this module *** settible via "defaults" */
volatile bool meter_had_power;
uint8_t ce_first_pass;
const uint8r_t pre_samps[] = { 42, 50, 84, 100 };
uint16x_t samples;
bool xfer_update; // Enables update only if changed.
bool xfer_busy;
uint8_t data decimate_ce_busy = CEB_DECIMATION; // decimates code in ce_busy
/*** Private functions declared within this module ***/
/*** Private variables declared within this module ***/
#if TRACE10
static uint8_t chop = _POSITIVE;
#endif
//===========================================================================//
// This runs each time the CE executes its halt instruction- once per pass.
// That is, this runs 2520.6 times per second. It collects the sag
// data, and performs other logic that must be synchronized to the CE.
#pragma save
#pragma REGISTERBANK (CE_BANK)
void ce_busyz_isr (void) small reentrant interrupt CE_BUSYZ_IV using CE_BANK
{
#if 1 // enable this entire interrupt's code
#if M6520
#elif TRACE10
CE2 = (CE2 & ~CHOP_EN) | CHOP_EN;
#endif
if ((IFLAGS & IE_XFER_) && xfer_busy)
{
xfer_busy = 0;
CONFIG1 &= ~MUX_ALT; // Clear, force alternate MUX sequence.
CONFIG1 |= MUX_ALT; // Set.
}
// This interrupt runs every 396us, and these tasks
// can be handled much less often without problems.
if ((--decimate_ce_busy) == 0)
{
#if STATUS
uint8_t ck;
uint8_t status_ce;
#define ea TRUE
#endif
// 8 * 396 = 3.2ms; psoft_out() depends on this running every 8th time
decimate_ce_busy = CEB_DECIMATION;
#if STATUS
ck = CKCON;
BEGIN_CE_CRITICAL_SECTION;
CLK_STRETCH; // Change stretch to '6' equivalent.
status_ce = * (uint8x_t *) &CE_Outputs.O_cestatus; // Just grab high order byte.
CLK_RELAX; // Back to default value.
END_CE_CRITICAL_SECTION;
// preserve the 3 conductor sag bits; F0 and 1_SEC are current data
Totals.Sums.T_Status.c[HI_HI] = status_ce;
// Are the compute-engine's sag detection bits set for all the phases
// that power the meter? (POWERED_PHASE is in options.h)
if ((status_ce & POWERED_PHASE) == POWERED_PHASE)
{
// Save when the power fails, not when it is off.
if (meter_had_power)
{
uint8_t ckcon = CONFIG0; // save clock speed
extern enum EEPROM_RC data eeprom_state;
EA = 0; // disable interrupts
// Changing the MPU speed causes serial communication
// to fail, since the uarts are clocked by the same clock.
// This is reasonable in code to manage power failure.
CONFIG0 &= ~MPU_DIV; // MPU to full speed
RESET_WD(); // push off the hardware watchdog
meter_had_power = FALSE;
#if EEPROM
// prepare to save the registers
// eeprom_enable();
eeprom_state = _OK;
memcpy_prx (
EEPROM_REGISTERS,
(uint8x_t*)&Totals.Acc, // The start of the data
// the second copy will be valid if the first is
// being recalculated, and vice-versa
(2*sizeof(struct Accumulators_t))); // save two copies
#endif
CONFIG0 = ckcon; // restore clock speed
EA = 1; // enable interrupts
}
}
else
{
meter_had_power = TRUE;
}
#undef ea
#endif // STATUS
#if PULSE_SOFT
psoft_out (); // software pulse outputs
#endif
#ifdef WD_CE_BUSYZ
wd_reset ( WD_CE_BUSYZ ); // notify the watchdog handler
#endif
}
#endif // this interrupt's code is enabled
}
#pragma restore
#if EXTRAS
// wait till CE busy completes
void ce_wait_for_busy (void)
{
uint8_t now;
uint16_t cnt;
now = decimate_ce_busy;
for (cnt = 400; (cnt > 0) && (now == decimate_ce_busy); --cnt)
;
}
#endif
//============================================================================//
// This runs from either of two interrupts, either the data available
// interrupt: xfer_busy, or the real-time-clock's one-second interrupt.
// The xfer_busy interrupt transfers data from the CE to the MPU on each
// accumulation interval- a few times per second, usually.
// The RTC interrupt performs the temperature compensation, and any other
// items that must be performed on precise one-second intervals.
// Both interrupts are rather infrequent.
#pragma save
#pragma NOAREGS
// called from the interrupt decode routines in io65??.c
void ce_xfer_busyz_isr (void) small reentrant
{
#if TRACE10
CE2 = (CE2 & ~CHOP_EN) | chop;
chop ^= CHOP_EN; // Toggle chop between 1 (01b) and 2 (10b).
#endif
// On the first two passes, the CE's calculations are incorrect,..
// ..so the results are not worth recording.
if (0 == ce_first_pass)
{
uint8p_t *pDst;
uint8x_t *pSrc;
uint8_t len;
// variables to save interrupt state for a CE transfer
CE_XFER_DEFINES;
// save a snapshot of the state
CE_XFER_SAVE;
// copy CE values to the MPU
pDst = MPU_Outputs;
pSrc = (uint8x_t *) &CE_Outputs;
len = sizeof (CE_Outputs) / sizeof (int32_t);
do
{
MEMCPY_MCE; // Copy single 32-bit word from CE to XRAM.
NEXT_MCE; // Point to start of next Dst & Src.
} while (--len);
xfer_update = TRUE; // Inform the main loop to process the data.
}
else if (0 == --ce_first_pass)
{
DIO |= DIO_PW; // Enable WPULSE.
DIO |= DIO_PV; // Enable VARPULSE.
}
#ifdef WD_XFER_BUSYZ // if it's required, reset it
wd_reset ( WD_XFER_BUSYZ );
#endif
#ifdef OSCOPE_H
OSCOPE_TOGGLE;
#endif
xfer_busy = 1; // permit ce_busy_isr to set alt_mux
}
#pragma restore
//============================================================================//
// This routine runs one second after the CE is started. At that point
// the CE's software PLL has locked to the line frequency, and the digital
// filtering is operating. Acquisition of data should be delayed till
// the second set of data is available after the PLL settles.
#if TIMERS
#pragma save
#pragma NOAREGS
static void ce_start(void) small reentrant
{
ce_first_pass = FIRST_PASSES; // Ignore CE data until the data is right.
}
#pragma restore
#endif
//============================================================================//
// Initialize the compute engine in the analog front end.
void ce_init (void)
{
uint16_t s = (NumCeCode * sizeof (CeCode[0])); // the size of CE code
#if PULSE_SOURCE && M6520
uint32_t temp;
#endif
// I/O constants at 2000 are set-up in defaults.c
CE_DISABLE (); // Turn off the CE.
// figure the samples per accumulation interval, needed to display data
samples = pre_samps[ (CE1 & PRE_SAMPS) >> 6 ] * (CE1 & SUM_CYCLES);
#if BROWNOUT_BATMODE
// In brownout return without setting up the CE; the CE can't
// run anyway because the ADCs are off. Copying the data
// takes time, and at a 32KHz clock rate, that's waste.
if (batmode_is_brownout ())
{
// note that samples is set up (see above),
// so display routines work.
// note that CE is disabled (see above)
EX_CE_BUSYZ = FALSE; // Disable busyz interrupt.
// The xfer interrupt is shared with the RTC clock, which continues
// to operate.
// clear both flags at once, forcing an edge to cause interrupt 6
// If this is not done, the unit can deadlock at reset.
IFLAGS &= ~(IE_XFER_ | IE_RTC_);
EX_XFER_RTC = TRUE; // Enable external interrupt 6
CE2 &= ~EX_XFER; // Disable the xfer interrupt
#ifdef WD_RTC
wd_create ( WD_RTC );
#endif
return;
}
#endif
irq_disable (); // start of a critical section
// set up the sag-detect flag
meter_had_power = FALSE;
#if TIMERS
// The CE's software PLL and filtering take one second to settle.
// Valid data occurs on the second collection after that.
ce_first_pass = 0xFF; // Ignore CE data until the timer runs
stm_start (milliseconds(1000), 0, ce_start); // start a software timer
#else
ce_first_pass = 2; // approximate the requirement
#endif
#if TRACE10
// Copy CE_CODE image to the CE's microcode RAM.
memcpy_xr ((int8x_t *) CE_CODE_BASE, (int8r_t *) CeCode, s);
// Assure that it halts.
* (uint16x_t *) (CE_CODE_BASE + ((CE_CODE_SIZE - 1) << 1)) = 0xFFFF;
#else // it's a 652x, with the CE code in flash.
CE3 = (uint16_t) CeCode >> 10; // tell the CE where its code is.
#endif
// Copy the CE's initial variable values to the CE's RAM.
if (NumCeData)
{
memcpy_cer (
(int32x_t *)CE_DATA_BASE,
(int32r_t *)&CeData[0],
(uint8_t)(0xff & NumCeData)
);
}
else
{
memset_x (
(uint8x_t *)CE_DATA_BASE,
0,
(CE_PARM_SIZE * 4)
);
}
#if PULSE_SOURCE
#if M6520
temp = memget_ce(&cestate);
temp |= CE_EXT_PULSE;
memset_ce (&cestate, temp);
#elif TRACE10
// memset_ce (&ext_pulse, 15); // experimental
#else
#error unknown device type
#endif
#endif
#if CONSTANTS_DBG
// Make CE defaults visible to the AMD-51 ICE.
// Note, if this code is enabled, overlap errors occur in the link,
// but they do not cause defective operation.
get_ce_constants ();
#endif
// After this, the watchdog is reset only if these interrupts
// have run.
RESET_WD(); // Reset watchdog.
// Set up the interrupts.
// Interrupt priorities are set in main.
I3FR = FALSE; // FALLING_EDGE_CE_BUSYZ.
EX_CE_BUSYZ = TRUE; // Enable busyz interrupt.
decimate_ce_busy = CEB_DECIMATION;
#ifdef WD_CE_BUSYZ
wd_create (WD_CE_BUSYZ); // if wd.h says, watch this interrupt
#endif
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -