Skip to content

Commit 338c2a0

Browse files
authored
Power management optimizes and fixes (#51)
* update readme for firmware hash check * pmu temperature range adjust * pmu system voltage regulation support * pmu reset mode select support * battery voltage monitoring support * low power mode enter logic optimize * minor changes and cleanups * chip self power warning support --------- Signed-off-by: Adam BZH <[email protected]>
1 parent be3739f commit 338c2a0

File tree

9 files changed

+181
-53
lines changed

9 files changed

+181
-53
lines changed

app/main.c

Lines changed: 109 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -459,12 +459,6 @@ static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event)
459459
switch ( event )
460460
{
461461
case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
462-
// stop bt adv
463-
if ( nrf_sdh_is_enabled() )
464-
{
465-
if ( !bt_advertising_ctrl(false, false) )
466-
return false;
467-
}
468462
// enable wakeup
469463
nrf_gpio_cfg_sense_input(PMIC_PWROK_IO, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
470464
// nrf_gpio_cfg_sense_input(PMIC_IRQ_IO, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
@@ -481,23 +475,6 @@ static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event)
481475
}
482476
NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0);
483477

484-
static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void* p_context)
485-
{
486-
if ( state == NRF_SDH_EVT_STATE_DISABLED )
487-
{
488-
// Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot.
489-
nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);
490-
491-
// Go to system off.
492-
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
493-
}
494-
}
495-
496-
/* nrf_sdh state observer. */
497-
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) = {
498-
.handler = buttonless_dfu_sdh_state_observer,
499-
};
500-
501478
/**@brief Function for assert macro callback.
502479
*
503480
* @details This function will be called in case of an assert in the SoftDevice.
@@ -521,18 +498,52 @@ static inline void gpio_uninit(void)
521498

522499
static void enter_low_power_mode(void)
523500
{
524-
if ( (pmu_p != NULL) && (pmu_p->isInitialized) )
525-
pmu_p->Deinit();
526-
gpio_uninit();
527-
nrf_gpio_cfg_default(ST_WAKE_IO);
501+
// stop uart
528502
if ( app_uart_is_initialized )
529503
{
530504
app_uart_close();
531505
app_uart_is_initialized = false;
532506
}
507+
508+
// stop bt adv
509+
if ( nrf_sdh_is_enabled() )
510+
{
511+
while ( !bt_advertising_ctrl(false, false) )
512+
{
513+
nrf_delay_ms(100);
514+
}
515+
}
516+
517+
// release pmu interface
518+
if ( (pmu_p != NULL) && (pmu_p->isInitialized) )
519+
pmu_p->Deinit();
520+
521+
// release gpio
522+
gpio_uninit();
523+
nrf_gpio_cfg_default(ST_WAKE_IO);
524+
525+
// shutdown
533526
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
534527
}
535528

529+
// sdh_soc_handler, mainly for power warning, no other event processed yet
530+
void sdh_soc_handler(uint32_t sys_evt, void* p_context)
531+
{
532+
UNUSED_VAR(p_context);
533+
534+
if ( sys_evt == NRF_EVT_POWER_FAILURE_WARNING )
535+
{
536+
// nrf_gpio_cfg_output(PMIC_PWROK_IO);
537+
// nrf_gpio_pin_clear(PMIC_PWROK_IO);
538+
NRF_LOG_INFO("NRF Power POF triggered!");
539+
NRF_LOG_FLUSH();
540+
541+
pmu_p->SetState(PWR_STATE_HARD_OFF);
542+
enter_low_power_mode();
543+
}
544+
}
545+
NRF_SDH_SOC_OBSERVER(m_soc_observer, 0, sdh_soc_handler, NULL);
546+
536547
void battery_level_meas_timeout_handler(void* p_context)
537548
{
538549
ret_code_t err_code;
@@ -2235,6 +2246,7 @@ static inline void pmu_status_print()
22352246
{
22362247
NRF_LOG_INFO("=== PowerStatus ===");
22372248
NRF_LOG_INFO("PMIC_IRQ_IO -> %s", (nrf_gpio_pin_read(PMIC_IRQ_IO) ? "HIGH" : "LOW"));
2249+
NRF_LOG_INFO("sysVoltage=%lu", pmu_p->PowerStatus->sysVoltage);
22382250
NRF_LOG_INFO("batteryPresent=%u", pmu_p->PowerStatus->batteryPresent);
22392251
NRF_LOG_INFO("batteryPercent=%u", pmu_p->PowerStatus->batteryPercent);
22402252
NRF_LOG_INFO("batteryVoltage=%lu", pmu_p->PowerStatus->batteryVoltage);
@@ -2347,6 +2359,56 @@ static void pmu_irq_pull(void* p_event_data, uint16_t event_size)
23472359
}
23482360
}
23492361

2362+
static void pmu_sys_voltage_monitor(void* p_event_data, uint16_t event_size)
2363+
{
2364+
static uint8_t match_count = 0;
2365+
const uint8_t match_required = 30;
2366+
const uint16_t minimum_mv = 3300;
2367+
2368+
if ( (match_count < match_required) )
2369+
{
2370+
// not triggered
2371+
if ( pmu_p->PowerStatus->batteryVoltage < minimum_mv )
2372+
{
2373+
// voltage low
2374+
if ( pmu_p->PowerStatus->chargerAvailable )
2375+
{
2376+
// has charger, ignore
2377+
// NRF_LOG_INFO("Low batteryVoltage detect skiped since charger available");
2378+
// reset counter
2379+
match_count = 0;
2380+
}
2381+
else
2382+
{
2383+
// increase counter
2384+
match_count++;
2385+
NRF_LOG_INFO(
2386+
"Low batteryVoltage debounce, match %u/%u (batteryVoltage=%lu)", match_count, match_required,
2387+
pmu_p->PowerStatus->batteryVoltage
2388+
);
2389+
}
2390+
}
2391+
else
2392+
{
2393+
// voltage normal
2394+
if ( match_count > 0 )
2395+
{
2396+
// reset counter if not zero
2397+
match_count = 0;
2398+
NRF_LOG_INFO("Low batteryVoltage debounce, match reset");
2399+
NRF_LOG_FLUSH();
2400+
}
2401+
}
2402+
}
2403+
else
2404+
{
2405+
// already triggered
2406+
NRF_LOG_INFO("Low batteryVoltage debounce, match fulfilled, force shutdown pmu");
2407+
NRF_LOG_FLUSH();
2408+
pmu_p->SetState(PWR_STATE_HARD_OFF);
2409+
}
2410+
}
2411+
23502412
static void led_ctl_process(void* p_event_data, uint16_t event_size)
23512413
{
23522414
// handle commands
@@ -2534,6 +2596,25 @@ int main(void)
25342596
false
25352597
); // TODO: check return!
25362598

2599+
// ###############################
2600+
// Power mode and warning (depends on SD, has to be here)
2601+
ExecuteCheck_ADV(sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE), NRF_SUCCESS, {
2602+
NRF_LOG_INFO("NRF Power enable DCDC failed");
2603+
NRF_LOG_FLUSH();
2604+
enter_low_power_mode();
2605+
});
2606+
ExecuteCheck_ADV(sd_power_pof_threshold_set(NRF_POWER_THRESHOLD_V28), NRF_SUCCESS, {
2607+
NRF_LOG_INFO("NRF Power set POF threadhold failed");
2608+
NRF_LOG_FLUSH();
2609+
enter_low_power_mode();
2610+
});
2611+
ExecuteCheck_ADV(sd_power_pof_enable(true), NRF_SUCCESS, {
2612+
NRF_LOG_INFO("NRF Power enable POF failed");
2613+
NRF_LOG_FLUSH();
2614+
enter_low_power_mode();
2615+
});
2616+
NRF_LOG_INFO("NRF Power configured");
2617+
25372618
// ###############################
25382619
// Main Loop
25392620
NRF_LOG_INFO("Main Loop Enter");
@@ -2542,6 +2623,7 @@ int main(void)
25422623
for ( ;; )
25432624
{
25442625
// event trigger
2626+
app_sched_event_put(NULL, 0, pmu_sys_voltage_monitor);
25452627
app_sched_event_put(NULL, 0, pmu_pwrok_pull);
25462628
app_sched_event_put(NULL, 0, pmu_irq_pull);
25472629
app_sched_event_put(NULL, 0, pmu_status_refresh);

app/power_manage.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,14 @@ static void pmu_if_irq(const uint64_t irq)
6464
// bak_buff[2] = (pmu_p->PowerStatus->wiredCharge ? AXP_CHARGE_TYPE_USB : AXP_CHARGE_TYPE_WIRELESS);
6565
// send_stm_data_p(bak_buff, 3);
6666
// }
67-
if ( 0 != (irq & (1 << PWR_IRQ_BATT_LOW)) ) {}
68-
if ( 0 != (irq & (1 << PWR_IRQ_BATT_CRITICAL)) ) {}
67+
if ( 0 != (irq & (1 << PWR_IRQ_BATT_LOW)) )
68+
{
69+
NRF_LOG_INFO("irq PWR_IRQ_BATT_LOW");
70+
}
71+
if ( 0 != (irq & (1 << PWR_IRQ_BATT_CRITICAL)) )
72+
{
73+
NRF_LOG_INFO("irq PWR_IRQ_BATT_CRITICAL");
74+
}
6975
if ( 0 != (irq & (1 << PWR_IRQ_PB_PRESS)) )
7076
{
7177
NRF_LOG_INFO("irq PWR_IRQ_PB_PRESS");
@@ -308,11 +314,11 @@ void axp_reg_dump(uint8_t pmu_addr)
308314
if ( !pmu_if.isInitialized )
309315
return;
310316

311-
pmu_if.Log(PWR_LOG_LEVEL_INFO, "**************** axp_reg_dump ****************\n");
317+
pmu_if.Log(PWR_LOG_LEVEL_INFO, "**************** axp_reg_dump ****************");
312318

313319
for ( uint16_t reg = 0; reg <= 0xff; reg++ )
314320
{
315321
pmu_if.Reg.Read(pmu_addr, reg, &val);
316-
pmu_if.Log(PWR_LOG_LEVEL_INFO, "reg 0x%02x = 0x%02x\n", reg, val);
322+
pmu_if.Log(PWR_LOG_LEVEL_INFO, "reg 0x%02x = 0x%02x", reg, val);
317323
}
318324
}

drivers/pmu/axp2101.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ static bool axp2101_config_voltage(void)
2424
// DCDC1 -> RAIL_3V3 3.3V
2525
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_DCDC1_CFG, 0x12));
2626

27+
// minimal vsys voltage -> 2.6V
28+
// there is a silicon logic bug for axp2101, batfet won't be closed if powered on by key, even if vsys is lower than
29+
// VOFF_THLD
30+
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VOFF_THLD, 0x00));
31+
2732
return true;
2833
}
2934

@@ -92,8 +97,8 @@ static bool axp2101_config_battery_param(void)
9297
return true;
9398
}
9499

95-
#define AXP2101_VTS_TO_VHTF(mv) (mv / 32)
96-
#define AXP2101_VTS_TO_VLTF(mv) (mv / 2)
100+
#define AXP2101_VTS_TO_VHTF(mv) (mv / 2)
101+
#define AXP2101_VTS_TO_VLTF(mv) (mv / 32)
97102
static bool axp2101_config_battery(void)
98103
{
99104
// warn level
@@ -116,16 +121,16 @@ static bool axp2101_config_battery(void)
116121
// Vl = reg_val * 2mv
117122

118123
// charge temp max
119-
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VHTF_CHG, (uint8_t)(AXP2101_VTS_TO_VHTF(196.96)))); // 196.96mv
124+
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VHTF_CHG, (uint8_t)(AXP2101_VTS_TO_VHTF(193.9))));
120125

121126
// charge temp min
122-
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VLTF_CHG, (uint8_t)(AXP2101_VTS_TO_VLTF(711.2)))); // 711.2mv
127+
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VLTF_CHG, (uint8_t)(AXP2101_VTS_TO_VLTF(736.3))));
123128

124129
// discharge temp max
125-
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VHTF_DISCHG, (uint8_t)(AXP2101_VTS_TO_VHTF(121.28)))); // 121.28mv
130+
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VHTF_DISCHG, (uint8_t)(AXP2101_VTS_TO_VHTF(119.3))));
126131

127132
// discharge temp min
128-
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VLTF_DISCHG, (uint8_t)(AXP2101_VTS_TO_VLTF(2520)))); // 2520mv
133+
EC_E_BOOL_R_BOOL(axp2101_reg_write(AXP2101_VLTF_DISCHG, (uint8_t)(AXP2101_VTS_TO_VLTF(3099))));
129134

130135
return true;
131136
}
@@ -220,9 +225,21 @@ Power_Error_t axp2101_deinit(void)
220225
return PWR_ERROR_NONE;
221226
}
222227

223-
Power_Error_t axp2101_reset(void)
228+
Power_Error_t axp2101_reset(bool hard_reset)
224229
{
225-
EC_E_BOOL_R_PWR_ERR(axp2101_set_bits(AXP2101_COMM_CFG, (1 << 1)));
230+
if ( !hard_reset )
231+
{
232+
EC_E_BOOL_R_PWR_ERR(axp2101_set_bits(AXP2101_COMM_CFG, (1 << 1)));
233+
}
234+
else
235+
{
236+
// pmu force reset by pull down pwrok
237+
pmu_interface_p->GPIO.Config(7, PWR_GPIO_Config_WRITE_NP);
238+
pmu_interface_p->GPIO.Write(7, false);
239+
pmu_interface_p->Delay_ms(100);
240+
pmu_interface_p->GPIO.Config(7, PWR_GPIO_Config_DEFAULT);
241+
}
242+
226243
return PWR_ERROR_NONE;
227244
}
228245

@@ -348,6 +365,12 @@ Power_Error_t axp2101_pull_status(void)
348365

349366
Power_Status_t status_temp = {0};
350367

368+
// sys voltage
369+
EC_E_BOOL_R_PWR_ERR(axp2101_reg_read(AXP2101_VSYS_H, &(hlbuff.u8_high)));
370+
hlbuff.u8_high &= 0b00111111; // drop bit 7:6
371+
EC_E_BOOL_R_PWR_ERR(axp2101_reg_read(AXP2101_VSYS_L, &(hlbuff.u8_low)));
372+
status_temp.sysVoltage = hlbuff.u16;
373+
351374
// battery present
352375
hlbuff.u8_high = 0;
353376
EC_E_BOOL_R_PWR_ERR(axp2101_reg_read(AXP2101_COMM_STAT0, &(hlbuff.u8_low)));

drivers/pmu/axp2101.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135

136136
Power_Error_t axp2101_init(void);
137137
Power_Error_t axp2101_deinit(void);
138-
Power_Error_t axp2101_reset(void);
138+
Power_Error_t axp2101_reset(bool hard_reset);
139139
Power_Error_t axp2101_config(void);
140140
Power_Error_t axp2101_irq(void);
141141
Power_Error_t axp2101_set_state(const Power_State_t state);

drivers/pmu/axp216.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ static bool axp216_config_voltage(void)
2828
// DCDC1 -> MAIN 3.3V
2929
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_DC1OUT_VOL, 0x11));
3030

31+
// minimal vsys voltage -> 2.6V
32+
EC_E_BOOL_R_BOOL(axp216_clr_bits(AXP216_VOFF_SET, 0b00000111));
33+
3134
return true;
3235
}
3336

@@ -60,13 +63,13 @@ static bool axp216_config_battery(void)
6063
// temp formula
6164
// V = reg_val * 0x10 * 0.0008V
6265
// charge temp max
63-
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VHTF_CHG, (uint8_t)(AXP216_VTS_TO_VXTF(196.96)))); // 196.96mv
66+
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VHTF_CHG, (uint8_t)(AXP216_VTS_TO_VXTF(193.9))));
6467
// charge temp min
65-
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VLTF_CHG, (uint8_t)(AXP216_VTS_TO_VXTF(711.2)))); // 711.2mv
68+
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VLTF_CHG, (uint8_t)(AXP216_VTS_TO_VXTF(736.3))));
6669
// discharge temp max
67-
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VHTF_DISCHG, (uint8_t)(AXP216_VTS_TO_VXTF(121.28)))); // 121.28mv
70+
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VHTF_DISCHG, (uint8_t)(AXP216_VTS_TO_VXTF(119.3))));
6871
// discharge temp min
69-
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VLTF_DISCHG, (uint8_t)(AXP216_VTS_TO_VXTF(2520)))); // 2520mv
72+
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VLTF_DISCHG, (uint8_t)(AXP216_VTS_TO_VXTF(3099))));
7073

7174
return true;
7275
}
@@ -115,8 +118,6 @@ static bool axp216_config_common(void)
115118
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_OFF_CTL, 0x48));
116119
// 16s key press force reboot, die ovtmp off, no irq turn on
117120
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_HOTOVER_CTL, 0x0f));
118-
// voff(ipsout/vsys) 3.3v, no irq wakeup
119-
EC_E_BOOL_R_BOOL(axp216_reg_write(AXP216_VOFF_SET, 0x07));
120121

121122
return true;
122123
}
@@ -168,9 +169,20 @@ Power_Error_t axp216_deinit(void)
168169
return PWR_ERROR_NONE;
169170
}
170171

171-
Power_Error_t axp216_reset(void)
172+
Power_Error_t axp216_reset(bool hard_reset)
172173
{
173-
EC_E_BOOL_R_PWR_ERR(axp216_set_bits(AXP216_VOFF_SET, (1 << 6)));
174+
if ( !hard_reset )
175+
{
176+
EC_E_BOOL_R_PWR_ERR(axp216_set_bits(AXP216_VOFF_SET, (1 << 6)));
177+
}
178+
else
179+
{
180+
// pmu force reset by pull down pwrok
181+
pmu_interface_p->GPIO.Config(7, PWR_GPIO_Config_WRITE_NP);
182+
pmu_interface_p->GPIO.Write(7, false);
183+
pmu_interface_p->Delay_ms(100);
184+
pmu_interface_p->GPIO.Config(7, PWR_GPIO_Config_DEFAULT);
185+
}
174186

175187
return PWR_ERROR_NONE;
176188
}
@@ -312,6 +324,9 @@ Power_Error_t axp216_pull_status(void)
312324

313325
Power_Status_t status_temp = {0};
314326

327+
// sys voltage (not supported by axp216, set to zero)
328+
status_temp.sysVoltage = 0;
329+
315330
// battery present
316331
hlbuff.u8_high = 0;
317332
EC_E_BOOL_R_PWR_ERR(axp216_reg_read(AXP216_MODE_CHGSTATUS, &(hlbuff.u8_low)));

drivers/pmu/axp216.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110

111111
Power_Error_t axp216_init(void);
112112
Power_Error_t axp216_deinit(void);
113-
Power_Error_t axp216_reset(void);
113+
Power_Error_t axp216_reset(bool hard_reset);
114114
Power_Error_t axp216_config(void);
115115
Power_Error_t axp216_irq(void);
116116
Power_Error_t axp216_set_state(const Power_State_t state);

0 commit comments

Comments
 (0)