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); }
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; }