Implemented the logic to detect and read the charge controller status pins using two different policies :
- the first one (also used right now) is using interrupts on the two lines - the second one was doing some polling using a timer interrupt to check the controller status
This commit is contained in:
parent
9f574f0486
commit
214e174ffc
@ -6,19 +6,107 @@
|
||||
#include "wm_timer.h"
|
||||
#include "wm_pwm.h"
|
||||
|
||||
#define INTERRUPT_POLICY (0)
|
||||
#define POLL_POLICY (1)
|
||||
|
||||
#define BATTERY_CONTROLLER_STATUS_DETECTION_POLICY INTERRUPT_POLICY
|
||||
|
||||
/* Battery voltage and ADC */
|
||||
static int8_t _adc_offset = 0;
|
||||
|
||||
/* Vibration motor timer */
|
||||
static uint8_t _vibration_motor_timer_id = WM_TIMER_ID_INVALID;
|
||||
|
||||
/* Battery charge controller status */
|
||||
static battery_controller_status_e _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING;
|
||||
static BatteryControllerStatusChangeCb_t _BatteryControllerStatusChangeCb = NULL;
|
||||
|
||||
static void vibration_motor_timer_irq_cb(void *p)
|
||||
{
|
||||
(void)p;
|
||||
tls_pwm_stop(VIBRATION_MOTOR_PWM_CHANNEL);
|
||||
tls_gpio_cfg(VIBRATION_MOTOR_ENABLE, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
|
||||
tls_gpio_write(VIBRATION_MOTOR_ENABLE, 0);
|
||||
APP_LOG_DEBUG("Vibration stopped");
|
||||
}
|
||||
|
||||
#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY
|
||||
static uint8_t _battery_status_timer_id = WM_TIMER_ID_INVALID;
|
||||
|
||||
static void battery_status_timer_irq_cb(void *p)
|
||||
{
|
||||
bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0;
|
||||
bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0;
|
||||
|
||||
battery_controller_status_e old_battery_status = _battery_fsm;
|
||||
|
||||
if(charging && !charged)
|
||||
_battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGING;
|
||||
else if(!charging && charged)
|
||||
_battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGED;
|
||||
else if (!charging && !charged)
|
||||
_battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING;
|
||||
else
|
||||
_battery_fsm = BATTERY_CONTROLLER_STATUS_ERROR;
|
||||
|
||||
if(old_battery_status != _battery_fsm)
|
||||
{
|
||||
// Let's call a user registered callback here
|
||||
APP_LOG_INFO("Battery status changed from %s to %s",
|
||||
battery_controller_status_2_str(old_battery_status),
|
||||
battery_controller_status_2_str(_battery_fsm));
|
||||
|
||||
if(_BatteryControllerStatusChangeCb) _BatteryControllerStatusChangeCb(old_battery_status, _battery_fsm);
|
||||
}
|
||||
}
|
||||
#elif BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY
|
||||
static void battery_controller_irq_cb(void *p)
|
||||
{
|
||||
enum tls_io_name gpio_pin = (enum tls_io_name)p;
|
||||
|
||||
if(BATTERY_CONTROLLER_CHARGING_STATUS == gpio_pin)
|
||||
{
|
||||
tls_clr_gpio_irq_status(BATTERY_CONTROLLER_CHARGING_STATUS);
|
||||
}
|
||||
if(BATTERY_CONTROLLER_CHARGED_STATUS == gpio_pin)
|
||||
{
|
||||
tls_clr_gpio_irq_status(BATTERY_CONTROLLER_CHARGED_STATUS);
|
||||
}
|
||||
|
||||
bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0;
|
||||
bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0;
|
||||
|
||||
battery_controller_status_e old_battery_status = _battery_fsm;
|
||||
|
||||
switch(old_battery_status)
|
||||
{
|
||||
case BATTERY_CONTROLLER_STATUS_CHARGING:
|
||||
if(charged) _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGED;
|
||||
else if(!charged && !charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING;
|
||||
break;
|
||||
case BATTERY_CONTROLLER_STATUS_CHARGED:
|
||||
if(!charged && !charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING;
|
||||
break;
|
||||
case BATTERY_CONTROLLER_STATUS_DISCHARGING:
|
||||
if(charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGING;
|
||||
break;
|
||||
default:
|
||||
_battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING;
|
||||
break;
|
||||
}
|
||||
|
||||
if(old_battery_status != _battery_fsm)
|
||||
{
|
||||
// Let's call a user registered callback here
|
||||
APP_LOG_INFO("Battery status changed from %s to : %s, IRQ : %u",
|
||||
battery_controller_status_2_str(old_battery_status),
|
||||
battery_controller_status_2_str(_battery_fsm),
|
||||
gpio_pin);
|
||||
|
||||
if(_BatteryControllerStatusChangeCb) _BatteryControllerStatusChangeCb(old_battery_status, _battery_fsm);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void watch_peripherals_io_init(void)
|
||||
{
|
||||
/* We initialize the ADC input as well as the gpio used to enabled the voltage divider bridge */
|
||||
@ -31,8 +119,34 @@ static void watch_peripherals_io_init(void)
|
||||
tls_gpio_write(VIBRATION_MOTOR_ENABLE, 0);
|
||||
|
||||
/* We initialize the pins used to read the battery controller IC charging and charged statuses */
|
||||
tls_gpio_cfg(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);
|
||||
tls_gpio_cfg(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);
|
||||
tls_gpio_cfg(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);
|
||||
|
||||
#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY
|
||||
tls_gpio_isr_register(BATTERY_CONTROLLER_CHARGED_STATUS, &(battery_controller_irq_cb), (int*) BATTERY_CONTROLLER_CHARGED_STATUS);
|
||||
tls_gpio_irq_enable(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); // Enabled when level is changing edge
|
||||
|
||||
tls_gpio_isr_register(BATTERY_CONTROLLER_CHARGING_STATUS, &(battery_controller_irq_cb), (int*) BATTERY_CONTROLLER_CHARGING_STATUS);
|
||||
tls_gpio_irq_enable(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); // Enabled when level is changing edge
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CASE_RETURN_STR
|
||||
#define CASE_RETURN_STR(const) case const: return #const;
|
||||
#endif
|
||||
|
||||
const char *battery_controller_status_2_str(battery_controller_status_e status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_CHARGING)
|
||||
CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_DISCHARGING)
|
||||
CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_CHARGED)
|
||||
CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_ERROR)
|
||||
|
||||
default:
|
||||
return "Unknown Battery Status";
|
||||
}
|
||||
}
|
||||
|
||||
void watch_peripherals_init(int8_t adcOffset)
|
||||
@ -43,7 +157,7 @@ void watch_peripherals_init(int8_t adcOffset)
|
||||
/* Prevent multiple init call !*/
|
||||
if(WM_TIMER_ID_INVALID == _vibration_motor_timer_id)
|
||||
{
|
||||
/* Let's initialize the timer w'll use to stop the vibration motor */
|
||||
/* Let's initialize the timer we'll use to stop the vibration motor */
|
||||
struct tls_timer_cfg vibration_motor_timer_cfg =
|
||||
{
|
||||
.arg = NULL,
|
||||
@ -55,8 +169,32 @@ void watch_peripherals_init(int8_t adcOffset)
|
||||
_vibration_motor_timer_id = tls_timer_create(&vibration_motor_timer_cfg);
|
||||
|
||||
if(WM_TIMER_ID_INVALID == _vibration_motor_timer_id)
|
||||
APP_LOG_ERROR("Failed to create timer");
|
||||
APP_LOG_ERROR("Failed to create vibration motor timer");
|
||||
}
|
||||
#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY
|
||||
if(WM_TIMER_ID_INVALID == _battery_status_timer_id)
|
||||
{
|
||||
struct tls_timer_cfg battery_status_timer_cfg =
|
||||
{
|
||||
.arg = NULL,
|
||||
.callback = &(battery_status_timer_irq_cb),
|
||||
.unit = TLS_TIMER_UNIT_MS,
|
||||
.is_repeat = true,
|
||||
.timeout = 200
|
||||
};
|
||||
_battery_status_timer_id = tls_timer_create(&battery_status_timer_cfg);
|
||||
|
||||
if(WM_TIMER_ID_INVALID == _battery_status_timer_id)
|
||||
APP_LOG_ERROR("Failed to create battery status timer");
|
||||
else
|
||||
tls_timer_start(_battery_status_timer_id);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void watch_peripherals_register_battery_controller_status_change_cb(BatteryControllerStatusChangeCb_t BatteryControllerStatusChangeCb)
|
||||
{
|
||||
_BatteryControllerStatusChangeCb = BatteryControllerStatusChangeCb;
|
||||
}
|
||||
|
||||
uint16_t watch_peripherals_get_battery_voltage(battery_unit_e unit)
|
||||
@ -100,22 +238,11 @@ uint8_t battery_voltage_to_percentage(uint16_t voltage_in_mV)
|
||||
|
||||
battery_controller_status_e watch_peripherals_get_battery_controller_status(void)
|
||||
{
|
||||
bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0;
|
||||
bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0;
|
||||
|
||||
if(charging && !charged)
|
||||
return BATTERY_CHARGING;
|
||||
else if(!charging && charged)
|
||||
return BATTERY_CHARGED;
|
||||
else if (!charging && !charged)
|
||||
return BATTERY_DISCHARGING;
|
||||
else
|
||||
return BATTERY_ERROR;
|
||||
return _battery_fsm;
|
||||
}
|
||||
|
||||
void watch_peripherals_vibrate(uint8_t strength, uint32_t durationMs)
|
||||
{
|
||||
APP_LOG_DEBUG("Vibration started");
|
||||
/* No need to do anything if the duration is 0 or if the strength is 0 */
|
||||
if(!strength || !durationMs) return;
|
||||
/* We start the timer which will stop the vibration after durationMs time */
|
||||
|
@ -15,12 +15,22 @@ typedef enum battery_unit
|
||||
|
||||
typedef enum battery_controller_status
|
||||
{
|
||||
BATTERY_CHARGING = 0,
|
||||
BATTERY_CHARGED,
|
||||
BATTERY_DISCHARGING,
|
||||
BATTERY_ERROR
|
||||
BATTERY_CONTROLLER_STATUS_DISCHARGING = 0,
|
||||
BATTERY_CONTROLLER_STATUS_CHARGING,
|
||||
BATTERY_CONTROLLER_STATUS_CHARGED,
|
||||
BATTERY_CONTROLLER_STATUS_ERROR
|
||||
} battery_controller_status_e;
|
||||
|
||||
typedef void (*BatteryControllerStatusChangeCb_t)(battery_controller_status_e old, battery_controller_status_e new);
|
||||
|
||||
/**
|
||||
* @brief Helper function to easily print the battery status enumeration name
|
||||
*
|
||||
* @param status the enumeration value for which to get the name
|
||||
* @return const char* a string representing the enumeration value
|
||||
*/
|
||||
const char *battery_controller_status_2_str(battery_controller_status_e status);
|
||||
|
||||
/**
|
||||
* @brief Inits the watch peripherals driver.
|
||||
* This must be called before using the API.
|
||||
@ -29,6 +39,14 @@ typedef enum battery_controller_status
|
||||
*/
|
||||
void watch_peripherals_init(int8_t adcOffset);
|
||||
|
||||
/**
|
||||
* @brief Registers the user provided callback function to notify the battery controller status change event
|
||||
* @note This function should be as short as possible, do not call LVGL functions in it.
|
||||
*
|
||||
* @param BatteryStatusChangeCb a pointer to the function having the right definition.
|
||||
*/
|
||||
void watch_peripherals_register_battery_controller_status_change_cb(BatteryControllerStatusChangeCb_t BatteryStatusChangeCb);
|
||||
|
||||
/**
|
||||
* @brief Reads and returns the current battery voltage in mV or it's corresponding capacity in percentage.
|
||||
* This function takes into account the adcOffset parameter provided in the @ref watch_peripherals_init
|
||||
@ -50,9 +68,9 @@ uint8_t battery_voltage_to_percentage(uint16_t voltage_in_mV);
|
||||
|
||||
/**
|
||||
* @brief Returns the current battery controller IC status.
|
||||
* It can be one of the following
|
||||
* It can be one of the following :
|
||||
*
|
||||
* @return battery_controller_status_e
|
||||
* @return battery_controller_status_e BATTERY_CHARGING, BATTERY_CHARGED, BATTERY_DISCHARGING and BATTERY_ERROR.
|
||||
*/
|
||||
battery_controller_status_e watch_peripherals_get_battery_controller_status(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user