From 49e8faef15bde8c3091aa15969f1390697199236 Mon Sep 17 00:00:00 2001 From: Riccardo Rizzo Date: Wed, 16 Mar 2022 12:29:58 +0100 Subject: [PATCH] added support for new pmic --- boards.txt | 2 +- cores/arduino/PMIC/BQ24195.h | 175 ++++++++++++++++ cores/arduino/PMIC/MP2629.h | 341 +++++++++++++++++++++++++++++++ cores/arduino/PMICClass.cpp | 177 ++++++++++++++++ cores/arduino/PMICClass.h | 56 +++++ variants/mkrwifi1010/variant.cpp | 59 ++---- 6 files changed, 769 insertions(+), 41 deletions(-) create mode 100644 cores/arduino/PMIC/BQ24195.h create mode 100644 cores/arduino/PMIC/MP2629.h create mode 100644 cores/arduino/PMICClass.cpp create mode 100644 cores/arduino/PMICClass.h diff --git a/boards.txt b/boards.txt index 20ad6b63b..7fe895759 100644 --- a/boards.txt +++ b/boards.txt @@ -208,7 +208,7 @@ mkrwifi1010.build.usb_product="Arduino MKR WiFi 1010" mkrwifi1010.build.usb_manufacturer="Arduino LLC" mkrwifi1010.build.board=SAMD_MKRWIFI1010 mkrwifi1010.build.core=arduino -mkrwifi1010.build.extra_flags=-DUSE_ARDUINO_MKR_PIN_LAYOUT -D__SAMD21G18A__ {build.usb_flags} -DUSE_BQ24195L_PMIC +mkrwifi1010.build.extra_flags=-DUSE_ARDUINO_MKR_PIN_LAYOUT -D__SAMD21G18A__ {build.usb_flags} -DUSE_BQ24195L_PMIC -DUSE_MP2629_PMIC mkrwifi1010.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld mkrwifi1010.build.openocdscript=openocd_scripts/arduino_zero.cfg mkrwifi1010.build.variant=mkrwifi1010 diff --git a/cores/arduino/PMIC/BQ24195.h b/cores/arduino/PMIC/BQ24195.h new file mode 100644 index 000000000..060e5bd16 --- /dev/null +++ b/cores/arduino/PMIC/BQ24195.h @@ -0,0 +1,175 @@ +/* + BQ24195.h - Register definitions for BQ24195/BQ24195L PMICs. + Copyright (c) 2020 Kevin P. Fleming. All right reserved. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + struct { + uint8_t IINLIM:3; + uint8_t VINDPM:4; + uint8_t EN_HIZ:1; + }; + uint8_t val; +} BQ24195_REG00; + +static_assert(sizeof(BQ24195_REG00) == 1, "BQ24195_REG00 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVD:1; + uint8_t SYS_MIN:3; + uint8_t CHG_CONFIG_ENABLE:1; + uint8_t CHG_CONFIG_OTG:1; + uint8_t WATCHDOG_TIMER_RESET:1; + uint8_t REGISTER_RESET:1; + }; + uint8_t val; +} BQ24195_REG01; + +static_assert(sizeof(BQ24195_REG01) == 1, "BQ24195_REG01 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t FORCE_20PCT:1; + uint8_t RSVD:1; + uint8_t ICHG:6; + }; + uint8_t val; +} BQ24195_REG02; + +static_assert(sizeof(BQ24195_REG02) == 1, "BQ24195_REG02 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t ITERM:4; + uint8_t IPRECHG:4; + }; + uint8_t val; +} BQ24195_REG03; + +static_assert(sizeof(BQ24195_REG03) == 1, "BQ24195_REG03 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VRECHG:1; + uint8_t BATLOWV:1; + uint8_t VREG:6; + }; + uint8_t val; +} BQ24195_REG04; + +static_assert(sizeof(BQ24195_REG04) == 1, "BQ24195_REG04 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVD:1; + uint8_t CHG_TIMER:2; + uint8_t EN_TIMER:1; + uint8_t WATCHDOG:2; + uint8_t TERM_STAT:1; + uint8_t EN_TERM:1; + }; + uint8_t val; +} BQ24195_REG05; + +static_assert(sizeof(BQ24195_REG05) == 1, "BQ24195_REG05 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VRECHG:1; + uint8_t BATLOWV:1; + uint8_t VREG:6; + }; + uint8_t val; +} BQ24195_REG06; + +static_assert(sizeof(BQ24195_REG06) == 1, "BQ24195_REG06 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t INT_MASK_BAT:1; + uint8_t INT_MASK_CHG:1; + uint8_t RSVD:3; + uint8_t BATFET_DISABLE:1; + uint8_t TMR2X_EN:1; + uint8_t DPDM_EN:1; + }; + uint8_t val; +} BQ24195_REG07; + +static_assert(sizeof(BQ24195_REG07) == 1, "BQ24195_REG07 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VSYS_STAT:1; + uint8_t THERM_STAT:1; + uint8_t PG_STAT:1; + uint8_t DPM_STAT:1; + uint8_t CHRG_STAT:2; + uint8_t VBUS_STAT:2; + }; + uint8_t val; +} BQ24195_REG08; + +static_assert(sizeof(BQ24195_REG08) == 1, "BQ24195_REG08 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t NTC_FAULT:3; + uint8_t BAT_FAULT:1; + uint8_t CHRG_FAULT:2; + uint8_t RSVD:1; + uint8_t WATCHDOG_FAULT:1; + }; + uint8_t val; +} BQ24195_REG09; + +static_assert(sizeof(BQ24195_REG09) == 1, "BQ24195_REG09 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t DEV_REG:2; + uint8_t TS_PROFILE:1; + uint8_t PN:3; + uint8_t RSVD:2; + }; + uint8_t val; +} BQ24195_REG0A; + +static_assert(sizeof(BQ24195_REG0A) == 1, "BQ24195_REG0A union size is incorrect, should be 1 byte."); + +#define BQ24195_ADDRESS 0x6B +#define BQ24195_REG00_ADDRESS 0x00 +#define BQ24195_REG01_ADDRESS 0x01 +#define BQ24195_REG02_ADDRESS 0x02 +#define BQ24195_REG03_ADDRESS 0x03 +#define BQ24195_REG04_ADDRESS 0x04 +#define BQ24195_REG05_ADDRESS 0x05 +#define BQ24195_REG06_ADDRESS 0x06 +#define BQ24195_REG07_ADDRESS 0x07 +#define BQ24195_REG08_ADDRESS 0x08 +#define BQ24195_REG09_ADDRESS 0x09 +#define BQ24195_REG0A_ADDRESS 0x0A + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/arduino/PMIC/MP2629.h b/cores/arduino/PMIC/MP2629.h new file mode 100644 index 000000000..602b7fae9 --- /dev/null +++ b/cores/arduino/PMIC/MP2629.h @@ -0,0 +1,341 @@ +/* + MP2629.h - Register definitions for MP2629/MP2629L PMICs. + Copyright (c) 2020 Kevin P. Fleming. All right reserved. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + struct { + uint8_t IIN_LIM:6; + uint8_t EN_LIM:1; + uint8_t EN_HIZ:1; + }; + uint8_t val; +} MP2629_REG00; + +static_assert(sizeof(MP2629_REG00) == 1, "MP2629_REG00 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VIN_MIN:4; + uint8_t RSVD:3; + uint8_t REGISTER_RESET:1; + }; + uint8_t val; +} MP2629_REG01; + +static_assert(sizeof(MP2629_REG01) == 1, "MP2629_REG01 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t AICO_EN:1; + uint8_t NTC_OPTION:1; + uint8_t TJ_REG:2; + uint8_t EN_CHG_NTC:1; + uint8_t EN_OTG_NTC:1; + uint8_t NTC_TYPE:1; + uint8_t TSM_DLY:1; + }; + uint8_t val; +} MP2629_REG02; + +static_assert(sizeof(MP2629_REG02) == 1, "MP2629_REG02 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t IIN_DSCHG:3; + uint8_t VIN_DSCHG:3; + uint8_t ADC_RATE:1; + uint8_t ADC_START:1; + }; + uint8_t val; +} MP2629_REG03; + +static_assert(sizeof(MP2629_REG03) == 1, "MP2629_REG03 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VTRACK:1; + uint8_t VSYS_MIN:3; + uint8_t CHG_CONFIG:2; + uint8_t STAT_EN:1; + uint8_t BAT_LOADEN:1; + }; + uint8_t val; +} MP2629_REG04; + +static_assert(sizeof(MP2629_REG04) == 1, "MP2629_REG04 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t ICC:7; + uint8_t VBATT_PRE:1; + }; + uint8_t val; +} MP2629_REG05; + +static_assert(sizeof(MP2629_REG05) == 1, "MP2629_REG05 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t ITERM:4; + uint8_t IPRE:4; + }; + uint8_t val; +} MP2629_REG06; + +static_assert(sizeof(MP2629_REG06) == 1, "MP2629_REG06 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VRECH:1; + uint8_t VBATT_REG:7; + }; + uint8_t val; +} MP2629_REG07; + +static_assert(sizeof(MP2629_REG07) == 1, "MP2629_REG07 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t EN_TIMER:1; + uint8_t CHG_TMR:2; + uint8_t WATCHDOG_TIM_RST:1; + uint8_t WATCHDOG:2; + uint8_t RSVD:1; + uint8_t EN_TERM:1; + }; + uint8_t val; +} MP2629_REG08; + +static_assert(sizeof(MP2629_REG08) == 1, "MP2629_REG08 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VCLAMP:3; + uint8_t RSVD:1; + uint8_t RBAT_CMP:4; + }; + uint8_t val; +} MP2629_REG09; + +static_assert(sizeof(MP2629_REG09) == 1, "MP2629_REG09 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t TDISC_L:2; + uint8_t TDISC_H:2; + uint8_t SYSRST_SEL:1; + uint8_t BATFET_DIS:1; + uint8_t TMR2X_EN:1; + uint8_t SW_FREQ:1; + }; + uint8_t val; +} MP2629_REG0A; + +static_assert(sizeof(MP2629_REG0A) == 1, "MP2629_REG0A union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVD:6; + uint8_t USB_DET_EN:1; + uint8_t INT_MASK:1; + }; + uint8_t val; +} MP2629_REG0B; + +static_assert(sizeof(MP2629_REG0B) == 1, "MP2629_REG0B union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VSYS_STAT:1; + uint8_t THERM_STAT:1; + uint8_t RNTC_FLOAT_STAT:1; + uint8_t CHG_STAT:2; + uint8_t VIN_STAT:3; + }; + uint8_t val; +} MP2629_REG0C; + +static_assert(sizeof(MP2629_REG0C) == 1, "MP2629_REG0C union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t NTC_FAULT:3; + uint8_t BAT_FAULT:1; + uint8_t THERMAL_SHUTDOWN:1; + uint8_t INPUT_FAULT:1; + uint8_t OTG_FAULT:1; + uint8_t WATCHDOG_FAULT:1; + }; + uint8_t val; +} MP2629_REG0D; + +static_assert(sizeof(MP2629_REG0D) == 1, "MP2629_REG0D union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VBATT:8; + }; + uint8_t val; +} MP2629_REG0E; + +static_assert(sizeof(MP2629_REG0E) == 1, "MP2629_REG0E union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VSYS:8; + }; + uint8_t val; +} MP2629_REG0F; + +static_assert(sizeof(MP2629_REG0F) == 1, "MP2629_REG0F union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t NTC:8; + }; + uint8_t val; +} MP2629_REG10; + +static_assert(sizeof(MP2629_REG10) == 1, "MP2629_REG10 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VIN:7; + uint8_t RSVD:1; + }; + uint8_t val; +} MP2629_REG11; + +static_assert(sizeof(MP2629_REG11) == 1, "MP2629_REG11 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t ICHG:8; + }; + uint8_t val; +} MP2629_REG12; + +static_assert(sizeof(MP2629_REG12) == 1, "MP2629_REG12 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t IIN:8; + }; + uint8_t val; +} MP2629_REG13; + +static_assert(sizeof(MP2629_REG13) == 1, "MP2629_REG13 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t IIN_DPM:6; + uint8_t IINPPM_STAT:1; + uint8_t VINPPM_STAT:1; + }; + uint8_t val; +} MP2629_REG14; + +static_assert(sizeof(MP2629_REG14) == 1, "MP2629_REG14 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVD:5; + uint8_t VINPPM_INT_MASK:2; + uint8_t AICO_STAT:1; + }; + uint8_t val; +} MP2629_REG15; + +static_assert(sizeof(MP2629_REG15) == 1, "MP2629_REG15 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t VCOLD:1; + uint8_t VCOOL:2; + uint8_t VWARM:2; + uint8_t VHOT:1; + uint8_t JEITA_ISET:1; + uint8_t JEITA_VSET:1; + }; + uint8_t val; +} MP2629_REG16; + +static_assert(sizeof(MP2629_REG16) == 1, "MP2629_REG16 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVDL3_0:3; + uint8_t PN:3; + uint8_t RSVD7:1; + uint8_t SAFETY_TIMER:1; + }; + uint8_t val; +} MP2629_REG17; + +static_assert(sizeof(MP2629_REG17) == 1, "MP2629_REG17 union size is incorrect, should be 1 byte."); + +typedef union { + struct { + uint8_t RSVD4_0:5; + uint8_t ADDRESS:1; + uint8_t RSVD7:1; + uint8_t IINLIM_VINMIN_RESET_EN:1; + }; + uint8_t val; +} MP2629_REG18; + +static_assert(sizeof(MP2629_REG18) == 1, "MP2629_REG18 union size is incorrect, should be 1 byte."); + + +#define MP2629_ADDRESS 0x4B +#define MP2629_REG00_ADDRESS 0x00 +#define MP2629_REG01_ADDRESS 0x01 +#define MP2629_REG02_ADDRESS 0x02 +#define MP2629_REG03_ADDRESS 0x03 +#define MP2629_REG04_ADDRESS 0x04 +#define MP2629_REG05_ADDRESS 0x05 +#define MP2629_REG06_ADDRESS 0x06 +#define MP2629_REG07_ADDRESS 0x07 +#define MP2629_REG08_ADDRESS 0x08 +#define MP2629_REG09_ADDRESS 0x09 +#define MP2629_REG0A_ADDRESS 0x0A +#define MP2629_REG0B_ADDRESS 0x0B +#define MP2629_REG0C_ADDRESS 0x0C +#define MP2629_REG0D_ADDRESS 0x0D +#define MP2629_REG0E_ADDRESS 0x0E +#define MP2629_REG0F_ADDRESS 0x0F +#define MP2629_REG0G_ADDRESS 0x0G +#define MP2629_REG10_ADDRESS 0x10 +#define MP2629_REG11_ADDRESS 0x11 +#define MP2629_REG12_ADDRESS 0x12 +#define MP2629_REG13_ADDRESS 0x13 +#define MP2629_REG14_ADDRESS 0x14 +#define MP2629_REG15_ADDRESS 0x15 +#define MP2629_REG16_ADDRESS 0x16 +#define MP2629_REG17_ADDRESS 0x17 +#define MP2629_REG18_ADDRESS 0x18 + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/arduino/PMICClass.cpp b/cores/arduino/PMICClass.cpp new file mode 100644 index 000000000..a69a67777 --- /dev/null +++ b/cores/arduino/PMICClass.cpp @@ -0,0 +1,177 @@ +/* + PMIC.cpp - initialization of Power Management ICs + Copyright (c) 2020 Kevin P. Fleming. All right reserved. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "PMICClass.h" + +PMICClass::PMICClass(void) { +} + +PMICClass::~PMICClass(void) { +} + + +void PMICClass::init(SERCOM * sercom) { + _sercom = sercom; +} + +void PMICClass::setupBQ24195(bool batteryPresent, bool USBDetect) { + BQ24195_REG00 reg00; + reg00.IINLIM = _ilim; // input current limit 500 mA + reg00.VINDPM = 0x00; // input voltage limit 3.88V + reg00.EN_HIZ = 0x00; // disable + + writereg(BQ24195_ADDRESS, BQ24195_REG00_ADDRESS, (reg00.val)); + + BQ24195_REG01 reg01; + reg01.RSVD = 0x01; + reg01.SYS_MIN = 0x05; // minimum system voltage 3.5V + reg01.CHG_CONFIG_ENABLE = (batteryPresent ? 0x01 : 0x00); // battery charge enable/disable + reg01.CHG_CONFIG_OTG = 0x00; + reg01.WATCHDOG_TIMER_RESET = 0x01; // reset watchdog timer + reg01.REGISTER_RESET = 0x00; // keep current register setting + + writereg(BQ24195_ADDRESS, BQ24195_REG01_ADDRESS, (reg01.val)); + + BQ24195_REG05 reg05; + reg05.RSVD = 0x00; + reg05.CHG_TIMER = 0x01; // fast charge timer 8 hours + reg05.EN_TIMER = (batteryPresent ? 0x01 : 0x00); // enable/disable charge safety timer + reg05.WATCHDOG = 0x00; // disable watchdog timer to stay in host mode + reg05.TERM_STAT = 0x00; // charge termination indicator match ITERM + reg05.EN_TERM = 0x01; // enable charge termination + + writereg(BQ24195_ADDRESS, BQ24195_REG05_ADDRESS, (reg05.val)); + + BQ24195_REG07 reg07; + reg07.INT_MASK_BAT = 0x01; // INT on battery fault + reg07.INT_MASK_CHG = 0x01; // INT on charge fault + reg07.RSVD = 0x02; + reg07.BATFET_DISABLE = (batteryPresent ? 0x00: 0x01); // battery FET enable/disable + reg07.TMR2X_EN = 0x00; // safety timer not slowed by 2X + reg07.DPDM_EN = 0x00; // D+/D- detection enable/disable + + writereg(BQ24195_ADDRESS, BQ24195_REG07_ADDRESS, (reg07.val)); + + BQ24195_REG04 reg04; + reg04.VRECHG = 0x2C; + reg04.BATLOWV = 0x01; + reg04.VREG = 0x01; + writereg(BQ24195_ADDRESS, BQ24195_REG04_ADDRESS, (reg04.val)); +} + +void PMICClass::setupMP2629(bool batteryPresent) { + // disable or enable battery bat feet + MP2629_REG0A reg0A; + uint8_t byte = readFrom(MP2629_ADDRESS, MP2629_REG0A_ADDRESS); + reg0A.TDISC_L = byte & 0x03; + reg0A.TDISC_H = (byte & 0x0C) >> 2; + reg0A.SYSRST_SEL = (byte & 0x10) >> 5; + reg0A.BATFET_DIS = (batteryPresent ? 0b0 : 0b1); + reg0A.TMR2X_EN = (byte & 0x40) >> 6; + reg0A.SW_FREQ = byte >> 7; + writereg(MP2629_ADDRESS, MP2629_REG0A_ADDRESS, reg0A.val); + delay(300); + + // disable watchdog timer reset + byte = readFrom(MP2629_ADDRESS, MP2629_REG08_ADDRESS); + MP2629_REG08 reg08; + reg08.EN_TIMER = byte & 0x01; + reg08.CHG_TMR = (byte & 0x06) >> 1; + reg08.WATCHDOG_TIM_RST = 0; + reg08.WATCHDOG = (byte & 0x30) >> 4; + reg08.RSVD = (byte & 0x40) >> 6; + reg08.EN_TIMER = byte >> 7; + writereg(MP2629_ADDRESS, MP2629_REG08_ADDRESS, reg08.val); + + MP2629_REG0B reg0B; + reg0B.RSVD = byte & 0x3F; + reg0B.USB_DET_EN = 1; + reg0B.INT_MASK = 1; + writereg(MP2629_ADDRESS, MP2629_REG0B_ADDRESS, reg0B.val); + + // set ICC + byte = readFrom(MP2629_ADDRESS, MP2629_REG05_ADDRESS); + MP2629_REG05 reg05; + reg05.ICC = 0x05; + reg05.VBATT_PRE = byte >> 7; + writereg(MP2629_ADDRESS, MP2629_REG05_ADDRESS, reg05.val); + + // set the vbat voltage to 4.1 V + byte = readFrom(MP2629_ADDRESS, MP2629_REG07_ADDRESS); + MP2629_REG07 reg07; + reg07.VRECH = byte & 0x01; + reg07.VBATT_REG = 0x46;//set vbat charge threshold to 4.1 V + writereg(MP2629_ADDRESS, MP2629_REG07_ADDRESS, reg07.val); +} + +bool PMICClass::isBatteryConnected() { + // reset bat feet to default value + MP2629_REG0A reg0A; + uint8_t byte = readFrom(MP2629_ADDRESS, MP2629_REG0A_ADDRESS); + reg0A.TDISC_L = byte & 0x03; + reg0A.TDISC_H = (byte & 0x0C) >> 2; + reg0A.SYSRST_SEL = (byte & 0x10) >> 5; + reg0A.BATFET_DIS = 0; + reg0A.TMR2X_EN = (byte & 0x40) >> 6; + reg0A.SW_FREQ = byte >> 7; + writereg(MP2629_ADDRESS, MP2629_REG0A_ADDRESS, reg0A.val); + + + MP2629_REG03 reg03; + // set MP2'S ADC in CONTINUOS acquision mode + byte = readFrom(MP2629_ADDRESS, MP2629_REG03_ADDRESS); + reg03.IIN_DSCHG = (byte & 0x07); + reg03.VIN_DSCHG = (byte & 0x56) >> 3; + reg03.ADC_RATE = 1; + reg03.ADC_START = byte >> 7; + writereg(MP2629_ADDRESS, MP2629_REG03_ADDRESS, reg03.val); + delay(10); + + return readFrom(MP2629_ADDRESS, MP2629_REG12_ADDRESS) > 0; +} + +bool PMICClass::isBQ24195() { + return (readFrom(BQ24195_ADDRESS, BQ24195_REG0A_ADDRESS) == 0x23); +} + +void PMICClass::setIlim(uint8_t ilim){ + _ilim = ilim; +} + +uint8_t PMICClass::readFrom(uint8_t pmicAddress, uint8_t address) { + uint8_t readedValue = 0; + + _sercom->startTransmissionWIRE(pmicAddress, WIRE_WRITE_FLAG); + _sercom->sendDataMasterWIRE(address); + _sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + + if (_sercom->startTransmissionWIRE(pmicAddress, WIRE_READ_FLAG)) + { + readedValue = _sercom->readDataWIRE(); + _sercom->prepareNackBitWIRE(); + _sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + } + return readedValue; +} + +void PMICClass::writereg(uint8_t pmicAddress, uint8_t address, uint8_t value) { + _sercom->startTransmissionWIRE(pmicAddress, WIRE_WRITE_FLAG ); + _sercom->sendDataMasterWIRE(address); + _sercom->sendDataMasterWIRE(value); + _sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); +} + +PMICClass PMICArduino; diff --git a/cores/arduino/PMICClass.h b/cores/arduino/PMICClass.h new file mode 100644 index 000000000..db3e06f2e --- /dev/null +++ b/cores/arduino/PMICClass.h @@ -0,0 +1,56 @@ +/* + PMIC.h - initialization of Power Management ICs + Copyright (c) 2020 Kevin P. Fleming. All right reserved. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _PMIC_ARDUINO_H_ +#define _PMIC_ARDUINO_H_ + +#include "Arduino.h" +#include "PMIC/BQ24195.h" +#include "PMIC/MP2629.h" +#include "wiring_private.h" + +#define ILIM_100MA 0x00 +#define ILIM_150MA 0x01 +#define ILIM_500MA 0x02 +#define ILIM_900MA 0x03 +#define ILIM_1_2A 0x04 +#define ILIM_1_5A 0x05 +#define ILIM_2_0A 0x06 +#define ILIM_3_0A 0x07 + + + + +class PMICClass +{ +public: + PMICClass(void); + ~PMICClass(void); + void init(SERCOM * sercom); + void setupBQ24195(bool batteryPresent, bool USBDetect); + void setupMP2629(bool batteryPresent); + bool isBatteryConnected(); + bool isBQ24195(); + void setIlim(uint8_t ilim = ILIM_500MA); +private: + uint8_t readFrom(uint8_t pmicAdd, uint8_t address); + void writereg(uint8_t pmicAdd, uint8_t address, uint8_t value); +private: + SERCOM * _sercom; + uint8_t _ilim = ILIM_500MA; +}; + +extern PMICClass PMICArduino; +#endif diff --git a/variants/mkrwifi1010/variant.cpp b/variants/mkrwifi1010/variant.cpp index eb146fa59..49e50b534 100644 --- a/variants/mkrwifi1010/variant.cpp +++ b/variants/mkrwifi1010/variant.cpp @@ -177,60 +177,39 @@ SERCOM sercom3(SERCOM3); SERCOM sercom4(SERCOM4); SERCOM sercom5(SERCOM5); -#if defined(USE_BQ24195L_PMIC) - +#ifdef USE_BQ24195L_PMIC +#include "PMICClass.h" #include "wiring_private.h" +#endif -#define PMIC_ADDRESS 0x6B -#define PMIC_REG01 0x01 -#define PMIC_REG07 0x07 +void initVariant() { -static inline void enable_battery_charging() { +#if defined(USE_BQ24195L_PMIC) or defined(USE_MP2629_PMIC) PERIPH_WIRE.initMasterWIRE(100000); PERIPH_WIRE.enableWIRE(); pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG01); - PERIPH_WIRE.sendDataMasterWIRE(0x1B); // Charge Battery + Minimum System Voltage 3.5V - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + PMICArduino.init(&PERIPH_WIRE); - PERIPH_WIRE.disableWIRE(); -} + if(PMICArduino.isBQ24195()){// USE_BQ24195L_PMIC + pinMode(ADC_BATTERY, OUTPUT); + digitalWrite(ADC_BATTERY, LOW); + delay(10); + pinMode(ADC_BATTERY, INPUT); + delay(100); -static inline void disable_battery_fet(bool disabled) { - PERIPH_WIRE.initMasterWIRE(100000); - PERIPH_WIRE.enableWIRE(); - pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); - pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG07); - // No D+/D– detection + Safety timer not slowed by 2X during input DPM or thermal regulation + - // BAT fet disabled/enabled + charge and bat fault INT - PERIPH_WIRE.sendDataMasterWIRE(0x0B | (disabled ? 0x20 : 0x00)); - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + bool batteryConnected = analogRead(ADC_BATTERY) > 600; + PMICArduino.setupBQ24195(batteryConnected, false); + } else {; + bool batteryConnected = PMICArduino.isBatteryConnected(); + PMICArduino.setupMP2629(batteryConnected); + } PERIPH_WIRE.disableWIRE(); -} - #endif -void initVariant() { -#if defined(USE_BQ24195L_PMIC) - pinMode(ADC_BATTERY, OUTPUT); - digitalWrite(ADC_BATTERY, LOW); - delay(10); - pinMode(ADC_BATTERY, INPUT); - delay(100); - - bool batteryPresent = analogRead(ADC_BATTERY) > 600; - if (batteryPresent) { - enable_battery_charging(); - } - disable_battery_fet(!batteryPresent); -#endif + // NINA - SPI boot pinMode(NINA_GPIO0, OUTPUT);