OpenRTX/platform/targets/ttwrplus/pmu.cpp

381 wiersze
12 KiB
C++

/***************************************************************************
* Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Silvano Seva IU2KWO *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <interfaces/delays.h>
#include <interfaces/keyboard.h>
#include <hwconfig.h>
#include "pmu.h"
// PMU is controlled through the XPowersLib external library
#define XPOWERS_CHIP_AXP2101
#include <XPowersLib.h>
#if DT_NODE_HAS_STATUS(DT_ALIAS(i2c_0), okay)
#define I2C_DEV_NODE DT_ALIAS(i2c_0)
#else
#error "Please set the correct I2C device"
#endif
#define PMU_IRQ_NODE DT_ALIAS(pmu_irq)
static const struct device *const i2c_dev = DEVICE_DT_GET(I2C_DEV_NODE);
static const struct gpio_dt_spec pmu_irq = GPIO_DT_SPEC_GET(PMU_IRQ_NODE, gpios);
static XPowersPMU PMU;
static uint8_t pwrOnPressed = 0;
static int pmu_registerReadByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data,
uint8_t len)
{
// Only single-byte reads are supported
if (len != 1)
return -1;
return i2c_reg_read_byte(i2c_dev, devAddr, regAddr, data);
}
static int pmu_registerWriteByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data,
uint8_t len)
{
// Only single-byte writes are supported
if (len != 1)
return -1;
return i2c_reg_write_byte(i2c_dev, devAddr, regAddr, *data);
}
void pmu_init()
{
// Configure I2C connection with PMU
if (device_is_ready(i2c_dev) == false)
{
printk("I2C device is not ready\n");
}
const uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_FAST) | I2C_MODE_CONTROLLER;
if (i2c_configure(i2c_dev, i2c_cfg) != 0)
{
printk("I2C config failed\n");
}
// Configure IRQ gpio
if(gpio_is_ready_dt(&pmu_irq) == false)
{
printk("PMU IRQ gpio is not ready\n");
}
int ret = gpio_pin_configure_dt(&pmu_irq, GPIO_INPUT);
if (ret != 0)
{
printk("Failed to configure PMU IRQ gpio\n");
}
bool result = PMU.begin(AXP2101_SLAVE_ADDRESS, pmu_registerReadByte,
pmu_registerWriteByte);
if (result == false)
{
while (1)
{
printk("PMU is not online...");
delayMs(500);
}
}
// Set the minimum common working voltage of the PMU VBUS input,
// below this value will turn off the PMU
PMU.setVbusVoltageLimit(XPOWERS_AXP2101_VBUS_VOL_LIM_3V88);
// Set the maximum current of the PMU VBUS input,
// higher than this value will turn off the PMU
PMU.setVbusCurrentLimit(XPOWERS_AXP2101_VBUS_CUR_LIM_2000MA);
// Get the VSYS shutdown voltage
uint16_t vol = PMU.getSysPowerDownVoltage();
printk("-> getSysPowerDownVoltage:%u\n", vol);
// Set VSY off voltage as 2600mV , Adjustment range 2600mV ~ 3300mV
PMU.setSysPowerDownVoltage(2600);
// High transmit power may cause voltage dropoff, disable PMU protection
PMU.disableDC3LowVoltageTurnOff();
//! DC1 ESP32S3 Core VDD , Don't change
// PMU.setDC1Voltage(3300);
//! DC3 Radio & Pixels VDD , Don't change
PMU.setDC3Voltage(3400);
//! ALDO2 MICRO TF Card VDD, Don't change
PMU.setALDO2Voltage(3300);
//! ALDO4 GNSS VDD, Don't change
PMU.setALDO4Voltage(3300);
//! BLDO1 MIC VDD, Don't change
PMU.setBLDO1Voltage(3300);
// DC5 IMAX=2A
// 1200mV
// 1400~3700mV,100mV/step,24steps
PMU.setDC5Voltage(3300);
//ALDO1 IMAX=300mA
//500~3500mV, 100mV/step,31steps
PMU.setALDO1Voltage(3300);
//ALDO3 IMAX=300mA
//500~3500mV, 100mV/step,31steps
PMU.setALDO3Voltage(3300);
//BLDO2 IMAX=300mA
//500~3500mV, 100mV/step,31steps
PMU.setBLDO2Voltage(3300);
// Turn on the power that needs to be used
//! DC1 ESP32S3 Core VDD , Don't change
// PMU.enableDC3();
//! External pin power supply
PMU.enableDC5();
PMU.enableALDO1();
PMU.enableALDO3();
PMU.enableBLDO2();
//! ALDO2 MICRO TF Card VDD
PMU.enableALDO2();
//! ALDO4 GNSS VDD
PMU.disableALDO4();
//! BLDO1 MIC VDD
PMU.enableBLDO1();
//! DC3 Radio & Pixels VDD
PMU.disableDC3();
// power off when not in use
PMU.disableDC2();
PMU.disableDC4();
PMU.disableCPUSLDO();
PMU.disableDLDO1();
PMU.disableDLDO2();
printk("DCDC=======================================================================\n");
printk("DC1 : %s Voltage:%u mV \n", PMU.isEnableDC1() ? "+" : "-", PMU.getDC1Voltage());
printk("DC2 : %s Voltage:%u mV \n", PMU.isEnableDC2() ? "+" : "-", PMU.getDC2Voltage());
printk("DC3 : %s Voltage:%u mV \n", PMU.isEnableDC3() ? "+" : "-", PMU.getDC3Voltage());
printk("DC4 : %s Voltage:%u mV \n", PMU.isEnableDC4() ? "+" : "-", PMU.getDC4Voltage());
printk("DC5 : %s Voltage:%u mV \n", PMU.isEnableDC5() ? "+" : "-", PMU.getDC5Voltage());
printk("ALDO=======================================================================\n");
printk("ALDO1: %s Voltage:%u mV\n", PMU.isEnableALDO1() ? "+" : "-", PMU.getALDO1Voltage());
printk("ALDO2: %s Voltage:%u mV\n", PMU.isEnableALDO2() ? "+" : "-", PMU.getALDO2Voltage());
printk("ALDO3: %s Voltage:%u mV\n", PMU.isEnableALDO3() ? "+" : "-", PMU.getALDO3Voltage());
printk("ALDO4: %s Voltage:%u mV\n", PMU.isEnableALDO4() ? "+" : "-", PMU.getALDO4Voltage());
printk("BLDO=======================================================================\n");
printk("BLDO1: %s Voltage:%u mV\n", PMU.isEnableBLDO1() ? "+" : "-", PMU.getBLDO1Voltage());
printk("BLDO2: %s Voltage:%u mV\n", PMU.isEnableBLDO2() ? "+" : "-", PMU.getBLDO2Voltage());
printk("===========================================================================\n");
// Set the time of pressing the button to turn off
PMU.setPowerKeyPressOffTime(XPOWERS_POWEROFF_10S);
uint8_t opt = PMU.getPowerKeyPressOffTime();
printk("PowerKeyPressOffTime:");
switch (opt)
{
case XPOWERS_POWEROFF_4S: printk("4 Second");
break;
case XPOWERS_POWEROFF_6S: printk("6 Second");
break;
case XPOWERS_POWEROFF_8S: printk("8 Second");
break;
case XPOWERS_POWEROFF_10S: printk("10 Second");
break;
default:
break;
}
printk("\n");
// Set the button power-on press time
PMU.setPowerKeyPressOnTime(XPOWERS_POWERON_128MS);
opt = PMU.getPowerKeyPressOnTime();
printk("PowerKeyPressOnTime:");
switch (opt)
{
case XPOWERS_POWERON_128MS: printk("128 Ms");
break;
case XPOWERS_POWERON_512MS: printk("512 Ms");
break;
case XPOWERS_POWERON_1S: printk("1 Second");
break;
case XPOWERS_POWERON_2S: printk("2 Second");
break;
default:
break;
}
printk("\n");
printk("===========================================================================\n");
// It is necessary to disable the detection function of the TS pin on the board
// without the battery temperature detection function, otherwise it will cause abnormal charging
PMU.disableTSPinMeasure();
// Enable internal ADC detection
PMU.enableBattDetection();
PMU.enableVbusVoltageMeasure();
PMU.enableBattVoltageMeasure();
PMU.enableSystemVoltageMeasure();
/*
The default setting is CHGLED is automatically controlled by the PMU.
- XPOWERS_CHG_LED_OFF,
- XPOWERS_CHG_LED_BLINK_1HZ,
- XPOWERS_CHG_LED_BLINK_4HZ,
- XPOWERS_CHG_LED_ON,
- XPOWERS_CHG_LED_CTRL_CHG,
* */
PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
// TODO: Implement IRQ
// pinMode(PMU_IRQ, INPUT_PULLUP);
// attachInterrupt(PMU_IRQ, setFlag, FALLING);
// Disable all interrupts
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
// Clear all interrupt flags
PMU.clearIrqStatus();
// Enable the required interrupt function
PMU.enableIRQ(
XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // BATTERY
XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS
XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | // POWER KEY ON/OFF
XPOWERS_AXP2101_PKEY_LONG_IRQ | // POWER KEY LONG PRESS
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // CHARGE
);
// Set the precharge charging current
PMU.setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_150MA);
// Set constant current charge current limit
//! Using inferior USB cables and adapters will not reach the maximum charging current.
//! Please pay attention to add a suitable heat sink above the PMU when setting the charging current to 1A
// NOTE: Charging current set to 500mAh to remove the need for a heat sink
PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
// Set stop charging termination current
PMU.setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_150MA);
// Set charge cut-off voltage
// NOTE: Target voltage set to 4.00V (80% charge) to extend battery lifespan of 2.5x-3x
PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V);
// Enable the PMU long press shutdown function (emergency shutdown)
PMU.enableLongPressShutdown();
// Get charging target current
static const uint16_t currTable[] =
{
0, 0, 0, 0, 100, 125, 150, 175, 200, 300, 400, 500, 600, 700, 800, 900, 1000
};
uint8_t val = PMU.getChargerConstantCurr();
printk("Val = %d\n", val);
printk("Setting Charge Target Current : %d\n", currTable[val]);
// Get charging target voltage
static const uint16_t tableVoltage[] =
{
0, 4000, 4100, 4200, 4350, 4400, 255
};
val = PMU.getChargeTargetVoltage();
printk("Setting Charge Target Voltage : %d\n", tableVoltage[val]);
}
void pmu_terminate()
{
PMU.disableDC3(); // Turn off baseband power
PMU.disableALDO4(); // Turn off GPS power
PMU.shutdown(); // General shutdown
}
uint16_t pmu_getVbat()
{
return PMU.isBatteryConnect() ? PMU.getBattVoltage() : 0;
}
void pmu_setBasebandPower(bool enable)
{
if (enable)
PMU.enableDC3();
else
PMU.disableDC3();
}
void pmu_setGPSPower(bool enable)
{
if (enable)
PMU.enableALDO4();
else
PMU.disableALDO4();
}
void pmu_handleIRQ()
{
// Check if we got some interrupts
if(gpio_pin_get_dt(&pmu_irq) == 0)
return;
uint32_t irqStatus = PMU.getIrqStatus();
PMU.clearIrqStatus();
// Power on key rising edge
if((irqStatus & XPOWERS_AXP2101_PKEY_POSITIVE_IRQ) != 0)
pwrOnPressed = 0;
// Power on key falling edge
if((irqStatus & XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ) != 0)
pwrOnPressed = 1;
// Power key long press
if ((irqStatus & XPOWERS_AXP2101_PKEY_LONG_IRQ) != 0)
pwrOnPressed = 2;
// Charger start IRQ
if((irqStatus & XPOWERS_AXP2101_BAT_CHG_START_IRQ) != 0)
{
if(PMU.isBatteryConnect())
PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
}
// Battery remove IRQ
if((irqStatus & XPOWERS_AXP2101_BAT_REMOVE_IRQ) != 0)
PMU.setChargingLedMode(XPOWERS_CHG_LED_BLINK_1HZ);
}
uint8_t pmu_pwrBtnStatus()
{
return pwrOnPressed;
}