38
+ − 1 /**
+ − 2 ******************************************************************************
+ − 3 * @file batteryCharger.c
+ − 4 * @author heinrichs weikamp gmbh
+ − 5 * @date 09-Dec-2014
+ − 6 * @version V0.0.1
+ − 7 * @since 09-Dec-2014
+ − 8 * @brief LTC4054 Battery Charger
+ − 9 *
+ − 10 @verbatim
+ − 11 ==============================================================================
+ − 12 ##### How to use #####
+ − 13 ==============================================================================
+ − 14
+ − 15 The bq5105x provides one status output, CHG. This output is an open-drain NMOS device that is rated to 20 V.
+ − 16 The open-drain FET connected to the CHG pin will be turned on whenever the output (BAT) of the charger is
+ − 17 enabled. As a note, the output of the charger supply will not be enabled if the VRECT-REG does not converge to the
+ − 18 no-load target voltage.
+ − 19
644
+ − 20 CHG F4 7 O Open-drain output � active when BAT is enabled. Float if not used.
38
+ − 21
+ − 22 @endverbatim
+ − 23 ******************************************************************************
+ − 24 * @attention
+ − 25 *
+ − 26 * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2>
+ − 27 *
+ − 28 ******************************************************************************
+ − 29 */
+ − 30 /* Includes ------------------------------------------------------------------*/
+ − 31 #include "batteryCharger.h"
+ − 32 #include "batteryGasGauge.h"
+ − 33 #include "stm32f4xx_hal.h"
+ − 34 #include "scheduler.h"
+ − 35
+ − 36
662
+ − 37 #define CHARGER_DEBOUNCE_SECONDS (6u) /* 6 seconds used to avoid problems with charger interrupts / disconnections */
38
+ − 38
668
+ − 39 static uint16_t battery_charger_counter = 0;
643
+ − 40 static chargerState_t batteryChargerState = Charger_NotConnected;
38
+ − 41
662
+ − 42 void set_charge_state(uint8_t newState)
+ − 43 {
+ − 44 if(newState < Charger_END)
+ − 45 {
+ − 46 batteryChargerState = newState;
+ − 47 }
+ − 48 }
+ − 49
+ − 50 uint8_t get_charge_state(void)
+ − 51 {
+ − 52 return batteryChargerState;
+ − 53 }
+ − 54
38
+ − 55 void init_battery_charger_status(void)
+ − 56 {
+ − 57 #ifdef OSTC_ON_DISCOVERY_HARDWARE
+ − 58 return;
+ − 59 #endif
+ − 60
+ − 61 CHARGE_IN_GPIO_ENABLE();
+ − 62 CHARGE_OUT_GPIO_ENABLE();
+ − 63
+ − 64 ReInit_battery_charger_status_pins();
+ − 65 }
+ − 66
+ − 67 void ReInit_battery_charger_status_pins(void)
+ − 68 {
+ − 69 #ifdef OSTC_ON_DISCOVERY_HARDWARE
+ − 70 return;
+ − 71 #endif
+ − 72
+ − 73 GPIO_InitTypeDef GPIO_InitStructure;
+ − 74
+ − 75 GPIO_InitStructure.Pin = CHARGE_IN_PIN;
+ − 76 GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ − 77 GPIO_InitStructure.Pull = GPIO_NOPULL;
+ − 78 GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ − 79 HAL_GPIO_Init(CHARGE_IN_GPIO_PORT, &GPIO_InitStructure);
+ − 80
+ − 81 GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+ − 82 GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
+ − 83 GPIO_InitStructure.Pull = GPIO_NOPULL;
+ − 84 GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ − 85 HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+ − 86 }
+ − 87
+ − 88
+ − 89 void DeInit_battery_charger_status_pins(void)
+ − 90 {
+ − 91 #ifdef OSTC_ON_DISCOVERY_HARDWARE
+ − 92 return;
+ − 93 #endif
+ − 94 GPIO_InitTypeDef GPIO_InitStructure;
+ − 95
+ − 96
+ − 97 GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
+ − 98 GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ − 99 GPIO_InitStructure.Pull = GPIO_NOPULL;
+ − 100
+ − 101 GPIO_InitStructure.Pin = CHARGE_IN_PIN;
+ − 102 HAL_GPIO_Init(CHARGE_IN_GPIO_PORT, &GPIO_InitStructure);
+ − 103
+ − 104 GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+ − 105 HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+ − 106 }
+ − 107
643
+ − 108 void battery_charger_get_status_and_contral_battery_gas_gauge(uint8_t cycleTimeBase)
38
+ − 109 {
643
+ − 110 static uint8_t notifyChargeComplete = 0;
+ − 111
38
+ − 112 #ifdef OSTC_ON_DISCOVERY_HARDWARE
+ − 113 return;
+ − 114 #endif
+ − 115
662
+ − 116 if(batteryChargerState == Charger_ColdStart) /* wait for the first valid voltage meassurement */
643
+ − 117 {
859
+ − 118 if(global.lifeData.battery_voltage != BATTERY_DEFAULT_VOLTAGE) /* wait for first valid voltage value */
643
+ − 119 {
859
+ − 120 if((global.lifeData.battery_voltage < BATTERY_CHARGER_CONNECTED_VOLTAGE)
+ − 121 && (global.lifeData.battery_voltage > BATTERY_ENDOF_CHARGE_VOLTAGE)) /* Voltage close to full state => maybe new battery inserted */
662
+ − 122 {
+ − 123 battery_gas_gauge_set_charge_full();
+ − 124 }
+ − 125 batteryChargerState = Charger_NotConnected;
643
+ − 126 }
+ − 127 }
+ − 128 else
662
+ − 129 { /* on disconnection or while disconnected */
+ − 130 if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))
643
+ − 131 {
662
+ − 132 switch(batteryChargerState)
+ − 133 {
686
+ − 134 case Charger_WarmUp:
662
+ − 135 case Charger_Active: global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
+ − 136 global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
+ − 137 batteryChargerState = Charger_LostConnection;
686
+ − 138 if(cycleTimeBase > CHARGER_DEBOUNCE_SECONDS) /* adapt connection lost detection to sleep mode */
+ − 139 {
+ − 140 battery_charger_counter = cycleTimeBase + 1;
+ − 141 }
+ − 142 else
+ − 143 {
+ − 144 battery_charger_counter = CHARGER_DEBOUNCE_SECONDS;
+ − 145 }
662
+ − 146 break;
859
+ − 147 case Charger_Finished: if((get_voltage() >= BATTERY_ENDOF_CHARGE_VOLTAGE) && (get_voltage() < BATTERY_CHARGER_CONNECTED_VOLTAGE)) /* stopping does not necessarily mean battery is full */
+ − 148 {
+ − 149 global.dataSendToMaster.chargeStatus = CHARGER_complete;
+ − 150 global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
+ − 151 notifyChargeComplete = 1;
+ − 152 }
+ − 153 battery_charger_counter = 10;
686
+ − 154 batteryChargerState = Charger_LostConnection;
+ − 155 /* no break */
668
+ − 156 case Charger_LostConnection: /* the charger stops charging when charge current is 1/10 */
+ − 157 /* Basically it is OK to rate a charging as complete if a defined voltage is reached */
686
+ − 158 if(((battery_gas_gauge_isChargeValueValid() == 0) || (global.lifeData.battery_charge < 90)) && (get_voltage() >= BATTERY_ENDOF_CHARGE_VOLTAGE) && (get_voltage() < BATTERY_CHARGER_CONNECTED_VOLTAGE))
662
+ − 159 {
+ − 160 notifyChargeComplete = 1;
+ − 161 }
686
+ − 162 if(battery_charger_counter >= cycleTimeBase)
662
+ − 163 {
+ − 164 battery_charger_counter -= cycleTimeBase;
+ − 165 }
+ − 166 else
+ − 167 {
+ − 168 battery_charger_counter = 0;
859
+ − 169
662
+ − 170 global.dataSendToMaster.chargeStatus = CHARGER_off;
+ − 171 global.deviceDataSendToMaster.chargeStatus = CHARGER_off;
643
+ − 172
662
+ − 173 if(notifyChargeComplete)
+ − 174 {
+ − 175 battery_gas_gauge_set_charge_full();
+ − 176 scheduleUpdateDeviceDataChargerFull();
+ − 177 }
859
+ − 178 notifyChargeComplete = 0;
662
+ − 179 batteryChargerState = Charger_NotConnected;
+ − 180 }
+ − 181 break;
859
+ − 182 default: batteryChargerState = Charger_NotConnected; /* unexpected state => reinitialize state machine */
+ − 183 break;
662
+ − 184 }
+ − 185 }
+ − 186 else
+ − 187 {
+ − 188 /* connected */
+ − 189 /* wait for disconnection to write and reset */
+ − 190 switch(batteryChargerState)
+ − 191 {
859
+ − 192 case Charger_NotConnected: battery_charger_counter = 0;
662
+ − 193 batteryChargerState = Charger_WarmUp;
+ − 194 break;
+ − 195 case Charger_LostConnection: batteryChargerState = Charger_Active;
+ − 196 break;
+ − 197 case Charger_WarmUp: battery_charger_counter += cycleTimeBase;
+ − 198 if(battery_charger_counter >= CHARGER_DEBOUNCE_SECONDS )
+ − 199 {
+ − 200 scheduleUpdateDeviceDataChargerCharging();
+ − 201 batteryChargerState = Charger_Active;
+ − 202 }
+ − 203 /* no break */
+ − 204 case Charger_Finished:
+ − 205 case Charger_Active: global.dataSendToMaster.chargeStatus = CHARGER_running;
+ − 206 global.deviceDataSendToMaster.chargeStatus = CHARGER_running;
643
+ − 207
662
+ − 208 /* drive the output pin high to determine the state of the charger */
+ − 209 GPIO_InitTypeDef GPIO_InitStructure;
+ − 210 GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+ − 211 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ − 212 GPIO_InitStructure.Pull = GPIO_NOPULL;
+ − 213 GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ − 214 HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+ − 215 HAL_GPIO_WritePin(CHARGE_OUT_GPIO_PORT, CHARGE_OUT_PIN,GPIO_PIN_SET);
+ − 216 HAL_Delay(1);
+ − 217
+ − 218 if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN)) /* high => charger stopped charging */
+ − 219 {
859
+ − 220 battery_charger_counter = 30;
662
+ − 221 batteryChargerState = Charger_Finished;
+ − 222 }
+ − 223 else
643
+ − 224 {
668
+ − 225 if(global.lifeData.battery_charge > 100.0) /* still charging but indicator is set to full => decrease to 99% to keep count increasing */
+ − 226 {
+ − 227 battery_gas_gauge_set(99.0);
+ − 228 }
662
+ − 229 if(batteryChargerState == Charger_Finished) /* voltage dropped below the hysteresis again => charging restarted */
+ − 230 {
+ − 231 batteryChargerState = Charger_Active;
+ − 232 notifyChargeComplete = 0;
+ − 233 }
643
+ − 234 }
+ − 235
662
+ − 236 /* restore high impedance to be able to detect disconnection */
+ − 237 GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+ − 238 GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
+ − 239 GPIO_InitStructure.Pull = GPIO_NOPULL;
+ − 240 GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+ − 241 HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+ − 242 HAL_Delay(1);
+ − 243 break;
643
+ − 244
859
+ − 245 default: batteryChargerState = Charger_NotConnected; /* unexpected state => reinitialize state machine */
662
+ − 246 break;
+ − 247 }
643
+ − 248 }
+ − 249 }
38
+ − 250 }
+ − 251
+ − 252 /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/