//////////////////////////////////////////////////////////////////////////////// //! See hw_lradc.h for details. //////////////////////////////////////////////////////////////////////////////// RtStatus_t hw_lradc_EnableBatteryMeasurement( hw_lradc_DelayTrigger_t eTrigger, uint16_t u16SamplingInterval) { hw_lradc_Channel_t eChannel = BATTERY_VOLTAGE_CH; // // Check if the lradc channel is present in this product // if( hw_lradc_GetChannelPresent(eChannel) == 0 ) return (ERROR_HW_LRADC_CH_NOT_PRESENT); // Disable the channel interrupt hw_lradc_EnableInterrupt(eChannel, FALSE); hw_lradc_ClearInterruptFlag(eChannel); // Configure the battery conversion register BF_WR(LRADC_CONVERSION, SCALE_FACTOR, 2); // Enable the automatic update mode of BATT_VALUE field in HW_POWER_MONITOR BF_SET(LRADC_CONVERSION, AUTOMATIC); hw_lradc_ConfigureChannel( eChannel, //Lradc channel FALSE, //DIVIDE_BY_TWO FALSE, //ACCUMULATE 0); //NUM_SAMPLES // schedule a conversion before the setting up of the delay channel // so the user can have a good value right after the function returns hw_lradc_ScheduleChannel(eChannel); // Setup the trigger loop forever, hw_lradc_SetDelayTrigger( eTrigger, // Trigger Index (1 << eChannel), // Lradc channels (1 << eTrigger), // Restart the triggers 0, // No loop count u16SamplingInterval); // 0.5*N msec on 2khz // Clear the accumulator & NUM_SAMPLES HW_LRADC_CHn_CLR(eChannel, 0xFFFFFFFF); // Kick off the LRADC battery measurement hw_lradc_SetDelayTriggerKick(eTrigger, TRUE); /* Wait for first measurement of battery. Should occur in 13 LRADC clock * cycles from the time of channel kickoff. Also add some wait time for * copy to the power supply BATT_VAL field to occur. */ hw_digctl_MicrosecondWait(10); return SUCCESS; }
RtStatus_t hw_power_InitBatteryMonitor(hw_lradc_DelayTrigger_t eTrigger, uint32_t u32SamplingInterval) { RtStatus_t rtn; //---------------------------------------------------------------------- // Start up the battery measurements //---------------------------------------------------------------------- rtn = hw_lradc_EnableBatteryMeasurement(eTrigger, u32SamplingInterval); // wait to make sure first automatic conversion and copy is complete // Todo: replace this with a manual first conversion and write to // BATT_VAL field. hw_digctl_MicrosecondWait(30); return rtn; }
///////////////////////////////////////////////////////////////////////////////// //! \brief Runs the test to determine if a battery is connected to device. //! //! \fntype Function //! //! The test will turn on the charger with minimal charge current to determine //! if a battery is present. This test should only be run once since subsequent //! tests may be invalid due to the charge left on the battery pin from //! capacitance. //! //! \retval True Test determined battery is connected. //! \retval False Test determined battery is not connected. ///////////////////////////////////////////////////////////////////////////////// bool ddi_power_TestBatteryConnection( void ) { //-------------------------------------------------------------------------- // Check if we've already run the test before. If so, we need to return // the result instead of running the test again. //-------------------------------------------------------------------------- if( DidCurrAppRunBattTest() ) { // This application ran the test once, so the battery connection flag is valid. return bBatteryConnected; } if( DidPrevAppRunBattTest() ) { // If a previous application ran this test, return the result. return GetPrevAppTestResult(); } //-------------------------------------------------------------------------- // Let's make sure we have a stable battery voltage first. //-------------------------------------------------------------------------- { uint16_t StartVolt, FirstVolt, SecondVolt; bool bVoltageStable = false; bool bPrevEnLoad = false; // Load the battery pin to drain the voltage if an open circuit. bPrevEnLoad = HW_POWER_CHARGE.B.ENABLE_LOAD; HW_POWER_CHARGE.B.ENABLE_LOAD = 1; StartVolt = hw_power_GetBatteryVoltage(); while( !bVoltageStable ) { // Take a reading, then wait some time before taking the // second reading. FirstVolt = hw_power_GetBatteryVoltage(); hw_digctl_MicrosecondWait( 100000 ); SecondVolt = hw_power_GetBatteryVoltage(); // Are the two measurements within the stable margin? if( FirstVolt > SecondVolt ) { if( FirstVolt - SecondVolt < 25 ) bVoltageStable = true; } else { if( SecondVolt - FirstVolt < 25 ) bVoltageStable = true; } // Has the voltage dropped significantly since test started? if( StartVolt > SecondVolt ) { if( StartVolt - SecondVolt > 200 ) { SetPrevAppTestResult( false ); bBatteryConnectionTestComplete = true; return false; } } else { if( SecondVolt - StartVolt > 200 ) { SetPrevAppTestResult( false ); bBatteryConnectionTestComplete = true; return false; } } } HW_POWER_CHARGE.B.ENABLE_LOAD = bPrevEnLoad; } //-------------------------------------------------------------------------- // Before we turn on the charger, first check if the battery voltage is // high enough to indicate a battery is present. //-------------------------------------------------------------------------- if( hw_power_GetBatteryVoltage() > BATT_TEST__MIN_BATT_VOLT ) { // If have any battery voltage at this point, then there is a battery. SetPrevAppTestResult( true ); bBatteryConnectionTestComplete = true; return true; } //-------------------------------------------------------------------------- // Run the battery detection test. //-------------------------------------------------------------------------- { bool bBattCon; //---------------------------------------------------------------------- // Save the previous settings, then initialize the charger for the // charger test. //---------------------------------------------------------------------- bool prevBATTCHRG_I = HW_POWER_CHARGE.B.BATTCHRG_I; bool prevCHARGE_4P2_ILIMIT = HW_POWER_5VCTRL.B.CHARGE_4P2_ILIMIT; bool prevPWD_BATTCHRG = HW_POWER_CHARGE.B.PWD_BATTCHRG; bool prevPWD_CHARGE_4P2 = HW_POWER_5VCTRL.B.PWD_CHARGE_4P2; bool prevENABLE_4P2 = HW_POWER_DCDC4P2.B.ENABLE_4P2; // Set the total 4P2/CHRG current limit to 30mA HW_POWER_5VCTRL.B.CHARGE_4P2_ILIMIT = 3; // Turn on 4p2 rail and wait a little bit to let it start up. HW_POWER_DCDC4P2.B.ENABLE_4P2 = 1; HW_POWER_5VCTRL.B.PWD_CHARGE_4P2 = 0; hw_digctl_MicrosecondWait( 10 ); // Turn on the charger with 30mA of charge current HW_POWER_CHARGE.B.BATTCHRG_I = 3; HW_POWER_CHARGE.B.PWD_BATTCHRG = 0; //---------------------------------------------------------------------- // The battery pin has started charging. The voltage on the battery pin // of an open circuit will jump to about 4.2V. A real battery will // sink the small amount of current and the voltage will stay very low. //---------------------------------------------------------------------- { bool bThresholdReached = false; bool bTimeoutExpired = false; uint32_t StartTime; StartTime = hw_digctl_GetCurrentTime(); while( !bThresholdReached && !bTimeoutExpired ) { // Check voltage threshold. if( hw_power_GetBatteryVoltage() > BATT_TEST__MIN_OPEN_CIRC_VOLT ) { // If the threshold was reached first, then we can // assume we have an open circuit. bThresholdReached = true; bBattCon = false; } // Check timeout. if( ( hw_digctl_GetCurrentTime() - StartTime ) > BATT_TEST__WAIT_TIME_US ) { // If the timeout expired, then we assume a battery is // present and it sank the current. bTimeoutExpired = true; bBattCon = true; } } } //---------------------------------------------------------------------- // Restore the previous settings and return our result. //---------------------------------------------------------------------- HW_POWER_CHARGE.B.PWD_BATTCHRG = prevPWD_BATTCHRG; HW_POWER_CHARGE.B.BATTCHRG_I = prevBATTCHRG_I; HW_POWER_5VCTRL.B.CHARGE_4P2_ILIMIT = prevCHARGE_4P2_ILIMIT; HW_POWER_5VCTRL.B.PWD_CHARGE_4P2 = prevPWD_CHARGE_4P2; HW_POWER_DCDC4P2.B.ENABLE_4P2 = prevENABLE_4P2; SetPrevAppTestResult(bBattCon); bBatteryConnectionTestComplete = true; return bBattCon; } }
//////////////////////////////////////////////////////////////////////////////// //! See hw_power.h for details. //////////////////////////////////////////////////////////////////////////////// RtStatus_t hw_power_Init(void) { RtStatus_t rtn = SUCCESS; //-------------------------------------------------------------------------- // Make the clock registers accessible by ungating power block //-------------------------------------------------------------------------- BF_CLR(POWER_CTRL, CLKGATE); //-------------------------------------------------------------------------- // Improve efficieny and reduce transient ripple //-------------------------------------------------------------------------- { //---------------------------------------------------------------------- // Change stepping voltage only after the diff control loop // has toggled as well. //---------------------------------------------------------------------- BF_SET(POWER_LOOPCTRL, TOGGLE_DIF); //---------------------------------------------------------------------- // Enable the commom mode and differential mode hysterisis //---------------------------------------------------------------------- BF_SET(POWER_LOOPCTRL, EN_CM_HYST); BF_SET(POWER_LOOPCTRL, EN_DF_HYST); //---------------------------------------------------------------------- // To run with a lower battery voltage, adjust the duty // cycle positive limit //---------------------------------------------------------------------- BF_WR(POWER_DCLIMITS, POSLIMIT_BUCK, 0x30); } //-------------------------------------------------------------------------- // Finally enable the battery adjust //-------------------------------------------------------------------------- BF_SET(POWER_BATTMONITOR,EN_BATADJ); //---------------------------------------------------------------------- // Increase the RCSCALE_THRESHOLD //---------------------------------------------------------------------- BF_SET(POWER_LOOPCTRL, RCSCALE_THRESH); //---------------------------------------------------------------------- // Increase the RCSCALE level for quick DCDC response to dynamic load //---------------------------------------------------------------------- hw_power_EnableRcScale(HW_POWER_RCSCALE_8X_INCR); hw_power_EnableHalfFets(FALSE); hw_power_EnableDoubleFets(TRUE); //-------------------------------------------------------------------------- // Initialize the variables we use in hw_power driver. //-------------------------------------------------------------------------- if( bMasterFlagsInitialized == false ) { // Initialize the brownout variables and synchronize these with the // master brownout register. bEnableMaster5vBrownout = HW_POWER_5VCTRL.B.PWDN_5VBRNOUT; bEnableMasterBattBrownout = HW_POWER_BATTMONITOR.B.PWDN_BATTBRNOUT; // Initialize the 4p2 and charger variables. Both the local and the // master have to be true for the variable to be true. bEnableMaster4p2 = HW_POWER_DCDC4P2.B.ENABLE_4P2 && !HW_POWER_5VCTRL.B.PWD_CHARGE_4P2; bEnableMasterCharge = !HW_POWER_CHARGE.B.PWD_BATTCHRG && !HW_POWER_5VCTRL.B.PWD_CHARGE_4P2; bMasterFlagsInitialized = true; } /* Enable 5V to battery source handoff on detection of 5V * disconnection. Get the DCDC control loop ready for * action. Leaving DCDC_XFER set causes problems with 4p2 * operation and has other issues so we only leave * it on long enough to prepare the DCDC control loop */ HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_DCDC_XFER); hw_digctl_MicrosecondWait(30); HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_DCDC_XFER); return rtn; }