⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ce.c

📁 TDK 6521 SOC 芯片 DEMO程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************
 * 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
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -