Esempio n. 1
0
bool BME280::WriteSettings()
{
   uint8_t ctrlHum, ctrlMeas, config;

   CalculateRegisters(ctrlHum, ctrlMeas, config);

   WriteRegister(CTRL_HUM_ADDR, ctrlHum);
   WriteRegister(CTRL_MEAS_ADDR, ctrlMeas);
   WriteRegister(CONFIG_ADDR, config);
}
Esempio n. 2
0
int BattOn(int vbhIn, int vblIn, int vbpIn)
{
	uint8 data[20] = { 0 };
	int i;
	uint16 vbhTarget;
	uint16 vblTarget;
	uint16 vbpTarget;
	uint8 vbhHex;
	uint8 vblHex;
	uint8 vbpHex;
	uint8 calVbhHex;
	uint8 calVblHex;
	uint8 calVbpHex;

	/* Argument checking */
	if (vblIn > 0) {
		mvOsPrintf("  VBL must be negative or zero\n");
		return -1;
	}
	if (vbhIn > 0) {
		mvOsPrintf("  VBH must be negative or zero\n");
		return -1;
	}
	if (vbpIn < 0) {
		mvOsPrintf("  VBP must be positive or zero\n");
		return -1;
	}
	if (vblIn - vbhIn < 5 && vblIn != 0) {
		mvOsPrintf("  VBH must be at least 5V more negative than VBL\n");
		return -1;
	}

	/* 16 no-ops to clear MPI buffer */
	for (i = 0; i < 16; i++)
		data[i] = VP880_NO_OP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_NO_OP, 16, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_NO_OP, 16, data);

	/* Read RCN/PCN and check that the devices are what we expect */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 1, RCN/PCN 0x%02X%02X\n", data[0], data[1]);
		return -1;
	}
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 2, RCN/PCN 0x%02X%02X\n", data[0], data[1]);
		return -1;
	}

	/* Run MPI checks on both devices to make sure that it's safe to start
	 * programming the devices.  If the signal integrity is bad, it could be
	 * dangerous to continue. */
	if (MpiTest(gDev1Id) < 0 || MpiTest(gDev2Id) < 0)
		return -1;

	/* HW reset */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_HW_RESET_CMD, 0, NULL);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_HW_RESET_CMD, 0, NULL);

	/* Configure 8.192MHz mclk */
	data[0] = 0x8A;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_MCLK_CNT_WRT, VP880_MCLK_CNT_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_MCLK_CNT_WRT, VP880_MCLK_CNT_LEN, data);

	/* Unmask CFAIL */
	data[0] = 0xFF & ~(VP880_CFAIL_MASK);
	data[1] = 0xFF;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, data);

	/* Make sure CFAIL clears on both devices */
	for (i = 0; i < 11; i++) {
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_UL_SIGREG_RD, VP880_UL_SIGREG_LEN, data);
		if ((data[0] & VP880_CFAIL_MASK) == 0)
			break;

		if (i == 10) {
			mvOsPrintf("Couldn't clear CFAIL on dev 1");
			return -1;
		}
		mvOsDelay(10);
	}
	for (i = 0; i < 11; i++) {
		VpMpiCmd(gDev2Id, EC_BOTH, VP880_UL_SIGREG_RD, VP880_UL_SIGREG_LEN, data);
		if ((data[0] & VP880_CFAIL_MASK) == 0)
			break;

		if (i == 10) {
			mvOsPrintf("Couldn't clear CFAIL on dev 2");
			return -1;
		}
		mvOsDelay(10);
	}

	/* Set the switcher timings */
	data[0] = 0xB2;		/* Device defaults */
	data[1] = 0x00;
	data[2] = 0xB1;
	data[3] = 0x00;
	data[4] = 0xB0;
	data[5] = 0x40;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);

	/* ICR2 settings: c_tip_on and c_ring_on for measuring in disconnect,
	 * 150V battery limit */
	data[0] = VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE;
	data[1] = VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE;
	data[2] = VP880_ICR2_SWY_LIM_CTRL | VP880_ICR2_SWY_LIM_CTRL1;
	data[3] = VP880_ICR2_SWY_LIM_CTRL | VP880_ICR2_SWY_LIM_CTRL1;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR2_WRT, VP880_ICR2_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	/* ICR3 settings: VREF ctrl, "line block control circuitry override" for
	 * measuring in disconnect */
	data[0] = VP880_ICR3_VREF_CTRL | VP880_ICR3_LINE_CTRL;
	data[1] = VP880_ICR3_VREF_CTRL | VP880_ICR3_LINE_CTRL;
	data[2] = 0;
	data[3] = 0;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR3_WRT, VP880_ICR3_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR3_WRT, VP880_ICR3_LEN, data);

	/* ICR4 settings: voice ADC override for measuring in disconnect */
	data[0] = VP880_ICR4_VOICE_ADC_CTRL;
	data[1] = VP880_ICR4_VOICE_ADC_CTRL;
	data[2] = 0;
	data[3] = 0;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR4_WRT, VP880_ICR4_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR4_WRT, VP880_ICR4_LEN, data);

	/* Wait for VREF to stabilize */
	mvOsDelay(20);

	/* Disable auto system state ctrl, zero cross ringing, auto clock fail
	 * switching, and thermal fault switching.  Enable auto battery shutdown */
	data[0] = VP880_ACFS_DIS | VP880_ATFS_DIS | VP880_ZXR_DIS | VP880_AUTO_SSC_DIS | VP880_AUTO_BAT_SHUTDOWN_EN;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, data);

	/* Zero out signal generator params for the channel (ch2 on dev1) that will
	 * be in ringing */
	for (i = 0; i < VP880_SIGA_PARAMS_LEN; i++)
		data[i] = 0;

	VpMpiCmd(gDev1Id, EC_2, VP880_SIGA_PARAMS_WRT, VP880_SIGA_PARAMS_LEN, data);

	/* Calculate the register settings.  Calculations are performed  based on
	 * units of cV and unsigned, for example -65.3 V == 6530 */
	vbhTarget = (ABS(vbhIn) * 100);
	vblTarget = (ABS(vblIn) * 100);
	vbpTarget = (ABS(vbpIn) * 100);

	DBG("VBH Calibration:\n");
	CalculateRegisters(vbhTarget, gVbhCalAry, &vbhHex, &calVbhHex);
	DBG("VBH results, vbhHex %02X, calVbhHex %02X\n\n", vbhHex, calVbhHex);

	DBG("VBL Calibration:\n");
	CalculateRegisters(vblTarget, gVblCalAry, &vblHex, &calVblHex);
	DBG("VBL results, vblHex %02X, calVblHex %02X\n\n", vblHex, calVblHex);

	DBG("VBP Calibration:\n");
	CalculateRegisters(vbpTarget, gVbpCalAry, &vbpHex, &calVbpHex);
	DBG("VBP results, vbpHex %02X, calVbpHex %02X\n\n", vbpHex, calVbpHex);

	/* Set up switching regulator params - fixed, programmable */
	data[0] = VP880_FLYBACK_MODE | VP880_ZRING_TRACK_DIS | VP880_YRING_TRACK_DIS;
	data[1] = VP880_SWY_AUTOPOWER_DIS | vbhHex;
	data[2] = VP880_SWZ_AUTOPOWER_DIS | vblHex;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_PARAM_WRT, VP880_REGULATOR_PARAM_LEN, data);

	data[0] = VP880_FLYBACK_MODE | VP880_ZRING_TRACK_DIS | VP880_YRING_TRACK_DIS;
	data[1] = VP880_SWY_AUTOPOWER_DIS | vbpHex;
	data[2] = VP880_SWZ_AUTOPOWER_DIS;
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_PARAM_WRT, VP880_REGULATOR_PARAM_LEN, data);

	/* Set battery calibration registers */
	data[1] = 0;
	data[0] = calVbhHex << 3;
	VpMpiCmd(gDev1Id, EC_1, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);
	data[0] = calVblHex << 3;
	VpMpiCmd(gDev1Id, EC_2, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);
	data[0] = calVbpHex << 3;
	VpMpiCmd(gDev2Id, EC_1, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);

	/* Disable high-pass filter, cut off TX/RX */
	data[0] = VP880_HIGH_PASS_DIS | VP880_CUT_TXPATH | VP880_CUT_RXPATH;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_OP_COND_WRT, VP880_OP_COND_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_OP_COND_WRT, VP880_OP_COND_LEN, data);

	/* Set to linear mode, use default filters */
	data[0] = VP880_LINEAR_CODEC | VP880_DEFAULT_OP_FUNC_MODE;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_OP_FUNC_WRT, VP880_OP_FUNC_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_OP_FUNC_WRT, VP880_OP_FUNC_LEN, data);

	/* Set default DISN (00) */
	data[0] = VP880_DEFAULT_DISN_GAIN;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_DISN_WRT, VP880_DISN_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_DISN_WRT, VP880_DISN_LEN, data);

	mvOsDelay(50);

    /*** Bring up HBAT ***/
	/* Set HBAT switcher to low power. */
	data[0] = 0;
	if (vbhTarget != 0)
		data[0] |= VP880_SWY_LP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line state:
	 *  Dev 1 ch 1: disconnect (switcher Y)
	 * Disconnect is needed so that the voltages don't track to VOC */
	data[0] = VP880_SS_DISCONNECT | VP880_SS_ACTIVATE_MASK;
	VpMpiCmd(gDev1Id, EC_1, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(100);

    /*** Bring up LBAT ***/
	/* Do a read/modify/write of ICR2 to override the LBAT switcher (Z) to off
	 * so that we can set the line state to ringing before turning it on */
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_RD, VP880_ICR2_LEN, data);
	data[2] |= VP880_ICR2_SWY_CTRL_EN;
	data[3] &= ~VP880_ICR2_SWY_CTRL_EN;
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	/* Set the switcher control to low power.  It won't actually turn on yet
	 * because of the ICR2 command above, but setting the register will allow
	 * the line state to be set to ringing. */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_RD, VP880_REGULATOR_CTRL_LEN, data);
	data[0] = 0;
	if (vblTarget != 0)
		data[0] |= VP880_SWZ_LP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line state:
	 *  Dev 1 ch 2: ringing (switcher Z) */
	data[0] = VP880_SS_BALANCED_RINGING;
	VpMpiCmd(gDev1Id, EC_2, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(10);

	/* Turn the switcher on */
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_RD, VP880_ICR2_LEN, data);
	data[2] |= VP880_ICR2_SWY_CTRL_EN;
	data[3] |= VP880_ICR2_SWY_CTRL_EN;
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	mvOsDelay(100);

    /*** Bring up PBAT ***/
	/* Set PBAT switcher to low power. */
	data[0] = 0;
	if (vbpTarget != 0)
		data[0] |= VP880_SWY_LP;

	VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line states:
	 *  Dev 2 ch 1: disconnect (switcher Y)
	 * Disconnect is needed so that the voltages don't track to VOC */
	data[0] = VP880_SS_DISCONNECT | VP880_SS_ACTIVATE_MASK;
	VpMpiCmd(gDev2Id, EC_1, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(100);

	/* Set switchers to high power for non-zero batteries, one at a time */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_RD, VP880_REGULATOR_CTRL_LEN, data);

	if (vbhTarget != 0) {
		data[0] &= ~VP880_SWY_MODE_MASK;
		data[0] |= VP880_SWY_HP;
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	mvOsDelay(20);

	if (vblTarget != 0) {
		data[0] &= ~VP880_SWZ_MODE_MASK;
		data[0] |= VP880_SWZ_HP;
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	mvOsDelay(20);

	data[0] = 0;
	if (vbpTarget != 0) {
		data[0] |= VP880_SWY_HP;
		VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	/* Set IOs to outputs to control the module LEDs */
	data[0] = VP880_IODIR_IO1_OUTPUT | VP880_IODIR_IO2_OUTPUT;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_IODIR_REG_WRT, VP880_IODIR_REG_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_IODIR_REG_WRT, VP880_IODIR_REG_LEN, data);

	/* Turn on the LEDs for non-zero batteries. */
	data[0] = 0;
	if (vbhTarget != 0) {
		/* gDev1Id IO1 controls the VBH (v1) LED */
		data[0] |= VP880_IODATA_IO1;
	}
	if (vblTarget != 0) {
		/* gDev1Id IO2 controls the VBL (v2) LED */
		data[0] |= VP880_IODATA_IO2;
	}
	VpMpiCmd(gDev1Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);

	data[0] = 0;
	if (vbpTarget != 0) {
		/* gDev2Id IO1 controls the VBP (v3) LED */
		data[0] |= VP880_IODATA_IO1;
	}
	VpMpiCmd(gDev2Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);

	mvOsPrintf("Power supply initialized successfully\n");

	return 0;
}