-
Notifications
You must be signed in to change notification settings - Fork 45
asterix: scrub watchdog and PMIC settings [FIRM-82] #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Large diffs are not rendered by default.
This file was deleted.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,25 @@ | |
#include <drivers/dbgserial.h> | ||
#include <nrfx_twi.h> | ||
|
||
#define VBUSIN_BASE 0x02U | ||
#define CHARGER_BASE 0x03U | ||
#define BUCK_BASE 0x04U | ||
#define ADC_BASE 0x05U | ||
#define GPIOS_BASE 0x06U | ||
#define TIMER_BASE 0x07U | ||
#define LDSW_BASE 0x08U | ||
#define SHIP_BASE 0x0BU | ||
#define ERRLOG_BASE 0x0EU | ||
|
||
// VBUSIN | ||
#define VBUSINILIMSTARTUP 0x02U | ||
#define VBUSLIM_500MA 0x00U | ||
|
||
// CHARGER | ||
#define TASKRELEASEERROR 0x0U | ||
|
||
#define TASKCLEARCHGERR 0x1U | ||
|
||
#define BCHGENABLESET 0x04U | ||
#define ENABLECHARGING_ENABLECHG 0x01U | ||
|
||
|
@@ -25,22 +37,71 @@ | |
#define BCHGVTERMR 0x0DU | ||
#define BCHGVTERMREDUCED_4V00 0x4U | ||
|
||
// BUCK | ||
#define BUCK1ENASET 0x0 | ||
#define BUCK2ENASET 0x2 | ||
|
||
#define BUCK1PWMCLR 0x5U | ||
#define BUCK2PWMCLR 0x7U | ||
#define BUCKPWMCLR_SET 0x01U | ||
|
||
#define BUCK1NORMVOUT 0x8U | ||
#define BUCK1RETVOUT 0x9U | ||
#define BUCK2NORMVOUT 0xAU | ||
#define BUCK2RETVOUT 0xBU | ||
#define BUCKVOUT_1V8 8U | ||
#define BUCKVOUT_3V0 20U | ||
|
||
#define BUCKENCTRL 0xC | ||
#define BUCKVRETCTRL 0xD | ||
#define BUCKPWMCTRL 0xE | ||
|
||
#define BUCKSWCTRLSET 0xFU | ||
#define BUCKSWCTRLSET_BUCK1SWCTRLSET 0x01U | ||
#define BUCKSWCTRLSET_BUCK2SWCTRLSET 0x02U | ||
|
||
#define BUCKCTRL0 0x15U | ||
|
||
// ADC | ||
#define ADCNTCRSEL 0x0AU | ||
#define ADCNTCRSEL_10K 0x1U | ||
|
||
// GPIOS | ||
#define GPIOMODE0 0x0U | ||
#define GPIOMODE1 0x1U | ||
#define GPIOMODE2 0x2U | ||
#define GPIOMODE3 0x3U | ||
#define GPIOMODE4 0x4U | ||
|
||
#define GPIOMODE_GPIINPUT 0U | ||
#define GPIOMODE_GPIEVENTFALL 4U | ||
#define GPIOMODE_GPOIRQ 5U | ||
|
||
#define GPIOPUEN0 0xAU | ||
#define GPIOOPENDRAIN0 0x14U | ||
|
||
// TIMER | ||
#define TIMERCLR 0x01U | ||
#define TIMERCLR_TASKTIMERDIS 0x01U | ||
|
||
// LDO | ||
#define TASKLDSW1SET 0x00U | ||
#define TASKLDSW2SET 0x02U | ||
|
||
#define LDSW1GPISEL 0x05U | ||
#define LDSW2GPISEL 0x06U | ||
|
||
#define LDSW1LDOSEL 0x08U | ||
#define LDSW2LDOSEL 0x09U | ||
#define LDSW2LDOSEL_LDO 0x01U | ||
#define LDSWLDOSEL_LDO 0x01U | ||
|
||
#define LDSW1VOUTSEL 0x0CU | ||
#define LDSW2VOUTSEL 0x0DU | ||
#define LDSW2VOUTSEL_1V8 0x08U | ||
#define LDSWVOUTSEL_1V8 0x08U | ||
|
||
// SHIP | ||
#define TASKSHPHLDCONFIGSTROBE 0x1U | ||
#define LPRESETCFG 0x6U | ||
|
||
// ERRLOG | ||
#define SCRATCH0 0x1U | ||
|
@@ -67,6 +128,12 @@ static int prv_pmic_write(uint8_t base, uint8_t reg, uint8_t val) { | |
return 0; | ||
} | ||
|
||
struct pmic_reg { | ||
uint8_t base; | ||
uint8_t reg; | ||
uint8_t val; | ||
}; | ||
|
||
int pmic_init(void) { | ||
int ret; | ||
nrfx_err_t err; | ||
|
@@ -78,72 +145,79 @@ int pmic_init(void) { | |
|
||
nrfx_twi_enable(&twi); | ||
|
||
// Turn off any watchdog / boot timer right away. | ||
ret = prv_pmic_write(TIMER_BASE, TIMERCLR, TIMERCLR_TASKTIMERDIS); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(ERRLOG_BASE, SCRATCH0, 0x00); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
// Configure charger (TODO: values are board/battery dependent) | ||
// - Thermistor: 10K NTC | ||
// - Termination voltage: 4.2V | ||
// - Reduced termination voltage (for warm region): 4.00V | ||
// - 64mA charge/discharge current (standard charging) | ||
// - Enable charging | ||
ret = prv_pmic_write(CHARGER_BASE, BCHGENABLECLR, ENABLECHARGING_DISABLECHG); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(ADC_BASE, ADCNTCRSEL, ADCNTCRSEL_10K); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(CHARGER_BASE, BCHGVTERM, BCHGVTERMNORM_4V20); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(CHARGER_BASE, BCHGVTERMR, BCHGVTERMREDUCED_4V00); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(CHARGER_BASE, BCHGISETMSB, 16); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(CHARGER_BASE, BCHGISETDISCHARGEMSB, 16); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(CHARGER_BASE, BCHGENABLESET, ENABLECHARGING_ENABLECHG); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
// LDO2 as LDO @ 1.8V (powers the QSPI flash) | ||
ret = prv_pmic_write(LDSW_BASE, LDSW2LDOSEL, LDSW2LDOSEL_LDO); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(LDSW_BASE, LDSW2VOUTSEL, LDSW2VOUTSEL_1V8); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
|
||
ret = prv_pmic_write(LDSW_BASE, TASKLDSW2SET, 0x01U); | ||
if (ret != 0) { | ||
return ret; | ||
const struct pmic_reg regs[] = { | ||
// Turn off any watchdog / boot timer right away. | ||
{ TIMER_BASE, TIMERCLR, TIMERCLR_TASKTIMERDIS }, | ||
{ ERRLOG_BASE, SCRATCH0, 0x00 /* contains boot timer bit */ }, | ||
|
||
// Make sure right away that we can reset the device if needed. | ||
{ SHIP_BASE, LPRESETCFG, 0 }, | ||
{ SHIP_BASE, TASKSHPHLDCONFIGSTROBE, 1 }, | ||
|
||
// Set up the BUCK1 regulator for manual control to 1.8V, automatic | ||
// PWM/hysteresis control. | ||
{ BUCK_BASE, BUCK1ENASET, 1 }, | ||
{ BUCK_BASE, BUCK2ENASET, 1 }, | ||
{ BUCK_BASE, BUCK1PWMCLR, 1 }, | ||
{ BUCK_BASE, BUCK2PWMCLR, 1 }, | ||
{ BUCK_BASE, BUCK1NORMVOUT, BUCKVOUT_1V8 }, | ||
{ BUCK_BASE, BUCK1RETVOUT, BUCKVOUT_1V8 }, | ||
{ BUCK_BASE, BUCK2NORMVOUT, BUCKVOUT_3V0 }, | ||
{ BUCK_BASE, BUCK2RETVOUT, BUCKVOUT_3V0 }, | ||
{ BUCK_BASE, BUCKENCTRL, 0 }, | ||
{ BUCK_BASE, BUCKVRETCTRL, 0 }, | ||
{ BUCK_BASE, BUCKPWMCTRL, 0 }, | ||
{ BUCK_BASE, BUCKSWCTRLSET, BUCKSWCTRLSET_BUCK1SWCTRLSET | BUCKSWCTRLSET_BUCK2SWCTRLSET /* use registers rather than resistor settings */ }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: vset resistors will always force nominal voltages (1.8 and 3.0V), so it may be unsafe to allow sw controlled values here. Also, as a general comment: holding the back button for 10s will reset the PMIC, so we have a known path to go back to a safe state in case things go terribly wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it will reset the PMIC as long as LPRESETCFG is set properly! But I would like to explicitly set these values, because 1) analog straps always kind of scare me, and 2) when we set them explicitly, the behavior changes in at least some way (!) vs. when we leave them implicitly set from Rset. |
||
{ BUCK_BASE, BUCKCTRL0, 0 }, | ||
|
||
// Configure charger (TODO: values are board/battery dependent) | ||
// - Thermistor: 10K NTC | ||
// - Termination voltage: 4.2V | ||
// - Reduced termination voltage (for warm region): 4.00V | ||
// - Charge current limit of 152 mA (approximately 1C for most reasonable wearable batteries) | ||
// - Discharge current limit of 200 mA (increase current measurement accuracy) | ||
// - Release charger from error state if applicable (but do not clear | ||
// safety timers) -- this doesn't happen in a loop because after we | ||
// fail to boot three times, we will sit at sadwatch until a button is | ||
// pressed | ||
// - Enable charging | ||
{ VBUSIN_BASE, VBUSINILIMSTARTUP, VBUSLIM_500MA }, // should be default, but 'reset value from OTP, value listed in this table may not be correct' | ||
{ CHARGER_BASE, BCHGENABLECLR, ENABLECHARGING_DISABLECHG }, | ||
{ ADC_BASE, ADCNTCRSEL, ADCNTCRSEL_10K }, | ||
{ CHARGER_BASE, BCHGVTERM, BCHGVTERMNORM_4V20 }, | ||
{ CHARGER_BASE, BCHGVTERMR, BCHGVTERMREDUCED_4V00 }, | ||
{ CHARGER_BASE, BCHGISETMSB, 38 }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0.5C may still be a safer limit here, considering discharge can be adjusted independently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really, 1C will be fine. (Actually, 1C will be too slow for most users and we will want to turn it up even further in firmware.) But 1C is definitely safe for the bootloader to do. |
||
{ CHARGER_BASE, BCHGISETDISCHARGEMSB, 42 }, | ||
{ CHARGER_BASE, TASKCLEARCHGERR, 1 }, | ||
{ CHARGER_BASE, TASKRELEASEERROR, 1 }, | ||
{ CHARGER_BASE, BCHGENABLESET, ENABLECHARGING_ENABLECHG }, | ||
|
||
// LDO1 as LDO @ 1.8V (powers the DA7212 ... do not back power it through I/O pins, and it must always be on because sensors share I2C bus with it!) | ||
{ LDSW_BASE, LDSW1GPISEL, 0 }, | ||
{ LDSW_BASE, LDSW1VOUTSEL, LDSWVOUTSEL_1V8 }, | ||
{ LDSW_BASE, LDSW1LDOSEL, LDSWLDOSEL_LDO }, | ||
{ LDSW_BASE, TASKLDSW1SET, 0x01U }, | ||
|
||
// LDO2 as LDO @ 1.8V (powers the QSPI flash) | ||
{ LDSW_BASE, LDSW2GPISEL, 0 }, | ||
{ LDSW_BASE, LDSW2VOUTSEL, LDSWVOUTSEL_1V8 }, | ||
{ LDSW_BASE, LDSW2LDOSEL, LDSWLDOSEL_LDO }, | ||
{ LDSW_BASE, TASKLDSW2SET, 0x01U }, | ||
|
||
// Firmware will set up GPIOs as desired; set up everything as an input | ||
// now to avoid drive fights in case it was previously set strangely. | ||
{ GPIOS_BASE, GPIOMODE0, GPIOMODE_GPIINPUT }, | ||
{ GPIOS_BASE, GPIOMODE1, GPIOMODE_GPIINPUT }, | ||
{ GPIOS_BASE, GPIOMODE2, GPIOMODE_GPIINPUT }, | ||
{ GPIOS_BASE, GPIOMODE3, GPIOMODE_GPIINPUT }, | ||
{ GPIOS_BASE, GPIOMODE4, GPIOMODE_GPIINPUT }, | ||
}; | ||
|
||
for (unsigned int i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) { | ||
ret = prv_pmic_write(regs[i].base, regs[i].reg, regs[i].val); | ||
if (ret != 0) { | ||
return ret; | ||
} | ||
} | ||
|
||
nrfx_twi_disable(&twi); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see previous comment