view Small_CPU/Src/batteryCharger.c @ 645:e58f81cb25a7

Small changes in charger state handling: Charger debounce time has been reduced to 5 seconds and the detection time of charger removal has been reduced to 15 second to be able to provide a faster feedback to the user. In addition the battery stage reset has been added (only relevant for a getState function which is not used within the firmware at the moment.
author Ideenmodellierer
date Tue, 13 Apr 2021 19:18:32 +0200
parents ebe3fc302ab8
children 1b995079c045
line wrap: on
line source

/**
  ******************************************************************************
  * @file    batteryCharger.c 
  * @author  heinrichs weikamp gmbh
  * @date    09-Dec-2014
  * @version V0.0.1
  * @since   09-Dec-2014
  * @brief   LTC4054 Battery Charger
  *           
  @verbatim                 
  ============================================================================== 
                        ##### How to use #####
  ============================================================================== 

The bq5105x provides one status output, CHG. This output is an open-drain NMOS device that is rated to 20 V.
The open-drain FET connected to the CHG pin will be turned on whenever the output (BAT) of the charger is
enabled. As a note, the output of the charger supply will not be enabled if the VRECT-REG does not converge to the
no-load target voltage.

CHG F4 7 O Open-drain output � active when BAT is enabled. Float if not used.

@endverbatim
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2015 heinrichs weikamp</center></h2>
  *
  ******************************************************************************
  */ 
/* Includes ------------------------------------------------------------------*/
#include "batteryCharger.h"
#include "batteryGasGauge.h"
#include "stm32f4xx_hal.h"
#include "scheduler.h"


/* Use This compile switch to select the new charger status control implementation */
#define ENABLE_CHARGER_STATUS_V2

#define CHARGE_IN_PIN							GPIO_PIN_2
#define CHARGE_IN_GPIO_PORT				GPIOC
#define CHARGE_IN_GPIO_ENABLE()		__GPIOC_CLK_ENABLE()

#define CHARGE_OUT_PIN						GPIO_PIN_1
#define CHARGE_OUT_GPIO_PORT			GPIOC
#define CHARGE_OUT_GPIO_ENABLE()	__GPIOC_CLK_ENABLE()

#define CHARGER_DEBOUNCE_SECONDS	(5u)		/* 5 seconds used to avoid problems with charger interrupts / disconnections */

uint8_t battery_i_charge_status = 0;
uint16_t battery_charger_counter = 0;

#ifdef ENABLE_CHARGER_STATUS_V2
typedef enum
{
	Charger_NotConnected = 0,		/* This is identified reading CHARGE_IN_PIN == HIGH */
	Charger_WarmUp,					/* Charging started but counter did not yet reach a certain limit (used to debounce connect / disconnect events to avoid multiple increases of statistic charging cycle counter) */
	Charger_Active,					/* Charging identified by  CHARGE_IN_PIN == LOW for a certain time */
	Charger_Finished,
	Charger_LostConnection			/* Intermediate state to debounce disconnecting events (including charging error state like over temperature) */
} chargerState_t;

static chargerState_t batteryChargerState = Charger_NotConnected;
#endif

/* can be 0, 1 or 255
 * 0 is disconnected
 * 1 is charging
 * 255 is full
 */
uint8_t get_charge_status(void)
{
	return battery_i_charge_status;
}

void init_battery_charger_status(void)
{
	#ifdef OSTC_ON_DISCOVERY_HARDWARE
		return;
	#endif

  CHARGE_IN_GPIO_ENABLE();
  CHARGE_OUT_GPIO_ENABLE();
	
	ReInit_battery_charger_status_pins();
}

void ReInit_battery_charger_status_pins(void)
{
	#ifdef OSTC_ON_DISCOVERY_HARDWARE
		return;
	#endif

  GPIO_InitTypeDef   GPIO_InitStructure;

  GPIO_InitStructure.Pin = CHARGE_IN_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(CHARGE_IN_GPIO_PORT, &GPIO_InitStructure); 

  GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure); 
}


void DeInit_battery_charger_status_pins(void)
{
	#ifdef OSTC_ON_DISCOVERY_HARDWARE
		return;
	#endif
  GPIO_InitTypeDef   GPIO_InitStructure;


	GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
  GPIO_InitStructure.Pull = GPIO_NOPULL;

  GPIO_InitStructure.Pin = CHARGE_IN_PIN;
  HAL_GPIO_Init(CHARGE_IN_GPIO_PORT, &GPIO_InitStructure); 

  GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
  HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure); 
}

/* static counter is used to avoid multiple counts of charge startings
	 and after that it is used, starting at 127 to count for the charge full signal

	there a short disconnections with the QI charger
	therefore the battery_charger_counter has a countdown instead of = 0.

	battery_gas_gauge_set_charge_full and  scheduleUpdateDeviceDataChargerFull are
	set after disconnection as the charging process continues as long as not disconnected
  to prevent the short disconnections the battery_charger_counter is used too including
	upcounting again while battery_i_charge_status == 255 and the connection is established

 */

void battery_charger_get_status_and_contral_battery_gas_gauge(uint8_t cycleTimeBase)
{
#ifdef ENABLE_CHARGER_STATUS_V2
	static uint8_t notifyChargeComplete = 0;
#endif 

	#ifdef OSTC_ON_DISCOVERY_HARDWARE
		return;
	#endif
	
#ifdef ENABLE_CHARGER_STATUS_V2
	/* on disconnection or while disconnected */
	if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))
	{
		switch(batteryChargerState)
		{
			case Charger_Active:				global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
												global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
												batteryChargerState = Charger_LostConnection;
												battery_charger_counter = CHARGER_DEBOUNCE_SECONDS;

												if(get_voltage() >= 4.1f)			/* the charger stops charging when charge current is 1/10. */
												{									/*  Basically it is OK to rate a charging as complete if a defined voltage is reached */
													batteryChargerState = Charger_Finished;
													global.dataSendToMaster.chargeStatus = CHARGER_complete;
													global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
													battery_charger_counter = 15;
													notifyChargeComplete = 1;
												}
										break;
			case Charger_WarmUp:
			case Charger_Finished:
			case Charger_LostConnection:		if(battery_charger_counter >= cycleTimeBase)
												{
													battery_charger_counter -= cycleTimeBase;
													global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
													global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
													batteryChargerState = Charger_LostConnection;
												}
												else
												{
													battery_charger_counter = 0;
													battery_i_charge_status = 0;
													global.dataSendToMaster.chargeStatus = CHARGER_off;
													global.deviceDataSendToMaster.chargeStatus = CHARGER_off;

													if(notifyChargeComplete)
													{
														battery_gas_gauge_set_charge_full();
														scheduleUpdateDeviceDataChargerFull();
														notifyChargeComplete = 0;
													}
													batteryChargerState = Charger_NotConnected;
												}
										break;
			default: break;
		}
	}
	else
	{
		/* connected */
		/* wait for disconnection to write and reset */
		switch(batteryChargerState)
		{
				case Charger_NotConnected:		battery_i_charge_status = 1;
												battery_charger_counter = 0;
												batteryChargerState = Charger_WarmUp;
										break;
				case Charger_LostConnection:		batteryChargerState = Charger_Active;
										break;
				case Charger_WarmUp:			battery_charger_counter += cycleTimeBase;
												if(battery_charger_counter >= CHARGER_DEBOUNCE_SECONDS )
												{
													battery_i_charge_status = 2;
													scheduleUpdateDeviceDataChargerCharging();
													batteryChargerState = Charger_Active;
												}
						/* no break */
				case Charger_Finished:
				case Charger_Active:			global.dataSendToMaster.chargeStatus = CHARGER_running;
												global.deviceDataSendToMaster.chargeStatus = CHARGER_running;

												/* drive the output pin high to determine the state of the charger */
												GPIO_InitTypeDef   GPIO_InitStructure;
												GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
												GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
												GPIO_InitStructure.Pull = GPIO_NOPULL;
												GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
												HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
												HAL_GPIO_WritePin(CHARGE_OUT_GPIO_PORT, CHARGE_OUT_PIN,GPIO_PIN_SET);
												HAL_Delay(1);

												if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))		/* high => charger stopped charging */
												{
													batteryChargerState = Charger_Finished;
													global.dataSendToMaster.chargeStatus = CHARGER_complete;
													global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
													battery_charger_counter = 30;
													notifyChargeComplete = 1;
												}
												else
												{
													if(batteryChargerState == Charger_Finished)				/* voltage dropped below the hysteresis again => charging restarted */
													{
														batteryChargerState = Charger_Active;
														notifyChargeComplete = 0;
													}
												}

												/* restore high impedance to be able to detect disconnection */
												GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
												GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
												GPIO_InitStructure.Pull = GPIO_NOPULL;
												GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
												HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
												HAL_Delay(1);
										break;

				default:						/* wait for disconnection */
					break;
		}
	}
#else
	/* on disconnection or while disconnected */
	if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))
	{
		if(battery_charger_counter)
		{
			battery_charger_counter--;
			global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
			global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
		}
		/* max count down to 127+5 or 127+20 */
		if((battery_i_charge_status == 255) && battery_charger_counter < 127)
		{
//			battery_gas_gauge_set_charge_full();
//			scheduleUpdateDeviceDataChargerFull();
			battery_charger_counter = 0;
		}
		
		if(battery_charger_counter == 0)
		{
			battery_i_charge_status = 0;
			global.dataSendToMaster.chargeStatus = CHARGER_off;
			global.deviceDataSendToMaster.chargeStatus = CHARGER_off;

		}
		return;
	}

	/* connected */
	
	/* wait for disconnection to write and reset */
	if(battery_i_charge_status == 255)
	{
		global.dataSendToMaster.chargeStatus = CHARGER_complete;
		global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
		
		if(((cycleTimeBase > 1) && (battery_charger_counter < 127+5)) || (battery_charger_counter < 127+20))
		battery_charger_counter++;
		return;
	}

	if(battery_charger_counter == 0)
		battery_i_charge_status = 1;

	/* charger is connected and didn't signal full yet */
	global.dataSendToMaster.chargeStatus = CHARGER_running;
	global.deviceDataSendToMaster.chargeStatus = CHARGER_running;

	GPIO_InitTypeDef   GPIO_InitStructure;
    GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure); 
	HAL_GPIO_WritePin(CHARGE_OUT_GPIO_PORT, CHARGE_OUT_PIN,GPIO_PIN_SET);
	HAL_Delay(1);

	
	if(battery_charger_counter < 120)
	{
		if(cycleTimeBase == 1)
			battery_charger_counter++;
		else
		{
			battery_charger_counter += 30;
			if(battery_charger_counter >= 127)
				battery_charger_counter = 126;
		}
	}
	else
	if(battery_charger_counter < 127)
	{
		battery_charger_counter = 127;
		if(battery_i_charge_status < 2)
		{
			battery_i_charge_status = 2;
			scheduleUpdateDeviceDataChargerCharging();
		}
	}

	if(battery_charger_counter >= 127)
	{
		if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN) || (get_voltage() >= 4.1f))
		{
			battery_charger_counter++;
			if(((cycleTimeBase > 1) && (battery_charger_counter > 127+5)) || (battery_charger_counter > 127+20))
			{
				battery_charger_counter = 127;
				if(get_voltage() >= 4.1f)
				{
					battery_i_charge_status = 255;
					battery_gas_gauge_set_charge_full();
					scheduleUpdateDeviceDataChargerFull();
				}					
			}
		}
		else
			battery_charger_counter = 127;
	}

  GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure); 
#endif
}

/************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/