Jump to main content

# 2.1.2 Using the Library

- The metrology module provides the essential components needed to fully define or derive all power system measurement quantities according to most commonly used power definitions

- Measurement data from one measurement interval is short-lived and does not persist longer than one measurement interval. At the end of a measurement interval, the user will be informed by software interrupt at which point the user must read all pertinent quantities before the next measurement period ends.

- All computed quantities available through the Metrology Module are integrated over a time interval equivalent to an integral number of periods of the fundamental frequency. All integration periods are approximated by the final output sample rate of the DSP filters, 4000 Hz; so, measurement accuracy will increase using longer integration periods. One second is the recommended minimum integration period (50 cycles of 50 Hz or 60 cycles of 60 Hz), but fewer numbers of samples may still yield acceptable results. DSP filters require a settling time before accurate measurements may be used for revenue-quality metering. It is recommended to wait at least 250 ms after start-up before testing when testing to revenue-grade accuracy.

- The Smart Meter DSP Module is specifically designed to accept samples from an Δ/Σ ADC using an OSR = 128, at an input sample rate of 16.000 kHz. This input data stream is filtered to an internal sample rate of 4.000 kHz for generation of metrology quantities. All computed metrology quantities are available at a rate of approximately 1 Hz, when using recommended settings.

- The multi-channel metrology library systematically acquires data from the signals connected to the MCP391x devices, designating each signal as a channel for the purpose of measuring electrical currents or voltages. A power is defined as a pair of one voltage and one current channel. The library's control registers offer users the capability to tailor the configuration of both channels and powers, ensuring an outstanding degree of adaptability.

- Values labeled as “_F” indicate values associated with the fundamental frequency component only, while values without the “_F” indicate values associated with fundamental + harmonics

Example application to handle metrology driver based on FreeRTOS application

    void SYS_Initialize ( void* data )
    {
        (...)

        /* Initialize Metrology Driver Instance */
        DRV_MCMETROLOGY_Initialize((SYS_MODULE_INIT *)&drvMCMetrologyInitData, RSTC_ResetCauseGet());

        (...)
    }

    static void _APP_METROLOGY_IntegrationCallback(void)
    {
        if (app_metrologyData.state == APP_METROLOGY_STATE_RUNNING)
        {
            /* Signal Metrology thread to update measurements for an integration period */
            OSAL_SEM_Post(&appMetrologySemID);
        }
    }

    static void _APP_METROLOGY_HarmonicAnalysisCallback(uint8_t harmonicNum)
    {
        if (app_metrologyData.stopHarmonicAnalysis)
        {
            app_metrologyData.harmonicAnalysisPending = false;
            DRV_MCMETROLOGY_StopHarmonicAnalysis();
        }

        if (app_metrologyData.pHarmonicAnalysisCallback)
        {
            if (app_metrologyData.sendHarmonicsToConsole)
            {
                app_metrologyData.sendHarmonicsToConsole = false;
                app_metrologyData.pHarmonicAnalysisCallback(harmonicNum);
            }
        }
    }

    void APP_METROLOGY_Initialize (void)
    {
        /* Place the App state machine in its initial state. */
        app_metrologyData.state = APP_METROLOGY_STATE_INIT;

        /* Flag to indicate if configuration should be applied */
        app_metrologyData.setConfiguration = false;

        /* Detection of the WDOG0 Reset */
        if (RSTC_ResetCauseGet() == RSTC_SR_RSTTYP(RSTC_SR_RSTTYP_WDT0_RST_Val))
        {
            app_metrologyData.startMode = DRV_MCMETROLOGY_START_SOFT;
        }
        else
        {
            app_metrologyData.startMode = DRV_MCMETROLOGY_START_HARD;
        }

        /* Get Pointers to metrology data regions */
        app_metrologyData.pMetControl = DRV_MCMETROLOGY_GetControl();
        app_metrologyData.pMetStatus = DRV_MCMETROLOGY_GetStatus();
        app_metrologyData.pMetAccData = DRV_MCMETROLOGY_GetAccData();
        app_metrologyData.pMetHarData = DRV_MCMETROLOGY_GetHarData();

        /* Set Callback for each metrology integration process */
        DRV_MCMETROLOGY_IntegrationCallbackRegister(_APP_METROLOGY_IntegrationCallback);
        /* Set Callback for harmonic analysis process */
        DRV_MCMETROLOGY_HarmonicAnalysisCallbackRegister(_APP_METROLOGY_HarmonicAnalysisCallback);

        /* Clear Harmonic Analysis Data */
        app_metrologyData.harmonicAnalysisPending = false;
        app_metrologyData.pHarmonicAnalisysCallback = NULL;
        app_metrologyData.pHarmonicAnalysisResponse = NULL;

        /* Create the Metrology Integration Semaphore. */
        if (OSAL_SEM_Create(&appMetrologySemID, OSAL_SEM_TYPE_BINARY, 0, 0) == OSAL_RESULT_FALSE)
        {
            /* Handle error condition. Not sufficient memory to create semaphore */
        }
    }

    void APP_METROLOGY_Tasks (void)
    {
        APP_ENERGY_QUEUE_DATA newMetrologyData;
        APP_EVENTS_QUEUE_DATA newEvent;

        /* Check the application's current state. */
        switch (app_metrologyData.state)
        {
            /* Application's initial state. */
            case APP_METROLOGY_STATE_INIT:
            {
                DRV_MCMETROLOGY_CONTROL * pConfiguration = NULL;

                /* Check if any specific configuration should be applied */
                if (app_metrologyData.setConfiguration)
                {
                    pConfiguration = &app_metrologyData.configuration;
                }

                if (DRV_MCMETROLOGY_Open(app_metrologyData.startMode, pConfiguration) == DRV_MCMETROLOGY_SUCCESS)
                {
                    if (app_metrologyData.startMode == DRV_MCMETROLOGY_START_HARD)
                    {
                        app_metrologyData.state = APP_METROLOGY_STATE_START;
                    }
                    else
                    {
                        app_metrologyData.state = APP_METROLOGY_STATE_RUNNING;
                    }
                }
                else
                {
                    app_metrologyData.state = APP_METROLOGY_STATE_ERROR;
                }

                vTaskDelay(10 / portTICK_PERIOD_MS);
                break;
            }

            case APP_METROLOGY_STATE_START:
            {
                if (DRV_MCMETROLOGY_GetStatus() == DRV_MCMETROLOGY_STATUS_READY)
                {
                    if (DRV_MCMETROLOGY_Start() == DRV_MCMETROLOGY_SUCCESS)
                    {
                        app_metrologyData.state = APP_METROLOGY_STATE_RUNNING;
                    }
                    else
                    {
                        app_metrologyData.state = APP_METROLOGY_STATE_ERROR;
                    }

                    vTaskDelay(10 / portTICK_PERIOD_MS);
                }

                break;
            }

            case APP_METROLOGY_STATE_RUNNING:
            {
                /* Wait for the metrology semaphore to get measurements at the end of the integration period. */
                OSAL_SEM_Pend(&appMetrologySemID, OSAL_WAIT_FOREVER);

                if (app_metrologyData.state == APP_METROLOGY_STATE_INIT)
                {
                    /* Received Reload Command */
                    break;
                }

                // Send new Energy values to the Energy Task
                app_metrologyData.queueFree = uxQueueSpacesAvailable(appEnergyQueueID);
                if (app_metrologyData.queueFree)
                {
                    newMetrologyData.energy = DRV_MCMETROLOGY_GetEnergyValue(true);
                    newMetrologyData.Pt = DRV_MCMETROLOGY_GetRMSValue(RMS_PT);
                    xQueueSend(appEnergyQueueID, &newMetrologyData, (TickType_t) 0);
                }
                else
                {
                    SYS_CMD_MESSAGE("ENERGY Queue is FULL!!!\r\n");
                }

                // Send new Events to the Events Task
                app_metrologyData.queueFree = uxQueueSpacesAvailable(appEventsQueueID);
                if (app_metrologyData.queueFree)
                {
                    RTC_TimeGet(&newEvent.eventTime);
                    DRV_MCMETROLOGY_GetEventsData(&newEvent.eventFlags);
                    xQueueSend(appEventsQueueID, &newEvent, (TickType_t) 0);
                }
                else
                {
                    SYS_CMD_MESSAGE("EVENTS Queue is FULL!!!\r\n");
                }

                break;
            }

            /* The default state should never be executed. */
            case APP_METROLOGY_STATE_ERROR:
            default:
            {
                /* TODO: Handle error in application's state machine. */
                break;
            }
        }
    }

Rev: E