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

📄 calphased.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) 2006 Teridian Semiconductor Corp. All Rights Reserved.    *
 ***************************************************************************/
//**************************************************************************
//  DESCRIPTION: 71M65xx POWER METER - Automatic calibration of the meter.
//  This includes temperature calibration, electrical calibration, including
//  phase compensation.  Assumes no reactive power in the test signal.
// 
//  AUTHOR:  RGV / MTF
//
//  HISTORY: See end of file.
//**************************************************************************
// File: calphased.c
//               
#include "options.h"
// if the meter uses current differences, then use the alternate
// calibration.c, a linear calibration of volts and current.
#if (CAL_SAVE || AUTOCAL) && \
    (EQUATION != _1ELEMENT_3WIRE \
     && EQUATION != _2ELEMENT_4WIRE_DELTA \
     && EQUATION != _2ELEMENT_4WIRE_WYE)
#include <math.h> // for sqrt()
#include "mmath.h"   // for s2f()
#include "error.h"
#include "meter.h"
#include "library.h"

#if NV_SELECT == NV_EEPROM
#include "eeprom.h"
#endif 
#if NV_SELECT == NV_FLASH
#include "flash.h"			// Disable CE while writing flash.
#endif 
#include "ce.h" // need "samples", disable CE while writing flash
#include "calibration.h"

#define ZERO  0L

/*** External functions referenced by this module ***/
// Refer to include files.

/*** External variables referenced by this module ***/
extern const int32r_t CeData[];    // The default data for the analog front end.
extern const int8r_t NumCeData[2];

/*** Public functions referenced by this module ***/
/* See 'calibration.h' */

/*** Public variables referenced by this module ***/
bool cal_flag;         // Keep calibrating.
static int8p_t cntDown;   // Remaining accumulation intervals of calibration.

/*** Private functions referenced by this module ***/
static void  adjust_element (uint8_t element_index);
static void cal_end (void);
static void compensation (void);
bool memcpy_cepr (int32x_t * pDst, uint16_t pSrc, uint16_t len);
void memcpy_prce (uint16_t pDst, int32x_t * pSrc, uint16_t len);

#if NV_SELECT == NV_FLASH
#define MANY 0xFF
void cal_save (void)                    // Save the calibration.
{
    if (CalibrationCount != MANY)
        CalibrationCount++;		

    // Compute & store checksums.	
    LRC_Calc_NVR ((uint8x_t *) &Totals.Parms, sizeof (struct Parameters_t), TRUE);	
    chksum_ce ((int32x_t *) CE_PARM_BASE, CE_PARM_SIZE, TRUE);

    CE_DISABLE();
    memcpy_rx  ((uint8r_t *) r_Parms, (uint8x_t*) &Totals.Parms, sizeof (struct Parameters_t) );
    memcpy_rce ((uint8r_t *) CeData, (uint8x_t *) CE_PARM_BASE, CE_PARM_SIZE);
    CE_ENABLE();
}
#elif NV_SELECT == NV_EEPROM
#define MANY 0xFF
void cal_save (void)                    // Save the calibration.
{
    if (CalibrationCount != MANY)
        CalibrationCount++;		

    // Compute & store checksums.	
    LRC_Calc_NVR ((uint8x_t *) &Totals.Parms, sizeof (struct Parameters_t), TRUE);	
    CE_DISABLE();
    lrc_ce ((int32x_t *) CE_PARM_BASE, CE_PARM_SIZE, TRUE );

    #if EEPROM
    eeprom_enable();                    // Enable non-volatile store.
    memcpy_prce (
            EEPROM_CALIBRATION, 
            (int32x_t *) CE_PARM_BASE, 
            CE_PARM_SIZE );
    memcpy_prx (
            EEPROM_CALIBRATION + (CE_PARM_SIZE * 4), 
            (uint8x_t *) &Totals.Parms, 
            sizeof (struct Parameters_t) );
    eeprom_disable();                   // Disable non-volatile store.
    #endif
    CE_ENABLE();
} 
#else
#error unknown NV type
#endif                                  // Validate the restored calibration.

#if NV_SELECT == NV_FLASH
bool cal_restore (void)                 // Restore the calibration.
{
    bool ok = 1;

    // get the CE's data
    memcpy_cer (
            (int32x_t *) CE_PARM_BASE, 
            &CeData[0], 
            CE_PARM_SIZE );
    // get the MPU's data
    memcpy_xr  ( 
            (uint8x_t *) &Totals.Parms, 
            (uint8r_t *) r_Parms, 
            sizeof (struct Parameters_t) );

    #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

    // test the data to see if it's valid
    ok &= LRC_Calc_NVR (
            (uint8x_t *) &Totals.Parms, 
            sizeof (struct Parameters_t), 
            FALSE);
    ok &= lrc_ce (
            (int32x_t *) CE_PARM_BASE, 
            CE_PARM_SIZE, 
            FALSE);

    if (!ok)
        Status |= CAL_BAD;  // dating, etc. is in the main loop
    else
        Status &= ~CAL_BAD;

    CE_ENABLE();

    return ok;
}
#elif NV_SELECT == NV_EEPROM && EEPROM
bool cal_restore (void)                 // Restore the calibration.
{
    bool ok = 1;
    enum EEPROM_RC data *state;

    #if EEPROM
    eeprom_enable();                    // Enable non-volatile store.
    CE_DISABLE();
    // get the CE's data
    ok &= memcpy_cepr (
            (int32x_t *) CE_PARM_BASE, 
            EEPROM_CALIBRATION, 
            CE_PARM_SIZE);
    // get the MPU's data
    state = memcpy_xpr (
	    (uint8x_t *) &Totals.Parms, 
	    EEPROM_CALIBRATION + (CE_PARM_SIZE * 4), 
	    sizeof (struct Parameters_t)
	    );
    ok &= eeprom_ok (state);
    eeprom_disable();                   // Disable non-volatile store.
    #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

    // test the data to see if it's valid
    ok &= LRC_Calc_NVR (
            (uint8x_t *) &Totals.Parms, 
            sizeof (struct Parameters_t), 
            FALSE);
    ok &= lrc_ce (
            (int32x_t *) CE_PARM_BASE, 
            CE_PARM_SIZE, 
            FALSE);

    memset_ce(&apulsew,0);  // do not restore the pulse rates
    memset_ce(&apulser,0);  // they cause spurious pulses at start-up

    if (!ok)
        Status |= CAL_BAD;  // dating, etc. is in the main loop
    else
        Status &= ~CAL_BAD;

    CE_ENABLE();

    return ok;
}

// copy data from EEPROM to the CE's data area
bool memcpy_cepr (int32x_t * pDst, uint16_t pSrc, uint16_t len)
{
    int32_t xdata nv_data;
    enum EEPROM_RC data *state;
    bool ok = 1;

    for(; len != 0; --len)
    {
        state = memcpy_xpr ((uint8x_t *)&nv_data, pSrc, sizeof (int32_t));
        ok &= eeprom_ok (state);
        memset_ce (pDst++, nv_data);
        pSrc += sizeof (int32_t);
    }
    return ok;
}

// copy data from the CE's data area to EEPROM
void memcpy_prce (uint16_t pDst, int32x_t * pSrc, uint16_t len)
{
    int32_t xdata nv_data;

    for(; len != 0; --len)
    {
        nv_data = memget_ce (pSrc++);
        memcpy_prx (pDst, (uint8x_t *)&nv_data, sizeof (int32_t));
        pDst += sizeof (int32_t);
    }
}
#else
#error unknown NV type
#endif


/*** Private variables referenced by this module ***/
#if AUTOCAL
#if EQUATION != _3ELEMENT_4WIRE_WYE
#define ELEMENT_CNT 2
#else
#define ELEMENT_CNT 3
#endif

struct Element_t
{
    uint8x_t *pwh;
    uint8x_t *pvarh;
    int32x_t *pvsqsum;
    int32x_t *pcal_v;
    int32x_t *pcal_i;
    int32x_t *pphase_adj;
};


// On equations that add currents, it's impossible to calibrate the phase of
// both currents with a single test signal.  Equation 1-element-3-wire is tested
// by putting the meter in equation 0, and using the undocumented "B" Wh
// and VARh registers of the CE code, calculated from VA * IB.
#if EQUATION == _1ELEMENT_2WIRE || EQUATION == _1ELEMENT_3WIRE 
#define CALIBRATIONS 3
#define ADJUSTS 2
#define ELEMENTS 2
#define CAL_EQUATION _1ELEMENT_2WIRE
static struct Element_t code element_array [ELEMENT_CNT] = {
{&Whn_B, &VARh_B, &v0sqsum, &cal_v0, &cal_i1, &phadj_1},
// The standard CE code calculates "B" as VA * IB for equation 1-element-2-wire
// Element A usually has the best data, so v0 is adjusted last from A's data
{&Whn_A, &VARh_A, &v0sqsum, &cal_v0, &cal_i0, &phadj_0}
};
#elif EQUATION == _2ELEMENT_3WIRE_DELTA 
#define CALIBRATIONS 4
#define ADJUSTS 2
#define ELEMENTS 2
#define CAL_EQUATION _2ELEMENT_3WIRE_DELTA
static struct Element_t code element_array [ELEMENT_CNT] = {
{&Whn_A, &VARh_A, &v0sqsum, &cal_v0, &cal_i0, &phadj_0},
{&Whn_B, &VARh_B, &v0sqsum, &cal_v1, &cal_i1, &phadj_1}
};
#elif EQUATION == _2ELEMENT_4WIRE_DELTA
#define CALIBRATIONS 5
#error equation not supported: use the non-phase-adjusting calibration code
// We believe that these two unsupported equations will be rarely used 
// with our chip, because many meter manufacturers simply run conductors 
// in opposite directions through a shared CT.  However, if you need it...
// The alternate calibration code uses the same test setup, but uses
// vsqsum and isqsum, without adjusting the phases of the current.  For CTs,
// that version is usually within 0.04%, the typical phase error of a CT.
// The interface to the rest of the code is unchanged.
#elif EQUATION == _2ELEMENT_4WIRE_WYE
#define CALIBRATIONS 5
#error equation not supported: use the non-phase-adjusting calibration code
#elif EQUATION == _3ELEMENT_4WIRE_WYE
#define CALIBRATIONS 6
#define ADJUSTS 3
#define ELEMENTS 3
#define CAL_EQUATION _3ELEMENT_4WIRE_WYE
static struct Element_t code element_array [ELEMENT_CNT] = {
{&Whn_A, &VARh_A, &v0sqsum, &cal_v0, &cal_i0, &phadj_0},
{&Whn_B, &VARh_B, &v1sqsum, &cal_v1, &cal_i1, &phadj_1},
{&Whn_C, &VARh_C, &v2sqsum, &cal_v2, &cal_i2, &phadj_2}
};
#else
#error no such equation
#endif

void cal_begin (void)                   // Begin calibration.
{
    int32x_t *px;
    int8_t i;

    // MPU calibrations are omitted intentionally, because
    // all of them are more like configurations set by a user
    // to adapt the meter.

    // Sets default calibration for CE, including temperature compensations.
    px = &cal_i0;
    i = CALIBRATIONS;
    do  {   memset_ce (px++, UNITY);    } while (--i);

    i = ADJUSTS;
    do  {   memset_ce (px++, ZERO);     } while (--i);

    // Change to a metering equation that does not sum current sensors.
    // If no such equation is possible, try the non-phase-adjusting
    // calibration, which still gets within 0.04%, the typical error
    // of a CT.
    CE0 = (CE0 & ~EQU) | CAL_EQUATION;

    #if ADC_COMPENSATION
    // Start the calibration process, with 2 accumulation intervals
    // before temperature is collected, to clear the data pipeline.
    // Then, it collects data for another two seconds with the
    // temperature compensation running.
    cntDown = 4 + Scal;
    #else
    // Start the calibration process, with 2 accumulation intervals
    // before measurement begins, to clear the data pipeline.
    cntDown = 2 + Scal;
    #endif

    // set the global calibration flag
    Config |= CFG_CAL;
}

/* This the calibration state machine.
 * 1. Let the CE settle, then 
 * 2. Measure temperature for calibration, then 
 * 3. Measure the current for calibration, then 
 * 4. Perform the calibrations.
 * This calibrates gains, and phase for power elements.
 * It does not calibrate neutral current sensors,
 * or other odd arrangements.
 */
void Calibrate (void)
{
    if (0 >= cntDown || cntDown > (Scal + 4) || (Config & CFG_CAL) == 0)
        return;
    // Scal, Vcal and Ical are defined in 'defaults.c'.

    #if ADC_COMPENSATION
    /* Need two (2) accumulation intervals before the
     * raw temperature will be correct.
     * At this point, it can set the nominal temperature,
     * and then begin to collect the data with
     * temperature compensation enabled. */
    if (cntDown == (Scal + 2))
        compensation ();                // Set temperature compensation values.
    #endif
    
    if (cntDown == (Scal + 1)) // On the first accumulation interval of calibration.
        Config |= CFG_CLEAR_ACC;     // Clear the registers to 0.

    if (0 == --cntDown)         // Count accumulation intervals.
    {                           // If the last accumulation interval, calibrate.
        cntDown = -1;           // Make the count invalid.
        Config &= ~CFG_CAL;     // Turn off calibration mode.

        CE_DISABLE();           // Leave data values for engineer to see.

        cal_end ();             // Adjust calibration constants.
        cal_save();             // Save the new calibration.
        #if ERROR_RECORDING
        Error_Clear();
        #endif

        // Turn ON all the pulse outputs to show it's done.
        // This is a convenient indication because it works with
        // automatic calibration or manual operation.
        DIO &= 0xF3;            // The pulse outputs are DIOs.
        #if 1 == M6520
        CONFIG2 = 0x40 | (CONFIG2 & 0x3F); // Force TX_DIS to DIO_2.
        USER0 &= 0x3D;          // Drive the outputs to ground (LEDs on).
        DIR0 |= 0xC4;           // Change the DIOs 2, 6, 7 to outputs.
        #elif TRACE10                  
        USER0 &= 0x3F;          // Drive both outputs to ground (LEDs on).
        DIR0  |= 0xC0;          // Change the DIOs 6, 7 to outputs.
        #else
        #error unknown device
        #endif
        // clear the global calibration flag
        Config &= ~CFG_CAL;
    }
}

⌨️ 快捷键说明

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