📄 emeter-setup.c
字号:
//--------------------------------------------------------------------------
//
// Software for MSP430 based e-meters.
//
// You may not use the Program in non-TI devices.
//
// File: emeter-setup.c
//
// Steve Underwood <steve-underwood@ti.com>
// Texas Instruments Hong Kong Ltd.
//
// $Id: emeter-setup.c,v 1.23 2005/12/20 10:17:57 a0754793 Exp $
//
/*! \file emeter-structs.h */
//
//--------------------------------------------------------------------------
//
// MSP430 setup routines for e-meters.
//
// This software is appropriate for single phase and three phase e-meters
// using a voltage sensor plus CT or shunt resistor current sensors, or
// a combination of a CT plus a shunt.
//
#include <stdint.h>
#include <string.h>
#if !defined(__MSP430__)
#include <stdio.h>
#include <stdlib.h>
#endif
#if defined(__GNUC__)
#include <signal.h>
#endif
#include <io.h>
#include <emeter-toolkit.h>
#include "emeter.h"
#include "emeter-structs.h"
#if defined(__MSP430_HAS_SD16_3__)
#define SD16CONF0_FUDGE 0xC0 //0x70 //0xC0
#define SD16CONF1_FUDGE 0x40 //0x38 //0x40
/*
* Analog front-end initialization routine.
*
* Configures the sigma-delta ADC module as analog front-end for
* a tamper-resistant meter using a current transformer and a
* shunt as current sensors (see configuration of channel 0 and 1).
*/
static __inline__ void init_analog_front_end_normal(void)
{
/*
* First it makes sure that the Embedded Signal Processing is
* disabled, otherwise it will not be possible to modify the
* SD16 registers.
*/
ESPCTL &= ~ESPEN;
/*
* Then the general configurations of the analog front-end are done
* that apply to all channels: clock selection (SMCLK) and divider
* settings (depending on SMCLK frequency) and reference voltage
* selections.
*/
SD16CCTL_VOLTAGE &= ~SD16SC;
SD16CCTL_LIVE &= ~SD16SC;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
SD16CCTL_NEUTRAL &= ~SD16SC;
#endif
#if defined(SINGLE_PHASE)
SD16CTL = 0x800
| SD16SSEL_1 /* Clock is SMCLK */
| SD16DIV_3 /* Divide by 8 => ADC clock: 1.048576MHz */
| SD16REFON; /* Use internal reference */
SD16INCTL_LIVE = SD16INCH_0 | CURRENT_LIVE_GAIN; /* Set gain for channel 0 (I1) */
SD16CCTL_LIVE = SD16OSR_256 | SD16DF | SD16GRP | SD16IE; /* Set oversampling ratio to 256 (default) */
SD16PRE_LIVE = 0;
#if defined(NEUTRAL_MONITOR_SUPPORT)
SD16INCTL_NEUTRAL = SD16INCH_0 | CURRENT_NEUTRAL_GAIN; /* Set gain for channel 1 (I2) */
SD16CCTL_NEUTRAL = SD16OSR_256 | SD16DF | SD16GRP | SD16IE; /* Set oversampling ratio to 256 (default) */
SD16PRE_NEUTRAL = 0;
#endif
/* Configure analog front-end channel 2 - Voltage */
SD16INCTL_VOLTAGE = SD16INCH_0 | VOLTAGE_GAIN; /* Set gain for channel 2 (V) */
SD16CCTL_VOLTAGE = SD16OSR_256 | SD16DF | SD16SC | SD16IE; /* Set oversampling ratio to 256 (default) */
SD16PRE_VOLTAGE = 0;
#else
SD16CTL = 0x800
| SD16SSEL_1 /* Clock is SMCLK */
| SD16DIV_0 /* Divide by 1 => ADC clock: 8*1.048576MHz */
| SD16REFON; /* Use internal reference */
SD16INCTL0 = SD16INCH_0 | SD16GAIN_1;
SD16CCTL0 = SD16OSR_128 | SD16DF | SD16SNGL | SD16GRP | SD16IE;
SD16PRE0 = 0;
SD16INCTL1 = SD16INCH_0 | SD16GAIN_1;
SD16CCTL1 = SD16OSR_128 | SD16DF | SD16SNGL | SD16GRP | SD16IE;
SD16PRE1 = 0;
SD16INCTL_VOLTAGE = SD16INCH_0 | SD16GAIN_1;
SD16CCTL_VOLTAGE = SD16OSR_128 | SD16DF | SD16SNGL | SD16IE;
SD16PRE_VOLTAGE = 0;
SD16CCTL2 |= SD16SC;
#endif
SD16CONF0 = SD16CONF0_FUDGE; /* Tweaks recommended by Freising */
SD16CONF1 = SD16CONF1_FUDGE;
#if defined(SINGLE_PHASE)
chan1.current.sd16_preloaded_offset = 0;
#if defined(NEUTRAL_MONITOR_SUPPORT)
chan1.neutral.sd16_preloaded_offset = 0;
#endif
#endif
/*
* \note
* Please note, the oversampling ratio should be the same
* for all channels. Default is 256.
*/
}
#if defined(LIMP_MODE_SUPPORT)
static __inline__ void init_analog_front_end_limp(void)
{
ESPCTL &= ~ESPEN;
SD16CCTL_VOLTAGE &= ~SD16SC;
SD16CCTL_LIVE &= ~SD16SC;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
SD16CCTL_NEUTRAL &= ~SD16SC;
#endif
SD16CTL = 0x800
| SD16SSEL_1 /* Clock is SMCLK */
| SD16DIV_3 /* Divide by 8 => ADC clock: 1.048576MHz */
| SD16REFON /* Use internal reference */
| SD16LP;
SD16INCTL_LIVE = SD16INCH_0 | CURRENT_LIVE_GAIN; /* Set gain for channel 0 (I1) */
SD16CCTL_LIVE = SD16OSR_32 | SD16DF | SD16SNGL | SD16GRP | SD16IE; /* Set oversampling ratio to 32 */
SD16PRE_LIVE = 0;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
SD16INCTL_NEUTRAL = SD16INCH_0 | CURRENT_NEUTRAL_GAIN; /* Set gain for channel 1 (I2) */
SD16CCTL_NEUTRAL = SD16OSR_32 | SD16DF | SD16SNGL | SD16GRP | SD16IE; /* Set oversampling ratio to 32 */
SD16PRE_NEUTRAL = 0;
#endif
SD16INCTL_VOLTAGE = SD16INCH_0 | VOLTAGE_GAIN; /* Set gain for channel 2 (V) */
SD16CCTL_VOLTAGE = SD16OSR_32 | SD16DF | SD16SNGL | SD16IE; /* Set oversampling ratio to 32 */
SD16PRE_VOLTAGE = 0;
SD16CONF0 = SD16CONF0_FUDGE; /* Tweaks recommended by Freising */
SD16CONF1 = SD16CONF1_FUDGE;
chan1.current.sd16_preloaded_offset = 0;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
chan1.neutral.sd16_preloaded_offset = 0;
#endif
}
#endif
static __inline__ void disable_analog_front_end(void)
{
ESPCTL &= ~ESPEN;
SD16INCTL_VOLTAGE = 0;
SD16CCTL_VOLTAGE = 0;
SD16PRE_VOLTAGE = 0;
SD16INCTL_LIVE = 0;
SD16CCTL_LIVE = 0;
SD16PRE_LIVE = 0;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
SD16INCTL_NEUTRAL = 0;
SD16CCTL_NEUTRAL = 0;
SD16PRE_NEUTRAL = 0;
#endif
SD16CTL = 0;
SD16CONF0 = SD16CONF0_FUDGE;
SD16CONF1 = SD16CONF1_FUDGE;
#if defined(SINGLE_PHASE)
chan1.current.sd16_preloaded_offset = 0;
#if defined(NEUTRAL_MONITOR_SUPPORT)
chan1.neutral.sd16_preloaded_offset = 0;
#endif
#endif
}
#endif
#if defined(__MSP430__)
void system_setup(void)
{
#if !defined(SINGLE_PHASE)
struct phase_parms_s *phase;
struct phase_nv_parms_s const *phase_nv;
int j;
#endif
#if defined(__MSP430_HAS_BT__) || defined(__MSP430_HAS_BT_RTC__)
/* Basic timer setup */
/* Set ticker to 32768/(256*256) */
#if defined(__MSP430_HAS_BT__)
BTCTL = BT_fLCD_DIV64 | BT_fCLK2_DIV128 | BT_fCLK2_ACLK_DIV256;
#else
BTCTL = BT_fCLK2_DIV128 | BT_fCLK2_ACLK_DIV256;
#endif
/* Enable the 1 second counter interrupt */
IE2 |= BTIE;
/* We want a real watchdog function, but it doesn't have to be fast. */
/* Use the longest timer - 1s */
#if USE_WATCHDOG
kick_watchdog(); /* Set the watchdog timer to exactly 1s */
#else
WDTCTL = (WDTCTL & 0xFF) | WDTPW | WDTHOLD;
#endif
#else
IE1 |= WDTIE; /* Enable the WDT interrupt */
#endif
#if (defined(BASIC_LCD_SUPPORT) || defined(CUSTOM_LCD_SUPPORT))
LCDinit();
custom_lcd_init();
#if defined(LCD_INIT) && defined(__MSP430_HAS_LCD4__)
LCDCTL = LCD_INIT;
#endif
#if defined(LCDACTL_INIT) && defined(__MSP430_HAS_LCD_A__)
LCDACTL = LCDACTL_INIT;
LCDAPCTL0 = LCDAPCTL0_INIT;
LCDAPCTL1 = LCDAPCTL1_INIT;
LCDAVCTL0 = LCDAVCTL0_INIT;
LCDAVCTL1 = LCDAVCTL1_INIT;
#endif
#endif
#if defined(P1OUT_INIT)
P1OUT = P1OUT_INIT;
#endif
#if defined(P1DIR_INIT)
P1DIR = P1DIR_INIT;
#endif
#if defined(P1SEL_INIT)
P1SEL = P1SEL_INIT;
#endif
#if defined(P2OUT_INIT)
P2OUT = P2OUT_INIT;
#endif
#if defined(P2DIR_INIT)
P2DIR = P2DIR_INIT;
#endif
#if defined(P2SEL_INIT)
P2SEL = P2SEL_INIT;
#endif
#if defined(P3OUT_INIT)
P3OUT = P3OUT_INIT;
#endif
#if defined(P3DIR_INIT)
P3DIR = P3DIR_INIT;
#endif
#if defined(P3SEL_INIT)
P3SEL = P3SEL_INIT;
#endif
#if defined(P4OUT_INIT)
P4OUT = P4OUT_INIT;
#endif
#if defined(P4DIR_INIT)
P4DIR = P4DIR_INIT;
#endif
#if defined(P4SEL_INIT)
P4SEL = P4SEL_INIT;
#endif
#if defined(P5OUT_INIT)
P5OUT = P5OUT_INIT;
#endif
#if defined(P5DIR_INIT)
P5DIR = P5DIR_INIT;
#endif
#if defined(P5SEL_INIT)
P5SEL = P5SEL_INIT;
#endif
#if defined(P6OUT_INIT)
P6OUT = P6OUT_INIT;
#endif
#if defined(P6DIR_INIT)
P6DIR = P6DIR_INIT;
#endif
#if defined(P6SEL_INIT)
P6SEL = P6SEL_INIT;
#endif
#if defined(IO_EXPANDER_SUPPORT)
set_io_expander(0, 0);
#endif
#if defined(BASIC_LCD_SUPPORT)
display_startup_message();
#endif
#if defined(__MSP430_HAS_DCO__)
/* Set up the DCO clock */
BCSCTL1 |= (RSEL0 | RSEL1 | RSEL2); /* Select the highest nominal freq */
BCSCTL2 |= DCOR; /* Select the external clock control resistor pin */
DCOCTL = 0xFF; /* Select the highest speed. */
#endif
#if defined(__MSP430_HAS_FLLPLUS__) || defined(__MSP430_HAS_FLLPLUS_SMALL__)
FLL_CTL0 |= XCAP10PF; /* Configure load caps */
#if defined(XT2OFF)
FLL_CTL1 |= XT2OFF;
#endif
SCFI0 = FLLD_1; /* Freq = 1.024MHz */
SCFQCTL = 32 - 1;
FLL_CTL0 |= DCOPLUS;
/* There seems no benefit in waiting for the FLL to settle at this point. */
#endif
#if defined(LIMP_MODE_SUPPORT)
samples_per_second = LIMP_SAMPLES_PER_10_SECONDS/10;
#else
samples_per_second = SAMPLES_PER_10_SECONDS/10;
#endif
#if defined(__MSP430_HAS_TA3__) && defined(__MSP430_HAS_ADC12__)
/* Use timer A to control the ADC sampling interval, and the ADC on/off timing. */
/* TACCR0 determines the sample period */
TAR = 0;
#if defined(LIMP_MODE_SUPPORT)
TACCR0 = (SAMPLE_PERIOD*LIMP_SAMPLING_RATIO) - 1;
TACCR1 = (SAMPLE_PERIOD*LIMP_SAMPLING_RATIO) - 3;
TACCR2 = (SAMPLE_PERIOD*LIMP_SAMPLING_RATIO) - 4;
#else
TACCR0 = SAMPLE_PERIOD - 1;
TACCR1 = SAMPLE_PERIOD - 3;
TACCR2 = SAMPLE_PERIOD - 4;
#endif
TACCTL0 = 0;
TACCTL1 = OUTMOD_3;
#if defined(FINE_ENERGY_PULSE_TIMING_SUPPORT)
TACCTL2 = OUTMOD_0 | OUT; /* Turn off the pulse LED */
#endif
TACTL = TACLR | MC_1 | TASSEL_1;
#endif
#if defined(__MSP430_HAS_TA3__) && defined(__MSP430_HAS_SD16_3__)
/* Use timer A to control the ADC sampling interval in limp mode. */
/* CCR0 determines the sample period - 1024Hz */
TAR = 0;
TACCR0 = 32 - 1;
TACCTL0 = 0;
TACCTL1 = OUTMOD_3;
TACTL = TACLR | MC_1 | TASSEL_1;
#endif
#if defined(PWM_DITHERING_SUPPORT)
/* Configure timer B to generate a dithering signal, to be added to the */
/* analogue signals, something like this. */
/* */
/* ----------------- 100n */
/* | __47k_ || __1M__ __4K7__ */
/* TB1 |->-|______|-- -||---|______|->---|_______|--< Signal */
/* | | || | */
/* | ----- | */
/* | -----2n2 | */
/* | | | */
/* | GND | */
/* | | */
/* A0 |-<----------------------------- */
/* | */
P2SEL |= BIT2; /* Select P2.2 for PWM output */
P2DIR |= BIT2; /* Select P2.2 for PWM output */
TBR = 0;
TBCCR0 = PWM_FREQ - 1; /* load period register */
TBCCR1 = PWM_MID_POINT; /* start with 50% PWM duty cycle */
TBCCR2 = PWM_FREQ - 1;
TBCCTL0 = OUTMOD_4; /* set outmode 4 for toggle */
TBCCTL1 = OUTMOD_6 | CLLD_1; /* set outmode 6 Toggle/set */
/* load new CCR1 when TBR = 0 */
TBCCTL2 = OUTMOD_4;
TBCTL = TBCLR | MC_1 | TBSSEL_2; /* start TIMER_B up mode, SMCLK as input clock */
#endif
#if defined(__MSP430_HAS_ADC12__)
/* Set up the ADC12 */
/* Disable conversion while changing the settings */
ADC12CTL0 = 0;
#if defined(SINGLE_PHASE)
ADC12MCTL0 = SREF_0 | AGND_INPUT;
ADC12MCTL1 = SREF_0 | NEUTRAL_CURRENT_INPUT;
ADC12MCTL2 = SREF_0 | AGND_INPUT;
ADC12MCTL3 = SREF_0 | LIVE_CURRENT_INPUT;
ADC12MCTL4 = SREF_0 | AGND_INPUT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -