/* * 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); }