Merge develop into main (#368)
New boards: - LilyGO T-Dongle S3 - M5Stack StickC Plus - M5Stack StickC Plus2 New drivers: - AXP192: power control via I2C - ButtonControl: GPIO button input as LVGL device Other changes: - Updated implementation of AXP192 driver for Core2 board - Fix launcher UX for vertical layout - Fix error when properties file had an empty line - Add `__floatsidf` to `tt_init.cpp`
This commit is contained in:
committed by
GitHub
parent
3a59540365
commit
d8346998ce
@@ -0,0 +1,8 @@
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS "Include"
|
||||
PRIV_INCLUDE_DIRS "Private"
|
||||
REQUIRES Tactility
|
||||
)
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <axp192/axp192.h>
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <Tactility/hal/i2c/I2c.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Axp192 final : public tt::hal::power::PowerDevice {
|
||||
|
||||
static int32_t i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buffer, uint16_t size);
|
||||
static int32_t i2cWrite(void* handle, uint8_t address, uint8_t reg, const uint8_t* buffer, uint16_t size);
|
||||
|
||||
public:
|
||||
|
||||
struct Configuration {
|
||||
i2c_port_t port;
|
||||
TickType_t readTimeout = 50 / portTICK_PERIOD_MS;
|
||||
TickType_t writeTimeout = 50 / portTICK_PERIOD_MS;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Configuration> configuration;
|
||||
|
||||
axp192_t axpDevice = {
|
||||
.read = i2cRead,
|
||||
.write = i2cWrite,
|
||||
.handle = this
|
||||
};
|
||||
|
||||
bool isInitialized = false;
|
||||
|
||||
public:
|
||||
|
||||
explicit Axp192(std::unique_ptr<Configuration> configuration) : configuration(std::move(configuration)) {}
|
||||
~Axp192() override {}
|
||||
|
||||
/**
|
||||
* @warning Must call this function before device can operate!
|
||||
* @param onInit
|
||||
*/
|
||||
bool init(const std::function<bool(axp192_t*)>& onInit) {
|
||||
isInitialized = onInit(&axpDevice);
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
axp192_t* getAxp192() { return &axpDevice; }
|
||||
|
||||
std::string getName() const override { return "AXP192"; }
|
||||
std::string getDescription() const override { return "AXP192 power management via I2C"; }
|
||||
|
||||
bool supportsMetric(MetricType type) const override;
|
||||
bool getMetric(MetricType type, MetricData& data) override;
|
||||
|
||||
bool supportsChargeControl() const override { return true; }
|
||||
bool isAllowedToCharge() const override;
|
||||
void setAllowedToCharge(bool canCharge) override;
|
||||
};
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2021 Mika Tuupola
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-cut-
|
||||
|
||||
This file is part of hardware agnostic I2C driver for AXP192:
|
||||
https://github.com/tuupola/axp192
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
Version: 0.6.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _AXP192_H
|
||||
#define _AXP192_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define AXP192_ADDRESS (0x34)
|
||||
|
||||
/* Power control registers */
|
||||
#define AXP192_POWER_STATUS (0x00)
|
||||
#define AXP192_CHARGE_STATUS (0x01)
|
||||
#define AXP192_OTG_VBUS_STATUS (0x04)
|
||||
#define AXP192_DATA_BUFFER0 (0x06)
|
||||
#define AXP192_DATA_BUFFER1 (0x07)
|
||||
#define AXP192_DATA_BUFFER2 (0x08)
|
||||
#define AXP192_DATA_BUFFER3 (0x09)
|
||||
#define AXP192_DATA_BUFFER4 (0x0a)
|
||||
#define AXP192_DATA_BUFFER5 (0x0b)
|
||||
/* Output control: 2 EXTEN, 0 DCDC2 */
|
||||
#define AXP192_EXTEN_DCDC2_CONTROL (0x10)
|
||||
/* Power output control: 6 EXTEN, 4 DCDC2, 3 LDO3, 2 LDO2, 1 DCDC3, 0 DCDC1 */
|
||||
#define AXP192_DCDC13_LDO23_CONTROL (0x12)
|
||||
#define AXP192_DCDC2_VOLTAGE (0x23)
|
||||
#define AXP192_DCDC2_SLOPE (0x25)
|
||||
#define AXP192_DCDC1_VOLTAGE (0x26)
|
||||
#define AXP192_DCDC3_VOLTAGE (0x27)
|
||||
/* Output voltage control: 7-4 LDO2, 3-0 LDO3 */
|
||||
#define AXP192_LDO23_VOLTAGE (0x28)
|
||||
#define AXP192_VBUS_IPSOUT_CHANNEL (0x30)
|
||||
#define AXP192_SHUTDOWN_VOLTAGE (0x31)
|
||||
#define AXP192_SHUTDOWN_BATTERY_CHGLED_CONTROL (0x32)
|
||||
#define AXP192_CHARGE_CONTROL_1 (0x33)
|
||||
#define AXP192_CHARGE_CONTROL_2 (0x34)
|
||||
#define AXP192_BATTERY_CHARGE_CONTROL (0x35)
|
||||
#define AXP192_PEK (0x36)
|
||||
#define AXP192_DCDC_FREQUENCY (0x37)
|
||||
#define AXP192_BATTERY_CHARGE_LOW_TEMP (0x38)
|
||||
#define AXP192_BATTERY_CHARGE_HIGH_TEMP (0x39)
|
||||
#define AXP192_APS_LOW_POWER1 (0x3A)
|
||||
#define AXP192_APS_LOW_POWER2 (0x3B)
|
||||
#define AXP192_BATTERY_DISCHARGE_LOW_TEMP (0x3c)
|
||||
#define AXP192_BATTERY_DISCHARGE_HIGH_TEMP (0x3d)
|
||||
#define AXP192_DCDC_MODE (0x80)
|
||||
#define AXP192_ADC_ENABLE_1 (0x82)
|
||||
#define AXP192_ADC_ENABLE_2 (0x83)
|
||||
#define AXP192_ADC_RATE_TS_PIN (0x84)
|
||||
#define AXP192_GPIO30_INPUT_RANGE (0x85)
|
||||
#define AXP192_GPIO0_ADC_IRQ_RISING (0x86)
|
||||
#define AXP192_GPIO0_ADC_IRQ_FALLING (0x87)
|
||||
#define AXP192_TIMER_CONTROL (0x8a)
|
||||
#define AXP192_VBUS_MONITOR (0x8b)
|
||||
#define AXP192_TEMP_SHUTDOWN_CONTROL (0x8f)
|
||||
|
||||
/* GPIO control registers */
|
||||
#define AXP192_GPIO0_CONTROL (0x90)
|
||||
#define AXP192_GPIO0_LDOIO0_VOLTAGE (0x91)
|
||||
#define AXP192_GPIO1_CONTROL (0x92)
|
||||
#define AXP192_GPIO2_CONTROL (0x93)
|
||||
#define AXP192_GPIO20_SIGNAL_STATUS (0x94)
|
||||
#define AXP192_GPIO43_FUNCTION_CONTROL (0x95)
|
||||
#define AXP192_GPIO43_SIGNAL_STATUS (0x96)
|
||||
#define AXP192_GPIO20_PULLDOWN_CONTROL (0x97)
|
||||
#define AXP192_PWM1_FREQUENCY (0x98)
|
||||
#define AXP192_PWM1_DUTY_CYCLE_1 (0x99)
|
||||
#define AXP192_PWM1_DUTY_CYCLE_2 (0x9a)
|
||||
#define AXP192_PWM2_FREQUENCY (0x9b)
|
||||
#define AXP192_PWM2_DUTY_CYCLE_1 (0x9c)
|
||||
#define AXP192_PWM2_DUTY_CYCLE_2 (0x9d)
|
||||
#define AXP192_N_RSTO_GPIO5_CONTROL (0x9e)
|
||||
|
||||
/* Interrupt control registers */
|
||||
#define AXP192_ENABLE_CONTROL_1 (0x40)
|
||||
#define AXP192_ENABLE_CONTROL_2 (0x41)
|
||||
#define AXP192_ENABLE_CONTROL_3 (0x42)
|
||||
#define AXP192_ENABLE_CONTROL_4 (0x43)
|
||||
#define AXP192_ENABLE_CONTROL_5 (0x4a)
|
||||
#define AXP192_IRQ_STATUS_1 (0x44)
|
||||
#define AXP192_IRQ_STATUS_2 (0x45)
|
||||
#define AXP192_IRQ_STATUS_3 (0x46)
|
||||
#define AXP192_IRQ_STATUS_4 (0x47)
|
||||
#define AXP192_IRQ_STATUS_5 (0x4d)
|
||||
|
||||
/* ADC data registers */
|
||||
#define AXP192_ACIN_VOLTAGE (0x56)
|
||||
#define AXP192_ACIN_CURRENT (0x58)
|
||||
#define AXP192_VBUS_VOLTAGE (0x5a)
|
||||
#define AXP192_VBUS_CURRENT (0x5c)
|
||||
#define AXP192_TEMP (0x5e)
|
||||
#define AXP192_TS_INPUT (0x62)
|
||||
#define AXP192_GPIO0_VOLTAGE (0x64)
|
||||
#define AXP192_GPIO1_VOLTAGE (0x66)
|
||||
#define AXP192_GPIO2_VOLTAGE (0x68)
|
||||
#define AXP192_GPIO3_VOLTAGE (0x6a)
|
||||
#define AXP192_BATTERY_POWER (0x70)
|
||||
#define AXP192_BATTERY_VOLTAGE (0x78)
|
||||
#define AXP192_CHARGE_CURRENT (0x7a)
|
||||
#define AXP192_DISCHARGE_CURRENT (0x7c)
|
||||
#define AXP192_APS_VOLTAGE (0x7e)
|
||||
#define AXP192_CHARGE_COULOMB (0xb0)
|
||||
#define AXP192_DISCHARGE_COULOMB (0xb4)
|
||||
#define AXP192_COULOMB_COUNTER_CONTROL (0xb8)
|
||||
|
||||
/* Computed ADC */
|
||||
#define AXP192_COULOMB_COUNTER (0xff)
|
||||
|
||||
/* IOCTL commands */
|
||||
#define AXP192_READ_POWER_STATUS (0x0001)
|
||||
#define AXP192_READ_CHARGE_STATUS (0x0101)
|
||||
|
||||
#define AXP192_COULOMB_COUNTER_ENABLE (0xb801)
|
||||
#define AXP192_COULOMB_COUNTER_DISABLE (0xb802)
|
||||
#define AXP192_COULOMB_COUNTER_SUSPEND (0xb803)
|
||||
#define AXP192_COULOMB_COUNTER_CLEAR (0xb804)
|
||||
|
||||
#define AXP192_LDOIO0_ENABLE (0x9000)
|
||||
#define AXP192_LDOIO0_DISABLE (0x9001)
|
||||
|
||||
#define AXP192_DCDC2_ENABLE (0x1000)
|
||||
#define AXP192_DCDC2_DISABLE (0x1001)
|
||||
#define AXP192_EXTEN_ENABLE (0x1002)
|
||||
#define AXP192_EXTEN_DISABLE (0x1003)
|
||||
|
||||
#define AXP192_LDO2_ENABLE (0x1200)
|
||||
#define AXP192_LDO2_DISABLE (0x1201)
|
||||
#define AXP192_LDO3_ENABLE (0x1202)
|
||||
#define AXP192_LDO3_DISABLE (0x1203)
|
||||
#define AXP192_DCDC1_ENABLE (0x1204)
|
||||
#define AXP192_DCDC1_DISABLE (0x1205)
|
||||
#define AXP192_DCDC3_ENABLE (0x1206)
|
||||
#define AXP192_DCDC3_DISABLE (0x1207)
|
||||
|
||||
#define AXP192_DCDC1_SET_VOLTAGE (0x2600)
|
||||
#define AXP192_DCDC2_SET_VOLTAGE (0x2300)
|
||||
#define AXP192_DCDC3_SET_VOLTAGE (0x2700)
|
||||
#define AXP192_LDO2_SET_VOLTAGE (0x2800)
|
||||
#define AXP192_LDO3_SET_VOLTAGE (0x2801)
|
||||
#define AXP192_LDOIO0_SET_VOLTAGE (0x9100)
|
||||
|
||||
#define AXP192_LOW (0)
|
||||
#define AXP192_HIGH (1)
|
||||
|
||||
#define AXP192_GPIO0_SET_LEVEL (0x9400)
|
||||
#define AXP192_GPIO1_SET_LEVEL (0x9401)
|
||||
#define AXP192_GPIO2_SET_LEVEL (0x9402)
|
||||
#define AXP192_GPIO4_SET_LEVEL (0x9601)
|
||||
|
||||
/* Error codes */
|
||||
#define AXP192_OK (0)
|
||||
#define AXP192_ERROR_NOTTY (-1)
|
||||
#define AXP192_ERROR_EINVAL (-22)
|
||||
#define AXP192_ERROR_ENOTSUP (-95)
|
||||
|
||||
typedef struct {
|
||||
uint8_t command;
|
||||
uint8_t data[2];
|
||||
uint8_t count;
|
||||
} axp192_init_command_t;
|
||||
|
||||
/* These should be provided by the HAL. */
|
||||
typedef struct {
|
||||
int32_t (* read)(void *handle, uint8_t address, uint8_t reg, uint8_t *buffer, uint16_t size);
|
||||
int32_t (* write)(void *handle, uint8_t address, uint8_t reg, const uint8_t *buffer, uint16_t size);
|
||||
void *handle;
|
||||
} axp192_t;
|
||||
|
||||
typedef int32_t axp192_err_t;
|
||||
|
||||
axp192_err_t axp192_init(const axp192_t *axp);
|
||||
axp192_err_t axp192_read(const axp192_t *axp, uint8_t reg, void *buffer);
|
||||
axp192_err_t axp192_write(const axp192_t *axp, uint8_t reg, uint8_t value);
|
||||
axp192_err_t axp192_ioctl(const axp192_t *axp, int command, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2021 Mika Tuupola
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,4 @@
|
||||
From https://github.com/tuupola/axp192
|
||||
|
||||
Changed some code for Tactility:
|
||||
- `axp192_write()` now accepts a byte value instead of a byte pointer
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2021 Mika Tuupola
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-cut-
|
||||
|
||||
This file is part of hardware agnostic I2C driver for AXP192:
|
||||
https://github.com/tuupola/axp192
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
Version: 0.6.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _AXP192_CONFIG_H
|
||||
#define _AXP192_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef AXP192_INCLUDE_SDKCONFIG_H
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* This requires you to run menuconfig first. */
|
||||
|
||||
#define CONFIG_AXP192_EXTEN_DCDC2_CONTROL ( \
|
||||
CONFIG_AXP192_EXTEN_DCDC2_CONTROL_BIT2 | \
|
||||
CONFIG_AXP192_EXTEN_DCDC2_CONTROL_BIT0 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_DCDC13_LDO23_CONTROL ( \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT6 | \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT4 | \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT3 | \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT2 | \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT1 | \
|
||||
CONFIG_AXP192_DCDC13_LDO23_CONTROL_BIT0 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_LDO23_VOLTAGE ( \
|
||||
CONFIG_AXP192_LDO23_VOLTAGE_BIT74 | \
|
||||
CONFIG_AXP192_LDO23_VOLTAGE_BIT30 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_DCDC1_VOLTAGE ( \
|
||||
CONFIG_AXP192_DCDC1_VOLTAGE_BIT60 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_DCDC3_VOLTAGE ( \
|
||||
CONFIG_AXP192_DCDC3_VOLTAGE_BIT60 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_ADC_ENABLE_1 ( \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT7 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT6 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT5 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT4 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT3 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT2 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT1 | \
|
||||
CONFIG_AXP192_ADC_ENABLE_1_BIT0 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_CHARGE_CONTROL_1 ( \
|
||||
CONFIG_AXP192_CHARGE_CONTROL_1_BIT7 | \
|
||||
CONFIG_AXP192_CHARGE_CONTROL_1_BIT65 | \
|
||||
CONFIG_AXP192_CHARGE_CONTROL_1_BIT4 | \
|
||||
CONFIG_AXP192_CHARGE_CONTROL_1_BIT30 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_BATTERY_CHARGE_CONTROL ( \
|
||||
CONFIG_AXP192_BATTERY_CHARGE_CONTROL_BIT7 | \
|
||||
CONFIG_AXP192_BATTERY_CHARGE_CONTROL_BIT65 | \
|
||||
CONFIG_AXP192_BATTERY_CHARGE_CONTROL_BIT10 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_GPIO0_CONTROL ( \
|
||||
CONFIG_AXP192_GPIO0_CONTROL_BIT20 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_GPIO1_CONTROL ( \
|
||||
CONFIG_AXP192_GPIO1_CONTROL_BIT20 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_GPIO2_CONTROL ( \
|
||||
CONFIG_AXP192_GPIO2_CONTROL_BIT20 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_GPIO43_FUNCTION_CONTROL ( \
|
||||
CONFIG_AXP192_GPIO43_FUNCTION_CONTROL_BIT7 | \
|
||||
CONFIG_AXP192_GPIO43_FUNCTION_CONTROL_BIT32 | \
|
||||
CONFIG_AXP192_GPIO43_FUNCTION_CONTROL_BIT10 \
|
||||
)
|
||||
|
||||
#define CONFIG_AXP192_GPIO0_LDOIO0_VOLTAGE ( \
|
||||
CONFIG_AXP192_GPIO0_LDOIO0_VOLTAGE_BIT74 \
|
||||
)
|
||||
|
||||
#endif /* AXP192_INCLUDE_SDKCONFIG_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
# AXP192
|
||||
|
||||
Power management with I2C interface. Used on M5Stack Core2 and StickCPlus.
|
||||
|
||||
It includes driver code from https://github.com/tuupola/axp192, Copyright (c) 2019-2021 Mika Tuupola, MIT License
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "Axp192.h"
|
||||
|
||||
constexpr auto TAG = "Axp192Power";
|
||||
|
||||
int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buffer, uint16_t size) {
|
||||
const auto* device = static_cast<Axp192*>(handle);
|
||||
if (tt::hal::i2c::masterReadRegister(device->configuration->port, address, reg, buffer, size, device->configuration->readTimeout)) {
|
||||
return AXP192_OK;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Axp192::i2cWrite(void* handle, uint8_t address, uint8_t reg, const uint8_t* buffer, uint16_t size) {
|
||||
const auto* device = static_cast<Axp192*>(handle);
|
||||
if (tt::hal::i2c::masterWriteRegister(device->configuration->port, address, reg, buffer, size, device->configuration->writeTimeout)) {
|
||||
return AXP192_OK;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Axp192::supportsMetric(MetricType type) const {
|
||||
if (!isInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
using enum MetricType;
|
||||
case BatteryVoltage:
|
||||
case ChargeLevel:
|
||||
case IsCharging:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Axp192::getMetric(MetricType type, MetricData& data) {
|
||||
switch (type) {
|
||||
using enum MetricType;
|
||||
case BatteryVoltage: {
|
||||
float voltage;
|
||||
if (axp192_read(&axpDevice, AXP192_BATTERY_VOLTAGE, &voltage) == ESP_OK) {
|
||||
data.valueAsUint32 = (uint32_t)std::max((voltage * 1000.f), 0.0f);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case ChargeLevel: {
|
||||
float vbat, charge_current;
|
||||
if (
|
||||
axp192_read(&axpDevice, AXP192_BATTERY_VOLTAGE, &vbat) == ESP_OK &&
|
||||
axp192_read(&axpDevice, AXP192_CHARGE_CURRENT, &charge_current) == ESP_OK
|
||||
) {
|
||||
float max_voltage = 4.20f;
|
||||
float min_voltage = 2.69f; // From M5Unified
|
||||
float voltage_correction = (charge_current > 0.01f) ? -0.1f : 0.f; // Roughly 0.1V drop when ccharging
|
||||
float corrected_voltage = vbat + voltage_correction;
|
||||
if (corrected_voltage > 2.69f) {
|
||||
float charge_factor = (corrected_voltage - min_voltage) / (max_voltage - min_voltage);
|
||||
data.valueAsUint8 = (uint8_t)(charge_factor * 100.f);
|
||||
} else {
|
||||
data.valueAsUint8 = 0;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case IsCharging: {
|
||||
float charge_current;
|
||||
if (axp192_read(&axpDevice, AXP192_CHARGE_CURRENT, &charge_current) == ESP_OK) {
|
||||
data.valueAsBool = charge_current > 0.001f;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case Current: {
|
||||
float charge_current, discharge_current;
|
||||
if (
|
||||
axp192_read(&axpDevice, AXP192_CHARGE_CURRENT, &charge_current) == ESP_OK &&
|
||||
axp192_read(&axpDevice, AXP192_DISCHARGE_CURRENT, &discharge_current) == ESP_OK
|
||||
) {
|
||||
if (charge_current > 0.0f) {
|
||||
data.valueAsInt32 = (int32_t) (charge_current * 1000.0f);
|
||||
} else {
|
||||
data.valueAsInt32 = -(int32_t) (discharge_current * 1000.0f);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Axp192::isAllowedToCharge() const {
|
||||
uint8_t buffer;
|
||||
if (axp192_read(&axpDevice, AXP192_CHARGE_CONTROL_1, &buffer) == ESP_OK) {
|
||||
return buffer & 0x80;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Axp192::setAllowedToCharge(bool canCharge) {
|
||||
uint8_t buffer;
|
||||
if (axp192_read(&axpDevice, AXP192_CHARGE_CONTROL_1, &buffer) == ESP_OK) {
|
||||
buffer = (buffer & 0x7F) + (canCharge ? 0x80 : 0x00);
|
||||
axp192_write(&axpDevice, AXP192_CHARGE_CONTROL_1, buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2021 Mika Tuupola
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-cut-
|
||||
|
||||
This file is part of hardware agnostic I2C driver for AXP192:
|
||||
https://github.com/tuupola/axp192
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
Version: 0.6.0
|
||||
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "axp192/axp192_config.h"
|
||||
#include "axp192/axp192.h"
|
||||
|
||||
static axp192_err_t read_coloumb_counter(const axp192_t *axp, float *buffer);
|
||||
static axp192_err_t read_battery_power(const axp192_t *axp, float *buffer);
|
||||
|
||||
static const axp192_init_command_t init_commands[] = {
|
||||
#ifdef AXP192_INCLUDE_SDKCONFIG_H
|
||||
/* Currently you have to use menuconfig to be able to use axp192_init() */
|
||||
{AXP192_DCDC1_VOLTAGE, {CONFIG_AXP192_DCDC1_VOLTAGE}, 1},
|
||||
{AXP192_DCDC3_VOLTAGE, {CONFIG_AXP192_DCDC3_VOLTAGE}, 1},
|
||||
{AXP192_LDO23_VOLTAGE, {CONFIG_AXP192_LDO23_VOLTAGE}, 1},
|
||||
{AXP192_GPIO0_LDOIO0_VOLTAGE, {CONFIG_AXP192_GPIO0_LDOIO0_VOLTAGE}, 1},
|
||||
{AXP192_DCDC13_LDO23_CONTROL, {CONFIG_AXP192_DCDC13_LDO23_CONTROL}, 1},
|
||||
{AXP192_EXTEN_DCDC2_CONTROL, {CONFIG_AXP192_EXTEN_DCDC2_CONTROL}, 1},
|
||||
{AXP192_GPIO0_CONTROL, {CONFIG_AXP192_GPIO0_CONTROL}, 1},
|
||||
{AXP192_GPIO1_CONTROL, {CONFIG_AXP192_GPIO1_CONTROL}, 1},
|
||||
{AXP192_GPIO2_CONTROL, {CONFIG_AXP192_GPIO2_CONTROL}, 1},
|
||||
{AXP192_GPIO43_FUNCTION_CONTROL, {CONFIG_AXP192_GPIO43_FUNCTION_CONTROL}, 1},
|
||||
{AXP192_ADC_ENABLE_1, {CONFIG_AXP192_ADC_ENABLE_1}, 1},
|
||||
{AXP192_CHARGE_CONTROL_1, {CONFIG_AXP192_CHARGE_CONTROL_1}, 1},
|
||||
{AXP192_BATTERY_CHARGE_CONTROL, {CONFIG_AXP192_BATTERY_CHARGE_CONTROL}, 1},
|
||||
#endif /* AXP192_INCLUDE_SDKCONFIG_H */
|
||||
/* End of commands. */
|
||||
{0, {0}, 0xff},
|
||||
};
|
||||
|
||||
axp192_err_t axp192_init(const axp192_t *axp)
|
||||
{
|
||||
uint8_t cmd = 0;
|
||||
axp192_err_t status;
|
||||
|
||||
/* Send all the commands. */
|
||||
while (init_commands[cmd].count != 0xff) {
|
||||
status = axp->write(
|
||||
axp->handle,
|
||||
AXP192_ADDRESS,
|
||||
init_commands[cmd].command,
|
||||
init_commands[cmd].data,
|
||||
init_commands[cmd].count & 0x1f
|
||||
);
|
||||
if (AXP192_OK != status) {
|
||||
return status;
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
|
||||
return AXP192_OK;
|
||||
}
|
||||
|
||||
static axp192_err_t axp192_read_adc(const axp192_t *axp, uint8_t reg, float *buffer)
|
||||
{
|
||||
uint8_t tmp[4];
|
||||
float sensitivity = 1.0;
|
||||
float offset = 0.0;
|
||||
axp192_err_t status;
|
||||
|
||||
switch (reg) {
|
||||
case AXP192_ACIN_VOLTAGE:
|
||||
case AXP192_VBUS_VOLTAGE:
|
||||
/* 1.7mV per LSB */
|
||||
sensitivity = 1.7 / 1000;
|
||||
break;
|
||||
case AXP192_ACIN_CURRENT:
|
||||
/* 0.375mA per LSB */
|
||||
sensitivity = 0.625 / 1000;
|
||||
break;
|
||||
case AXP192_VBUS_CURRENT:
|
||||
/* 0.375mA per LSB */
|
||||
sensitivity = 0.375 / 1000;
|
||||
break;
|
||||
case AXP192_TEMP:
|
||||
/* 0.1C per LSB, 0x00 = -144.7C */
|
||||
sensitivity = 0.1;
|
||||
offset = -144.7;
|
||||
break;
|
||||
case AXP192_TS_INPUT:
|
||||
/* 0.8mV per LSB */
|
||||
sensitivity = 0.8 / 1000;
|
||||
break;
|
||||
case AXP192_BATTERY_POWER:
|
||||
/* 1.1mV * 0.5mA per LSB */
|
||||
return read_battery_power(axp, buffer);
|
||||
break;
|
||||
case AXP192_BATTERY_VOLTAGE:
|
||||
/* 1.1mV per LSB */
|
||||
sensitivity = 1.1 / 1000;
|
||||
break;
|
||||
case AXP192_CHARGE_CURRENT:
|
||||
case AXP192_DISCHARGE_CURRENT:
|
||||
/* 0.5mV per LSB */
|
||||
sensitivity = 0.5 / 1000;
|
||||
break;
|
||||
case AXP192_APS_VOLTAGE:
|
||||
/* 1.4mV per LSB */
|
||||
sensitivity = 1.4 / 1000;
|
||||
break;
|
||||
case AXP192_COULOMB_COUNTER:
|
||||
/* This is currently untested. */
|
||||
return read_coloumb_counter(axp, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
status = axp->read(axp->handle, AXP192_ADDRESS, reg, tmp, 2);
|
||||
if (AXP192_OK != status) {
|
||||
return status;
|
||||
}
|
||||
*buffer = (((tmp[0] << 4) + tmp[1]) * sensitivity) + offset;
|
||||
|
||||
return AXP192_OK;
|
||||
}
|
||||
|
||||
axp192_err_t axp192_read(const axp192_t *axp, uint8_t reg, void *buffer) {
|
||||
switch (reg) {
|
||||
case AXP192_ACIN_VOLTAGE:
|
||||
case AXP192_VBUS_VOLTAGE:
|
||||
case AXP192_ACIN_CURRENT:
|
||||
case AXP192_VBUS_CURRENT:
|
||||
case AXP192_TEMP:
|
||||
case AXP192_TS_INPUT:
|
||||
case AXP192_BATTERY_POWER:
|
||||
case AXP192_BATTERY_VOLTAGE:
|
||||
case AXP192_CHARGE_CURRENT:
|
||||
case AXP192_DISCHARGE_CURRENT:
|
||||
case AXP192_APS_VOLTAGE:
|
||||
case AXP192_COULOMB_COUNTER:
|
||||
/* Return ADC value. */
|
||||
return axp192_read_adc(axp, reg, buffer);
|
||||
break;
|
||||
default:
|
||||
/* Return raw register value. */
|
||||
return axp->read(axp->handle, AXP192_ADDRESS, reg, buffer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
axp192_err_t axp192_write(const axp192_t *axp, uint8_t reg, uint8_t value) {
|
||||
switch (reg) {
|
||||
case AXP192_ACIN_VOLTAGE:
|
||||
case AXP192_VBUS_VOLTAGE:
|
||||
case AXP192_ACIN_CURRENT:
|
||||
case AXP192_VBUS_CURRENT:
|
||||
case AXP192_TEMP:
|
||||
case AXP192_TS_INPUT:
|
||||
case AXP192_BATTERY_POWER:
|
||||
case AXP192_BATTERY_VOLTAGE:
|
||||
case AXP192_CHARGE_CURRENT:
|
||||
case AXP192_DISCHARGE_CURRENT:
|
||||
case AXP192_APS_VOLTAGE:
|
||||
case AXP192_COULOMB_COUNTER:
|
||||
/* Read only register. */
|
||||
return AXP192_ERROR_ENOTSUP;
|
||||
break;
|
||||
default:
|
||||
/* Write raw register value. */
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
axp192_err_t axp192_ioctl(const axp192_t *axp, int command, ...)
|
||||
{
|
||||
uint8_t reg = command >> 8;
|
||||
uint8_t tmp;
|
||||
uint16_t argument;
|
||||
va_list ap;
|
||||
|
||||
switch (command) {
|
||||
case AXP192_COULOMB_COUNTER_ENABLE:
|
||||
tmp = 0b10000000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_COULOMB_COUNTER_DISABLE:
|
||||
tmp = 0b00000000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_COULOMB_COUNTER_SUSPEND:
|
||||
tmp = 0b11000000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_COULOMB_COUNTER_CLEAR:
|
||||
tmp = 0b10100000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_LDOIO0_ENABLE:
|
||||
/* 0x02 = LDO */
|
||||
tmp = 0b00000010;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_LDOIO0_DISABLE:
|
||||
/* 0x07 = float */
|
||||
tmp = 0b00000111;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_LDO2_ENABLE:
|
||||
/* This is currently untested. */
|
||||
case AXP192_EXTEN_ENABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp |= 0b00000100;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_LDO2_DISABLE:
|
||||
/* This is currently untested. */
|
||||
case AXP192_EXTEN_DISABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp &= ~0b00000100;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_GPIO2_SET_LEVEL:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
va_start(ap, command);
|
||||
argument = (uint8_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
if (argument) {
|
||||
tmp |= 0b00000100;
|
||||
} else {
|
||||
tmp &= ~0b00000100;
|
||||
}
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_LDO3_ENABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp |= 0b00001000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_LDO3_DISABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp &= ~0b00001000;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_DCDC1_ENABLE:
|
||||
/* This is currently untested. */
|
||||
case AXP192_DCDC2_ENABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp |= 0b00000001;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_DCDC1_DISABLE:
|
||||
/* This is currently untested. */
|
||||
case AXP192_DCDC2_DISABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp &= ~0b00000001;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_DCDC3_ENABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp |= 0b00000010;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_DCDC3_DISABLE:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
tmp &= ~0b00000010;
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_GPIO1_SET_LEVEL:
|
||||
case AXP192_GPIO4_SET_LEVEL:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
va_start(ap, command);
|
||||
argument = (uint8_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
if (argument) {
|
||||
tmp |= 0b00000010;
|
||||
} else {
|
||||
tmp &= ~0b00000010;
|
||||
}
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_GPIO0_SET_LEVEL:
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
va_start(ap, command);
|
||||
argument = (uint8_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
if (argument) {
|
||||
tmp |= 0b00000001;
|
||||
} else {
|
||||
tmp &= ~0b00000001;
|
||||
}
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
case AXP192_DCDC1_SET_VOLTAGE:
|
||||
case AXP192_DCDC3_SET_VOLTAGE:
|
||||
va_start(ap, command);
|
||||
argument = (uint16_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
/* 700-3500mv 25mV per step */
|
||||
if ((argument < 700) || (argument > 3500)) {
|
||||
return AXP192_ERROR_EINVAL;
|
||||
}
|
||||
tmp = (argument - 700) / 25;
|
||||
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_DCDC2_SET_VOLTAGE:
|
||||
va_start(ap, command);
|
||||
argument = (uint16_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
/* 700-2275mV 25mV per step */
|
||||
if ((argument < 700) || (argument > 2275)) {
|
||||
return AXP192_ERROR_EINVAL;
|
||||
}
|
||||
tmp = (argument - 700) / 25;
|
||||
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_LDO2_SET_VOLTAGE:
|
||||
va_start(ap, command);
|
||||
argument = (uint16_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
/* 1800-3300mV 100mV per step */
|
||||
if ((argument < 1800) || (argument > 3300)) {
|
||||
return AXP192_ERROR_EINVAL;
|
||||
}
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
|
||||
tmp &= ~0xf0;
|
||||
tmp |= (((argument - 1800) / 100) << 4);
|
||||
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_LDO3_SET_VOLTAGE:
|
||||
va_start(ap, command);
|
||||
argument = (uint16_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
/* 1800-3300mV 100mV per step */
|
||||
if ((argument < 1800) || (argument > 3300)) {
|
||||
return AXP192_ERROR_EINVAL;
|
||||
}
|
||||
axp->read(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
|
||||
tmp &= ~0x0f;
|
||||
tmp |= ((argument - 1800) / 100);
|
||||
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
/* This is currently untested. */
|
||||
case AXP192_LDOIO0_SET_VOLTAGE:
|
||||
va_start(ap, command);
|
||||
argument = (uint16_t) va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
/* 1800-3300mV 100mV per step, 2800mV default. */
|
||||
if ((argument < 1800) || (argument > 3300)) {
|
||||
return AXP192_ERROR_EINVAL;
|
||||
}
|
||||
tmp = (((argument - 1800) / 100) << 4);
|
||||
|
||||
return axp->write(axp->handle, AXP192_ADDRESS, reg, &tmp, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
return AXP192_ERROR_NOTTY;
|
||||
}
|
||||
|
||||
static axp192_err_t read_coloumb_counter(const axp192_t *axp, float *buffer)
|
||||
{
|
||||
uint8_t tmp[4];
|
||||
int32_t coin, coout;
|
||||
axp192_err_t status;
|
||||
|
||||
status = axp->read(axp->handle, AXP192_ADDRESS, AXP192_CHARGE_COULOMB, tmp, sizeof(coin));
|
||||
if (AXP192_OK != status) {
|
||||
return status;
|
||||
}
|
||||
coin = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3];
|
||||
|
||||
status = axp->read(axp->handle, AXP192_ADDRESS, AXP192_DISCHARGE_COULOMB, tmp, sizeof(coout));
|
||||
if (AXP192_OK != status) {
|
||||
return status;
|
||||
}
|
||||
coout = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3];
|
||||
|
||||
/* CmAh = 65536 * 0.5mA *(coin - cout) / 3600 / ADC sample rate */
|
||||
*buffer = 32768 * (coin - coout) / 3600 / 25;
|
||||
|
||||
return AXP192_OK;
|
||||
}
|
||||
|
||||
static axp192_err_t read_battery_power(const axp192_t *axp, float *buffer)
|
||||
{
|
||||
uint8_t tmp[4];
|
||||
float sensitivity;
|
||||
axp192_err_t status;
|
||||
|
||||
/* 1.1mV * 0.5mA per LSB */
|
||||
sensitivity = 1.1 * 0.5 / 1000;
|
||||
status = axp->read(axp->handle, AXP192_ADDRESS, AXP192_BATTERY_POWER, tmp, 3);
|
||||
if (AXP192_OK != status) {
|
||||
return status;
|
||||
}
|
||||
*buffer = (((tmp[0] << 16) + (tmp[1] << 8) + tmp[2]) * sensitivity);
|
||||
return AXP192_OK;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS "Source"
|
||||
REQUIRES Tactility esp_lvgl_port driver
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Button Control
|
||||
|
||||
A driver for navigating apps with 1 or more GPIO buttons.
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "ButtonControl.h"
|
||||
|
||||
#include <Tactility/Log.h>
|
||||
|
||||
#include <esp_lvgl_port.h>
|
||||
|
||||
constexpr auto* TAG = "ButtonControl";
|
||||
|
||||
ButtonControl::ButtonControl(const std::vector<PinConfiguration>& pinConfigurations) : pinConfigurations(pinConfigurations) {
|
||||
pinStates.resize(pinConfigurations.size());
|
||||
for (const auto& pinConfiguration : pinConfigurations) {
|
||||
tt::hal::gpio::configure(pinConfiguration.pin, tt::hal::gpio::Mode::Input, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
ButtonControl::~ButtonControl() {
|
||||
if (driverThread != nullptr && driverThread->getState() != tt::Thread::State::Stopped) {
|
||||
interruptDriverThread = true;
|
||||
driverThread->join();
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonControl::readCallback(lv_indev_t* indev, lv_indev_data_t* data) {
|
||||
// Defaults
|
||||
data->enc_diff = 0;
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
|
||||
auto* self = static_cast<ButtonControl*>(lv_indev_get_driver_data(indev));
|
||||
|
||||
if (self->mutex.lock(100)) {
|
||||
|
||||
for (int i = 0; i < self->pinConfigurations.size(); i++) {
|
||||
const auto& config = self->pinConfigurations[i];
|
||||
std::vector<PinState>::reference state = self->pinStates[i];
|
||||
const bool trigger = (config.event == Event::ShortPress && state.triggerShortPress) ||
|
||||
(config.event == Event::LongPress && state.triggerLongPress);
|
||||
state.triggerShortPress = false;
|
||||
state.triggerLongPress = false;
|
||||
if (trigger) {
|
||||
switch (config.action) {
|
||||
case Action::UiSelectNext:
|
||||
data->enc_diff = 1;
|
||||
break;
|
||||
case Action::UiSelectPrevious:
|
||||
data->enc_diff = -1;
|
||||
break;
|
||||
case Action::UiPressSelected:
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
break;
|
||||
case Action::AppClose:
|
||||
// TODO: implement
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonControl::updatePin(std::vector<PinConfiguration>::const_reference configuration, std::vector<PinState>::reference state) {
|
||||
if (tt::hal::gpio::getLevel(configuration.pin)) { // if pressed
|
||||
if (state.pressState) {
|
||||
// check time for long press trigger
|
||||
auto time_passed = tt::kernel::getMillis() - state.pressStartTime;
|
||||
if (time_passed > 500) {
|
||||
// state.triggerLongPress = true;
|
||||
}
|
||||
} else {
|
||||
state.pressStartTime = tt::kernel::getMillis();
|
||||
state.pressState = true;
|
||||
}
|
||||
} else { // released
|
||||
if (state.pressState) {
|
||||
auto time_passed = tt::kernel::getMillis() - state.pressStartTime;
|
||||
if (time_passed < 500) {
|
||||
TT_LOG_D(TAG, "Trigger short press");
|
||||
state.triggerShortPress = true;
|
||||
}
|
||||
state.pressState = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonControl::driverThreadMain() {
|
||||
while (!shouldInterruptDriverThread()) {
|
||||
if (mutex.lock(100)) {
|
||||
for (int i = 0; i < pinConfigurations.size(); i++) {
|
||||
updatePin(pinConfigurations[i], pinStates[i]);
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
tt::kernel::delayMillis(5);
|
||||
}
|
||||
}
|
||||
|
||||
bool ButtonControl::shouldInterruptDriverThread() const {
|
||||
bool interrupt = false;
|
||||
if (mutex.lock(50 / portTICK_PERIOD_MS)) {
|
||||
interrupt = interruptDriverThread;
|
||||
mutex.unlock();
|
||||
}
|
||||
return interrupt;
|
||||
}
|
||||
|
||||
void ButtonControl::startThread() {
|
||||
TT_LOG_I(TAG, "Start");
|
||||
|
||||
mutex.lock();
|
||||
|
||||
interruptDriverThread = false;
|
||||
|
||||
driverThread = std::make_shared<tt::Thread>("ButtonControl", 4096, [this] {
|
||||
driverThreadMain();
|
||||
return 0;
|
||||
});
|
||||
|
||||
driverThread->start();
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void ButtonControl::stopThread() {
|
||||
TT_LOG_I(TAG, "Stop");
|
||||
|
||||
mutex.lock();
|
||||
interruptDriverThread = true;
|
||||
mutex.unlock();
|
||||
|
||||
driverThread->join();
|
||||
|
||||
mutex.lock();
|
||||
driverThread = nullptr;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
bool ButtonControl::startLvgl(lv_display_t* display) {
|
||||
if (deviceHandle != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
startThread();
|
||||
|
||||
deviceHandle = lv_indev_create();
|
||||
lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_ENCODER);
|
||||
lv_indev_set_driver_data(deviceHandle, this);
|
||||
lv_indev_set_read_cb(deviceHandle, readCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ButtonControl::stopLvgl() {
|
||||
if (deviceHandle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_indev_delete(deviceHandle);
|
||||
deviceHandle = nullptr;
|
||||
|
||||
stopThread();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/encoder/EncoderDevice.h>
|
||||
#include <Tactility/hal/gpio/Gpio.h>
|
||||
#include <Tactility/TactilityCore.h>
|
||||
|
||||
class ButtonControl final : public tt::hal::encoder::EncoderDevice {
|
||||
|
||||
public:
|
||||
|
||||
enum class Event {
|
||||
ShortPress,
|
||||
LongPress
|
||||
};
|
||||
|
||||
enum class Action {
|
||||
UiSelectNext,
|
||||
UiSelectPrevious,
|
||||
UiPressSelected,
|
||||
AppClose,
|
||||
};
|
||||
|
||||
struct PinConfiguration {
|
||||
tt::hal::gpio::Pin pin;
|
||||
Event event;
|
||||
Action action;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct PinState {
|
||||
long pressStartTime = 0;
|
||||
long pressReleaseTime = 0;
|
||||
bool pressState = false;
|
||||
bool triggerShortPress = false;
|
||||
bool triggerLongPress = false;
|
||||
};
|
||||
|
||||
lv_indev_t* _Nullable deviceHandle = nullptr;
|
||||
std::shared_ptr<tt::Thread> driverThread;
|
||||
bool interruptDriverThread = false;
|
||||
tt::Mutex mutex;
|
||||
std::vector<PinConfiguration> pinConfigurations;
|
||||
std::vector<PinState> pinStates;
|
||||
|
||||
bool shouldInterruptDriverThread() const;
|
||||
|
||||
static void updatePin(std::vector<PinConfiguration>::const_reference value, std::vector<PinState>::reference pin_state);
|
||||
|
||||
void driverThreadMain();
|
||||
|
||||
static void readCallback(lv_indev_t* indev, lv_indev_data_t* data);
|
||||
|
||||
void startThread();
|
||||
void stopThread();
|
||||
|
||||
public:
|
||||
|
||||
explicit ButtonControl(const std::vector<PinConfiguration>& pinConfigurations);
|
||||
|
||||
~ButtonControl() override;
|
||||
|
||||
std::string getName() const override { return "ButtonControl"; }
|
||||
std::string getDescription() const override { return "ButtonControl input driver"; }
|
||||
|
||||
bool startLvgl(lv_display_t* display) override;
|
||||
bool stopLvgl() override;
|
||||
|
||||
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
|
||||
|
||||
static std::shared_ptr<ButtonControl> createOneButtonControl(tt::hal::gpio::Pin pin) {
|
||||
return std::make_shared<ButtonControl>(std::vector {
|
||||
PinConfiguration {
|
||||
.pin = pin,
|
||||
.event = Event::ShortPress,
|
||||
.action = Action::UiSelectNext
|
||||
},
|
||||
PinConfiguration {
|
||||
.pin = pin,
|
||||
.event = Event::LongPress,
|
||||
.action = Action::UiPressSelected
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static std::shared_ptr<ButtonControl> createTwoButtonControl(tt::hal::gpio::Pin primaryPin, tt::hal::gpio::Pin secondaryPin) {
|
||||
return std::make_shared<ButtonControl>(std::vector {
|
||||
PinConfiguration {
|
||||
.pin = primaryPin,
|
||||
.event = Event::ShortPress,
|
||||
.action = Action::UiPressSelected
|
||||
},
|
||||
PinConfiguration {
|
||||
.pin = primaryPin,
|
||||
.event = Event::LongPress,
|
||||
.action = Action::AppClose
|
||||
},
|
||||
PinConfiguration {
|
||||
.pin = secondaryPin,
|
||||
.event = Event::ShortPress,
|
||||
.action = Action::UiSelectNext
|
||||
},
|
||||
PinConfiguration {
|
||||
.pin = secondaryPin,
|
||||
.event = Event::LongPress,
|
||||
.action = Action::UiSelectPrevious
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRC_DIRS "Source"
|
||||
INCLUDE_DIRS "Source"
|
||||
REQUIRES Tactility driver EspLcdCompat esp_lcd_st7735
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
# ST7735
|
||||
|
||||
A basic ESP32 LVGL driver for ST7735 displays.
|
||||
@@ -0,0 +1,170 @@
|
||||
#include "St7735Display.h"
|
||||
|
||||
#include <Tactility/Log.h>
|
||||
|
||||
#include <esp_lcd_panel_commands.h>
|
||||
#include <esp_lcd_panel_dev.h>
|
||||
#include <esp_lcd_st7735.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
|
||||
constexpr auto TAG = "ST7735";
|
||||
|
||||
bool St7735Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
|
||||
TT_LOG_I(TAG, "Starting");
|
||||
|
||||
const esp_lcd_panel_io_spi_config_t panel_io_config = {
|
||||
.cs_gpio_num = configuration->csPin,
|
||||
.dc_gpio_num = configuration->dcPin,
|
||||
.spi_mode = 0,
|
||||
.pclk_hz = configuration->pixelClockFrequency,
|
||||
.trans_queue_depth = configuration->transactionQueueDepth,
|
||||
.on_color_trans_done = nullptr,
|
||||
.user_ctx = nullptr,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.cs_ena_pretrans = 0,
|
||||
.cs_ena_posttrans = 0,
|
||||
.flags = {
|
||||
.dc_high_on_cmd = 0,
|
||||
.dc_low_on_data = 0,
|
||||
.dc_low_on_param = 0,
|
||||
.octal_mode = 0,
|
||||
.quad_mode = 0,
|
||||
.sio_mode = 1,
|
||||
.lsb_first = 0,
|
||||
.cs_high_active = 0
|
||||
}
|
||||
};
|
||||
|
||||
if (esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to create panel");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool St7735Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
|
||||
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = configuration->resetPin,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
||||
.bits_per_pixel = 16,
|
||||
.flags = {
|
||||
.reset_active_high = false
|
||||
},
|
||||
.vendor_config = nullptr
|
||||
};
|
||||
|
||||
if (esp_lcd_new_panel_st7735(ioHandle, &panel_config, &panelHandle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to create panel");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_reset(panelHandle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to reset panel");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_init(panelHandle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to init panel");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to set panel to invert");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Warning: it looks like LVGL rotation is broken when "gap" is set and the screen is moved to a non-default orientation
|
||||
int gap_x = configuration->swapXY ? configuration->gapY : configuration->gapX;
|
||||
int gap_y = configuration->swapXY ? configuration->gapX : configuration->gapY;
|
||||
if (esp_lcd_panel_set_gap(panelHandle, gap_x, gap_y) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to set panel gap");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to swap XY ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to set panel to mirror");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to turn display on");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
lvgl_port_display_cfg_t St7735Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
|
||||
return lvgl_port_display_cfg_t {
|
||||
.io_handle = ioHandle,
|
||||
.panel_handle = panelHandle,
|
||||
.control_handle = nullptr,
|
||||
.buffer_size = configuration->bufferSize,
|
||||
.double_buffer = false,
|
||||
.trans_size = 0,
|
||||
.hres = configuration->horizontalResolution,
|
||||
.vres = configuration->verticalResolution,
|
||||
.monochrome = false,
|
||||
.rotation = {
|
||||
.swap_xy = configuration->swapXY,
|
||||
.mirror_x = configuration->mirrorX,
|
||||
.mirror_y = configuration->mirrorY,
|
||||
},
|
||||
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||
.flags = {
|
||||
.buff_dma = true,
|
||||
.buff_spiram = false,
|
||||
.sw_rotate = false,
|
||||
.swap_bytes = true,
|
||||
.full_refresh = false,
|
||||
.direct_mode = false
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Note:
|
||||
* The datasheet implies this should work, but it doesn't:
|
||||
* https://www.digikey.com/htmldatasheets/production/1640716/0/0/1/ILI9341-Datasheet.pdf
|
||||
*
|
||||
* This repo claims it only has 1 curve:
|
||||
* https://github.com/brucemack/hello-ili9341
|
||||
*
|
||||
* I'm leaving it in as I'm not sure if it's just my hardware that's problematic.
|
||||
*/
|
||||
void St7735Display::setGammaCurve(uint8_t index) {
|
||||
uint8_t gamma_curve;
|
||||
switch (index) {
|
||||
case 0:
|
||||
gamma_curve = 0x01;
|
||||
break;
|
||||
case 1:
|
||||
gamma_curve = 0x04;
|
||||
break;
|
||||
case 2:
|
||||
gamma_curve = 0x02;
|
||||
break;
|
||||
case 3:
|
||||
gamma_curve = 0x08;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
const uint8_t param[] = {
|
||||
gamma_curve
|
||||
};
|
||||
|
||||
auto io_handle = getIoHandle();
|
||||
assert(io_handle != nullptr);
|
||||
if (esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_GAMSET, param, 1) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to set gamma");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tactility/hal/spi/Spi.h"
|
||||
|
||||
#include <EspLcdDisplay.h>
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_types.h>
|
||||
#include <functional>
|
||||
#include <lvgl.h>
|
||||
|
||||
class St7735Display final : public EspLcdDisplay {
|
||||
|
||||
std::shared_ptr<tt::Lock> lock;
|
||||
|
||||
public:
|
||||
|
||||
class Configuration {
|
||||
|
||||
public:
|
||||
|
||||
Configuration(
|
||||
spi_host_device_t spiHostDevice,
|
||||
gpio_num_t csPin,
|
||||
gpio_num_t dcPin,
|
||||
gpio_num_t resetPin,
|
||||
unsigned int horizontalResolution,
|
||||
unsigned int verticalResolution,
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> touch,
|
||||
bool swapXY = false,
|
||||
bool mirrorX = false,
|
||||
bool mirrorY = false,
|
||||
bool invertColor = false,
|
||||
uint32_t bufferSize = 0, // Size in pixel count. 0 means default, which is 1/10 of the screen size
|
||||
int gapX = 0,
|
||||
int gapY = 0
|
||||
) : spiHostDevice(spiHostDevice),
|
||||
csPin(csPin),
|
||||
dcPin(dcPin),
|
||||
resetPin(resetPin),
|
||||
horizontalResolution(horizontalResolution),
|
||||
verticalResolution(verticalResolution),
|
||||
gapX(gapX),
|
||||
gapY(gapY),
|
||||
swapXY(swapXY),
|
||||
mirrorX(mirrorX),
|
||||
mirrorY(mirrorY),
|
||||
invertColor(invertColor),
|
||||
bufferSize(bufferSize),
|
||||
touch(std::move(touch))
|
||||
{
|
||||
if (this->bufferSize == 0) {
|
||||
this->bufferSize = horizontalResolution * verticalResolution / 10;
|
||||
}
|
||||
}
|
||||
|
||||
spi_host_device_t spiHostDevice;
|
||||
gpio_num_t csPin;
|
||||
gpio_num_t dcPin;
|
||||
gpio_num_t resetPin = GPIO_NUM_NC;
|
||||
unsigned int pixelClockFrequency = 27'000'000; // Hertz
|
||||
size_t transactionQueueDepth = 10;
|
||||
unsigned int horizontalResolution;
|
||||
unsigned int verticalResolution;
|
||||
int gapX;
|
||||
int gapY;
|
||||
bool swapXY = false;
|
||||
bool mirrorX = false;
|
||||
bool mirrorY = false;
|
||||
bool invertColor = false;
|
||||
uint32_t bufferSize = 0; // Size in pixel count. 0 means default, which is 1/10 of the screen size
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
|
||||
std::function<void(uint8_t)> _Nullable backlightDutyFunction = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Configuration> configuration;
|
||||
|
||||
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
|
||||
|
||||
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
|
||||
|
||||
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
|
||||
|
||||
public:
|
||||
|
||||
explicit St7735Display(std::unique_ptr<Configuration> inConfiguration) :
|
||||
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
|
||||
configuration(std::move(inConfiguration)
|
||||
) {
|
||||
assert(configuration != nullptr);
|
||||
assert(getLock() != nullptr);
|
||||
}
|
||||
|
||||
std::string getName() const override { return "ST7735"; }
|
||||
|
||||
std::string getDescription() const override { return "ST7735 display"; }
|
||||
|
||||
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
|
||||
|
||||
void setBacklightDuty(uint8_t backlightDuty) override {
|
||||
if (configuration->backlightDutyFunction != nullptr) {
|
||||
configuration->backlightDutyFunction(backlightDuty);
|
||||
}
|
||||
}
|
||||
|
||||
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
|
||||
|
||||
void setGammaCurve(uint8_t index) override;
|
||||
uint8_t getGammaCurveCount() const override { return 4; };
|
||||
};
|
||||
|
||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
|
||||
Reference in New Issue
Block a user