Files
2026-08-03 20:31:28 -07:00

81 lines
2.3 KiB
C

/*
* STC8H1K28 board controller, CrowPanel 7" Advance v1.3.
*
* A small 8051-class MCU sitting on the I2C bus at 0x30. It drives the LCD
* backlight and, critically, the GT911 reset line -- there is no ESP32 GPIO
* for touch reset on this board, so the GT911 stays mute until the sequence
* below has run.
*
* Protocol is single raw bytes, no register addressing:
* 0x19 wake
* 0x10, 0x18 configure / release GT911 from reset
* 0x00 - 0xF5 brightness, INVERTED (0x00 = full, 0xF5 = off)
*
* v1.2 boards use a different, narrower range (0x05 = off .. 0x10 = max).
*/
#include "esp_check.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "backlight.h"
#include "i2c_bus.h"
static const char *TAG = "backlight";
#define STC8_ADDR 0x30
#define STC8_I2C_HZ 100000
#define STC8_TIMEOUT_MS 100
#define STC8_CMD_WAKE 0x19
#define STC8_CMD_CFG1 0x10
#define STC8_CMD_CFG2 0x18
/* Inverted brightness range. */
#define STC8_DUTY_MAX_ON 0x00
#define STC8_DUTY_OFF 0xF5
static i2c_master_dev_handle_t dev = NULL;
static esp_err_t stc8_cmd(uint8_t cmd)
{
return i2c_master_transmit(dev, &cmd, 1, STC8_TIMEOUT_MS);
}
esp_err_t backlight_init(void)
{
const i2c_device_config_t cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = STC8_ADDR,
.scl_speed_hz = STC8_I2C_HZ,
};
ESP_RETURN_ON_ERROR(i2c_master_bus_add_device(i2c_bus_get(), &cfg, &dev), TAG,
"could not add STC8H1K28 at 0x%02X", STC8_ADDR);
ESP_RETURN_ON_ERROR(stc8_cmd(STC8_CMD_WAKE), TAG, "wake failed");
vTaskDelay(pdMS_TO_TICKS(10));
/* These two also release the GT911 from reset. */
ESP_RETURN_ON_ERROR(stc8_cmd(STC8_CMD_CFG1), TAG, "config 1 failed");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(stc8_cmd(STC8_CMD_CFG2), TAG, "config 2 failed");
vTaskDelay(pdMS_TO_TICKS(100));
ESP_LOGI(TAG, "STC8H1K28 initialized (GT911 released from reset)");
return ESP_OK;
}
esp_err_t backlight_set(uint8_t brightness)
{
if (dev == NULL) {
return ESP_ERR_INVALID_STATE;
}
/* Map 0..255 (intuitive) onto 0xF5..0x00 (wire, inverted). */
const uint8_t duty = (uint8_t)(STC8_DUTY_OFF -
((uint32_t)brightness * STC8_DUTY_OFF) / 255);
return stc8_cmd(duty);
}